Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

1366 строки
86 KiB

  1. import { useEffect, useState, } from 'react';
  2. // material-ui
  3. import {
  4. Button,
  5. FormHelperText,
  6. Grid, IconButton,
  7. InputLabel, OutlinedInput,
  8. Stack,
  9. Typography,
  10. FormGroup,
  11. TextField,
  12. Checkbox
  13. // MenuItem
  14. } from '@mui/material';
  15. import { useForm, } from 'react-hook-form'
  16. import Autocomplete from "@mui/material/Autocomplete";
  17. // third party
  18. import { useFormik, FormikProvider } from 'formik';
  19. import * as yup from 'yup';
  20. import axios from "axios";
  21. import { POST_IAMSMART_USER_REGISTER, POST_CAPTCHA, POST_USER_EMAIL, POST_CAPTCHA_AUDIO} from "utils/ApiPathConst";
  22. import * as ComboData from "utils/ComboData";
  23. import Loadable from 'components/Loadable';
  24. import { lazy } from 'react';
  25. const LoadingComponent = Loadable(lazy(() => import('../../extra-pages/LoadingComponent')));
  26. import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
  27. import CancelOutlinedIcon from '@mui/icons-material/CancelOutlined';
  28. import iAmSmartICon from 'assets/images/icons/icon_iAmSmart.png';
  29. import { EyeInvisibleOutlined, EyeOutlined } from '@ant-design/icons';
  30. import { Link } from 'react-router-dom';
  31. import * as HttpUtils from "../../../utils/HttpUtils";
  32. import LoopIcon from '@mui/icons-material/Loop';
  33. import { useTheme } from '@mui/material/styles';
  34. import { useLocation } from "react-router-dom";
  35. import { FormattedMessage, useIntl } from "react-intl";
  36. import { handleActionKeyDown, notifyActionError } from 'utils/CommonFunction';
  37. import { ADDRESS_LINE_MAX_LENGTH, isAddressLineWithinLimit, isRegisterAddressValid, splitAddressIntoLines } from 'utils/registerValidation';
  38. // ============================|| FIREBASE - REGISTER ||============================ //
  39. const CustomFormWizard = (props) => {
  40. const location = useLocation();
  41. const theme = useTheme();
  42. const intl = useIntl();
  43. const { locale } = intl;
  44. const [iAmSmartData, setIAmSmartData] = useState({});
  45. const [checkUpload, setCheckUpload] = useState(false);
  46. const [isLoading, setLoding] = useState(true);
  47. const [isLoadingData, setLodingData] = useState(true);
  48. const [captchaImg, setCaptchaImage] = useState("");
  49. const [selectedAddress4, setSelectedAddress4] = useState(null);
  50. const [selectedAddress5, setSelectedAddress5] = useState(ComboData.country[0]);
  51. const [termsAndConAccept, setTermsAndConAccept] = useState(false);
  52. const [termsAndConNotAccept, setTermsAndConNotAccept] = useState(false);
  53. const [isValid, setisValid] = useState(false);
  54. const [checkCountry, setCheckCountry] = useState(false);
  55. const email = document.getElementById("email-login")
  56. const [checkEmail, setCheckEmail] = useState(false)
  57. const [checkEmailBlur, setCheckEmailBlur] = useState(false)
  58. const district = document.getElementById("address4-combo")
  59. const [checkDistrict, setCheckDistrict] = useState(false)
  60. const [checkDistrictBlur, setCheckDistrictBlur] = useState(false)
  61. const [districtErrStr, setDistrictErrStr] = useState("")
  62. const address4ComboList = ComboData.district;
  63. const address5ComboList = ComboData.country;
  64. const [showId, setshowId] = useState(false);
  65. const [showComId, setshowComId] = useState(false);
  66. const [base64Url, setBase64Url] = useState("")
  67. const [checkCode, setCheckCode] = useState("")
  68. useEffect(() => {
  69. location.state?.responseData ?? window.location.assign("/login");
  70. if (captchaImg == "")
  71. onCaptchaChange();
  72. responseToData();
  73. }, []);
  74. const playCaptchaAudio = async () => {
  75. try {
  76. const resp = await axios.post(
  77. `${POST_CAPTCHA_AUDIO}`,
  78. { base64Url, lang: intl.locale },
  79. { responseType: "arraybuffer" }
  80. );
  81. const blob = new Blob([resp.data], { type: "audio/wav" });
  82. const url = URL.createObjectURL(blob);
  83. const audio = new Audio(url);
  84. await audio.play();
  85. } catch (error) {
  86. let message = intl.formatMessage({ id: "captchaAudioError" });
  87. if (error.response) {
  88. if (error.response.status === 404) {
  89. message = intl.formatMessage({ id: "captchaExpired" });
  90. } else if (error.response.status === 500) {
  91. message = intl.formatMessage({ id: "captchaAudioServerError" });
  92. }
  93. } else if (error.request) {
  94. message = intl.formatMessage({ id: "connectionError" });
  95. }
  96. notifyActionError(message);
  97. }
  98. };
  99. const handleClickShowId = () => {
  100. setshowId(!showId);
  101. };
  102. const handleMouseDownId = (event) => {
  103. event.preventDefault();
  104. };
  105. const handleClickShowComId = () => {
  106. setshowComId(!showId);
  107. };
  108. const handleMouseDownComId = (event) => {
  109. event.preventDefault();
  110. };
  111. useEffect(() => {
  112. if (district) {
  113. district.addEventListener("blur", function () {
  114. setCheckDistrictBlur(true)
  115. })
  116. }
  117. }, [district])
  118. useEffect(() => {
  119. if (checkDistrictBlur) {
  120. handleCheckDistrict()
  121. setCheckDistrictBlur(false)
  122. }
  123. }, [checkDistrictBlur])
  124. /** Synchronous HK district rule — must match enable logic for Continue (async handleCheckDistrict() was always truthy). */
  125. const isDistrictSelectionValid = () => {
  126. if (selectedAddress5?.type !== "hongKong") {
  127. return true;
  128. }
  129. return !(selectedAddress4 == null || selectedAddress4 === "");
  130. };
  131. const handleCheckDistrict = () => {
  132. setDistrictErrStr("");
  133. if (selectedAddress5?.type === "hongKong") {
  134. if (selectedAddress4 == null || selectedAddress4 == "" || selectedAddress4 == {}){
  135. setCheckDistrict(true)
  136. setDistrictErrStr(getRequiredErrStr("district"))
  137. }else {
  138. setCheckDistrict(false)
  139. }
  140. } else {
  141. setCheckDistrict(false);
  142. }
  143. }
  144. useEffect(() => {
  145. handleCheckDistrict();
  146. }, [selectedAddress4, selectedAddress5]);
  147. function getRequiredErrStr(fieldname) {
  148. return displayErrorMsg(intl.formatMessage({ id: 'require' }, { fieldname: fieldname ? intl.formatMessage({ id: fieldname }) : "" }));
  149. }
  150. function getMaxErrStr(num, fieldname) {
  151. return displayErrorMsg(intl.formatMessage({ id: 'noMoreThenNWords' }, { num: num, fieldname: fieldname ? intl.formatMessage({ id: fieldname }) + ": " : "" }));
  152. }
  153. const responseToData = () => {
  154. //let rd = JSON.parse("{\"emailAddress\":\"[email protected]\",\"postalAddress\":{\"EngPremisesAddress\":{\"EngDistrict\":{\"DcDistrict\":\"KC\",\"Sub-district\":\"TSING YI\"},\"EngEstate\":{\"EstateName\":\"Cheung Hang Estate\",\"EngPhase\":{\"PhaseName\":\"N/A\"}},\"BuildingName\":\"Hang Lai House\",\"EngBlock\":{\"BlockDescriptor\":\"Block\",\"BlockNo\":\"2\"},\"Region\":\"NT\",\"EngStreet\":{\"StreetName\":\"Liu To Road\",\"BuildingNoFrom\":\"6\"},\"Eng3dAddress\":{\"EngFloor\":{\"FloorNum\":\"33\"},\"EngUnit\":{\"UnitDescriptor\":\"Room\",\"UnitNo\":\"3301\"}}}},\"mobileNumber\":{\"CountryCode\":\"852\",\"SubscriberNumber\":\"99999999\"},\"residentialAddress\":{\"ChiPremisesAddress\":{\"Chi3dAddress\":{\"ChiUnit\":{\"UnitDescriptor\":\"室\",\"UnitNo\":\"1010\"},\"ChiFloor\":{\"FloorNum\":\"10\"}},\"ChiBlock\":{\"BlockDescriptor\":\"座\",\"BlockNo\":\"2\"},\"BuildingName\":\"亨麗樓(第2座)\",\"ChiDistrict\":{\"DcDistrict\":\"KC\",\"Sub-district\":\"青衣\"},\"Region\":\"新界\",\"ChiEstate\":{\"EstateName\":\"長亨邨\"},\"ChiStreet\":{\"StreetName\":\"寮肚路\",\"BuildingNoFrom\":\"6\"}}},\"enName\":{\"UnstructuredName\":\"Testing Co One\"},\"idNo\":{\"Identification\":\"G561107\",\"CheckDigit\":\"4\"},\"chName\":{\"ChineseName\":\"測試商一\"}}");
  155. let rd = JSON.parse(location.state?.responseData.data);
  156. let data = {
  157. "enName": rd?.enName?.UnstructuredName ?? "",
  158. "chName": rd?.chName?.ChineseName ?? "",
  159. "idNo": rd?.idNo?.Identification ?? "",
  160. "checkDigit": rd?.idNo?.CheckDigit ?? "",
  161. "email": rd?.emailAddress ?? "",
  162. "phone": rd?.mobileNumber?.SubscriberNumber ?? "",
  163. "phoneCountryCode": rd?.mobileNumber?.CountryCode ?? "",
  164. };
  165. let fullAddress = '';
  166. if (rd?.postalAddress?.EngPremisesAddress) {
  167. fullAddress = getAddressEng(rd.postalAddress.EngPremisesAddress);
  168. } else if (rd?.postalAddress?.ChiPremisesAddress) {
  169. fullAddress = getAddressChi(rd.postalAddress.ChiPremisesAddress);
  170. } else if (rd?.residentialAddress?.EngPremisesAddress) {
  171. fullAddress = getAddressEng(rd.residentialAddress.EngPremisesAddress);
  172. } else if (rd?.residentialAddress?.ChiPremisesAddress) {
  173. fullAddress = getAddressChi(rd.residentialAddress.ChiPremisesAddress);
  174. }
  175. const { address1, address2, address3 } = splitAddressIntoLines(fullAddress);
  176. data["address1"] = address1;
  177. data["address2"] = address2;
  178. data["address3"] = address3;
  179. setIAmSmartData(data);
  180. }
  181. const getAddressEng = (pAdd) => {
  182. let unit = (pAdd.Eng3dAddress?.EngUnit?.UnitDescriptor ?? "") + " " + (pAdd.Eng3dAddress?.EngUnit?.UnitNo ?? "");
  183. let block = (pAdd.EngBlock?.BlockDescriptor ?? "") + " " + (pAdd.EngBlock?.BlockNo ?? "");
  184. let floor = pAdd.Eng3dAddress?.EngFloor?.FloorNum ? pAdd.Eng3dAddress?.EngFloor?.FloorNum + "/F " : "";
  185. let street = (pAdd.EngStreet?.EngUnit?.UnitDescriptor ?? "") + " " + (pAdd.Eng3dAddress?.EngUnit?.UnitNo ?? "");
  186. //let region = pAdd.Region ?? "";
  187. let buildingName = pAdd.BuildingName ?? "";
  188. let estate = pAdd.EngEstate?.EstateName ?? "";
  189. let district = pAdd.EngDistrict["Sub - district"] ?? "";
  190. return getAddressStr([unit, block, floor, buildingName, estate, street, district]);
  191. }
  192. const getAddressChi = (pAdd) => {
  193. let unit = (pAdd.Chi3dAddress?.ChiUnit?.UnitDescriptor ?? "") + " " + (pAdd.Chi3dAddress?.ChiUnit?.UnitNo ?? "");
  194. let block = (pAdd.ChiBlock?.BlockDescriptor ?? "") + " " + (pAdd.ChiBlock?.BlockNo ?? "");
  195. let floor = pAdd.Chi3dAddress?.ChiFloor?.FloorNum ? pAdd.Chi3dAddress?.ChiFloor?.FloorNum + "樓 " : "";
  196. let street = (pAdd.ChiStreet?.ChiUnit?.UnitDescriptor ?? "") + " " + (pAdd.Chi3dAddress?.ChiUnit?.UnitNo ?? "");
  197. //let region = pAdd.Region ?? "";
  198. let buildingName = pAdd.BuildingName ?? "";
  199. let estate = pAdd.ChiEstate?.EstateName ?? "";
  200. let district = pAdd.ChiDistrict["Sub - district"] ?? "";
  201. return getAddressStr([district, street, estate, buildingName, street, floor, block, unit]);
  202. }
  203. const getAddressStr = (strs) => {
  204. let add = ""
  205. strs.forEach(str => {
  206. add += str.trim() ? str.trim() + ", " : "";
  207. });
  208. add = add.trim();
  209. if (add?.slice(- 1) == ",") {
  210. add = add.substring(0, add.length - 1);
  211. }
  212. return add;
  213. }
  214. /** POST /user/checkE1 — returns true if email is already registered */
  215. const checkEmailRegistered = async (emailStr) => {
  216. const em = emailStr?.trim();
  217. if (!em) return false;
  218. const response = await axios.post(`${POST_USER_EMAIL}`, { e1: em });
  219. return Number(response.data[0]) > 0;
  220. };
  221. const handleCheckEmail = async () => {
  222. if (!values?.email) return false;
  223. try {
  224. const taken = await checkEmailRegistered(values.email);
  225. setCheckEmail(taken);
  226. return taken;
  227. } catch (error) {
  228. notifyActionError(intl.formatMessage({ id: 'connectionError' }));
  229. return false;
  230. }
  231. };
  232. useEffect(() => {
  233. if (email) {
  234. email.addEventListener("blur", function () {
  235. setCheckEmailBlur(true)
  236. })
  237. }
  238. }, [email])
  239. useEffect(() => {
  240. if (checkEmailBlur) {
  241. handleCheckEmail()
  242. setCheckEmailBlur(false)
  243. }
  244. }, [checkEmailBlur])
  245. useEffect(() => {
  246. if (iAmSmartData) {
  247. formik.setFieldValue("enName", iAmSmartData.enName ?? "");
  248. formik.setFieldValue("chName", iAmSmartData.chName ?? "");
  249. formik.setFieldValue("idNo", iAmSmartData.idNo ?? "");
  250. formik.setFieldValue("checkDigit", iAmSmartData.checkDigit ?? "");
  251. formik.setFieldValue("email", iAmSmartData.email ?? "");
  252. formik.setFieldValue("emailConfirm", iAmSmartData.email ?? "");
  253. formik.setFieldValue("phone", iAmSmartData.phone ?? "");
  254. formik.setFieldValue("phoneCountryCode", iAmSmartData.phoneCountryCode ?? "");
  255. formik.setFieldValue("address1", iAmSmartData.address1 ?? "");
  256. formik.setFieldValue("address2", iAmSmartData.address2 ?? "");
  257. formik.setFieldValue("address3", iAmSmartData.address3 ?? "");
  258. props.setIdNo(iAmSmartData.idNo ?? "");
  259. setLodingData(false)
  260. }
  261. }, [iAmSmartData])
  262. const onCaptchaChange = () => {
  263. HttpUtils.post({
  264. url: POST_CAPTCHA,
  265. params: { width: 130, height: 40, captcha: captchaImg },
  266. onSuccess: (responseData) => {
  267. props.setBase64Url(responseData.base64Url)
  268. setBase64Url(responseData.base64Url)
  269. localStorage.setItem("base64Url", responseData.base64Url);
  270. setCaptchaImage(localStorage.getItem('base64Url'));
  271. }
  272. });
  273. }
  274. /** All step-0 checks except duplicate-email result from /checkE1 (see checkEmail state). */
  275. const computeStep0ValidSync = (data) => (
  276. isRegisterAddressValid(data) &&
  277. data.email !== "" &&
  278. data.emailConfirm !== "" &&
  279. data.email == data.emailConfirm &&
  280. data.phone !== "" &&
  281. data.phoneCountryCode !== "" &&
  282. termsAndConAccept == true &&
  283. data.captchaField &&
  284. handleEmail(data.email) &&
  285. handlePhone(data.phone) &&
  286. handleCaptcha(data.captchaField) &&
  287. isDistrictSelectionValid()
  288. );
  289. const computeStep0Valid = (data) => computeStep0ValidSync(data) && !checkEmail;
  290. const checkDataField = (data) => {
  291. const can = computeStep0Valid(data);
  292. setisValid(can);
  293. return can;
  294. };
  295. const handleCheckBoxChange = (event) => {
  296. if (event.target.name == 'termsAndConAccept') {
  297. setTermsAndConAccept(event.target.checked)
  298. setTermsAndConNotAccept(!event.target.checked)
  299. }
  300. if (event.target.name == 'termsAndConNotAccept') {
  301. setTermsAndConNotAccept(event.target.checked)
  302. setTermsAndConAccept(!event.target.checked)
  303. }
  304. };
  305. useEffect(() => {
  306. props.setUpdateValid(isValid)
  307. }, [isValid])
  308. useEffect(() => {
  309. checkDataField(values)
  310. }, [
  311. selectedAddress4, selectedAddress5,
  312. termsAndConAccept, termsAndConNotAccept])
  313. useEffect(() => {
  314. props.step == 2 ? _onSubmit() : null;
  315. if (captchaImg == "")
  316. onCaptchaChange();
  317. checkDataField(values)
  318. }, [props.step])
  319. const { handleSubmit } = useForm({})
  320. const _onSubmit = () => {
  321. setLoding(true);
  322. const userAddress = {
  323. "addressLine1": "",
  324. "addressLine2": "",
  325. "addressLine3": "",
  326. "district": "",
  327. "country": ""
  328. };
  329. userAddress.addressLine1 = values.address1
  330. userAddress.addressLine2 = values.address2
  331. userAddress.addressLine3 = values.address3
  332. userAddress.district = selectedAddress4 == null ? "" : selectedAddress4.type
  333. userAddress.country = selectedAddress5.type
  334. const userFaxNo = {
  335. "countryCode": values.faxCountryCode,
  336. "faxNumber": values.fax,
  337. };
  338. const userMobileNumber = {
  339. "countryCode": values.phoneCountryCode,
  340. "phoneNumber": values.phone,
  341. };
  342. let tncFlag = false;
  343. if (termsAndConAccept) {
  344. tncFlag = true
  345. }
  346. if (termsAndConNotAccept) {
  347. tncFlag = false
  348. }
  349. const preferLocale = locale === 'en' ? 'en' : locale === 'zh-HK' ? 'zh_HK' : 'zh-CN'
  350. const formData = {
  351. enName: iAmSmartData.enName,
  352. chName: iAmSmartData.chName,
  353. emailAddress: values.email,
  354. idDocType: "HKID",
  355. identification: iAmSmartData.idNo,
  356. checkDigit: iAmSmartData.checkDigit,
  357. tncFlag: tncFlag,
  358. type: "IND",
  359. userFaxNo: JSON.stringify(userFaxNo),
  360. userMobileNumber: JSON.stringify(userMobileNumber),
  361. userAddress: JSON.stringify(userAddress),
  362. captcha: base64Url,
  363. checkCode: checkCode,
  364. preferLocale: preferLocale
  365. };
  366. if (isValid) {
  367. axios.post(POST_IAMSMART_USER_REGISTER, formData, {
  368. headers: {
  369. "Content-Type": "multipart/form-data"
  370. }
  371. })
  372. .then((response) => {
  373. console.log(response)
  374. setCheckUpload(true)
  375. props.onRegistrationComplete?.();
  376. setLoding(false);
  377. })
  378. .catch(error => {
  379. console.error(error);
  380. setLoding(false);
  381. });
  382. } else {
  383. setLoding(false);
  384. }
  385. }
  386. function handlePhone(phone) {
  387. if (phone.length < 8) {
  388. return false;
  389. } else {
  390. return true;
  391. }
  392. }
  393. function handleCaptcha(captchaField) {
  394. if (captchaField.length == 5) {
  395. return true
  396. } else {
  397. return false
  398. }
  399. }
  400. function handleEmail(email) {
  401. var validRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
  402. if (!email.match(validRegex)) {
  403. return false;
  404. } else {
  405. return true;
  406. }
  407. }
  408. function displayErrorMsg(errorMsg) {
  409. return <Typography variant="errorMessage1">{errorMsg}</Typography>
  410. }
  411. const formik = useFormik({
  412. initialValues: ({
  413. email: iAmSmartData.email ?? "",
  414. emailConfirm: iAmSmartData.email ?? "",
  415. address1: iAmSmartData.address1 ?? "",
  416. address2: '',
  417. address3: '',
  418. phone: iAmSmartData.phone ?? "",
  419. phoneCountryCode: iAmSmartData.phoneCountryCode ?? "852",
  420. submit: null,
  421. fax: '',
  422. faxCountryCode: '852',
  423. captchaField: ''
  424. }),
  425. validationSchema: yup.object().shape({
  426. address1: yup.string().max(40, getMaxErrStr(40)).required(displayErrorMsg(intl.formatMessage({ id: 'validateAddressLine1' }))),
  427. address2: yup.string().max(40),
  428. address3: yup.string().max(40),
  429. email: yup.string().email(displayErrorMsg(intl.formatMessage({ id: 'validEmailFormat' }))).max(128, getMaxErrStr(128)).required(displayErrorMsg(intl.formatMessage({ id: 'requireEmail' }))),
  430. emailConfirm: yup.string().email(displayErrorMsg(intl.formatMessage({ id: 'validEmailFormat' }))).max(128, getMaxErrStr(128)).required(displayErrorMsg(intl.formatMessage({ id: 'requireEmail' }))).oneOf([yup.ref('email'), null], displayErrorMsg(intl.formatMessage({ id: 'validSameEmail' }))),
  431. phoneCountryCode: yup.string().min(2, displayErrorMsg(intl.formatMessage({ id: 'requireAtLeast2Number' }))).required(displayErrorMsg(intl.formatMessage({ id: 'requireDialingCode' }))),
  432. phone: yup.string().min(8, displayErrorMsg(intl.formatMessage({ id: 'requireAtLeast8Number' }))).required(displayErrorMsg(intl.formatMessage({ id: 'requireContactNumber' }))),
  433. captchaField: yup.string().max(5, getMaxErrStr(5)).required(displayErrorMsg(intl.formatMessage({ id: 'requireVerify' }))).min(5, displayErrorMsg(intl.formatMessage({ id: 'requireVerify' }))),//.oneOf([captcha], displayErrorMsg('請輸入有效驗證')),
  434. }),
  435. });
  436. const handleCCPChange = (e) => {
  437. e.preventDefault();
  438. };
  439. const { values } = formik
  440. useEffect(() => {
  441. if (!props.step0GuardRef) return;
  442. props.step0GuardRef.current = async () => {
  443. const syncOk = computeStep0ValidSync(values);
  444. if (!syncOk) {
  445. setisValid(false);
  446. if (!isRegisterAddressValid(values)) {
  447. if (values.address1 === '') {
  448. notifyActionError(intl.formatMessage({ id: 'validateAddressLine1' }));
  449. } else if (!isAddressLineWithinLimit(values.address1)) {
  450. notifyActionError(intl.formatMessage({ id: 'noMoreThenNWords' }, { num: ADDRESS_LINE_MAX_LENGTH, fieldname: intl.formatMessage({ id: 'addressLine1' }) + ": " }));
  451. } else if (!isAddressLineWithinLimit(values.address2)) {
  452. notifyActionError(intl.formatMessage({ id: 'noMoreThenNWords' }, { num: ADDRESS_LINE_MAX_LENGTH, fieldname: intl.formatMessage({ id: 'addressLine2' }) + ": " }));
  453. } else if (!isAddressLineWithinLimit(values.address3)) {
  454. notifyActionError(intl.formatMessage({ id: 'noMoreThenNWords' }, { num: ADDRESS_LINE_MAX_LENGTH, fieldname: intl.formatMessage({ id: 'addressLine3' }) + ": " }));
  455. }
  456. } else if (!isDistrictSelectionValid()) {
  457. setDistrictErrStr(getRequiredErrStr("district"));
  458. setCheckDistrict(true);
  459. notifyActionError(intl.formatMessage({ id: 'require' }, { fieldname: intl.formatMessage({ id: 'district' }) }));
  460. }
  461. return false;
  462. }
  463. try {
  464. const taken = await checkEmailRegistered(values.email);
  465. setCheckEmail(taken);
  466. if (taken) {
  467. setisValid(false);
  468. notifyActionError(intl.formatMessage({ id: 'emailUsed' }));
  469. return false;
  470. }
  471. } catch (error) {
  472. notifyActionError(intl.formatMessage({ id: 'connectionError' }));
  473. return false;
  474. }
  475. setisValid(true);
  476. return true;
  477. };
  478. }, [values, selectedAddress4, selectedAddress5, termsAndConAccept, checkEmail]);
  479. useEffect(() => {
  480. checkDataField(values)
  481. }, [values])
  482. return (
  483. isLoadingData ?
  484. <LoadingComponent /> :
  485. <FormikProvider value={formik}>
  486. <form onSubmit={handleSubmit(_onSubmit)}>
  487. {/* Input Form */}
  488. <FormGroup id={"inputForm"} sx={{ display: props.step === 0 ? "" : "none" }}>
  489. <Grid container spacing={3}>
  490. <Grid item xs={12} md={12}>
  491. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  492. <div style={{ borderBottom: "3px solid #1A4399", width: "100%", margin_right: "15px" }}>
  493. <Typography display="inline" variant="h3" component="h1" sx={{ color: '#1A4399' }}>
  494. <FormattedMessage id="becomeNewPersonalUser" />
  495. </Typography>
  496. </div>
  497. <Typography mt={0.25} variant="h6" component="span" sx={{ color: '#B00020' }}>
  498. <FormattedMessage id="requireString" />。
  499. </Typography>
  500. <Stack mt={1} direction="row" style={{ alignItems: "center" }}><img src={iAmSmartICon} alt="iAM Smart" width="25" /><Typography mt={0.25} variant="h6" component="span" >: <FormattedMessage id="MSG.providedByIAmSmart" /></Typography></Stack>
  501. </Stack>
  502. </Grid>
  503. <Grid item xs={12} md={12}>
  504. <Grid container spacing={1}>
  505. <Grid item xs={12} mt={1} mb={1}>
  506. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  507. <Typography display="inline" variant="h4" component="h2" sx={{ color: 'primary.primary' }}>
  508. <FormattedMessage id="yourPersonalInformation" />
  509. </Typography>
  510. </Stack>
  511. </Grid>
  512. <Grid item xs={12} md={12} >
  513. <Grid container sx={{ mb: 1 }}>
  514. <InputLabel htmlFor="idDocType-signup">
  515. <Typography variant="h5" component="span" sx={{ mr: 1 }}>
  516. <FormattedMessage id="HKIDcard" />: {iAmSmartData.idNo ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : <></>}
  517. {/* {iAmSmartData.idNo + "(" + iAmSmartData.checkDigit + ")"} */}
  518. </Typography>
  519. <Stack direction="row">
  520. <Typography variant="h5" component="span">
  521. {iAmSmartData?.idNo?.slice(0, 4)}{showId ? iAmSmartData?.idNo?.slice(4) : "****"}{showId ? '(' + iAmSmartData.checkDigit + ')' : null}
  522. </Typography>
  523. <IconButton
  524. role="button"
  525. tabIndex={0}
  526. aria-label={intl.formatMessage({ id: 'ariaToggleIdVisibility' })}
  527. onClick={handleClickShowId}
  528. onKeyDown={(event) => handleActionKeyDown(event, handleClickShowId)}
  529. onMouseDown={handleMouseDownId}
  530. edge="end"
  531. size="medium"
  532. >
  533. {showId ? <EyeOutlined /> : <EyeInvisibleOutlined />}
  534. </IconButton>
  535. </Stack>
  536. </InputLabel>
  537. </Grid>
  538. </Grid>
  539. <Grid item xs={12} md={6}>
  540. <Stack spacing={1}>
  541. <InputLabel htmlFor="enName-signup">
  542. <Typography variant="h5" component="span">
  543. <FormattedMessage id="userEnglishName" />: {iAmSmartData.enName}{iAmSmartData.enName ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : <></>}
  544. </Typography>
  545. </InputLabel>
  546. </Stack>
  547. </Grid>
  548. <Grid item xs={12} md={6}>
  549. <Stack spacing={1}>
  550. <InputLabel htmlFor="chName-signup">
  551. <Typography variant="h5" component="span">
  552. {intl.formatMessage({ id: 'userChineseName' })}: {iAmSmartData.chName}{iAmSmartData.chName ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : <></>}
  553. </Typography>
  554. </InputLabel>
  555. </Stack>
  556. </Grid>
  557. <Grid item xs={12}>
  558. <Stack spacing={1}>
  559. <InputLabel htmlFor="address1-signup">
  560. <Typography variant="h5" component="span">
  561. <FormattedMessage id="formAddress" />
  562. <span style={{ color: '#B00020' }}>*</span>
  563. </Typography>
  564. </InputLabel>
  565. <Stack direction="row" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  566. <OutlinedInput
  567. fullWidth
  568. autoFocus
  569. error={Boolean(formik.touched.address1 && formik.errors.address1)}
  570. id="address1-signup"
  571. value={formik.values.address1}
  572. name="address1"
  573. onChange={formik.handleChange}
  574. placeholder={intl.formatMessage({ id: 'addressLine1' })}
  575. onBlur={formik.handleBlur}
  576. inputProps={{
  577. maxLength: ADDRESS_LINE_MAX_LENGTH,
  578. onKeyDown: (e) => {
  579. if (e.key === 'Enter') {
  580. e.preventDefault();
  581. }
  582. },
  583. }}
  584. />
  585. {iAmSmartData.address1 != "" && iAmSmartData.address1 == formik.values.address1 ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : null}
  586. </Stack>
  587. <Stack direction="row" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  588. <OutlinedInput
  589. fullWidth
  590. error={Boolean(formik.touched.address2 && formik.errors.address2)}
  591. id="address2-signup"
  592. value={formik.values.address2}
  593. name="address2"
  594. onBlur={formik.handleBlur}
  595. onChange={formik.handleChange}
  596. placeholder={intl.formatMessage({ id: 'addressLine2' })}
  597. inputProps={{
  598. maxLength: ADDRESS_LINE_MAX_LENGTH,
  599. onKeyDown: (e) => {
  600. if (e.key === 'Enter') {
  601. e.preventDefault();
  602. }
  603. },
  604. }}
  605. />
  606. {iAmSmartData.address2 != "" && iAmSmartData.address2 == formik.values.address2 ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : null}
  607. </Stack>
  608. <Stack direction="row" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  609. <OutlinedInput
  610. fullWidth
  611. error={Boolean(formik.touched.address3 && formik.errors.address3)}
  612. id="address3-signup"
  613. value={formik.values.address3}
  614. name="address3"
  615. onBlur={formik.handleBlur}
  616. onChange={formik.handleChange}
  617. placeholder={intl.formatMessage({ id: 'addressLine3' })}
  618. inputProps={{
  619. maxLength: ADDRESS_LINE_MAX_LENGTH,
  620. onKeyDown: (e) => {
  621. if (e.key === 'Enter') {
  622. e.preventDefault();
  623. }
  624. },
  625. }}
  626. />
  627. {iAmSmartData.address3 != "" && iAmSmartData.address3 == formik.values.address3 ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : null}
  628. </Stack>
  629. <Autocomplete
  630. disablePortal
  631. id="address4-combo"
  632. value={selectedAddress4}
  633. options={address4ComboList}
  634. disabled={checkCountry}
  635. // error={Boolean(districtErrStr != "")}
  636. onBlur={formik.handleBlur}
  637. getOptionLabel={(option) => option.type ? intl.formatMessage({ id: option.type }) : ""}
  638. onChange={(event, newValue) => {
  639. setSelectedAddress4(newValue);
  640. }}
  641. sx={{
  642. '& .MuiInputBase-root': { alignItems: 'center' },
  643. '& .MuiAutocomplete-endAdornment': { top: '50%', transform: 'translateY(-50%)' },
  644. '& .MuiOutlinedInput-root': { height: 40 }
  645. }}
  646. renderInput={(params) => <TextField error={checkDistrict} {...params} placeholder={intl.formatMessage({ id: 'region' })}
  647. />}
  648. clearText={intl.formatMessage({ id: "muiClear" })}
  649. closeText={intl.formatMessage({ id: "muiClose" })}
  650. openText={intl.formatMessage({ id: "muiOpen" })}
  651. noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
  652. />
  653. <Autocomplete
  654. disablePortal
  655. id="address5-combo"
  656. value={selectedAddress5}
  657. options={address5ComboList}
  658. disabled= {true}
  659. getOptionLabel={(option) => option.type ? intl.formatMessage({ id: option.type }) : ""}
  660. onChange={(event, newValue) => {
  661. if (newValue !== null) {
  662. setSelectedAddress5(newValue);
  663. if (newValue.type === 'hongKong') {
  664. setCheckCountry(false)
  665. } else {
  666. setSelectedAddress4("");
  667. setCheckCountry(true)
  668. }
  669. } else {
  670. setSelectedAddress4("");
  671. setCheckCountry(true)
  672. }
  673. }}
  674. sx={{
  675. '& .MuiInputBase-root': { alignItems: 'center' },
  676. '& .MuiAutocomplete-endAdornment': { top: '50%', transform: 'translateY(-50%)' },
  677. '& .MuiOutlinedInput-root': { height: 40 }
  678. }}
  679. renderInput={(params) => <TextField {...params} placeholder={intl.formatMessage({ id: 'regionOrCountry' })} />}
  680. clearText={intl.formatMessage({ id: "muiClear" })}
  681. closeText={intl.formatMessage({ id: "muiClose" })}
  682. openText={intl.formatMessage({ id: "muiOpen" })}
  683. noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
  684. />
  685. {formik.touched.address1 && formik.errors.address1 && (
  686. <FormHelperText error id="helper-text-address1-signup">
  687. {formik.errors.address1}
  688. </FormHelperText>
  689. )}
  690. {formik.touched.address2 && formik.errors.address2 && (
  691. <FormHelperText error id="helper-text-address2-signup">
  692. {formik.errors.address2}
  693. </FormHelperText>
  694. )}
  695. {formik.touched.address3 && formik.errors.address3 && (
  696. <FormHelperText error id="helper-text-address3-signup">
  697. {formik.errors.address3}
  698. </FormHelperText>
  699. )}
  700. {checkDistrict && (
  701. <FormHelperText error >
  702. {districtErrStr}
  703. </FormHelperText>
  704. )}
  705. </Stack>
  706. </Grid>
  707. <Grid item xs={12} mt={1} mb={1}>
  708. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  709. <Typography display="inline" variant="h4" component="h2" sx={{ color: 'primary.primary' }}>
  710. <FormattedMessage id="yourContact" />
  711. </Typography>
  712. </Stack>
  713. </Grid>
  714. <Grid item xs={12} md={12}>
  715. <Grid container>
  716. <Grid item xs={12} md={6}>
  717. <Stack spacing={1} sx={{ mr: { md: 1 }, mb: 1 }}>
  718. <InputLabel htmlFor="email-login">
  719. <Typography variant="h5" component="span">
  720. <FormattedMessage id="userContactEmail" />
  721. <span style={{ color: '#B00020' }}>*</span>
  722. </Typography>
  723. </InputLabel>
  724. <Stack direction="row" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  725. <OutlinedInput
  726. fullWidth
  727. error={Boolean((formik.touched.email && formik.errors.email) || checkEmail)}
  728. id="email-login"
  729. type="email"
  730. value={formik.values.email.trim()}
  731. name="email"
  732. onChange={formik.handleChange}
  733. placeholder={intl.formatMessage({ id: 'userContactEmail' })}
  734. onBlur={formik.handleBlur}
  735. inputProps={{
  736. "aria-describedby": "helper-text-email-signup",
  737. "aria-label": intl.formatMessage({ id: "userContactEmail" }),
  738. onKeyDown: (e) => {
  739. if (e.key === 'Enter') {
  740. e.preventDefault();
  741. }
  742. },
  743. }}
  744. />
  745. {iAmSmartData.email && iAmSmartData.email == formik.values.email ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : null}
  746. </Stack>
  747. {formik.touched.email && formik.errors.email && (
  748. <FormHelperText error id="helper-text-email-signup">
  749. {formik.errors.email}
  750. </FormHelperText>
  751. )}
  752. {checkEmail && (
  753. <FormHelperText error id="helper-text-email-signup">
  754. <FormattedMessage id="emailUsed" />
  755. </FormHelperText>
  756. )}
  757. </Stack>
  758. </Grid>
  759. <Grid item xs={12} md={6}>
  760. <Stack spacing={1} >
  761. <InputLabel htmlFor="emailConfirm-login">
  762. <Typography variant="h5" component="span">
  763. <FormattedMessage id="confirmEmail" />
  764. <span style={{ color: '#B00020' }}>*</span>
  765. </Typography>
  766. </InputLabel>
  767. <Stack direction="row" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  768. <OutlinedInput
  769. fullWidth
  770. error={Boolean(formik.touched.emailConfirm && formik.errors.emailConfirm)}
  771. id="emailConfirm-login"
  772. type="email"
  773. value={formik.values.emailConfirm}
  774. name="emailConfirm"
  775. // onBlur={formik.handleBlur}
  776. onChange={formik.handleChange}
  777. placeholder={intl.formatMessage({ id: 'confirmEmail' })}
  778. onBlur={formik.handleBlur}
  779. onCut={handleCCPChange}
  780. onCopy={handleCCPChange}
  781. onPaste={handleCCPChange}
  782. inputProps={{
  783. "aria-label": intl.formatMessage({ id: "confirmEmail" }),
  784. "aria-describedby": "helper-text-emailConfirm-signup",
  785. onKeyDown: (e) => {
  786. if (e.key === 'Enter') {
  787. e.preventDefault();
  788. }
  789. },
  790. }}
  791. />
  792. {iAmSmartData.email && iAmSmartData.email == formik.values.emailConfirm ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : null}
  793. </Stack>
  794. {formik.touched.emailConfirm && formik.errors.emailConfirm && (
  795. <FormHelperText error id="helper-text-emailConfirm-signup">
  796. {formik.errors.emailConfirm}
  797. </FormHelperText>
  798. )}
  799. </Stack>
  800. </Grid>
  801. </Grid>
  802. </Grid>
  803. <Grid item xs={12} md={12}>
  804. <Grid container>
  805. <Grid item xs={12} md={6}>
  806. <Grid container>
  807. <Grid item xs={12} md={12}>
  808. <Stack direction="column" spacing={1} sx={{ mr: { md: 1 }, mb: 1 }}>
  809. <InputLabel htmlFor="phone-signup">
  810. <Typography variant="h5" component="span">
  811. <FormattedMessage id="userContactNumber" />
  812. <span style={{ color: '#B00020' }}>*</span>
  813. </Typography>
  814. </InputLabel>
  815. <Stack direction="row" ustifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  816. <OutlinedInput
  817. id="phoneCountryCode-login"
  818. type="phoneCountryCode"
  819. value={formik.values.phoneCountryCode.trim()}
  820. name="phoneCountryCode"
  821. // onBlur={formik.handleBlur}
  822. // onChange={formik.handleChange}
  823. onChange={(event) => {
  824. const value = event.target.value;
  825. if (value.match(/[^0-9]/)) {
  826. return event.preventDefault();
  827. }
  828. formik.setFieldValue("phoneCountryCode", value);
  829. }}
  830. placeholder={intl.formatMessage({ id: 'dialingCode' })}
  831. error={Boolean(formik.touched.phone && formik.errors.phone)}
  832. onBlur={formik.handleBlur}
  833. inputProps={{
  834. maxLength: 3,
  835. onKeyDown: (e) => {
  836. if (e.key === 'Enter') {
  837. e.preventDefault();
  838. }
  839. },
  840. }}
  841. sx={{ width: '25%' }}
  842. />
  843. <OutlinedInput
  844. id="phone-login"
  845. type="phone"
  846. value={formik.values.phone.trim()}
  847. name="phone"
  848. // onBlur={formik.handleBlur}
  849. // onChange={formik.handleChange}
  850. onChange={(event) => {
  851. const value = event.target.value;
  852. if (value.match(/[^0-9]/)) {
  853. return event.preventDefault();
  854. }
  855. formik.setFieldValue("phone", value);
  856. }}
  857. placeholder={intl.formatMessage({ id: 'userContactNumber' })}
  858. error={Boolean(formik.touched.phone && formik.errors.phone)}
  859. onBlur={formik.handleBlur}
  860. inputProps={{
  861. "aria-label": intl.formatMessage({ id: "userContactNumber" }),
  862. "aria-describedby": 'helper-text-phone-signup',
  863. maxLength: 11,
  864. onKeyDown: (e) => {
  865. if (e.key === 'Enter') {
  866. e.preventDefault();
  867. }
  868. },
  869. }}
  870. fullWidth
  871. />
  872. {iAmSmartData.phone && iAmSmartData.phone == formik.values.phone && iAmSmartData.phoneCountryCode == formik.values.phoneCountryCode ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : null}
  873. </Stack>
  874. {formik.touched.phone && formik.errors.phone && (
  875. <FormHelperText error id="helper-text-phone-signup">
  876. {formik.errors.phone}
  877. </FormHelperText>
  878. )}
  879. </Stack>
  880. </Grid>
  881. </Grid>
  882. </Grid>
  883. <Grid item xs={12} md={6}>
  884. <Grid container>
  885. <Grid item xs={12} md={12}>
  886. <Stack spacing={1} direction="column">
  887. <InputLabel htmlFor="fax-signup">
  888. <Typography variant="h5" component="span">
  889. <FormattedMessage id="userFaxNumber" />
  890. </Typography>
  891. </InputLabel>
  892. <Stack direction="row" ustifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  893. <OutlinedInput
  894. error={Boolean(formik.touched.fax && formik.errors.fax)}
  895. id="faxCountryCode-login"
  896. type="faxCountryCode"
  897. value={formik.values.faxCountryCode.trim()}
  898. name="faxCountryCode"
  899. // onChange={formik.handleChange}
  900. onChange={(event) => {
  901. const value = event.target.value;
  902. if (value.match(/[^0-9]/)) {
  903. return event.preventDefault();
  904. }
  905. formik.setFieldValue("faxCountryCode", value);
  906. }}
  907. placeholder={intl.formatMessage({ id: 'dialingCode' })}
  908. onBlur={formik.handleBlur}
  909. inputProps={{
  910. maxLength: 3,
  911. onKeyDown: (e) => {
  912. if (e.key === 'Enter') {
  913. e.preventDefault();
  914. }
  915. },
  916. }}
  917. sx={{ width: '25%' }}
  918. />
  919. <OutlinedInput
  920. id="fax-login"
  921. type="fax"
  922. value={formik.values.fax.trim()}
  923. name="fax"
  924. onBlur={formik.handleBlur}
  925. // onChange={formik.handleChange}
  926. onChange={(event) => {
  927. const value = event.target.value;
  928. if (value.match(/[^0-9]/)) {
  929. return event.preventDefault();
  930. }
  931. formik.setFieldValue("fax", value);
  932. }}
  933. placeholder={intl.formatMessage({ id: 'userFaxNumber' })}
  934. inputProps={{
  935. maxLength: 8,
  936. onKeyDown: (e) => {
  937. if (e.key === 'Enter') {
  938. e.preventDefault();
  939. }
  940. },
  941. }}
  942. sx={{ width: '75%' }}
  943. />
  944. </Stack>
  945. </Stack>
  946. </Grid>
  947. </Grid>
  948. </Grid>
  949. </Grid>
  950. </Grid>
  951. </Grid>
  952. <Grid item xs={12} md={12}>
  953. <Grid container>
  954. <Grid item xs={12} md={12}>
  955. <Typography display="inline" variant="h4" component="h2" sx={{ color: 'primary.primary' }}>
  956. <FormattedMessage id="termsAndCondition" />
  957. <span style={{ color: '#B00020' }}>*</span>
  958. </Typography>
  959. </Grid>
  960. <Grid item xs={12} md={12}>
  961. <Grid container>
  962. <Grid item xs={12} md={12}>
  963. <Typography sx={{ textAlign: "left", borderRadius: "inherit", borderStyle: "solid", borderWidth: "1px", borderColor: "#0c489e" }}>
  964. <div style={{ padding: 12 }} dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: "termsAndCon" }) }} />
  965. </Typography>
  966. </Grid>
  967. </Grid>
  968. <Grid item xs={12} s={12} md={12} lg={12}>
  969. <Grid container>
  970. <Grid item xs={6} s={6} md={11} lg={11}>
  971. <Grid container>
  972. <Grid item sx={{ display: 'flex', alignItems: 'center' }}>
  973. <Checkbox
  974. checked={termsAndConAccept}
  975. onChange={handleCheckBoxChange}
  976. name="termsAndConAccept"
  977. color="primary"
  978. size="small"
  979. />
  980. <Typography variant="h5" component="span">
  981. <FormattedMessage id="iConfirm" />
  982. </Typography>
  983. </Grid>
  984. </Grid>
  985. </Grid>
  986. <Grid item xs={6} s={6} md={3} lg={3}>
  987. <Grid container style={{ display: "none" }}>
  988. <Grid item sx={{ display: 'flex', alignItems: 'center' }}>
  989. <Checkbox
  990. checked={termsAndConNotAccept}
  991. onChange={handleCheckBoxChange}
  992. name="termsAndConNotAccept"
  993. color="primary"
  994. size="small"
  995. />
  996. <Typography variant="h5" component="span">
  997. <FormattedMessage id="rejectTerms" />
  998. </Typography>
  999. </Grid>
  1000. </Grid>
  1001. </Grid>
  1002. </Grid>
  1003. </Grid>
  1004. </Grid>
  1005. </Grid>
  1006. </Grid>
  1007. <Grid item xs={12} lg={12}>
  1008. <Grid container>
  1009. <Stack direction="column">
  1010. <Typography display="inline" variant="h4" component="h2" sx={{ color: 'primary.primary' }}>
  1011. <FormattedMessage id="verify" />
  1012. <span style={{ color: '#B00020' }}>*</span>
  1013. </Typography>
  1014. <Stack spacing={1} direction="row">
  1015. <Grid item xs={5} lg={5} style={{ "border": "1px solid black" }}>
  1016. <img src={captchaImg} alt="" />
  1017. </Grid>
  1018. <Grid item xs={1} lg={1} style={{ "border": "0px solid black" }}>
  1019. <IconButton
  1020. role="button"
  1021. tabIndex={0}
  1022. aria-label={intl.formatMessage({ id: 'ariaRefreshCaptcha' })}
  1023. size="large"
  1024. onClick={() => { onCaptchaChange() }}
  1025. onKeyDown={(event) => handleActionKeyDown(event, () => onCaptchaChange())}
  1026. >
  1027. <LoopIcon fontSize="inherit" />
  1028. </IconButton>
  1029. </Grid>
  1030. <Grid item xs={6} lg={6}>
  1031. <OutlinedInput
  1032. fullWidth
  1033. id="captchaField"
  1034. type="text"
  1035. value={formik.values.captchaField.trim()}
  1036. onBlur={formik.handleBlur}
  1037. error={Boolean(formik.touched.captchaField && formik.errors.captchaField)}
  1038. name="captchaField"
  1039. onChange={(event) => {
  1040. const value = event.target.value;
  1041. props.setCheckCode(event.target.value);
  1042. setCheckCode(event.target.value);
  1043. formik.setFieldValue("captchaField", value);
  1044. }}
  1045. sx={{ width: '75%' }}
  1046. />
  1047. </Grid>
  1048. </Stack>
  1049. {formik.touched.captchaField && formik.errors.captchaField && (
  1050. <FormHelperText error id="helper-text-captcha-signup">
  1051. {formik.errors.captchaField}
  1052. </FormHelperText>
  1053. )}
  1054. <Stack spacing={1} direction="row" sx={{ mt: 0.25 }}>
  1055. <Button
  1056. variant="contained"
  1057. onClick={playCaptchaAudio}
  1058. aria-label={intl.formatMessage({ id: "captchaPlayAudio" })}
  1059. sx={{
  1060. backgroundColor: '#0c489e',
  1061. color: '#FFFFFF',
  1062. '&:hover': { backgroundColor: '#1565c0' },
  1063. }}
  1064. >
  1065. <FormattedMessage id="captchaPlayAudio" />
  1066. </Button>
  1067. </Stack>
  1068. </Stack>
  1069. </Grid>
  1070. </Grid>
  1071. </Grid>
  1072. </Grid>
  1073. </FormGroup>
  1074. {/* Preview Form */}
  1075. <FormGroup id={"previewForm"} sx={{ display: props.step === 1 ? "" : "none" }}>
  1076. <Grid container spacing={3}>
  1077. <Grid item xs={12} md={12}>
  1078. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1079. <div style={{ borderBottom: "3px solid #1A4399", width: "100%", margin_right: "15px" }}>
  1080. <Typography display="inline" variant="h3" component="h1" sx={{ color: '#1A4399' }}>
  1081. <FormattedMessage id="becomeNewPersonalUser" />
  1082. </Typography>
  1083. </div>
  1084. </Stack>
  1085. </Grid>
  1086. <Grid item xs={12} md={12}>
  1087. <Grid container spacing={2}>
  1088. <Grid item xs={12} mt={1} mb={1}>
  1089. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1090. <Typography display="inline" variant="h4" component="h2" sx={{ color: 'primary.primary' }}>
  1091. <FormattedMessage id="yourPersonalInformation" />
  1092. </Typography>
  1093. {/* <Typography component={Link} to="/login" variant="body1" sx={{ textDecoration: 'none' }} color="primary">
  1094. Already have an account?
  1095. </Typography> */}
  1096. </Stack>
  1097. </Grid>
  1098. <Grid item xs={12} md={12} >
  1099. <Stack direction="row">
  1100. <Typography variant="h5" component="h2" color={theme.palette.grey[600]} sx={{ mr: 1 }}>
  1101. <FormattedMessage id="userIdDoc" />
  1102. </Typography>
  1103. <Typography variant="h5" component="span" name="preview-idDocType-1">
  1104. {formik?.values?.idNo?.slice(0, 4)}
  1105. {/* {formik.values.idNo + "(" + formik.values.checkDigit + ")"} */}
  1106. </Typography>
  1107. <Typography variant="h5" component="span" name="preview-idDocType-2">
  1108. {showComId ? formik?.values?.idNo?.slice(4) : "****"}{showComId ? '(' + formik.values.checkDigit + ')' : null}
  1109. {/* {formik.values.idNo + "(" + formik.values.checkDigit + ")"} */}
  1110. </Typography>
  1111. <IconButton
  1112. role="button"
  1113. tabIndex={0}
  1114. aria-label={intl.formatMessage({ id: 'ariaToggleIdVisibility' })}
  1115. onClick={handleClickShowComId}
  1116. onKeyDown={(event) => handleActionKeyDown(event, handleClickShowComId)}
  1117. onMouseDown={handleMouseDownComId}
  1118. edge="end"
  1119. size="medium"
  1120. >
  1121. {showComId ? <EyeOutlined /> : <EyeInvisibleOutlined />}
  1122. </IconButton>
  1123. </Stack>
  1124. </Grid>
  1125. <Grid item xs={12} md={6}>
  1126. <Stack spacing={1} direction="row">
  1127. <Typography variant="h5" component="span" color={theme.palette.grey[600]}>
  1128. <FormattedMessage id="userEnglishName" />:
  1129. </Typography>
  1130. <Typography variant="h5" component="span" id="preview-enName-signup">
  1131. {formik.values.enName}
  1132. </Typography>
  1133. {iAmSmartData.enName ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : <></>}
  1134. </Stack>
  1135. </Grid>
  1136. <Grid item xs={12} md={6}>
  1137. <Stack spacing={1} direction="row">
  1138. <Typography variant="h5" component="span" color={theme.palette.grey[600]}>
  1139. <FormattedMessage id="userChineseName" />:
  1140. </Typography>
  1141. <Typography variant="h5" component="span" id="preview-chName-signup">
  1142. {formik.values.chName}
  1143. </Typography>
  1144. </Stack>
  1145. </Grid>
  1146. <Grid item xs={12}>
  1147. <Stack spacing={1} direction="column">
  1148. <Typography variant="h5" component="span" color={theme.palette.grey[600]}>
  1149. <FormattedMessage id="formAddress" />:
  1150. </Typography>
  1151. <Stack spacing={1} direction="column">
  1152. <Typography variant="h5" component="span" id="preview-address1-signup">
  1153. {formik.values.address1}
  1154. </Typography>
  1155. {formik.values.address2 != null ?
  1156. <Typography variant="h5" component="span" id="preview-address2-signup">
  1157. {formik.values.address2}
  1158. </Typography>
  1159. : null}
  1160. {formik.values.address3 != null ?
  1161. <Typography variant="h5" component="span" id="preview-address3-signup">
  1162. {formik.values.address3}
  1163. </Typography>
  1164. : null}
  1165. {selectedAddress5.type === "hongKong" ?
  1166. <Stack direction="column">
  1167. {/* <Typography variant="h5" component="span" color={theme.palette.grey[600]} id="preview-address4-signup">
  1168. <FormattedMessage id="region" />:
  1169. </Typography> */}
  1170. <Typography variant="h5" component="span">
  1171. {!selectedAddress4 ? "" : intl.formatMessage({ id: selectedAddress4.type })}
  1172. </Typography>
  1173. </Stack>
  1174. : null}
  1175. <Stack direction="column">
  1176. {/* <Typography variant="h5" component="span" color={theme.palette.grey[600]} id="preview-address5-signup">
  1177. <FormattedMessage id="regionOrCountry" />:
  1178. </Typography> */}
  1179. <Typography variant="h5" component="span">
  1180. {intl.formatMessage({ id: selectedAddress5.type })}
  1181. </Typography>
  1182. </Stack>
  1183. </Stack>
  1184. </Stack>
  1185. </Grid>
  1186. <Grid item xs={12} mt={1} mb={1}>
  1187. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1188. <Typography display="inline" variant="h4" component="h2" sx={{ color: 'primary.primary' }}>
  1189. <FormattedMessage id="yourContact" />
  1190. </Typography>
  1191. </Stack>
  1192. </Grid>
  1193. <Grid item xs={12} md={12}>
  1194. <Stack spacing={1} direction="row">
  1195. <Typography variant="h5" component="span" color={theme.palette.grey[600]}>
  1196. <FormattedMessage id="userContactEmail" />:
  1197. </Typography>
  1198. <Typography variant="h5" component="span" id="preview-email-signup">
  1199. {formik.values.email}
  1200. </Typography>
  1201. </Stack>
  1202. </Grid>
  1203. <Grid item xs={12} md={6}>
  1204. <Stack spacing={1} direction="row">
  1205. <Typography variant="h5" component="span" color={theme.palette.grey[600]}>
  1206. <FormattedMessage id="userContactNumber" />:
  1207. </Typography>
  1208. <Typography variant="h5" component="span" id="preview-phone-signup">
  1209. +{formik.values.phoneCountryCode} {formik.values.phone}
  1210. </Typography>
  1211. </Stack>
  1212. </Grid>
  1213. {formik.values.faxCountryCode != "" && formik.values.fax != "" ?
  1214. <Grid item xs={12} md={6}>
  1215. <Stack spacing={1} direction="row">
  1216. <Typography variant="h5" component="span" color={theme.palette.grey[600]}>
  1217. <FormattedMessage id="userFaxNumber" />:
  1218. </Typography>
  1219. <Typography variant="h5" component="span" id="preview-fax-signup">
  1220. +{formik.values.faxCountryCode} {formik.values.fax}
  1221. </Typography>
  1222. </Stack>
  1223. </Grid>
  1224. : null}
  1225. </Grid>
  1226. </Grid>
  1227. </Grid>
  1228. </FormGroup>
  1229. {/* Submit page */}
  1230. <FormGroup id={"submitForm"} sx={{ display: props.step === 2 ? "" : "none" }}>
  1231. <Grid container spacing={3}>
  1232. {isLoading ?
  1233. <LoadingComponent /> :
  1234. <Grid item xs={12}>
  1235. {checkUpload ?
  1236. // SUCCESS page
  1237. <Stack mt={1} direction="column" justifyContent="flex-start" alignItems="center" spacing={2}>
  1238. <CheckCircleOutlineIcon color="success" sx={{ width: "200px", height: "200px" }} />
  1239. <Typography display="inline" variant="h4" component="span">
  1240. <FormattedMessage id="registerSubmitted" />
  1241. </Typography>
  1242. <Typography display="inline" variant="h4" component="span">
  1243. <FormattedMessage id="emailSent" />
  1244. </Typography>
  1245. <Button variant="outlined" component={Link} to="/login" ><Typography variant="h5" component="span">
  1246. <FormattedMessage id="backToLogin" />
  1247. </Typography></Button>
  1248. </Stack>
  1249. :
  1250. // ERROR page
  1251. <Stack mt={1} direction="column" justifyContent="flex-start" alignItems="center" spacing={2}>
  1252. {/* <Button disabled={true} hidden={true} variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button> */}
  1253. <CancelOutlinedIcon color="error" sx={{ width: "200px", height: "200px" }} />
  1254. <Typography display="inline" variant="h4" component="span">
  1255. <FormattedMessage id="registerFail" />
  1256. </Typography>
  1257. <Button color="error" variant="outlined" component={Link} to="/login" ><Typography variant="h5" component="span">
  1258. <FormattedMessage id="backToLogin" />
  1259. </Typography></Button>
  1260. </Stack>
  1261. }
  1262. </Grid>
  1263. }
  1264. </Grid>
  1265. </FormGroup>
  1266. </form>
  1267. </FormikProvider>
  1268. );
  1269. }
  1270. export default CustomFormWizard;