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.
 
 

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