| @@ -1,5 +1,5 @@ | |||
| // import { Link } from 'react-router-dom'; | |||
| import React, { useState } from 'react'; | |||
| import React, { useState, useRef } from 'react'; | |||
| // material-ui | |||
| import { | |||
| @@ -31,6 +31,7 @@ const BusRegister = () => { | |||
| const [activeStep, setActiveStep] = useState(0); | |||
| const [completed, setCompleted] = useState([false]); | |||
| const [updateValid, setUpdateValid] = useState(false); | |||
| const step0GuardRef = useRef(null); | |||
| const [username, setUsername] = useState("") | |||
| const [base64Url, setBase64Url] = useState("") | |||
| const [checkCode, setCheckCode] = useState("") | |||
| @@ -97,6 +98,12 @@ const BusRegister = () => { | |||
| } | |||
| const handleNext = async () => { | |||
| if (activeStep === 0 && step0GuardRef.current) { | |||
| const step0Ok = await Promise.resolve(step0GuardRef.current()); | |||
| if (!step0Ok) { | |||
| return; | |||
| } | |||
| } | |||
| const captchaTest = await handleCaptcha(); | |||
| if (!captchaTest) { | |||
| notifyActionError(intl.formatMessage({id: 'validVerify'})) | |||
| @@ -193,6 +200,7 @@ const BusRegister = () => { | |||
| <AuthWrapper> | |||
| <CustomFormWizard | |||
| setUpdateValid={setUpdateValid} | |||
| step0GuardRef={step0GuardRef} | |||
| step={activeStep} | |||
| setUsername={setUsername} | |||
| setBase64Url={setBase64Url} | |||
| @@ -1,7 +1,7 @@ | |||
| // import { Link } from 'react-router-dom'; | |||
| import React, { | |||
| useState | |||
| // ,useEffect | |||
| useState, | |||
| useRef, | |||
| } from 'react'; | |||
| // material-ui | |||
| @@ -54,6 +54,7 @@ const Register = () => { | |||
| const [activeStep, setActiveStep] = useState(0); | |||
| const [completed, setCompleted] = useState([false]); | |||
| const [updateValid, setUpdateValid] = useState(false); | |||
| const step0GuardRef = useRef(null); | |||
| const [base64Url, setBase64Url] = useState("") | |||
| const [checkCode, setCheckCode] = useState("") | |||
| const [idNo, setIdNo] = useState(""); | |||
| @@ -102,6 +103,12 @@ const Register = () => { | |||
| notifyActionError(intl.formatMessage({id: 'iAmSmartNoIdNoMsg'})) | |||
| return; | |||
| } | |||
| if (activeStep === 0 && step0GuardRef.current) { | |||
| const step0Ok = await Promise.resolve(step0GuardRef.current()); | |||
| if (!step0Ok) { | |||
| return; | |||
| } | |||
| } | |||
| const captchaTest = await handleCaptcha(); | |||
| if (!captchaTest) { | |||
| notifyActionError(intl.formatMessage({id: 'validVerify'})) | |||
| @@ -184,6 +191,7 @@ const Register = () => { | |||
| <CustomFormWizard | |||
| id={"CustomFormWizard"} | |||
| setUpdateValid={setUpdateValid} | |||
| step0GuardRef={step0GuardRef} | |||
| step={activeStep} | |||
| setIdNo={setIdNo} | |||
| setBase64Url={setBase64Url} | |||
| @@ -1,7 +1,7 @@ | |||
| // import { Link } from 'react-router-dom'; | |||
| import React, { | |||
| useState | |||
| // ,useEffect | |||
| useState, | |||
| useRef, | |||
| } from 'react'; | |||
| // material-ui | |||
| @@ -32,6 +32,7 @@ const Register = () => { | |||
| const [activeStep, setActiveStep] = useState(0); | |||
| const [completed, setCompleted] = useState([false]); | |||
| const [updateValid, setUpdateValid] = useState(false); | |||
| const step0GuardRef = useRef(null); | |||
| const [username, setUsername] = useState(""); | |||
| const [base64Url, setBase64Url] = useState("") | |||
| const [checkCode, setCheckCode] = useState("") | |||
| @@ -101,6 +102,12 @@ const Register = () => { | |||
| const handleNext = async () => { | |||
| if (activeStep === 0 && step0GuardRef.current) { | |||
| const step0Ok = await Promise.resolve(step0GuardRef.current()); | |||
| if (!step0Ok) { | |||
| return; | |||
| } | |||
| } | |||
| const captchaTest = await handleCaptcha(); | |||
| if (!captchaTest) { | |||
| @@ -198,6 +205,7 @@ const Register = () => { | |||
| <AuthWrapper> | |||
| <CustomFormWizard | |||
| setUpdateValid={setUpdateValid} | |||
| step0GuardRef={step0GuardRef} | |||
| step={activeStep} | |||
| setUsername={setUsername} | |||
| setBase64Url={setBase64Url} | |||
| @@ -220,7 +220,14 @@ const BusCustomFormWizard = (props) => { | |||
| } | |||
| }, [checkDistrictBlur]) | |||
| const handleCheckDistrict = async () => { | |||
| const isDistrictSelectionValid = () => { | |||
| if (selectedAddress5?.type !== "hongKong") { | |||
| return true; | |||
| } | |||
| return !(selectedAddress4 == null || selectedAddress4 === ""); | |||
| }; | |||
| const handleCheckDistrict = () => { | |||
| setDistrictErrStr(""); | |||
| if (selectedAddress5?.type === "hongKong") { | |||
| if (selectedAddress4 == null || selectedAddress4 == "" || selectedAddress4 == {}){ | |||
| @@ -229,9 +236,15 @@ const BusCustomFormWizard = (props) => { | |||
| }else { | |||
| setCheckDistrict(false) | |||
| } | |||
| } else { | |||
| setCheckDistrict(false); | |||
| } | |||
| } | |||
| useEffect(() => { | |||
| handleCheckDistrict(); | |||
| }, [selectedAddress4, selectedAddress5]); | |||
| function getRequiredErrStr(fieldname){ | |||
| return displayErrorMsg(intl.formatMessage({ id: 'require'},{fieldname:fieldname?intl.formatMessage({ id: fieldname}):""})); | |||
| } | |||
| @@ -253,43 +266,39 @@ const BusCustomFormWizard = (props) => { | |||
| }); | |||
| } | |||
| const computeStep0Valid = (data) => ( | |||
| handleCaptcha(data.captchaField) && | |||
| data.username !== "" && | |||
| data.password !== "" && | |||
| data.confirmPassword !== "" && | |||
| data.password === data.confirmPassword && | |||
| (data.chCompanyName !== "" || data.enCompanyName !== "") && | |||
| data.enName !== "" && | |||
| data.chName !== "" && | |||
| data.address1 !== "" && | |||
| data.email !== "" && | |||
| data.emailConfirm !== "" && | |||
| data.email === data.emailConfirm && | |||
| data.phone !== "" && | |||
| data.phoneCountryCode !== "" && | |||
| termsAndConAccept === true && | |||
| fileList.length !== 0 && | |||
| data.brNo !== "" && | |||
| data.brExpiryDate !== "" && | |||
| handlePassword(data.password) && | |||
| handleEmail(data.email) && | |||
| handlePhone(data.phone) && | |||
| handleUserName(data.username) && | |||
| handleBrNo(data.brNo) && | |||
| isDistrictSelectionValid() && | |||
| !checkUsername&& | |||
| !checkEmail | |||
| ); | |||
| const checkDataField = (data) => { | |||
| // console.log(data.brExpiryDate) | |||
| if ( | |||
| handleCaptcha(data.captchaField) && | |||
| data.username !== "" && | |||
| data.password !== "" && | |||
| data.confirmPassword !== "" && | |||
| data.password === data.confirmPassword && | |||
| (data.chCompanyName !== "" || data.enCompanyName !== "") && | |||
| data.enName !== "" && | |||
| data.chName !== "" && | |||
| data.address1 !== "" && | |||
| data.email !== "" && | |||
| data.emailConfirm !== "" && | |||
| data.email === data.emailConfirm && | |||
| data.phone !== "" && | |||
| data.phoneCountryCode !== "" && | |||
| termsAndConAccept === true && | |||
| fileList.length !== 0 && | |||
| data.brNo !== "" && | |||
| data.brExpiryDate !== "" && | |||
| handlePassword(data.password) && | |||
| handleEmail(data.email) && | |||
| handlePhone(data.phone) && | |||
| handleUserName(data.username) && | |||
| handleBrNo(data.brNo) && | |||
| handleCheckDistrict()&& | |||
| !checkUsername&& | |||
| !checkEmail&& | |||
| !checkDistrict | |||
| ) { | |||
| setisValid(true) | |||
| return isValid | |||
| } else { | |||
| setisValid(false) | |||
| return isValid | |||
| } | |||
| const can = computeStep0Valid(data); | |||
| setisValid(can); | |||
| return can; | |||
| }; | |||
| const handleCheckBoxChange = (event) => { | |||
| @@ -641,6 +650,21 @@ const BusCustomFormWizard = (props) => { | |||
| }; | |||
| const { values } = formik | |||
| useEffect(() => { | |||
| if (!props.step0GuardRef) return; | |||
| props.step0GuardRef.current = () => { | |||
| const can = computeStep0Valid(values); | |||
| setisValid(can); | |||
| if (!can && !isDistrictSelectionValid()) { | |||
| setDistrictErrStr(getRequiredErrStr("district")); | |||
| setCheckDistrict(true); | |||
| notifyActionError(intl.formatMessage({ id: 'require' }, { fieldname: intl.formatMessage({ id: 'district' }) })); | |||
| } | |||
| return can; | |||
| }; | |||
| }, [values, selectedAddress4, selectedAddress5, termsAndConAccept, fileList, checkUsername, checkEmail]); | |||
| useEffect(() => { | |||
| checkDataField(values) | |||
| }, [values]) | |||
| @@ -230,7 +230,14 @@ const CustomFormWizard = (props) => { | |||
| } | |||
| } | |||
| const handleCheckDistrict = async () => { | |||
| const isDistrictSelectionValid = () => { | |||
| if (selectedAddress5?.type !== "hongKong") { | |||
| return true; | |||
| } | |||
| return !(selectedAddress4 == null || selectedAddress4 === ""); | |||
| }; | |||
| const handleCheckDistrict = () => { | |||
| setDistrictErrStr(""); | |||
| if (selectedAddress5?.type === "hongKong") { | |||
| if (selectedAddress4 == null || selectedAddress4 == "" || selectedAddress4 == {}){ | |||
| @@ -239,9 +246,15 @@ const CustomFormWizard = (props) => { | |||
| }else { | |||
| setCheckDistrict(false) | |||
| } | |||
| } else { | |||
| setCheckDistrict(false); | |||
| } | |||
| } | |||
| useEffect(() => { | |||
| handleCheckDistrict(); | |||
| }, [selectedAddress4, selectedAddress5]); | |||
| useEffect(() => { | |||
| if (username) { | |||
| username.addEventListener("blur", function () { | |||
| @@ -345,45 +358,38 @@ const CustomFormWizard = (props) => { | |||
| }); | |||
| } | |||
| const computeStep0Valid = (data) => ( | |||
| handleCaptcha(data.captchaField) && | |||
| data.username !== "" && | |||
| data.password !== "" && | |||
| data.confirmPassword !== "" && | |||
| data.password == data.confirmPassword && | |||
| selectedIdDocType.type !== "" && | |||
| data.idNo !== "" && | |||
| handleName(data.enName, data.chName) && | |||
| data.address1 !== "" && | |||
| data.email !== "" && | |||
| data.emailConfirm !== "" && | |||
| data.email == data.emailConfirm && | |||
| data.phone !== "" && | |||
| data.phoneCountryCode !== "" && | |||
| termsAndConAccept == true && | |||
| fileList.length !== 0 && | |||
| handlePassword(data.password) && | |||
| handleEmail(data.email) && | |||
| handleIdNo(data.idNo, selectedIdDocType.type, data.checkDigit) && | |||
| handlePhone(data.phone) && | |||
| handleUsername(data.username) && | |||
| isDistrictSelectionValid() && | |||
| !checkUsername && | |||
| !checkEmail && | |||
| !checkIdDocNumber | |||
| ); | |||
| const checkDataField = (data) => { | |||
| // console.log(data) | |||
| if ( | |||
| handleCaptcha(data.captchaField) && | |||
| data.username !== "" && | |||
| data.password !== "" && | |||
| data.confirmPassword !== "" && | |||
| data.password == data.confirmPassword && | |||
| selectedIdDocType.type !== "" && | |||
| data.idNo !== "" && | |||
| // (data.enName !== "" || selectedIdDocType.type === "CNID") && | |||
| // data.chName !== "" && | |||
| handleName(data.enName, data.chName) && | |||
| data.address1 !== "" && | |||
| data.email !== "" && | |||
| data.emailConfirm !== "" && | |||
| data.email == data.emailConfirm && | |||
| data.phone !== "" && | |||
| data.phoneCountryCode !== "" && | |||
| termsAndConAccept == true && | |||
| fileList.length !== 0 && | |||
| // data.captchaField && | |||
| handlePassword(data.password) && | |||
| handleEmail(data.email) && | |||
| handleIdNo(data.idNo, selectedIdDocType.type, data.checkDigit) && | |||
| handlePhone(data.phone) && | |||
| handleUsername(data.username) && | |||
| handleCheckDistrict()&& | |||
| !checkUsername && | |||
| !checkEmail && | |||
| !checkIdDocNumber&& | |||
| !checkDistrict | |||
| ) { | |||
| setisValid(true) | |||
| return isValid | |||
| } else { | |||
| setisValid(false) | |||
| return isValid | |||
| } | |||
| const can = computeStep0Valid(data); | |||
| setisValid(can); | |||
| return can; | |||
| }; | |||
| const handleCheckBoxChange = (event) => { | |||
| @@ -462,10 +468,6 @@ const CustomFormWizard = (props) => { | |||
| props.setUpdateValid(isValid) | |||
| }, [isValid]) | |||
| useEffect(() => { | |||
| props.setUpdateValid(isValid) | |||
| }, [isValid]) | |||
| useEffect(() => { | |||
| checkDataField(values) | |||
| }, [ | |||
| @@ -871,6 +873,20 @@ const CustomFormWizard = (props) => { | |||
| const { values } = formik | |||
| useEffect(() => { | |||
| if (!props.step0GuardRef) return; | |||
| props.step0GuardRef.current = () => { | |||
| const can = computeStep0Valid(values); | |||
| setisValid(can); | |||
| if (!can && !isDistrictSelectionValid()) { | |||
| setDistrictErrStr(getRequiredErrStr("district")); | |||
| setCheckDistrict(true); | |||
| notifyActionError(intl.formatMessage({ id: 'require' }, { fieldname: intl.formatMessage({ id: 'district' }) })); | |||
| } | |||
| return can; | |||
| }; | |||
| }, [values, selectedAddress4, selectedAddress5, termsAndConAccept, fileList, checkUsername, checkEmail, checkIdDocNumber, selectedIdDocType]); | |||
| useEffect(() => { | |||
| checkDataField(values) | |||
| }, [values]) | |||
| @@ -151,7 +151,15 @@ const CustomFormWizard = (props) => { | |||
| } | |||
| }, [checkDistrictBlur]) | |||
| const handleCheckDistrict = async () => { | |||
| /** Synchronous HK district rule — must match enable logic for Continue (async handleCheckDistrict() was always truthy). */ | |||
| const isDistrictSelectionValid = () => { | |||
| if (selectedAddress5?.type !== "hongKong") { | |||
| return true; | |||
| } | |||
| return !(selectedAddress4 == null || selectedAddress4 === ""); | |||
| }; | |||
| const handleCheckDistrict = () => { | |||
| setDistrictErrStr(""); | |||
| if (selectedAddress5?.type === "hongKong") { | |||
| if (selectedAddress4 == null || selectedAddress4 == "" || selectedAddress4 == {}){ | |||
| @@ -160,9 +168,15 @@ const CustomFormWizard = (props) => { | |||
| }else { | |||
| setCheckDistrict(false) | |||
| } | |||
| } else { | |||
| setCheckDistrict(false); | |||
| } | |||
| } | |||
| useEffect(() => { | |||
| handleCheckDistrict(); | |||
| }, [selectedAddress4, selectedAddress5]); | |||
| function getRequiredErrStr(fieldname) { | |||
| return displayErrorMsg(intl.formatMessage({ id: 'require' }, { fieldname: fieldname ? intl.formatMessage({ id: fieldname }) : "" })); | |||
| } | |||
| @@ -240,15 +254,25 @@ const CustomFormWizard = (props) => { | |||
| return add; | |||
| } | |||
| /** POST /user/checkE1 — returns true if email is already registered */ | |||
| const checkEmailRegistered = async (emailStr) => { | |||
| const em = emailStr?.trim(); | |||
| if (!em) return false; | |||
| const response = await axios.post(`${POST_USER_EMAIL}`, { e1: em }); | |||
| return Number(response.data[0]) > 0; | |||
| }; | |||
| const handleCheckEmail = async () => { | |||
| if (values?.email) { | |||
| const response = await axios.post(`${POST_USER_EMAIL}`, { | |||
| e1: values.email, | |||
| }) | |||
| setCheckEmail((Number(response.data[0]) > 0)) | |||
| return Number(response.data[0]) > 0 | |||
| if (!values?.email) return false; | |||
| try { | |||
| const taken = await checkEmailRegistered(values.email); | |||
| setCheckEmail(taken); | |||
| return taken; | |||
| } catch (error) { | |||
| notifyActionError(intl.formatMessage({ id: 'connectionError' })); | |||
| return false; | |||
| } | |||
| } | |||
| }; | |||
| useEffect(() => { | |||
| if (email) { | |||
| @@ -295,28 +319,28 @@ const CustomFormWizard = (props) => { | |||
| } | |||
| /** All step-0 checks except duplicate-email result from /checkE1 (see checkEmail state). */ | |||
| const computeStep0ValidSync = (data) => ( | |||
| data.address1 !== "" && | |||
| data.email !== "" && | |||
| data.emailConfirm !== "" && | |||
| data.email == data.emailConfirm && | |||
| data.phone !== "" && | |||
| data.phoneCountryCode !== "" && | |||
| termsAndConAccept == true && | |||
| data.captchaField && | |||
| handleEmail(data.email) && | |||
| handlePhone(data.phone) && | |||
| handleCaptcha(data.captchaField) && | |||
| isDistrictSelectionValid() | |||
| ); | |||
| const computeStep0Valid = (data) => computeStep0ValidSync(data) && !checkEmail; | |||
| const checkDataField = (data) => { | |||
| if (data.address1 !== "" && | |||
| data.email !== "" && | |||
| data.emailConfirm !== "" && | |||
| data.email == data.emailConfirm && | |||
| data.phone !== "" && | |||
| data.phoneCountryCode !== "" && | |||
| termsAndConAccept == true && | |||
| data.captchaField && | |||
| handleEmail(data.email) && | |||
| handlePhone(data.phone) && | |||
| handleCaptcha(data.captchaField) && | |||
| handleCheckDistrict()&& | |||
| !checkEmail&& | |||
| !checkDistrict | |||
| ) { | |||
| setisValid(true) | |||
| return isValid | |||
| } else { | |||
| setisValid(false) | |||
| return isValid | |||
| } | |||
| const can = computeStep0Valid(data); | |||
| setisValid(can); | |||
| return can; | |||
| }; | |||
| const handleCheckBoxChange = (event) => { | |||
| @@ -478,6 +502,37 @@ const CustomFormWizard = (props) => { | |||
| }; | |||
| const { values } = formik | |||
| useEffect(() => { | |||
| if (!props.step0GuardRef) return; | |||
| props.step0GuardRef.current = async () => { | |||
| const syncOk = computeStep0ValidSync(values); | |||
| if (!syncOk) { | |||
| setisValid(false); | |||
| if (!isDistrictSelectionValid()) { | |||
| setDistrictErrStr(getRequiredErrStr("district")); | |||
| setCheckDistrict(true); | |||
| notifyActionError(intl.formatMessage({ id: 'require' }, { fieldname: intl.formatMessage({ id: 'district' }) })); | |||
| } | |||
| return false; | |||
| } | |||
| try { | |||
| const taken = await checkEmailRegistered(values.email); | |||
| setCheckEmail(taken); | |||
| if (taken) { | |||
| setisValid(false); | |||
| notifyActionError(intl.formatMessage({ id: 'emailUsed' })); | |||
| return false; | |||
| } | |||
| } catch (error) { | |||
| notifyActionError(intl.formatMessage({ id: 'connectionError' })); | |||
| return false; | |||
| } | |||
| setisValid(true); | |||
| return true; | |||
| }; | |||
| }, [values, selectedAddress4, selectedAddress5, termsAndConAccept, checkEmail]); | |||
| useEffect(() => { | |||
| checkDataField(values) | |||
| }, [values]) | |||