You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

1140 lines
69 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, GET_USER_EMAIL } 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. // ============================|| FIREBASE - REGISTER ||============================ //
  37. const CustomFormWizard = (props) => {
  38. const location = useLocation();
  39. const theme = useTheme();
  40. const intl = useIntl();
  41. const [iAmSmartData, setIAmSmartData] = useState({});
  42. const [checkUpload, setCheckUpload] = useState(false);
  43. const [isLoading, setLoding] = useState(true);
  44. const [captchaImg, setCaptchaImage] = useState("");
  45. const [selectedAddress4, setSelectedAddress4] = useState(null);
  46. const [selectedAddress5, setSelectedAddress5] = useState(ComboData.country[0]);
  47. const [termsAndConAccept, setTermsAndConAccept] = useState(false);
  48. const [termsAndConNotAccept, setTermsAndConNotAccept] = useState(false);
  49. const [isValid, setisValid] = useState(false);
  50. const [checkCountry, setCheckCountry] = useState(false);
  51. const email = document.getElementById("email-login")
  52. const [checkEmail, setCheckEmail] = useState(false)
  53. const [checkEmailBlur, setCheckEmailBlur] = useState(false)
  54. const [districtErrStr, setDistrictErrStr] = useState("")
  55. const address4ComboList = ComboData.district;
  56. const address5ComboList = ComboData.country;
  57. const [showId, setshowId] = useState(false);
  58. const [showComId, setshowComId] = useState(false);
  59. useEffect(() => {
  60. location.state?.responseData ?? {}
  61. if (captchaImg == "")
  62. onCaptchaChange();
  63. responseToData();
  64. }, []);
  65. const handleClickShowId = () => {
  66. setshowId(!showId);
  67. };
  68. const handleMouseDownId = (event) => {
  69. event.preventDefault();
  70. };
  71. const handleClickShowComId = () => {
  72. setshowComId(!showId);
  73. };
  74. const handleMouseDownComId = (event) => {
  75. event.preventDefault();
  76. };
  77. useEffect(() => {
  78. setDistrictErrStr("");
  79. if (selectedAddress5?.type === "hongKong") {
  80. if (selectedAddress4 == null || selectedAddress4 == "" || selectedAddress4 == {})
  81. setDistrictErrStr(getRequiredErrStr("district"))
  82. }
  83. }, [selectedAddress4, selectedAddress5])
  84. function getRequiredErrStr(fieldname) {
  85. return displayErrorMsg(intl.formatMessage({ id: 'require' }, { fieldname: fieldname ? intl.formatMessage({ id: fieldname }) : "" }));
  86. }
  87. function getMaxErrStr(num, fieldname) {
  88. return displayErrorMsg(intl.formatMessage({ id: 'noMoreThenNWords' }, { num: num, fieldname: fieldname ? intl.formatMessage({ id: fieldname }) + ": " : "" }));
  89. }
  90. const responseToData = () => {
  91. 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\":\"測試商一\"}}");
  92. //let rd = JSON.parse(location.state?.responseData.data);
  93. let data = {
  94. "enName": rd?.enName?.UnstructuredName ?? "",
  95. "chName": rd?.chName?.ChineseName ?? "",
  96. "idNo": rd?.idNo?.Identification ?? "",
  97. "checkDigit": rd?.idNo?.CheckDigit ?? "",
  98. "email": rd?.emailAddress ?? "",
  99. "phone": rd?.mobileNumber?.SubscriberNumber ?? "",
  100. "phoneCountryCode": rd?.mobileNumber?.CountryCode ?? "",
  101. };
  102. if (rd?.postalAddress) {
  103. if (rd?.postalAddress?.EngPremisesAddress) {
  104. data["address1"] = getAddressEng(rd?.postalAddress?.EngPremisesAddress);
  105. } else if (rd.postalAddress.ChiPremisesAddress) {
  106. data["address1"] = getAddressChi(rd?.postalAddress?.ChiPremisesAddress);
  107. }
  108. } else if (rd?.residentialAddress) {
  109. if (rd?.residentialAddress?.EngPremisesAddress) {
  110. data["address1"] = getAddressEng(rd?.residentialAddress?.EngPremisesAddress);
  111. } else if (rd?.residentialAddress?.ChiPremisesAddress) {
  112. data["address1"] = getAddressChi(rd?.residentialAddress?.ChiPremisesAddress);
  113. }
  114. }
  115. setIAmSmartData(data);
  116. }
  117. const getAddressEng = (pAdd) => {
  118. let unit = (pAdd.Eng3dAddress?.EngUnit?.UnitDescriptor ?? "") + " " + (pAdd.Eng3dAddress?.EngUnit?.UnitNo ?? "");
  119. let block = (pAdd.EngBlock?.BlockDescriptor ?? "") + " " + (pAdd.EngBlock?.BlockNo ?? "");
  120. let floor = pAdd.Eng3dAddress?.EngFloor?.FloorNum ? pAdd.Eng3dAddress?.EngFloor?.FloorNum + "/F " : "";
  121. let street = (pAdd.EngStreet?.EngUnit?.UnitDescriptor ?? "") + " " + (pAdd.Eng3dAddress?.EngUnit?.UnitNo ?? "");
  122. //let region = pAdd.Region ?? "";
  123. let buildingName = pAdd.BuildingName ?? "";
  124. let estate = pAdd.EngEstate?.EstateName ?? "";
  125. let district = pAdd.EngDistrict["Sub - district"] ?? "";
  126. return getAddressStr([unit, block, floor, buildingName, estate, street, district]);
  127. }
  128. const getAddressChi = (pAdd) => {
  129. let unit = (pAdd.Chi3dAddress?.ChiUnit?.UnitDescriptor ?? "") + " " + (pAdd.Chi3dAddress?.ChiUnit?.UnitNo ?? "");
  130. let block = (pAdd.ChiBlock?.BlockDescriptor ?? "") + " " + (pAdd.ChiBlock?.BlockNo ?? "");
  131. let floor = pAdd.Chi3dAddress?.ChiFloor?.FloorNum ? pAdd.Chi3dAddress?.ChiFloor?.FloorNum + "樓 " : "";
  132. let street = (pAdd.ChiStreet?.ChiUnit?.UnitDescriptor ?? "") + " " + (pAdd.Chi3dAddress?.ChiUnit?.UnitNo ?? "");
  133. //let region = pAdd.Region ?? "";
  134. let buildingName = pAdd.BuildingName ?? "";
  135. let estate = pAdd.ChiEstate?.EstateName ?? "";
  136. let district = pAdd.ChiDistrict["Sub - district"] ?? "";
  137. return getAddressStr([district, street, estate, buildingName, street, floor, block, unit]);
  138. }
  139. const getAddressStr = (strs) => {
  140. let add = ""
  141. strs.forEach(str => {
  142. add += str.trim() ? str.trim() + ", " : "";
  143. });
  144. add = add.trim();
  145. if (add?.slice(- 1) == ",") {
  146. add = add.substring(0, add.length - 1);
  147. }
  148. return add;
  149. }
  150. const handleCheckEmail = async () => {
  151. if (values?.email) {
  152. const response = await axios.get(`${GET_USER_EMAIL}`, {
  153. params: {
  154. email: values.email,
  155. }
  156. })
  157. setCheckEmail((Number(response.data[0]) === 1))
  158. return Number(response.data[0]) === 1
  159. }
  160. }
  161. useEffect(() => {
  162. if (email) {
  163. email.addEventListener("blur", function () {
  164. setCheckEmailBlur(true)
  165. })
  166. }
  167. }, [email])
  168. useEffect(() => {
  169. if (checkEmailBlur) {
  170. handleCheckEmail()
  171. setCheckEmailBlur(false)
  172. }
  173. }, [checkEmailBlur])
  174. useEffect(() => {
  175. if (iAmSmartData) {
  176. formik.setFieldValue("enName", iAmSmartData.enName ?? "");
  177. formik.setFieldValue("chName", iAmSmartData.chName ?? "");
  178. formik.setFieldValue("idNo", iAmSmartData.idNo ?? "");
  179. formik.setFieldValue("checkDigit", iAmSmartData.checkDigit ?? "");
  180. formik.setFieldValue("email", iAmSmartData.email ?? "");
  181. formik.setFieldValue("emailConfirm", iAmSmartData.email ?? "");
  182. formik.setFieldValue("phone", iAmSmartData.phone ?? "");
  183. formik.setFieldValue("phoneCountryCode", iAmSmartData.phoneCountryCode ?? "");
  184. formik.setFieldValue("address1", iAmSmartData.address1 ?? "");
  185. props.setIdNo(iAmSmartData.idNo ?? "");
  186. }
  187. }, [iAmSmartData])
  188. const onCaptchaChange = () => {
  189. HttpUtils.post({
  190. url: POST_CAPTCHA,
  191. params: { width: 130, height: 40, captcha: captchaImg },
  192. onSuccess: (responseData) => {
  193. props.setBase64Url(responseData.base64Url)
  194. localStorage.setItem("base64Url", responseData.base64Url);
  195. setCaptchaImage(localStorage.getItem('base64Url'));
  196. }
  197. });
  198. }
  199. const checkDataField = (data) => {
  200. if (data.address1 !== "" &&
  201. data.email !== "" &&
  202. data.emailConfirm !== "" &&
  203. data.email == data.emailConfirm &&
  204. data.phone !== "" &&
  205. data.phoneCountryCode !== "" &&
  206. termsAndConAccept == true &&
  207. data.captchaField &&
  208. handleEmail(data.email) &&
  209. handlePhone(data.phone) &&
  210. handleCaptcha(data.captchaField) &&
  211. !checkEmail
  212. ) {
  213. setisValid(true)
  214. return isValid
  215. } else {
  216. setisValid(false)
  217. return isValid
  218. }
  219. };
  220. const handleCheckBoxChange = (event) => {
  221. if (event.target.name == 'termsAndConAccept') {
  222. setTermsAndConAccept(event.target.checked)
  223. setTermsAndConNotAccept(!event.target.checked)
  224. }
  225. if (event.target.name == 'termsAndConNotAccept') {
  226. setTermsAndConNotAccept(event.target.checked)
  227. setTermsAndConAccept(!event.target.checked)
  228. }
  229. };
  230. useEffect(() => {
  231. props.setUpdateValid(isValid)
  232. }, [isValid])
  233. useEffect(() => {
  234. checkDataField(values)
  235. }, [
  236. selectedAddress4, selectedAddress5,
  237. termsAndConAccept, termsAndConNotAccept])
  238. useEffect(() => {
  239. props.step == 2 ? _onSubmit() : null;
  240. if (captchaImg == "")
  241. onCaptchaChange();
  242. checkDataField(values)
  243. }, [props.step])
  244. const { handleSubmit } = useForm({})
  245. const _onSubmit = () => {
  246. setLoding(true);
  247. const userAddress = {
  248. "addressLine1": "",
  249. "addressLine2": "",
  250. "addressLine3": "",
  251. "district": "",
  252. "country": ""
  253. };
  254. userAddress.addressLine1 = values.address1
  255. userAddress.addressLine2 = values.address2
  256. userAddress.addressLine3 = values.address3
  257. values.address4 = selectedAddress4 == null ? "" : selectedAddress4.type
  258. values.address5 = selectedAddress5.type
  259. const userFaxNo = {
  260. "countryCode": values.faxCountryCode,
  261. "faxNumber": values.fax,
  262. };
  263. const userMobileNumber = {
  264. "countryCode": values.phoneCountryCode,
  265. "phoneNumber": values.phone,
  266. };
  267. let tncFlag = false;
  268. if (termsAndConAccept) {
  269. tncFlag = true
  270. }
  271. if (termsAndConNotAccept) {
  272. tncFlag = false
  273. }
  274. const formData = {
  275. enName: iAmSmartData.enName,
  276. chName: iAmSmartData.chName,
  277. emailAddress: values.email,
  278. idDocType: "HKID",
  279. identification: iAmSmartData.idNo,
  280. checkDigit: iAmSmartData.checkDigit,
  281. tncFlag: tncFlag,
  282. type: "IND",
  283. userFaxNo: JSON.stringify(userFaxNo),
  284. userMobileNumber: JSON.stringify(userMobileNumber),
  285. userAddress: JSON.stringify(userAddress)
  286. };
  287. if (isValid) {
  288. axios.post(POST_IAMSMART_USER_REGISTER, formData, {
  289. headers: {
  290. "Content-Type": "multipart/form-data"
  291. }
  292. })
  293. .then((response) => {
  294. console.log(response)
  295. setCheckUpload(true)
  296. setLoding(false);
  297. })
  298. .catch(error => {
  299. console.error(error);
  300. setLoding(false);
  301. });
  302. } else {
  303. setLoding(false);
  304. }
  305. }
  306. function handlePhone(phone) {
  307. if (phone.length < 8) {
  308. return false;
  309. } else {
  310. return true;
  311. }
  312. }
  313. function handleCaptcha(captchaField) {
  314. return captchaField;
  315. }
  316. function handleEmail(email) {
  317. var validRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
  318. if (!email.match(validRegex)) {
  319. return false;
  320. } else {
  321. return true;
  322. }
  323. }
  324. function displayErrorMsg(errorMsg) {
  325. return <Typography variant="errorMessage1">{errorMsg}</Typography>
  326. }
  327. const formik = useFormik({
  328. initialValues: ({
  329. email: iAmSmartData.email ?? "",
  330. emailConfirm: iAmSmartData.email ?? "",
  331. address1: iAmSmartData.address1 ?? "",
  332. address2: '',
  333. address3: '',
  334. phone: iAmSmartData.phone ?? "",
  335. phoneCountryCode: iAmSmartData.phoneCountryCode ?? "852",
  336. submit: null,
  337. fax: '',
  338. faxCountryCode: '852',
  339. captchaField: ''
  340. }),
  341. validationSchema: yup.object().shape({
  342. address1: yup.string().max(40, getMaxErrStr(40)).required(displayErrorMsg(intl.formatMessage({ id: 'validateAddressLine1' }))),
  343. address2: yup.string().max(40),
  344. address3: yup.string().max(40),
  345. email: yup.string().email(displayErrorMsg(intl.formatMessage({ id: 'validEmailFormat' }))).max(128, getMaxErrStr(128)).required(displayErrorMsg(intl.formatMessage({ id: 'requireEmail' }))),
  346. 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' }))),
  347. phoneCountryCode: yup.string().min(2, displayErrorMsg(intl.formatMessage({ id: 'requireAtLeast2Number' }))).required(displayErrorMsg(intl.formatMessage({ id: 'requireDialingCode' }))),
  348. phone: yup.string().min(8, displayErrorMsg(intl.formatMessage({ id: 'requireAtLeast8Number' }))).required(displayErrorMsg(intl.formatMessage({ id: 'requireContactNumber' }))),
  349. captchaField: yup.string().max(5, getMaxErrStr(5)).required(displayErrorMsg(intl.formatMessage({ id: 'requireVerify' }))),//.oneOf([captcha], displayErrorMsg('請輸入有效驗證')),
  350. }),
  351. });
  352. const { values } = formik
  353. useEffect(() => {
  354. checkDataField(values)
  355. }, [values])
  356. return (
  357. <FormikProvider value={formik}>
  358. <form onSubmit={handleSubmit(_onSubmit)}>
  359. {/* Input Form */}
  360. <FormGroup id={"inputForm"} sx={{ display: props.step === 0 ? "" : "none" }}>
  361. <Grid container spacing={3}>
  362. <Grid item xs={12} md={12}>
  363. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  364. <div style={{ borderBottom: "3px solid #1A4399", width: "100%", margin_right: "15px" }}>
  365. <Typography display="inline" variant="h3" sx={{ color: '#1A4399' }}>
  366. <FormattedMessage id="becomeNewPersonalUser" />
  367. </Typography><img src={iAmSmartICon} alt="iAM Smart" width="50" />
  368. </div>
  369. <Typography mt={0.25} variant="h6" sx={{ color: '#f10000' }}>
  370. <FormattedMessage id="requireString" />。
  371. </Typography>
  372. <Stack mt={1} direction="row" style={{ alignItems: "center" }}><img src={iAmSmartICon} alt="iAM Smart" width="25" /><Typography mt={0.25} variant="h6" >: <FormattedMessage id="MSG.providedByIAmSmart" /></Typography></Stack>
  373. </Stack>
  374. </Grid>
  375. <Grid item xs={12} md={12}>
  376. <Grid container spacing={1}>
  377. <Grid item xs={12} mt={1} mb={1}>
  378. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  379. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>
  380. <FormattedMessage id="yourPersonalInformation" />
  381. </Typography>
  382. </Stack>
  383. </Grid>
  384. <Grid item xs={12} md={12} >
  385. <Grid container sx={{ mb: 1 }}>
  386. <InputLabel htmlFor="idDocType-signup">
  387. <Typography variant="h5" sx={{ mr: 1 }}>
  388. <FormattedMessage id="HKIDcard" />: {iAmSmartData.idNo ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : <></>}
  389. {/* {iAmSmartData.idNo + "(" + iAmSmartData.checkDigit + ")"} */}
  390. </Typography>
  391. <Stack direction="row">
  392. <Typography variant="h5">
  393. {iAmSmartData?.idNo?.slice(0, 4)}{showId ? iAmSmartData?.idNo?.slice(4) : "****"}{showId ? '(' + iAmSmartData.checkDigit + ')' : null}
  394. </Typography>
  395. <IconButton
  396. aria-label="toggle id visibility"
  397. onClick={handleClickShowId}
  398. onMouseDown={handleMouseDownId}
  399. edge="end"
  400. size="medium"
  401. >
  402. {showId ? <EyeOutlined /> : <EyeInvisibleOutlined />}
  403. </IconButton>
  404. </Stack>
  405. </InputLabel>
  406. </Grid>
  407. </Grid>
  408. <Grid item xs={12} md={6}>
  409. <Stack spacing={1}>
  410. <InputLabel htmlFor="enName-signup">
  411. <Typography variant="h5">
  412. <FormattedMessage id="userEnglishName" />: {iAmSmartData.enName}{iAmSmartData.enName ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : <></>}
  413. </Typography>
  414. </InputLabel>
  415. </Stack>
  416. </Grid>
  417. <Grid item xs={12} md={6}>
  418. <Stack spacing={1}>
  419. <InputLabel htmlFor="chName-signup">
  420. <Typography variant="h5">
  421. {intl.formatMessage({ id: 'userChineseName' })}: {iAmSmartData.chName}{iAmSmartData.chName ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : <></>}
  422. </Typography>
  423. </InputLabel>
  424. </Stack>
  425. </Grid>
  426. <Grid item xs={12}>
  427. <Stack spacing={1}>
  428. <InputLabel htmlFor="address1-signup">
  429. <Typography variant="h5">
  430. <FormattedMessage id="formAddress" />
  431. <span style={{ color: '#f10000' }}>*</span>
  432. {iAmSmartData.address1 !="" && iAmSmartData.address1 ==formik.values.address1 ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : null}
  433. </Typography>
  434. </InputLabel>
  435. <OutlinedInput
  436. fullWidth
  437. autoFocus
  438. error={Boolean(formik.touched.address1 && formik.errors.address1)}
  439. id="address1-signup"
  440. value={formik.values.address1}
  441. name="address1"
  442. onChange={formik.handleChange}
  443. placeholder={intl.formatMessage({ id: 'addressLine1' })}
  444. onBlur={formik.handleBlur}
  445. inputProps={{
  446. onKeyDown: (e) => {
  447. if (e.key === 'Enter') {
  448. e.preventDefault();
  449. }
  450. },
  451. }}
  452. />
  453. <OutlinedInput
  454. fullWidth
  455. error={Boolean(formik.touched.address2 && formik.errors.address2)}
  456. id="address2-signup"
  457. value={formik.values.address2}
  458. name="address2"
  459. onBlur={formik.handleBlur}
  460. onChange={formik.handleChange}
  461. placeholder={intl.formatMessage({ id: 'addressLine2' })}
  462. inputProps={{
  463. onKeyDown: (e) => {
  464. if (e.key === 'Enter') {
  465. e.preventDefault();
  466. }
  467. },
  468. }}
  469. />
  470. <OutlinedInput
  471. fullWidth
  472. error={Boolean(formik.touched.address3 && formik.errors.address3)}
  473. id="address3-signup"
  474. value={formik.values.address3}
  475. name="address3"
  476. onBlur={formik.handleBlur}
  477. onChange={formik.handleChange}
  478. placeholder={intl.formatMessage({ id: 'addressLine3' })}
  479. inputProps={{
  480. onKeyDown: (e) => {
  481. if (e.key === 'Enter') {
  482. e.preventDefault();
  483. }
  484. },
  485. }}
  486. />
  487. <Autocomplete
  488. disablePortal
  489. id="address4-combo"
  490. value={selectedAddress4}
  491. options={address4ComboList}
  492. disabled={checkCountry}
  493. error={Boolean(districtErrStr != "")}
  494. onBlur={formik.handleBlur}
  495. getOptionLabel={(option) => option.type ? intl.formatMessage({ id: option.type }) : ""}
  496. onChange={(event, newValue) => {
  497. setSelectedAddress4(newValue);
  498. }}
  499. sx={{ "& .MuiInputBase-root": { height: "41px" }, "#address4-combo": { padding: "0px 0px 0px 0px" }, "& .MuiAutocomplete-endAdornment": { top: "auto" }, }}
  500. renderInput={(params) => <TextField {...params} placeholder={intl.formatMessage({ id: 'region' })}
  501. />}
  502. />
  503. <Autocomplete
  504. disablePortal
  505. id="address5-combo"
  506. value={selectedAddress5}
  507. options={address5ComboList}
  508. getOptionLabel={(option) => option.type ? intl.formatMessage({ id: option.type }) : ""}
  509. onChange={(event, newValue) => {
  510. if (newValue !== null) {
  511. setSelectedAddress5(newValue);
  512. if (newValue.type === 'hongKong') {
  513. setCheckCountry(false)
  514. } else {
  515. setSelectedAddress4("");
  516. setCheckCountry(true)
  517. }
  518. } else {
  519. setSelectedAddress4("");
  520. setCheckCountry(true)
  521. }
  522. }}
  523. sx={{ "& .MuiInputBase-root": { height: "41px" }, "#address5-combo": { padding: "0px 0px 0px 0px" }, "& .MuiAutocomplete-endAdornment": { top: "auto" }, }}
  524. renderInput={(params) => <TextField {...params} placeholder={intl.formatMessage({ id: 'regionOrCountry' })} />}
  525. />
  526. {formik.touched.address1 && formik.errors.address1 && (
  527. <FormHelperText error id="helper-text-address1-signup">
  528. {formik.errors.address1}
  529. </FormHelperText>
  530. )}
  531. {formik.touched.address2 && formik.errors.address2 && (
  532. <FormHelperText error id="helper-text-address2-signup">
  533. {formik.errors.address2}
  534. </FormHelperText>
  535. )}
  536. {formik.touched.address3 && formik.errors.address3 && (
  537. <FormHelperText error id="helper-text-address3-signup">
  538. {formik.errors.address3}
  539. </FormHelperText>
  540. )}
  541. {districtErrStr != "" && (
  542. <FormHelperText error >
  543. {districtErrStr}
  544. </FormHelperText>
  545. )}
  546. </Stack>
  547. </Grid>
  548. <Grid item xs={12} mt={1} mb={1}>
  549. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  550. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>
  551. <FormattedMessage id="yourContact" />
  552. </Typography>
  553. </Stack>
  554. </Grid>
  555. <Grid item xs={12} md={12}>
  556. <Grid container>
  557. <Grid item xs={12} md={6}>
  558. <Stack spacing={1} sx={{ mr: { md: 1 }, mb: 1 }}>
  559. <InputLabel htmlFor="email-signup">
  560. <Typography variant="h5">
  561. <FormattedMessage id="userContactEmail" />
  562. <span style={{ color: '#f10000' }}>*</span>
  563. {iAmSmartData.email && iAmSmartData.email ==formik.values.email ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : null}
  564. </Typography>
  565. </InputLabel>
  566. <OutlinedInput
  567. fullWidth
  568. error={Boolean((formik.touched.email && formik.errors.email) || checkEmail)}
  569. id="email-login"
  570. type="email"
  571. value={formik.values.email.trim()}
  572. name="email"
  573. onChange={formik.handleChange}
  574. placeholder={intl.formatMessage({ id: 'userContactEmail' })}
  575. onBlur={formik.handleBlur}
  576. inputProps={{
  577. onKeyDown: (e) => {
  578. if (e.key === 'Enter') {
  579. e.preventDefault();
  580. }
  581. },
  582. }}
  583. />
  584. {formik.touched.email && formik.errors.email && (
  585. <FormHelperText error id="helper-text-email-signup">
  586. {formik.errors.email}
  587. </FormHelperText>
  588. )}
  589. {checkEmail && (
  590. <FormHelperText error id="helper-text-email-signup">
  591. <FormattedMessage id="emailUsed" />
  592. </FormHelperText>
  593. )}
  594. </Stack>
  595. </Grid>
  596. <Grid item xs={12} md={6}>
  597. <Stack spacing={1} >
  598. <InputLabel htmlFor="emailConfirm-signup">
  599. <Typography variant="h5">
  600. <FormattedMessage id="userContactEmail" />
  601. <span style={{ color: '#f10000' }}>*</span>
  602. </Typography>
  603. </InputLabel>
  604. <OutlinedInput
  605. fullWidth
  606. error={Boolean(formik.touched.emailConfirm && formik.errors.emailConfirm)}
  607. id="emailConfirm-login"
  608. type="email"
  609. value={formik.values.emailConfirm}
  610. name="emailConfirm"
  611. // onBlur={formik.handleBlur}
  612. onChange={formik.handleChange}
  613. placeholder={intl.formatMessage({ id: 'confirmEmail' })}
  614. onBlur={formik.handleBlur}
  615. inputProps={{
  616. onKeyDown: (e) => {
  617. if (e.key === 'Enter') {
  618. e.preventDefault();
  619. }
  620. },
  621. }}
  622. />
  623. {formik.touched.emailConfirm && formik.errors.emailConfirm && (
  624. <FormHelperText error id="helper-text-emailConfirm-signup">
  625. {formik.errors.emailConfirm}
  626. </FormHelperText>
  627. )}
  628. </Stack>
  629. </Grid>
  630. </Grid>
  631. </Grid>
  632. <Grid item xs={12} md={12}>
  633. <Grid container>
  634. <Grid item xs={12} md={6}>
  635. <Grid container>
  636. <Grid item xs={12} md={12}>
  637. <Stack direction="column" spacing={1} sx={{ mr: { md: 1 }, mb: 1 }}>
  638. <InputLabel htmlFor="phone-signup">
  639. <Typography variant="h5">
  640. <FormattedMessage id="userContactNumber" />
  641. <span style={{ color: '#f10000' }}>*</span>
  642. {iAmSmartData.phone && iAmSmartData.phone ==formik.values.phone && iAmSmartData.phoneCountryCode ==formik.values.phoneCountryCode ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : null}
  643. </Typography>
  644. </InputLabel>
  645. <Stack direction="row">
  646. <OutlinedInput
  647. id="phoneCountryCode-login"
  648. type="phoneCountryCode"
  649. value={formik.values.phoneCountryCode.trim()}
  650. name="phoneCountryCode"
  651. // onBlur={formik.handleBlur}
  652. // onChange={formik.handleChange}
  653. onChange={(event) => {
  654. const value = event.target.value;
  655. if (value.match(/[^0-9]/)) {
  656. return event.preventDefault();
  657. }
  658. formik.setFieldValue("phoneCountryCode", value);
  659. }}
  660. placeholder={intl.formatMessage({ id: 'dialingCode' })}
  661. error={Boolean(formik.touched.phone && formik.errors.phone)}
  662. onBlur={formik.handleBlur}
  663. inputProps={{
  664. maxLength: 3,
  665. onKeyDown: (e) => {
  666. if (e.key === 'Enter') {
  667. e.preventDefault();
  668. }
  669. },
  670. }}
  671. sx={{ width: '25%' }}
  672. />
  673. <OutlinedInput
  674. id="phone-login"
  675. type="phone"
  676. value={formik.values.phone.trim()}
  677. name="phone"
  678. // onBlur={formik.handleBlur}
  679. // onChange={formik.handleChange}
  680. onChange={(event) => {
  681. const value = event.target.value;
  682. if (value.match(/[^0-9]/)) {
  683. return event.preventDefault();
  684. }
  685. formik.setFieldValue("phone", value);
  686. }}
  687. placeholder={intl.formatMessage({ id: 'userContactNumber' })}
  688. error={Boolean(formik.touched.phone && formik.errors.phone)}
  689. onBlur={formik.handleBlur}
  690. inputProps={{
  691. maxLength: 11,
  692. onKeyDown: (e) => {
  693. if (e.key === 'Enter') {
  694. e.preventDefault();
  695. }
  696. },
  697. }}
  698. sx={{ width: '75%' }}
  699. />
  700. </Stack>
  701. {formik.touched.phone && formik.errors.phone && (
  702. <FormHelperText error id="helper-text-phone-signup">
  703. {formik.errors.phone}
  704. </FormHelperText>
  705. )}
  706. </Stack>
  707. </Grid>
  708. </Grid>
  709. </Grid>
  710. <Grid item xs={12} md={6}>
  711. <Grid container>
  712. <Grid item xs={12} md={12}>
  713. <Stack spacing={1} direction="column">
  714. <InputLabel htmlFor="fax-signup">
  715. <Typography variant="h5">
  716. <FormattedMessage id="userFaxNumber" />
  717. </Typography>
  718. </InputLabel>
  719. <Stack direction="row">
  720. <OutlinedInput
  721. error={Boolean(formik.touched.fax && formik.errors.fax)}
  722. id="faxCountryCode-login"
  723. type="faxCountryCode"
  724. value={formik.values.faxCountryCode.trim()}
  725. name="faxCountryCode"
  726. // onChange={formik.handleChange}
  727. onChange={(event) => {
  728. const value = event.target.value;
  729. if (value.match(/[^0-9]/)) {
  730. return event.preventDefault();
  731. }
  732. formik.setFieldValue("faxCountryCode", value);
  733. }}
  734. placeholder={intl.formatMessage({ id: 'dialingCode' })}
  735. onBlur={formik.handleBlur}
  736. inputProps={{
  737. maxLength: 3,
  738. onKeyDown: (e) => {
  739. if (e.key === 'Enter') {
  740. e.preventDefault();
  741. }
  742. },
  743. }}
  744. sx={{ width: '25%' }}
  745. />
  746. <OutlinedInput
  747. id="fax-login"
  748. type="fax"
  749. value={formik.values.fax.trim()}
  750. name="fax"
  751. onBlur={formik.handleBlur}
  752. // onChange={formik.handleChange}
  753. onChange={(event) => {
  754. const value = event.target.value;
  755. if (value.match(/[^0-9]/)) {
  756. return event.preventDefault();
  757. }
  758. formik.setFieldValue("fax", value);
  759. }}
  760. placeholder={intl.formatMessage({ id: 'userFaxNumber' })}
  761. inputProps={{
  762. maxLength: 8,
  763. onKeyDown: (e) => {
  764. if (e.key === 'Enter') {
  765. e.preventDefault();
  766. }
  767. },
  768. }}
  769. sx={{ width: '75%' }}
  770. />
  771. </Stack>
  772. </Stack>
  773. </Grid>
  774. </Grid>
  775. </Grid>
  776. </Grid>
  777. </Grid>
  778. </Grid>
  779. <Grid item xs={12} md={12}>
  780. <Grid container>
  781. <Grid item xs={12} md={12}>
  782. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>
  783. <FormattedMessage id="termsAndCondition" />
  784. <span style={{ color: '#f10000' }}>*</span>
  785. </Typography>
  786. </Grid>
  787. <Grid item xs={12} md={12}>
  788. <Grid container>
  789. <Grid item xs={12} md={12}>
  790. <Typography variant="h5" sx={{ textAlign: "left", borderRadius: "inherit", borderStyle: "solid", borderWidth: "1px", borderColor: "#0C489E" }}>
  791. <div style={{ padding: 12 }} dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: "termsAndCon" }) }} />
  792. </Typography>
  793. </Grid>
  794. </Grid>
  795. <Grid item xs={12} s={12} md={12} lg={12}>
  796. <Grid container>
  797. <Grid item xs={6} s={6} md={2} lg={2}>
  798. <Grid container>
  799. <Grid item sx={{ display: 'flex', alignItems: 'center' }}>
  800. <Checkbox
  801. checked={termsAndConAccept}
  802. onChange={handleCheckBoxChange}
  803. name="termsAndConAccept"
  804. color="primary"
  805. size="small"
  806. />
  807. <Typography variant="h5">
  808. <FormattedMessage id="acceptTerms" />
  809. </Typography>
  810. </Grid>
  811. </Grid>
  812. </Grid>
  813. <Grid item xs={6} s={6} md={3} lg={3}>
  814. <Grid container>
  815. <Grid item sx={{ display: 'flex', alignItems: 'center' }}>
  816. <Checkbox
  817. checked={termsAndConNotAccept}
  818. onChange={handleCheckBoxChange}
  819. name="termsAndConNotAccept"
  820. color="primary"
  821. size="small"
  822. />
  823. <Typography variant="h5">
  824. <FormattedMessage id="rejectTerms" />
  825. </Typography>
  826. </Grid>
  827. </Grid>
  828. </Grid>
  829. </Grid>
  830. </Grid>
  831. </Grid>
  832. </Grid>
  833. </Grid>
  834. <Grid item xs={12} lg={12}>
  835. <Grid container>
  836. <Stack direction="column">
  837. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>
  838. <FormattedMessage id="verify" />
  839. <span style={{ color: '#f10000' }}>*</span>
  840. </Typography>
  841. <Stack spacing={1} direction="row">
  842. <Grid item xs={5} lg={5} style={{ "border": "1px solid black" }}>
  843. <img src={captchaImg} alt="" />
  844. </Grid>
  845. <Grid item xs={1} lg={1} style={{ "border": "0px solid black" }}>
  846. <IconButton aria-label="refrashCaptcha" size="large" onClick={() => { onCaptchaChange() }}>
  847. <LoopIcon fontSize="inherit" />
  848. </IconButton>
  849. </Grid>
  850. <Grid item xs={6} lg={6}>
  851. <OutlinedInput
  852. fullWidth
  853. id="captchaField"
  854. type="text"
  855. value={formik.values.captchaField.trim()}
  856. onBlur={formik.handleBlur}
  857. error={Boolean(formik.touched.captchaField && formik.errors.captchaField)}
  858. name="captchaField"
  859. onChange={(event) => {
  860. const value = event.target.value;
  861. props.setCheckCode(event.target.value);
  862. formik.setFieldValue("captchaField", value);
  863. }}
  864. sx={{ width: '75%' }}
  865. />
  866. </Grid>
  867. </Stack>
  868. {formik.touched.captchaField && formik.errors.captchaField && (
  869. <FormHelperText error id="helper-text-captcha-signup">
  870. {formik.errors.captchaField}
  871. </FormHelperText>
  872. )}
  873. </Stack>
  874. </Grid>
  875. </Grid>
  876. </Grid>
  877. </Grid>
  878. </FormGroup>
  879. {/* Preview Form */}
  880. <FormGroup id={"previewForm"} sx={{ display: props.step === 1 ? "" : "none" }}>
  881. <Grid container spacing={3}>
  882. <Grid item xs={12} md={12}>
  883. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  884. <div style={{ borderBottom: "3px solid #1A4399", width: "100%", margin_right: "15px" }}>
  885. <Typography display="inline" variant="h3" sx={{ color: '#1A4399' }}>
  886. <FormattedMessage id="becomeNewPersonalUser" />
  887. </Typography>
  888. </div>
  889. </Stack>
  890. </Grid>
  891. <Grid item xs={12} md={12}>
  892. <Grid container spacing={2}>
  893. <Grid item xs={12} mt={1} mb={1}>
  894. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  895. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>
  896. <FormattedMessage id="yourPersonalInformation" />
  897. </Typography>
  898. {/* <Typography component={Link} to="/login" variant="body1" sx={{ textDecoration: 'none' }} color="primary">
  899. Already have an account?
  900. </Typography> */}
  901. </Stack>
  902. </Grid>
  903. <Grid item xs={12} md={12} >
  904. <Stack direction="row">
  905. <Typography variant="h5" color={theme.palette.grey[600]} sx={{ mr: 1 }}>
  906. <FormattedMessage id="userIdDoc" />
  907. </Typography>
  908. <Typography variant="h5" name="preview-idDocType-1">
  909. {formik?.values?.idNo?.slice(0, 4)}
  910. {/* {formik.values.idNo + "(" + formik.values.checkDigit + ")"} */}
  911. </Typography>
  912. <Typography variant="h5" name="preview-idDocType-2">
  913. {showComId ? formik?.values?.idNo?.slice(4) : "****"}{showComId ? '(' + formik.values.checkDigit + ')' : null}
  914. {/* {formik.values.idNo + "(" + formik.values.checkDigit + ")"} */}
  915. </Typography>
  916. <IconButton
  917. aria-label="toggle id visibility"
  918. onClick={handleClickShowComId}
  919. onMouseDown={handleMouseDownComId}
  920. edge="end"
  921. size="medium"
  922. >
  923. {showComId ? <EyeOutlined /> : <EyeInvisibleOutlined />}
  924. </IconButton>
  925. </Stack>
  926. </Grid>
  927. <Grid item xs={12} md={6}>
  928. <Stack spacing={1} direction="row">
  929. <Typography variant="h5" color={theme.palette.grey[600]}>
  930. <FormattedMessage id="userEnglishName" />:
  931. </Typography>
  932. <Typography variant="h5" id="preview-enName-signup">
  933. {formik.values.enName}
  934. </Typography>
  935. {iAmSmartData.enName ? <img src={iAmSmartICon} alt="iAM Smart" width="25" /> : <></>}
  936. </Stack>
  937. </Grid>
  938. <Grid item xs={12} md={6}>
  939. <Stack spacing={1} direction="row">
  940. <Typography variant="h5" color={theme.palette.grey[600]}>
  941. <FormattedMessage id="userChineseName" />:
  942. </Typography>
  943. <Typography variant="h5" id="preview-chName-signup">
  944. {formik.values.chName}
  945. </Typography>
  946. </Stack>
  947. </Grid>
  948. <Grid item xs={12}>
  949. <Stack spacing={1} direction="column">
  950. <Typography variant="h5" color={theme.palette.grey[600]}>
  951. <FormattedMessage id="formAddress" />:
  952. </Typography>
  953. <Stack spacing={1} direction="column">
  954. <Typography variant="h5" id="preview-address1-signup">
  955. {formik.values.address1}
  956. </Typography>
  957. {formik.values.address2 != null ?
  958. <Typography variant="h5" id="preview-address2-signup">
  959. {formik.values.address2}
  960. </Typography>
  961. : null}
  962. {formik.values.address3 != null ?
  963. <Typography variant="h5" id="preview-address3-signup">
  964. {formik.values.address3}
  965. </Typography>
  966. : null}
  967. {selectedAddress5.type === "hongKong" ?
  968. <Stack direction="column">
  969. <Typography variant="h5" color={theme.palette.grey[600]} id="preview-address4-signup">
  970. <FormattedMessage id="region" />:
  971. </Typography>
  972. <Typography variant="h5">
  973. {!selectedAddress4 ? "" : intl.formatMessage({ id: selectedAddress4.type })}
  974. </Typography>
  975. </Stack>
  976. : null}
  977. <Stack direction="column">
  978. <Typography variant="h5" color={theme.palette.grey[600]} id="preview-address5-signup">
  979. <FormattedMessage id="regionOrCountry" />:
  980. </Typography>
  981. <Typography variant="h5">
  982. {intl.formatMessage({ id: selectedAddress5.type })}
  983. </Typography>
  984. </Stack>
  985. </Stack>
  986. </Stack>
  987. </Grid>
  988. <Grid item xs={12} mt={1} mb={1}>
  989. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  990. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>
  991. <FormattedMessage id="yourContact" />
  992. </Typography>
  993. </Stack>
  994. </Grid>
  995. <Grid item xs={12} md={12}>
  996. <Stack spacing={1} direction="row">
  997. <Typography variant="h5" color={theme.palette.grey[600]}>
  998. <FormattedMessage id="userContactEmail" />:
  999. </Typography>
  1000. <Typography variant="h5" id="preview-email-signup">
  1001. {formik.values.email}
  1002. </Typography>
  1003. </Stack>
  1004. </Grid>
  1005. <Grid item xs={12} md={6}>
  1006. <Stack spacing={1} direction="row">
  1007. <Typography variant="h5" color={theme.palette.grey[600]}>
  1008. <FormattedMessage id="userContactNumber" />:
  1009. </Typography>
  1010. <Typography variant="h5" id="preview-phone-signup">
  1011. +{formik.values.phoneCountryCode} {formik.values.phone}
  1012. </Typography>
  1013. </Stack>
  1014. </Grid>
  1015. {formik.values.faxCountryCode != "" && formik.values.fax != "" ?
  1016. <Grid item xs={12} md={6}>
  1017. <Stack spacing={1} direction="row">
  1018. <Typography variant="h5" color={theme.palette.grey[600]}>
  1019. <FormattedMessage id="userFaxNumber" />:
  1020. </Typography>
  1021. <Typography variant="h5" id="preview-fax-signup">
  1022. +{formik.values.faxCountryCode} {formik.values.fax}
  1023. </Typography>
  1024. </Stack>
  1025. </Grid>
  1026. : null}
  1027. </Grid>
  1028. </Grid>
  1029. </Grid>
  1030. </FormGroup>
  1031. {/* Submit page */}
  1032. <FormGroup id={"submitForm"} sx={{ display: props.step === 2 ? "" : "none" }}>
  1033. <Grid container spacing={3}>
  1034. {isLoading ?
  1035. <LoadingComponent /> :
  1036. <Grid item xs={12}>
  1037. {checkUpload ?
  1038. // SUCCESS page
  1039. <Stack mt={1} direction="column" justifyContent="flex-start" alignItems="center" spacing={2}>
  1040. <CheckCircleOutlineIcon color="success" sx={{ width: "200px", height: "200px" }} />
  1041. <Typography display="inline" variant="h4">
  1042. <FormattedMessage id="registerSubmitted" />
  1043. </Typography>
  1044. <Typography display="inline" variant="h4">
  1045. <FormattedMessage id="emailSent" />
  1046. </Typography>
  1047. <Button variant="outlined" component={Link} to="/login" ><Typography variant="h5">
  1048. <FormattedMessage id="backToLogin" />
  1049. </Typography></Button>
  1050. </Stack>
  1051. :
  1052. // ERROR page
  1053. <Stack mt={1} direction="column" justifyContent="flex-start" alignItems="center" spacing={2}>
  1054. {/* <Button disabled={true} hidden={true} variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button> */}
  1055. <CancelOutlinedIcon color="error" sx={{ width: "200px", height: "200px" }} />
  1056. <Typography display="inline" variant="h4">
  1057. <FormattedMessage id="registerFail" />
  1058. </Typography>
  1059. <Button color="error" variant="outlined" component={Link} to="/login" ><Typography variant="h5">
  1060. <FormattedMessage id="backToLogin" />
  1061. </Typography></Button>
  1062. </Stack>
  1063. }
  1064. </Grid>
  1065. }
  1066. </Grid>
  1067. </FormGroup>
  1068. </form>
  1069. </FormikProvider>
  1070. );
  1071. }
  1072. export default CustomFormWizard;