| @@ -56,6 +56,7 @@ import {ThemeProvider} from "@emotion/react"; | |||
| import {FormattedMessage, useIntl} from "react-intl"; | |||
| //import { Invaild } from 'utils/IconUtils'; | |||
| import { handleActionKeyDown, notifyActionError } from 'utils/CommonFunction'; | |||
| import { ADDRESS_LINE_MAX_LENGTH, isAddressLineWithinLimit, isRegisterAddressValid } from 'utils/registerValidation'; | |||
| // ============================|| FIREBASE - REGISTER ||============================ // | |||
| @@ -286,7 +287,7 @@ const BusCustomFormWizard = (props) => { | |||
| (data.chCompanyName !== "" || data.enCompanyName !== "") && | |||
| data.enName !== "" && | |||
| data.chName !== "" && | |||
| data.address1 !== "" && | |||
| isRegisterAddressValid(data) && | |||
| data.email !== "" && | |||
| data.emailConfirm !== "" && | |||
| data.email === data.emailConfirm && | |||
| @@ -676,7 +677,17 @@ const BusCustomFormWizard = (props) => { | |||
| const syncOk = computeStep0ValidSync(values); | |||
| if (!syncOk) { | |||
| setisValid(false); | |||
| if (!isDistrictSelectionValid()) { | |||
| if (!isRegisterAddressValid(values)) { | |||
| if (values.address1 === '') { | |||
| notifyActionError(intl.formatMessage({ id: 'validateAddressLine1' })); | |||
| } else if (!isAddressLineWithinLimit(values.address1)) { | |||
| notifyActionError(intl.formatMessage({ id: 'noMoreThenNWords' }, { num: ADDRESS_LINE_MAX_LENGTH, fieldname: intl.formatMessage({ id: 'addressLine1' }) + ": " })); | |||
| } else if (!isAddressLineWithinLimit(values.address2)) { | |||
| notifyActionError(intl.formatMessage({ id: 'noMoreThenNWords' }, { num: ADDRESS_LINE_MAX_LENGTH, fieldname: intl.formatMessage({ id: 'addressLine2' }) + ": " })); | |||
| } else if (!isAddressLineWithinLimit(values.address3)) { | |||
| notifyActionError(intl.formatMessage({ id: 'noMoreThenNWords' }, { num: ADDRESS_LINE_MAX_LENGTH, fieldname: intl.formatMessage({ id: 'addressLine3' }) + ": " })); | |||
| } | |||
| } else if (!isDistrictSelectionValid()) { | |||
| setDistrictErrStr(getRequiredErrStr("district")); | |||
| setCheckDistrict(true); | |||
| notifyActionError(intl.formatMessage({ id: 'require' }, { fieldname: intl.formatMessage({ id: 'district' }) })); | |||
| @@ -1115,6 +1126,7 @@ const BusCustomFormWizard = (props) => { | |||
| onBlur={formik.handleBlur} | |||
| inputProps={{ | |||
| "aria-label": intl.formatMessage({ id: "addressLine1" }), | |||
| maxLength: ADDRESS_LINE_MAX_LENGTH, | |||
| onKeyDown: (e) => { | |||
| if (e.key === 'Enter') { | |||
| e.preventDefault(); | |||
| @@ -1133,6 +1145,7 @@ const BusCustomFormWizard = (props) => { | |||
| placeholder={intl.formatMessage({id: 'addressLine2'})} | |||
| inputProps={{ | |||
| "aria-label": intl.formatMessage({ id: "addressLine2" }), | |||
| maxLength: ADDRESS_LINE_MAX_LENGTH, | |||
| onKeyDown: (e) => { | |||
| if (e.key === 'Enter') { | |||
| e.preventDefault(); | |||
| @@ -1151,6 +1164,7 @@ const BusCustomFormWizard = (props) => { | |||
| placeholder={intl.formatMessage({id: 'addressLine3'})} | |||
| inputProps={{ | |||
| "aria-label": intl.formatMessage({ id: "addressLine3" }), | |||
| maxLength: ADDRESS_LINE_MAX_LENGTH, | |||
| onKeyDown: (e) => { | |||
| if (e.key === 'Enter') { | |||
| e.preventDefault(); | |||
| @@ -48,6 +48,7 @@ import { Link } from 'react-router-dom'; | |||
| import { PNSPS_LONG_BUTTON_THEME } from "../../../themes/buttonConst"; | |||
| import * as HttpUtils from "../../../utils/HttpUtils"; | |||
| import { handleActionKeyDown, notifyActionError } from 'utils/CommonFunction'; | |||
| import { ADDRESS_LINE_MAX_LENGTH, isAddressLineWithinLimit, isRegisterAddressValid } from 'utils/registerValidation'; | |||
| // ============================|| FIREBASE - REGISTER ||============================ // | |||
| const CustomFormWizard = (props) => { | |||
| @@ -377,7 +378,7 @@ const CustomFormWizard = (props) => { | |||
| selectedIdDocType.type !== "" && | |||
| data.idNo !== "" && | |||
| handleName(data.enName, data.chName) && | |||
| data.address1 !== "" && | |||
| isRegisterAddressValid(data) && | |||
| data.email !== "" && | |||
| data.emailConfirm !== "" && | |||
| data.email == data.emailConfirm && | |||
| @@ -897,7 +898,17 @@ const CustomFormWizard = (props) => { | |||
| const syncOk = computeStep0ValidSync(values); | |||
| if (!syncOk) { | |||
| setisValid(false); | |||
| if (!isDistrictSelectionValid()) { | |||
| if (!isRegisterAddressValid(values)) { | |||
| if (values.address1 === '') { | |||
| notifyActionError(intl.formatMessage({ id: 'validateAddressLine1' })); | |||
| } else if (!isAddressLineWithinLimit(values.address1)) { | |||
| notifyActionError(intl.formatMessage({ id: 'noMoreThenNWords' }, { num: ADDRESS_LINE_MAX_LENGTH, fieldname: intl.formatMessage({ id: 'addressLine1' }) + ": " })); | |||
| } else if (!isAddressLineWithinLimit(values.address2)) { | |||
| notifyActionError(intl.formatMessage({ id: 'noMoreThenNWords' }, { num: ADDRESS_LINE_MAX_LENGTH, fieldname: intl.formatMessage({ id: 'addressLine2' }) + ": " })); | |||
| } else if (!isAddressLineWithinLimit(values.address3)) { | |||
| notifyActionError(intl.formatMessage({ id: 'noMoreThenNWords' }, { num: ADDRESS_LINE_MAX_LENGTH, fieldname: intl.formatMessage({ id: 'addressLine3' }) + ": " })); | |||
| } | |||
| } else if (!isDistrictSelectionValid()) { | |||
| setDistrictErrStr(getRequiredErrStr("district")); | |||
| setCheckDistrict(true); | |||
| notifyActionError(intl.formatMessage({ id: 'require' }, { fieldname: intl.formatMessage({ id: 'district' }) })); | |||
| @@ -1475,6 +1486,7 @@ const CustomFormWizard = (props) => { | |||
| onBlur={formik.handleBlur} | |||
| inputProps={{ | |||
| "aria-label": intl.formatMessage({ id: "addressLine1" }), | |||
| maxLength: ADDRESS_LINE_MAX_LENGTH, | |||
| onKeyDown: (e) => { | |||
| if (e.key === 'Enter') { | |||
| e.preventDefault(); | |||
| @@ -1493,6 +1505,7 @@ const CustomFormWizard = (props) => { | |||
| placeholder={intl.formatMessage({ id: 'addressLine2' })} | |||
| inputProps={{ | |||
| "aria-label": intl.formatMessage({ id: "addressLine2" }), | |||
| maxLength: ADDRESS_LINE_MAX_LENGTH, | |||
| onKeyDown: (e) => { | |||
| if (e.key === 'Enter') { | |||
| e.preventDefault(); | |||
| @@ -1511,6 +1524,7 @@ const CustomFormWizard = (props) => { | |||
| placeholder={intl.formatMessage({ id: 'addressLine3' })} | |||
| inputProps={{ | |||
| "aria-label": intl.formatMessage({ id: "addressLine3" }), | |||
| maxLength: ADDRESS_LINE_MAX_LENGTH, | |||
| onKeyDown: (e) => { | |||
| if (e.key === 'Enter') { | |||
| e.preventDefault(); | |||
| @@ -41,6 +41,7 @@ import { useTheme } from '@mui/material/styles'; | |||
| import { useLocation } from "react-router-dom"; | |||
| import { FormattedMessage, useIntl } from "react-intl"; | |||
| import { handleActionKeyDown, notifyActionError } from 'utils/CommonFunction'; | |||
| import { ADDRESS_LINE_MAX_LENGTH, isAddressLineWithinLimit, isRegisterAddressValid, splitAddressIntoLines } from 'utils/registerValidation'; | |||
| // ============================|| FIREBASE - REGISTER ||============================ // | |||
| @@ -199,20 +200,22 @@ const CustomFormWizard = (props) => { | |||
| "phoneCountryCode": rd?.mobileNumber?.CountryCode ?? "", | |||
| }; | |||
| if (rd?.postalAddress) { | |||
| if (rd?.postalAddress?.EngPremisesAddress) { | |||
| data["address1"] = getAddressEng(rd?.postalAddress?.EngPremisesAddress); | |||
| } else if (rd.postalAddress.ChiPremisesAddress) { | |||
| data["address1"] = getAddressChi(rd?.postalAddress?.ChiPremisesAddress); | |||
| } | |||
| } else if (rd?.residentialAddress) { | |||
| if (rd?.residentialAddress?.EngPremisesAddress) { | |||
| data["address1"] = getAddressEng(rd?.residentialAddress?.EngPremisesAddress); | |||
| } else if (rd?.residentialAddress?.ChiPremisesAddress) { | |||
| data["address1"] = getAddressChi(rd?.residentialAddress?.ChiPremisesAddress); | |||
| } | |||
| let fullAddress = ''; | |||
| if (rd?.postalAddress?.EngPremisesAddress) { | |||
| fullAddress = getAddressEng(rd.postalAddress.EngPremisesAddress); | |||
| } else if (rd?.postalAddress?.ChiPremisesAddress) { | |||
| fullAddress = getAddressChi(rd.postalAddress.ChiPremisesAddress); | |||
| } else if (rd?.residentialAddress?.EngPremisesAddress) { | |||
| fullAddress = getAddressEng(rd.residentialAddress.EngPremisesAddress); | |||
| } else if (rd?.residentialAddress?.ChiPremisesAddress) { | |||
| fullAddress = getAddressChi(rd.residentialAddress.ChiPremisesAddress); | |||
| } | |||
| const { address1, address2, address3 } = splitAddressIntoLines(fullAddress); | |||
| data["address1"] = address1; | |||
| data["address2"] = address2; | |||
| data["address3"] = address3; | |||
| setIAmSmartData(data); | |||
| } | |||
| @@ -300,6 +303,8 @@ const CustomFormWizard = (props) => { | |||
| formik.setFieldValue("phone", iAmSmartData.phone ?? ""); | |||
| formik.setFieldValue("phoneCountryCode", iAmSmartData.phoneCountryCode ?? ""); | |||
| formik.setFieldValue("address1", iAmSmartData.address1 ?? ""); | |||
| formik.setFieldValue("address2", iAmSmartData.address2 ?? ""); | |||
| formik.setFieldValue("address3", iAmSmartData.address3 ?? ""); | |||
| props.setIdNo(iAmSmartData.idNo ?? ""); | |||
| setLodingData(false) | |||
| } | |||
| @@ -321,7 +326,7 @@ const CustomFormWizard = (props) => { | |||
| /** All step-0 checks except duplicate-email result from /checkE1 (see checkEmail state). */ | |||
| const computeStep0ValidSync = (data) => ( | |||
| data.address1 !== "" && | |||
| isRegisterAddressValid(data) && | |||
| data.email !== "" && | |||
| data.emailConfirm !== "" && | |||
| data.email == data.emailConfirm && | |||
| @@ -510,7 +515,17 @@ const CustomFormWizard = (props) => { | |||
| const syncOk = computeStep0ValidSync(values); | |||
| if (!syncOk) { | |||
| setisValid(false); | |||
| if (!isDistrictSelectionValid()) { | |||
| if (!isRegisterAddressValid(values)) { | |||
| if (values.address1 === '') { | |||
| notifyActionError(intl.formatMessage({ id: 'validateAddressLine1' })); | |||
| } else if (!isAddressLineWithinLimit(values.address1)) { | |||
| notifyActionError(intl.formatMessage({ id: 'noMoreThenNWords' }, { num: ADDRESS_LINE_MAX_LENGTH, fieldname: intl.formatMessage({ id: 'addressLine1' }) + ": " })); | |||
| } else if (!isAddressLineWithinLimit(values.address2)) { | |||
| notifyActionError(intl.formatMessage({ id: 'noMoreThenNWords' }, { num: ADDRESS_LINE_MAX_LENGTH, fieldname: intl.formatMessage({ id: 'addressLine2' }) + ": " })); | |||
| } else if (!isAddressLineWithinLimit(values.address3)) { | |||
| notifyActionError(intl.formatMessage({ id: 'noMoreThenNWords' }, { num: ADDRESS_LINE_MAX_LENGTH, fieldname: intl.formatMessage({ id: 'addressLine3' }) + ": " })); | |||
| } | |||
| } else if (!isDistrictSelectionValid()) { | |||
| setDistrictErrStr(getRequiredErrStr("district")); | |||
| setCheckDistrict(true); | |||
| notifyActionError(intl.formatMessage({ id: 'require' }, { fieldname: intl.formatMessage({ id: 'district' }) })); | |||
| @@ -642,6 +657,7 @@ const CustomFormWizard = (props) => { | |||
| placeholder={intl.formatMessage({ id: 'addressLine1' })} | |||
| onBlur={formik.handleBlur} | |||
| inputProps={{ | |||
| maxLength: ADDRESS_LINE_MAX_LENGTH, | |||
| onKeyDown: (e) => { | |||
| if (e.key === 'Enter') { | |||
| e.preventDefault(); | |||
| @@ -663,6 +679,7 @@ const CustomFormWizard = (props) => { | |||
| onChange={formik.handleChange} | |||
| placeholder={intl.formatMessage({ id: 'addressLine2' })} | |||
| inputProps={{ | |||
| maxLength: ADDRESS_LINE_MAX_LENGTH, | |||
| onKeyDown: (e) => { | |||
| if (e.key === 'Enter') { | |||
| e.preventDefault(); | |||
| @@ -685,6 +702,7 @@ const CustomFormWizard = (props) => { | |||
| onChange={formik.handleChange} | |||
| placeholder={intl.formatMessage({ id: 'addressLine3' })} | |||
| inputProps={{ | |||
| maxLength: ADDRESS_LINE_MAX_LENGTH, | |||
| onKeyDown: (e) => { | |||
| if (e.key === 'Enter') { | |||
| e.preventDefault(); | |||
| @@ -0,0 +1,67 @@ | |||
| export const ADDRESS_LINE_MAX_LENGTH = 40; | |||
| export function isAddressLineWithinLimit(line, maxLen = ADDRESS_LINE_MAX_LENGTH) { | |||
| if (line == null || line === '') return true; | |||
| return line.length <= maxLen; | |||
| } | |||
| /** Step-0 gate: line1 required; lines 1–3 each <= maxLen */ | |||
| export function isRegisterAddressValid(data, maxLen = ADDRESS_LINE_MAX_LENGTH) { | |||
| return ( | |||
| data.address1 !== '' && | |||
| isAddressLineWithinLimit(data.address1, maxLen) && | |||
| isAddressLineWithinLimit(data.address2, maxLen) && | |||
| isAddressLineWithinLimit(data.address3, maxLen) | |||
| ); | |||
| } | |||
| /** | |||
| * Split a comma-separated address into up to 3 lines, each <= maxLen chars. | |||
| * Packs at comma boundaries where possible. | |||
| */ | |||
| export function splitAddressIntoLines(address, maxLen = ADDRESS_LINE_MAX_LENGTH) { | |||
| const empty = { address1: '', address2: '', address3: '' }; | |||
| if (address == null || address === '') return empty; | |||
| const trimmed = address.trim(); | |||
| if (trimmed.length <= maxLen) { | |||
| return { address1: trimmed, address2: '', address3: '' }; | |||
| } | |||
| const segments = trimmed.split(',').map((s) => s.trim()).filter(Boolean); | |||
| const lines = []; | |||
| let current = ''; | |||
| const pushCurrent = () => { | |||
| if (current) { | |||
| lines.push(current); | |||
| current = ''; | |||
| } | |||
| }; | |||
| for (const segment of segments) { | |||
| const candidate = current ? `${current}, ${segment}` : segment; | |||
| if (candidate.length <= maxLen) { | |||
| current = candidate; | |||
| } else if (segment.length <= maxLen) { | |||
| pushCurrent(); | |||
| current = segment; | |||
| } else { | |||
| pushCurrent(); | |||
| let remaining = segment; | |||
| while (remaining.length > maxLen) { | |||
| lines.push(remaining.slice(0, maxLen)); | |||
| remaining = remaining.slice(maxLen); | |||
| } | |||
| current = remaining; | |||
| } | |||
| if (lines.length >= 3) break; | |||
| } | |||
| pushCurrent(); | |||
| return { | |||
| address1: lines[0] ?? '', | |||
| address2: lines[1] ?? '', | |||
| address3: lines[2] ?? '', | |||
| }; | |||
| } | |||