diff --git a/src/pages/authentication/auth-forms/BusCustomFormWizard.js b/src/pages/authentication/auth-forms/BusCustomFormWizard.js index 8405b81..c8f32b8 100644 --- a/src/pages/authentication/auth-forms/BusCustomFormWizard.js +++ b/src/pages/authentication/auth-forms/BusCustomFormWizard.js @@ -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(); diff --git a/src/pages/authentication/auth-forms/CustomFormWizard.js b/src/pages/authentication/auth-forms/CustomFormWizard.js index 1cb743e..ff80270 100644 --- a/src/pages/authentication/auth-forms/CustomFormWizard.js +++ b/src/pages/authentication/auth-forms/CustomFormWizard.js @@ -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(); diff --git a/src/pages/authentication/auth-forms/IAmSmartFormWizard.js b/src/pages/authentication/auth-forms/IAmSmartFormWizard.js index dcd4aaf..c18f0f5 100644 --- a/src/pages/authentication/auth-forms/IAmSmartFormWizard.js +++ b/src/pages/authentication/auth-forms/IAmSmartFormWizard.js @@ -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(); diff --git a/src/utils/registerValidation.js b/src/utils/registerValidation.js new file mode 100644 index 0000000..403c1f8 --- /dev/null +++ b/src/utils/registerValidation.js @@ -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] ?? '', + }; +}