25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

2236 lines
136 KiB

  1. import { useEffect, useState, useRef } from 'react';
  2. import {
  3. Box,
  4. Button, Checkbox
  5. // MenuItem
  6. , FormControl, FormGroup, FormHelperText,
  7. Grid, IconButton,
  8. InputAdornment,
  9. InputLabel, OutlinedInput,
  10. Stack, TextField, Typography
  11. } from '@mui/material';
  12. import Autocomplete from "@mui/material/Autocomplete";
  13. import { useForm } from 'react-hook-form';
  14. // third party
  15. import { FormikProvider, useFormik } from 'formik';
  16. import * as yup from 'yup';
  17. // import axios from "axios";
  18. // project import
  19. // import AnimateButton from 'components/@extended/AnimateButton';
  20. import { strengthColorChi, strengthIndicator } from 'utils/password-strength';
  21. // import {apiPath} from "auth/utils";
  22. import axios from "axios";
  23. import { POST_USERNAME, POST_USER_EMAIL, POST_CAPTCHA, POST_PUBLIC_USER_REGISTER, POST_IDNO, POST_CAPTCHA_AUDIO } from "utils/ApiPathConst";
  24. // import * as HttpUtils from 'utils/HttpUtils';
  25. import * as ComboData from "utils/ComboData";
  26. import Loadable from 'components/Loadable';
  27. import { lazy } from 'react';
  28. const UploadFileTable = Loadable(lazy(() => import('./UploadFileTable')));
  29. const PreviewUploadFileTable = Loadable(lazy(() => import('./PreviewUploadFileTable')));
  30. const LoadingComponent = Loadable(lazy(() => import('../../extra-pages/LoadingComponent')));
  31. // import UploadFileTable from './UploadFileTable';
  32. // import LoadingComponent from "../../extra-pages/LoadingComponent";
  33. // assets
  34. import { EyeInvisibleOutlined, EyeOutlined } from '@ant-design/icons';
  35. // import { Paper } from '../../../../node_modules/@mui/material/index';
  36. import { ThemeProvider } from "@emotion/react";
  37. import CancelOutlinedIcon from '@mui/icons-material/CancelOutlined';
  38. import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
  39. import LoopIcon from '@mui/icons-material/Loop';
  40. import { useTheme } from '@mui/material/styles';
  41. import { FormattedMessage, useIntl } from "react-intl";
  42. import { Link } from 'react-router-dom';
  43. import { PNSPS_LONG_BUTTON_THEME } from "../../../themes/buttonConst";
  44. import * as HttpUtils from "../../../utils/HttpUtils";
  45. import { notifyActionError } from 'utils/CommonFunction';
  46. // ============================|| FIREBASE - REGISTER ||============================ //
  47. const CustomFormWizard = (props) => {
  48. const intl = useIntl();
  49. const { locale } = intl;
  50. const theme = useTheme()
  51. const [level, setLevel] = useState();
  52. const [showPassword, setShowPassword] = useState(false);
  53. const [showConfirmPassword, setshowConfirmPassword] = useState(false);
  54. const [showId, setshowId] = useState(false);
  55. const [fileList, setFileList] = useState([]);
  56. const [fileListData, setFileListData] = useState([]);
  57. const [checkUpload, setCheckUpload] = useState(false);
  58. const [isLoading, setLoding] = useState(true);
  59. const [updateRows, setUpdateRows] = useState([]);
  60. const [captchaImg, setCaptchaImage] = useState("");
  61. const [base64Url, setBase64Url] = useState("")
  62. const [checkCode, setCheckCode] = useState("")
  63. const handleClickShowPassword = () => {
  64. setShowPassword(!showPassword);
  65. };
  66. const handleClickShowConfirmPassword = () => {
  67. setshowConfirmPassword(!showConfirmPassword);
  68. };
  69. const handleMouseDownPassword = (event) => {
  70. event.preventDefault();
  71. };
  72. const handleClickShowId = () => {
  73. setshowId(!showId);
  74. };
  75. const handleMouseDownId = (event) => {
  76. event.preventDefault();
  77. };
  78. const changePassword = (value) => {
  79. const temp = strengthIndicator(value);
  80. setLevel(strengthColorChi(temp));
  81. };
  82. const [selectedIdDocType, setSelectedIdDocType] = useState({});
  83. const [selectedIdDocInputType, setSelectedIdDocInputType] = useState();
  84. const [selectedAddress4, setSelectedAddress4] = useState(null);
  85. const [selectedAddress5, setSelectedAddress5] = useState(ComboData.country[0]);
  86. const [termsAndConAccept, setTermsAndConAccept] = useState(false);
  87. const [termsAndConNotAccept, setTermsAndConNotAccept] = useState(false);
  88. const [isValid, setisValid] = useState(false);
  89. const [checkCountry, setCheckCountry] = useState(false);
  90. // eslint-disable-next-line no-unused-vars -- used as ref for hidden file input (ref={fileInputRef}) and in click handlers
  91. const fileInputRef = useRef(null);
  92. const username = document.getElementById("username-login")
  93. const [checkUsername, setCheckUsername] = useState(false);
  94. const [checkUsernameBlur, setCheckUsernameBlur] = useState(false)
  95. const idDocNumber = document.getElementById("idNo-login")
  96. const [checkIdDocNumber, setCheckIdDocNumber] = useState(false)
  97. const [checkIdDocNumberBlur, setCheckIdDocNumberBlur] = useState(false)
  98. const [idDocHKIDNumber, setIdDocHKIDNumber] = useState(document.getElementById("idNo-hkid-login"))
  99. const [checkIdDocHKIDNumberBlur, setCheckIdDocHKIDNumberBlur] = useState(false)
  100. const [checkDigit, setCheckDigit] = useState(document.getElementById("checkDigit-login"))
  101. const [checkCheckDigitBlur, setCheckCheckDigitBlur] = useState(false)
  102. const [checkHKIdDocWithCheckDigit, setCheckHKIdDocWithCheckDigit] = useState(false)
  103. const email = document.getElementById("email-login")
  104. const [checkEmail, setCheckEmail] = useState(false)
  105. const [checkEmailBlur, setCheckEmailBlur] = useState(false)
  106. const district = document.getElementById("address4-combo")
  107. const [checkDistrict, setCheckDistrict] = useState(false)
  108. const [checkDistrictBlur, setCheckDistrictBlur] = useState(false)
  109. const [districtErrStr, setDistrictErrStr] = useState("")
  110. const idDocTypeComboList = ComboData.idDocType;
  111. const refType = "identification";
  112. useEffect(() => {
  113. changePassword('');
  114. if (captchaImg == ""){
  115. onCaptchaChange();
  116. }
  117. }, []);
  118. const playCaptchaAudio = async () => {
  119. try {
  120. const resp = await axios.post(
  121. `${POST_CAPTCHA_AUDIO}`,
  122. { base64Url, lang: intl.locale },
  123. { responseType: "arraybuffer" }
  124. );
  125. const blob = new Blob([resp.data], { type: "audio/wav" });
  126. const url = URL.createObjectURL(blob);
  127. const audio = new Audio(url);
  128. await audio.play();
  129. } catch (error) {
  130. let message = intl.formatMessage({ id: "captchaAudioError" });
  131. if (error.response) {
  132. if (error.response.status === 404) {
  133. message = intl.formatMessage({ id: "captchaExpired" });
  134. } else if (error.response.status === 500) {
  135. message = intl.formatMessage({ id: "captchaAudioServerError" });
  136. }
  137. } else if (error.request) {
  138. message = intl.formatMessage({ id: "connectionError" });
  139. }
  140. notifyActionError(message);
  141. }
  142. };
  143. useEffect(() => {
  144. if (selectedIdDocType.type === "HKID"){
  145. setIdDocHKIDNumber(document.getElementById("idNo-hkid-login"))
  146. setCheckDigit(document.getElementById("checkDigit-login"))
  147. // setTimeout(() => {
  148. // }, 1000);
  149. }
  150. }, [selectedIdDocType]);
  151. const handleCheckUsername = async () => {
  152. if (values?.username) {
  153. if (handleUsername(values.username)){
  154. const response = await axios.post(`${POST_USERNAME}`, {
  155. u1: values.username,
  156. })
  157. setCheckUsername((Number(response.data[0]) === 1))
  158. return Number(response.data[0]) === 1
  159. }
  160. }
  161. }
  162. const handleCheckIdDocNumber = async () => {
  163. if (values?.idNo&&values?.checkDigit !="") {
  164. if (handleIdNo(values.idNo, selectedIdDocType.type, values.checkDigit)){
  165. const response = await axios.post(`${POST_IDNO}`, {
  166. i1: values.idNo,
  167. })
  168. // console.log(response.data.Vaild)
  169. setCheckIdDocNumber(response.data.Vaild === false)
  170. return response.data.Vaild === false
  171. }
  172. }
  173. }
  174. const handleCheckIdDocNumberbyCheckDigit = async () => {
  175. if (values?.checkDigit) {
  176. if (handleIdNo(values.idNo, selectedIdDocType.type, values.checkDigit)){
  177. const response = await axios.post(`${POST_IDNO}`, {
  178. i1: values.idNo,
  179. })
  180. // console.log(response.data.Vaild)
  181. setCheckIdDocNumber(response.data.Vaild === false)
  182. return response.data.Vaild === false
  183. }
  184. }
  185. }
  186. const handleCheckEmail = async () => {
  187. if (values?.email) {
  188. if(handleEmail(values.email)){
  189. const response = await axios.post(`${POST_USER_EMAIL}`, {
  190. e1: values.email,
  191. })
  192. setCheckEmail((Number(response.data[0]) === 1))
  193. return Number(response.data[0]) === 1
  194. }
  195. }
  196. }
  197. const handleCheckDistrict = async () => {
  198. setDistrictErrStr("");
  199. if (selectedAddress5?.type === "hongKong") {
  200. if (selectedAddress4 == null || selectedAddress4 == "" || selectedAddress4 == {}){
  201. setCheckDistrict(true)
  202. setDistrictErrStr(getRequiredErrStr("district"))
  203. }else {
  204. setCheckDistrict(false)
  205. }
  206. }
  207. }
  208. useEffect(() => {
  209. if (username) {
  210. username.addEventListener("blur", function () {
  211. setCheckUsernameBlur(true)
  212. })
  213. }
  214. }, [username])
  215. useEffect(() => {
  216. if (checkUsernameBlur) {
  217. handleCheckUsername()
  218. setCheckUsernameBlur(false)
  219. }
  220. }, [checkUsernameBlur])
  221. useEffect(() => {
  222. if (idDocNumber) {
  223. idDocNumber.addEventListener("blur", function () {
  224. setCheckIdDocNumberBlur(true)
  225. })
  226. }
  227. }, [idDocNumber])
  228. useEffect(() => {
  229. if (checkIdDocNumberBlur) {
  230. handleCheckIdDocNumber()
  231. setCheckIdDocNumberBlur(false)
  232. }
  233. }, [checkIdDocNumberBlur])
  234. useEffect(() => {
  235. if (idDocHKIDNumber) {
  236. idDocHKIDNumber.addEventListener("blur", function () {
  237. setCheckIdDocHKIDNumberBlur(true)
  238. })
  239. }
  240. }, [idDocHKIDNumber])
  241. useEffect(() => {
  242. if (checkIdDocHKIDNumberBlur) {
  243. handleCheckIdDocNumber()
  244. setCheckIdDocHKIDNumberBlur(false)
  245. }
  246. }, [checkIdDocHKIDNumberBlur])
  247. useEffect(() => {
  248. if (checkDigit) {
  249. checkDigit.addEventListener("blur", function () {
  250. setCheckCheckDigitBlur(true)
  251. })
  252. }
  253. }, [checkDigit])
  254. useEffect(() => {
  255. if (checkCheckDigitBlur) {
  256. handleCheckIdDocNumberbyCheckDigit()
  257. setCheckCheckDigitBlur(false)
  258. }
  259. }, [checkCheckDigitBlur])
  260. useEffect(() => {
  261. if (email) {
  262. email.addEventListener("blur", function () {
  263. setCheckEmailBlur(true)
  264. })
  265. }
  266. }, [email])
  267. useEffect(() => {
  268. if (checkEmailBlur) {
  269. handleCheckEmail()
  270. setCheckEmailBlur(false)
  271. }
  272. }, [checkEmailBlur])
  273. useEffect(() => {
  274. if (district) {
  275. district.addEventListener("blur", function () {
  276. setCheckDistrictBlur(true)
  277. })
  278. }
  279. }, [district])
  280. useEffect(() => {
  281. if (checkDistrictBlur) {
  282. handleCheckDistrict()
  283. setCheckDistrictBlur(false)
  284. }
  285. }, [checkDistrictBlur])
  286. const onCaptchaChange = () => {
  287. HttpUtils.post({
  288. url: POST_CAPTCHA,
  289. params: { width: 130, height: 40, captcha: captchaImg },
  290. onSuccess: (responseData) => {
  291. props.setBase64Url(responseData.base64Url)
  292. setBase64Url(responseData.base64Url)
  293. localStorage.setItem("base64Url", responseData.base64Url);
  294. setCaptchaImage(localStorage.getItem('base64Url'));
  295. }
  296. });
  297. }
  298. const checkDataField = (data) => {
  299. // console.log(data)
  300. if (
  301. handleCaptcha(data.captchaField) &&
  302. data.username !== "" &&
  303. data.password !== "" &&
  304. data.confirmPassword !== "" &&
  305. data.password == data.confirmPassword &&
  306. selectedIdDocType.type !== "" &&
  307. data.idNo !== "" &&
  308. // (data.enName !== "" || selectedIdDocType.type === "CNID") &&
  309. // data.chName !== "" &&
  310. handleName(data.enName, data.chName) &&
  311. data.address1 !== "" &&
  312. data.email !== "" &&
  313. data.emailConfirm !== "" &&
  314. data.email == data.emailConfirm &&
  315. data.phone !== "" &&
  316. data.phoneCountryCode !== "" &&
  317. termsAndConAccept == true &&
  318. fileList.length !== 0 &&
  319. // data.captchaField &&
  320. handlePassword(data.password) &&
  321. handleEmail(data.email) &&
  322. handleIdNo(data.idNo, selectedIdDocType.type, data.checkDigit) &&
  323. handlePhone(data.phone) &&
  324. handleUsername(data.username) &&
  325. handleCheckDistrict()&&
  326. !checkUsername &&
  327. !checkEmail &&
  328. !checkIdDocNumber&&
  329. !checkDistrict
  330. ) {
  331. setisValid(true)
  332. return isValid
  333. } else {
  334. setisValid(false)
  335. return isValid
  336. }
  337. };
  338. const handleCheckBoxChange = (event) => {
  339. if (event.target.name == 'termsAndConAccept') {
  340. setTermsAndConAccept(event.target.checked)
  341. setTermsAndConNotAccept(!event.target.checked)
  342. }
  343. if (event.target.name == 'termsAndConNotAccept') {
  344. setTermsAndConNotAccept(event.target.checked)
  345. setTermsAndConAccept(!event.target.checked)
  346. }
  347. };
  348. useEffect(() => {
  349. let updateRowList = new DataTransfer();
  350. var updateRowsIndex = updateRows.length;
  351. const saveFileList = [];
  352. if (updateRowsIndex != null) {
  353. for (let i = 0; i < updateRowsIndex; i++) {
  354. const file = updateRows[i]
  355. file.id = i;
  356. updateRowList.items.add(file);
  357. saveFileList.push(file);
  358. }
  359. let updatedFileList = updateRowList.files;
  360. setFileList(updatedFileList);
  361. setFileListData(saveFileList)
  362. }
  363. }, [updateRows]);
  364. const handleFileUpload = (event) => {
  365. let updateList = new DataTransfer();
  366. let currentFileList = fileListData;
  367. const uploadFileList = event.target.files;
  368. const saveFileList = [];
  369. var currentIndex = 0;
  370. if (currentFileList.length != null) {
  371. currentIndex = currentFileList.length;
  372. for (let i = 0; i < currentIndex; i++) {
  373. const file = currentFileList[i]
  374. // file.id = currentIndex;
  375. updateList.items.add(file);
  376. saveFileList.push(file);
  377. }
  378. }
  379. for (let i = 0; i < uploadFileList.length && currentIndex < 5; i++) {
  380. const file = event.target.files[i]
  381. let isDuplicate = false;
  382. // Check if the file name already exists in saveFileList
  383. for (let j = 0; j < saveFileList.length; j++) {
  384. if (saveFileList[j].name === file.name) {
  385. isDuplicate = true;
  386. break;
  387. }
  388. }
  389. if (!isDuplicate && i + currentIndex < 5) {
  390. file.id = currentIndex + i
  391. saveFileList.push(file)
  392. updateList.items.add(file);
  393. }
  394. }
  395. let updatedFileList = updateList.files;
  396. setFileListData(saveFileList)
  397. setFileList(updatedFileList);
  398. };
  399. useEffect(() => {
  400. props.setUpdateValid(isValid)
  401. }, [isValid])
  402. useEffect(() => {
  403. props.setUpdateValid(isValid)
  404. }, [isValid])
  405. useEffect(() => {
  406. checkDataField(values)
  407. }, [
  408. selectedIdDocType,
  409. selectedAddress4, selectedAddress5,
  410. termsAndConAccept, termsAndConNotAccept, fileList])
  411. // useEffect(() => {
  412. // setDistrictErrStr("");
  413. // if (selectedAddress5?.type === "hongKong") {
  414. // if (selectedAddress4 == null || selectedAddress4 == "" || selectedAddress4 == {})
  415. // setDistrictErrStr(getRequiredErrStr("district"))
  416. // }
  417. // }, [selectedAddress4, selectedAddress5])
  418. useEffect(() => {
  419. props.step == 2 ? _onSubmit() : null;
  420. if (captchaImg == "")
  421. onCaptchaChange();
  422. checkDataField(values)
  423. }, [props.step])
  424. const { handleSubmit } = useForm({})
  425. const _onSubmit = () => {
  426. setLoding(true);
  427. values.idDocType = selectedIdDocType.type
  428. values.address4 = selectedAddress4 == null ? "" : selectedAddress4.type
  429. values.address5 = selectedAddress5.type
  430. // console.log(values)
  431. const userAddress = {
  432. "addressLine1": "",
  433. "addressLine2": "",
  434. "addressLine3": "",
  435. "district": "",
  436. "country": ""
  437. };
  438. userAddress.addressLine1 = values.address1
  439. userAddress.addressLine2 = values.address2
  440. userAddress.addressLine3 = values.address3
  441. userAddress.district = values.address4
  442. userAddress.country = values.address5
  443. const userFaxNo = {
  444. "countryCode": values.faxCountryCode,
  445. "faxNumber": values.fax,
  446. };
  447. const userMobileNumber = {
  448. "countryCode": values.phoneCountryCode,
  449. "phoneNumber": values.phone,
  450. };
  451. let tncFlag = false;
  452. if (termsAndConAccept) {
  453. tncFlag = true
  454. }
  455. if (termsAndConNotAccept) {
  456. tncFlag = false
  457. }
  458. const preferLocale = locale === 'en' ? 'en': locale === 'zh-HK' ? 'zh_HK': 'zh-CN'
  459. const user = {
  460. username: values.username,
  461. password: values.password,
  462. name: values.username,
  463. enName: values.enName,
  464. chName: values.chName,
  465. emailAddress: values.email,
  466. idDocType: values.idDocType,
  467. identification: values.idNo,
  468. checkDigit: values.checkDigit,
  469. tncFlag: tncFlag,
  470. type: "IND",
  471. captcha: base64Url,
  472. checkCode: checkCode,
  473. preferLocale: preferLocale
  474. };
  475. var formData = new FormData();
  476. for (let i = 0; i < fileListData.length; i++) {
  477. const file = fileListData[i]
  478. formData.append("multipartFileList", file);
  479. }
  480. formData.append("refType", refType);
  481. for (const [key, value] of Object.entries(user)) {
  482. formData.append(key, value);
  483. }
  484. formData.append("userFaxNo", JSON.stringify(userFaxNo));
  485. formData.append("userMobileNumber", JSON.stringify(userMobileNumber));
  486. formData.append("userAddress", JSON.stringify(userAddress));
  487. // formData.append("preferLocale", "en");
  488. // if(refCode){
  489. // formData.append("refCode", refCode);
  490. // }
  491. if (isValid) {
  492. axios.post(POST_PUBLIC_USER_REGISTER, formData, {
  493. headers: {
  494. "Content-Type": "multipart/form-data"
  495. }
  496. })
  497. .then((
  498. // response
  499. ) => {
  500. // console.log(response)
  501. setCheckUpload(true)
  502. setLoding(false);
  503. })
  504. .catch(error => {
  505. console.error(error);
  506. setLoding(false);
  507. });
  508. } else {
  509. setLoding(false);
  510. }
  511. }
  512. function handlePhone(phone) {
  513. if (phone.length < 8) {
  514. return false;
  515. } else {
  516. // console.log("Phone true")
  517. return true;
  518. }
  519. }
  520. function handleUsername(username) {
  521. var symbol = /^(?=.*\W)/;
  522. var space = /\s/;
  523. if (username.length < 6) {
  524. return false;
  525. } else if (username.match(symbol)) {
  526. return false;
  527. } else if (username.match(space)) {
  528. return false;
  529. } else {
  530. return true;
  531. }
  532. }
  533. function handleCaptcha(captchaField) {
  534. // console.log(captchaField.length)
  535. if (captchaField.length == 5 ){
  536. return true
  537. } else {
  538. return false
  539. }
  540. }
  541. function handleIdNo(idNo, selectedIdDocType, checkDigit) {
  542. // var pattern = /^[A-Z][0-9]*$/;
  543. var pattern_HKIDv1 = /^[A-Z]{1}[0-9]{6}$/;
  544. var pattern_HKIDv2 = /^[A-Z]{2}[0-9]{6}$/;
  545. var pattern_passport = /^[A-Z]{1}[0-9]{8}$/;
  546. var pattern_CHID = /^[0-9]{6}(20|19)[0-9]{2}(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])[0-9]{3}[0-9X]{1}/;
  547. var pattern_otherCert = /^[A-Z]{1}[0-9]{5,}/;
  548. // var space = /\s/;
  549. // if (!idNo.match(pattern)) {
  550. // return false;
  551. // } else if (selectedIdDocType=="HKID"&&checkDigit==""){
  552. // return false;
  553. // } else if (idNo.match(space)) {
  554. // return false;
  555. // } else if (idNo.length < 6) {
  556. // return false;
  557. // } else {
  558. // // console.log("IdNo true")
  559. // return true;
  560. // }
  561. switch (selectedIdDocType) {
  562. case "HKID":
  563. if (checkDigit === ""){
  564. setCheckHKIdDocWithCheckDigit(true)
  565. return false
  566. } else{
  567. setCheckHKIdDocWithCheckDigit(false)
  568. }
  569. if (idNo.match(pattern_HKIDv1)) {
  570. return true
  571. } else if (idNo.match(pattern_HKIDv2)) {
  572. return true
  573. } else {
  574. return false
  575. }
  576. case "passport":
  577. if (idNo.match(pattern_passport)) {
  578. return true
  579. } else {
  580. return false
  581. }
  582. case "CNID":
  583. if (idNo.match(pattern_CHID)) {
  584. const subStr_year = idNo.substring(6, 10)
  585. const subStr_month = idNo.substring(10, 12)
  586. const subStr_date = idNo.substring(12, 14)
  587. const today = new Date()
  588. const inputDate = new Date(`${subStr_year}-${subStr_month}-${subStr_date}`)
  589. if (inputDate > today || inputDate === "Invalid Date" || inputDate.getFullYear().toString() !== subStr_year || (inputDate.getMonth() + 1).toString().padStart(2, "0") !== subStr_month || inputDate.getDate().toString().padStart(2, "0") !== subStr_date) {
  590. return false
  591. } else {
  592. return true
  593. }
  594. } else {
  595. return false
  596. }
  597. case "otherCert":
  598. if (idNo.match(pattern_otherCert)) {
  599. return true
  600. } else {
  601. return false
  602. }
  603. default:
  604. break;
  605. }
  606. }
  607. function handleName(enName, chName) {
  608. if (enName == "" && chName !== ""){
  609. return true
  610. } else if (enName !== "" && chName == ""){
  611. return true
  612. } else if (enName !== "" && chName !== "") {
  613. return true
  614. } else {
  615. return false
  616. }
  617. }
  618. function handlePassword(password) {
  619. let new_pass = password;
  620. // regular expressions to validate password
  621. var lowerCase = /[a-z]/g;
  622. var upperCase = /[A-Z]/g;
  623. var numbers = /[0-9]/g;
  624. var symbol = /^(?=.*\W)/;
  625. var space = /\s/;
  626. if (!new_pass.match(lowerCase)) {
  627. return false;
  628. } else if (!new_pass.match(upperCase)) {
  629. return false;
  630. } else if (!new_pass.match(numbers)) {
  631. return false;
  632. } else if (!new_pass.match(symbol)) {
  633. return false;
  634. } else if (new_pass.length < 8) {
  635. return false;
  636. }
  637. else if (new_pass.match(space)) {
  638. return false;
  639. } else {
  640. // console.log("password true")
  641. return true;
  642. }
  643. }
  644. function handleEmail(email) {
  645. var validRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
  646. if (!email.match(validRegex)) {
  647. return false;
  648. } else {
  649. return true;
  650. }
  651. }
  652. function displayErrorMsg(errorMsg) {
  653. return <Typography variant="errorMessage1">{errorMsg}</Typography>
  654. }
  655. function getMaxErrStr(num, fieldname) {
  656. return displayErrorMsg(intl.formatMessage({ id: 'noMoreThenNWords' }, { num: num, fieldname: fieldname ? intl.formatMessage({ id: fieldname }) + ": " : "" }));
  657. }
  658. function getRequiredErrStr(fieldname) {
  659. return displayErrorMsg(intl.formatMessage({ id: 'require' }, { fieldname: fieldname ? intl.formatMessage({ id: fieldname }) : "" }));
  660. }
  661. const formik = useFormik({
  662. initialValues: ({
  663. username: '',
  664. enName: '',
  665. chName: '',
  666. email: '',
  667. emailConfirm: '',
  668. address1: '',
  669. address2: '',
  670. address3: '',
  671. password: '',
  672. confirmPassword: '',
  673. phone: '',
  674. phoneCountryCode: '852',
  675. idNo: '',
  676. checkDigit: '',
  677. submit: null,
  678. fax: '',
  679. faxCountryCode: '852',
  680. idDocType: '',
  681. captchaField: ''
  682. }),
  683. validationSchema: yup.object().shape({
  684. username: yup.string().min(6, displayErrorMsg(intl.formatMessage({ id: 'atLeast6CharAccount' }))).max(30, getMaxErrStr(30)).required(displayErrorMsg(intl.formatMessage({ id: 'requireUsername' })))
  685. .matches(/^[aA-zZ0-9\s]+$/, { message: displayErrorMsg(intl.formatMessage({ id: 'noSpecialCharAccount' })) })
  686. .matches(/^\S*$/, { message: displayErrorMsg(intl.formatMessage({ id: 'noSpaceAccount' })) }),
  687. password: yup.string().min(8, displayErrorMsg(intl.formatMessage({ id: 'atLeast8CharPassword' }))).max(60, getMaxErrStr(60)).required(displayErrorMsg(intl.formatMessage({ id: 'requirePassword' })))
  688. .matches(/^\S*$/, { message: displayErrorMsg(intl.formatMessage({ id: 'noSpacePassword' })) })
  689. .matches(/^(?=.*[a-z])/, { message: displayErrorMsg(intl.formatMessage({ id: 'atLeastOneSmallLetter' })) })
  690. .matches(/^(?=.*[A-Z])/, { message: displayErrorMsg(intl.formatMessage({ id: 'atLeastOneCapLetter' })) })
  691. .matches(/^(?=.*[0-9])/, { message: displayErrorMsg(intl.formatMessage({ id: 'atLeast1Number' })) })
  692. .matches(/^(?=.*\W)/, { message: displayErrorMsg(intl.formatMessage({ id: 'atLeast1SpecialChar' })) }),
  693. confirmPassword: yup.string().min(8, displayErrorMsg(intl.formatMessage({ id: 'atLeast8CharPassword' }))).required(displayErrorMsg(intl.formatMessage({ id: 'pleaseConfirmPassword' }))).oneOf([yup.ref('password'), null], displayErrorMsg(intl.formatMessage({ id: 'samePassword' }))),
  694. chName: yup.string().max(6, getMaxErrStr(6)),
  695. enName: yup.string().max(40, getMaxErrStr(40)).when('chName', {
  696. is: (chName) => chName?false:true,
  697. then: yup.string().required(displayErrorMsg(intl.formatMessage({ id: 'registerNameLabel' })))
  698. }),
  699. address1: yup.string().max(40, getMaxErrStr(40, "addressLine1")).required(displayErrorMsg(intl.formatMessage({ id: 'validateAddressLine1' }))),
  700. address2: yup.string().max(40, getMaxErrStr(40, "addressLine2")),
  701. address3: yup.string().max(40, getMaxErrStr(40, "addressLine3")),
  702. email: yup.string().email(displayErrorMsg(intl.formatMessage({ id: 'validEmailFormat' }))).max(128, getMaxErrStr(128)).required(displayErrorMsg(intl.formatMessage({ id: 'requireEmail' }))),
  703. 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' }))),
  704. idNo: yup.string().required(getRequiredErrStr('number'))
  705. .matches(/^[aA-zZ0-9\s]+$/, { message: displayErrorMsg(`${selectedIdDocInputType}${intl.formatMessage({ id: 'noSpecialCharacter' })}`) })
  706. .matches(/^\S*$/, { message: displayErrorMsg(`${selectedIdDocInputType}${intl.formatMessage({ id: 'noSpace' })}`) })
  707. .test('checkIDCardFormat', displayErrorMsg(`${intl.formatMessage({ id: 'requiredValid' })}${selectedIdDocInputType==undefined?"":selectedIdDocInputType}${intl.formatMessage({ id: 'number' })}`), function (value) {
  708. const idDocType = selectedIdDocType.type;
  709. var pattern_HKIDv1 = /^[A-Z]{1}[0-9]{6}$/;
  710. var pattern_HKIDv2 = /^[A-Z]{2}[0-9]{6}$/;
  711. var pattern_passport = /^[A-Z]{1}[0-9]{8}$/;
  712. var pattern_CHID = /^[0-9]{6}(20|19)[0-9]{2}(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])[0-9]{3}[0-9X]{1}/;
  713. var pattern_otherCert = /^[A-Z]{1}[0-9]{5,}/;
  714. if (value !== undefined) {
  715. switch (idDocType) {
  716. case "HKID":
  717. if (value.match(pattern_HKIDv1)) {
  718. return true
  719. } else if (value.match(pattern_HKIDv2)) {
  720. return true
  721. } else {
  722. return false
  723. }
  724. case "passport":
  725. if (value.match(pattern_passport)) {
  726. return true
  727. } else {
  728. return false
  729. }
  730. case "CNID":
  731. if (value.match(pattern_CHID)) {
  732. const subStr_year = value.substring(6, 10)
  733. const subStr_month = value.substring(10, 12)
  734. const subStr_date = value.substring(12, 14)
  735. const today = new Date()
  736. const inputDate = new Date(`${subStr_year}-${subStr_month}-${subStr_date}`)
  737. if (inputDate > today || inputDate === "Invalid Date" || inputDate.getFullYear().toString() !== subStr_year || (inputDate.getMonth() + 1).toString().padStart(2, "0") !== subStr_month || inputDate.getDate().toString().padStart(2, "0") !== subStr_date) {
  738. return false
  739. } else {
  740. return true
  741. }
  742. } else {
  743. return false
  744. }
  745. case "otherCert":
  746. if (value.match(pattern_otherCert)) {
  747. return true
  748. } else {
  749. return false
  750. }
  751. default:
  752. break;
  753. }
  754. }
  755. }),
  756. checkDigit: yup.string().max(1, getMaxErrStr(1)).required(displayErrorMsg(intl.formatMessage({ id: 'requiredNumberInQuote' }))),
  757. idDocType: yup.string().max(255, getMaxErrStr(255)).required(displayErrorMsg(intl.formatMessage({ id: 'requireIdDocType' }))),
  758. phoneCountryCode: yup.string().min(2, displayErrorMsg(intl.formatMessage({ id: 'requireAtLeast2Number' }))).required(displayErrorMsg(intl.formatMessage({ id: 'requireDialingCode' }))),
  759. // faxCountryCode: yup.string().min(3,'請輸入3位數字'),
  760. phone: yup.string().min(8, displayErrorMsg(intl.formatMessage({ id: 'requireAtLeast8Number' }))).required(displayErrorMsg(intl.formatMessage({ id: 'requireContactNumber' }))),
  761. // fax: yup.string().min(8,'請輸入8位數字'),
  762. captchaField: yup.string().max(5, getMaxErrStr(5)).required(displayErrorMsg(intl.formatMessage({ id: 'requireVerify' }))).min(5, displayErrorMsg(intl.formatMessage({ id: 'requireVerify' }))),//.oneOf([captcha], displayErrorMsg('請輸入有效驗證')),
  763. }),
  764. });
  765. const handleReset = (resetForm) => {
  766. resetForm();
  767. setSelectedAddress4("")
  768. setSelectedAddress5(ComboData.country[0])
  769. setCheckCountry(false)
  770. setSelectedIdDocType({})
  771. setSelectedIdDocInputType("");
  772. setFileList([])
  773. setFileListData([])
  774. onCaptchaChange()
  775. // setSelectedIdDocLabel("")
  776. };
  777. const handleCCPChange = (e) => {
  778. e.preventDefault();
  779. };
  780. const { values } = formik
  781. useEffect(() => {
  782. checkDataField(values)
  783. }, [values])
  784. return (
  785. <FormikProvider value={formik}>
  786. <form onSubmit={handleSubmit(_onSubmit)}>
  787. {/* Input Form */}
  788. <FormGroup id={"inputForm"} sx={{ display: props.step === 0 ? "" : "none" }}>
  789. <Grid container spacing={3}>
  790. <Grid item xs={12} md={12}>
  791. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  792. <Button
  793. variant="outlined"
  794. type="reset"
  795. onClick={handleReset.bind(null, formik.resetForm)}
  796. sx={{
  797. height: '40px',
  798. borderColor: '#616161',
  799. color: '#424242',
  800. '&:hover': { borderColor: '#424242', backgroundColor: 'rgba(97,97,97,0.08)' },
  801. }}
  802. >
  803. <Typography variant="pnspsFormHeader">
  804. <FormattedMessage id="reset" />
  805. </Typography>
  806. </Button>
  807. <div style={{ borderBottom: "3px solid #1A4399", width: "100%", margin_right: "15px" }}>
  808. <Typography display="inline" variant="h3" sx={{ color: '#1A4399' }}>
  809. <FormattedMessage id="becomeNewPersonalUser" />
  810. </Typography>
  811. </div>
  812. <Typography mt={0.25} variant="h6" sx={{ color: '#B00020' }}>
  813. <FormattedMessage id="requireString" />
  814. </Typography>
  815. <Typography mt={0.25} variant="h4" sx={{ color: 'primary.primary' }}>
  816. <FormattedMessage id="yourLoginInformation" />
  817. </Typography>
  818. </Stack>
  819. </Grid>
  820. <Grid item xs={12} md={12}>
  821. <Grid container spacing={1}>
  822. <Grid item xs={12} md={12} >
  823. <Stack spacing={1}>
  824. <InputLabel htmlFor="username-signup">
  825. <Typography variant="pnspsFormHeader">
  826. <FormattedMessage id="userLoginName" />
  827. <span style={{ color: '#B00020' }}>*</span>
  828. {/*<Button*/}
  829. {/* variant="contained"*/}
  830. {/* onClick={handleCheckUsername}*/}
  831. {/* sx={{ ml: 2, height: "40px" }}>*/}
  832. {/* <Typography variant="h6">檢查是否重覆</Typography>*/}
  833. {/*</Button> **/}
  834. </Typography>
  835. </InputLabel>
  836. <OutlinedInput
  837. id="username-signup"
  838. type="text"
  839. value={formik.values.username.trim()}
  840. name="username"
  841. onChange={(e) => {
  842. setCheckUsername(false)
  843. props.setUsername(e.target.value)
  844. formik.handleChange(e)
  845. }}
  846. placeholder={intl.formatMessage({ id: 'userLoginName' })}
  847. fullWidth
  848. autoFocus
  849. error={Boolean((formik.touched.username && formik.errors.username) || checkUsername)}
  850. onBlur={formik.handleBlur}
  851. inputProps={{
  852. "aria-label": intl.formatMessage({ id: "userLoginName" }),
  853. "aria-describedby": 'helper-text-username-signup',
  854. onKeyDown: (e) => {
  855. if (e.key === 'Enter') {
  856. e.preventDefault();
  857. }
  858. },
  859. }}
  860. />
  861. {formik.touched.username && formik.errors.username && (
  862. <FormHelperText error id="helper-text-username-signup">
  863. {formik.errors.username}
  864. </FormHelperText>
  865. )}
  866. {checkUsername && (
  867. <FormHelperText error id="helper-text-username-signup">
  868. <FormattedMessage id="usernameTaken" />
  869. </FormHelperText>
  870. )}
  871. </Stack>
  872. </Grid>
  873. <Grid item xs={12} md={12}>
  874. <Grid container>
  875. <Grid item xs={12} md={6} >
  876. <Stack spacing={1} sx={{ mr: { md: 1 }, mb: 1 }}>
  877. <Stack direction="row" justifyContent="space-between">
  878. <InputLabel htmlFor="password-signup">
  879. <Typography variant="pnspsFormHeader">
  880. <FormattedMessage id="userPassword" />
  881. <span style={{ color: '#B00020' }}>*</span>
  882. </Typography>
  883. </InputLabel>
  884. </Stack>
  885. <OutlinedInput
  886. fullWidth
  887. error={Boolean(formik.touched.password && formik.errors.password)}
  888. id="password-signup"
  889. type={showPassword ? 'text' : 'password'}
  890. value={formik.values.password.trim()}
  891. name="password"
  892. onChange={(e) => {
  893. formik.handleChange(e);
  894. changePassword(e.target.value);
  895. }}
  896. endAdornment={
  897. <InputAdornment position="end">
  898. <IconButton
  899. aria-label={intl.formatMessage({
  900. id: showPassword ? "ariaHidePassword" : "ariaShowPassword"
  901. })}
  902. onClick={handleClickShowPassword}
  903. onMouseDown={handleMouseDownPassword}
  904. edge="end"
  905. size="large"
  906. >
  907. {showPassword ? <EyeOutlined /> : <EyeInvisibleOutlined />}
  908. </IconButton>
  909. </InputAdornment>
  910. }
  911. placeholder={intl.formatMessage({ id: 'userPassword' })}
  912. onBlur={formik.handleBlur}
  913. inputProps={{
  914. "aria-label": intl.formatMessage({ id: "userPassword" }),
  915. "aria-describedby": 'helper-text-password-signup',
  916. onKeyDown: (e) => {
  917. if (e.key === 'Enter') {
  918. e.preventDefault();
  919. }
  920. },
  921. }}
  922. />
  923. {formik.touched.password && formik.errors.password && (
  924. <FormHelperText error id="helper-text-password-signup">
  925. {formik.errors.password}
  926. </FormHelperText>
  927. )}
  928. </Stack>
  929. <FormControl fullWidth sx={{ mt: 2 }}>
  930. <Grid container spacing={2} alignItems="center">
  931. <Grid item>
  932. <Box sx={{ bgcolor: level?.color, width: 85, height: 8, borderRadius: '7px' }} />
  933. </Grid>
  934. <Grid item>
  935. <Typography variant="subtitle1">
  936. <FormattedMessage id={level ? level?.label : "pwWeak"} />
  937. </Typography>
  938. </Grid>
  939. </Grid>
  940. </FormControl>
  941. </Grid>
  942. <Grid item xs={12} md={6} >
  943. <Stack spacing={1}>
  944. <InputLabel htmlFor="confirmPassword-signup">
  945. <Typography variant="pnspsFormHeader">
  946. <FormattedMessage id="confirmPassword" />
  947. <span style={{ color: '#B00020' }}>*</span>
  948. </Typography>
  949. </InputLabel>
  950. <OutlinedInput
  951. id="confirmPassword-signup"
  952. type={showConfirmPassword ? 'text' : 'password'}
  953. value={formik.values.confirmPassword.trim()}
  954. name="confirmPassword"
  955. onBlur={formik.handleBlur}
  956. onCut={handleCCPChange}
  957. onCopy={handleCCPChange}
  958. onPaste={handleCCPChange}
  959. onChange={(e) => {
  960. formik.handleChange(e);
  961. // changePassword(e.target.value);
  962. }}
  963. inputProps={{
  964. "aria-label": intl.formatMessage({ id: "confirmPassword" }),
  965. "aria-describedby": 'helper-text-confirmPassword-signup',
  966. onKeyDown: (e) => {
  967. if (e.key === 'Enter') {
  968. e.preventDefault();
  969. }
  970. },
  971. }}
  972. endAdornment={
  973. <InputAdornment position="end">
  974. <IconButton
  975. aria-label={intl.formatMessage({
  976. id: showConfirmPassword ? "ariaHidePassword" : "ariaShowPassword"
  977. })}
  978. onClick={handleClickShowConfirmPassword}
  979. onMouseDown={handleMouseDownPassword}
  980. edge="end"
  981. size="large"
  982. >
  983. {showConfirmPassword ? <EyeOutlined /> : <EyeInvisibleOutlined />}
  984. </IconButton>
  985. </InputAdornment>
  986. }
  987. placeholder={intl.formatMessage({ id: 'confirmPassword' })}
  988. fullWidth
  989. error={Boolean(formik.touched.confirmPassword && formik.errors.confirmPassword)}
  990. />
  991. {formik.touched.confirmPassword && formik.errors.confirmPassword && (
  992. <FormHelperText error id="helper-text-confirmPassword-signup">
  993. {formik.errors.confirmPassword}
  994. </FormHelperText>
  995. )}
  996. </Stack>
  997. <Grid container spacing={2} alignItems="center">
  998. <Grid item sx={{ mt: 1 }}>
  999. <Typography variant="subtitle1">
  1000. •<FormattedMessage id="pwRemark1" /><br />
  1001. •<FormattedMessage id="pwRemark2" /><br />
  1002. •<FormattedMessage id="pwRemark3" /><br />
  1003. •<FormattedMessage id="pwRemark4" /><br />
  1004. •<FormattedMessage id="pwRemark5"/><br />
  1005. </Typography>
  1006. </Grid>
  1007. </Grid>
  1008. </Grid>
  1009. </Grid>
  1010. </Grid>
  1011. <Grid item xs={12} mt={1} mb={1}>
  1012. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1013. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>
  1014. <FormattedMessage id="yourPersonalInformation" />
  1015. </Typography>
  1016. {/* <Typography component={Link} to="/login" variant="body1" sx={{ textDecoration: 'none' }} color="primary">
  1017. Already have an account?
  1018. </Typography> */}
  1019. </Stack>
  1020. </Grid>
  1021. <Grid item xs={12} md={12} >
  1022. <Grid container sx={{ mb: 1 }}>
  1023. <Stack spacing={1}>
  1024. <InputLabel htmlFor="idDocType-signup">
  1025. <Typography variant="pnspsFormHeader">
  1026. <FormattedMessage id="userIdDoc" />
  1027. <span style={{ color: '#B00020' }}>*</span>
  1028. </Typography>
  1029. </InputLabel>
  1030. {/* {formik.touched.enName && formik.errors.enName && (
  1031. <FormHelperText error id="helper-text-enName-signup">
  1032. {formik.errors.enName}
  1033. </FormHelperText>
  1034. )} */}
  1035. </Stack>
  1036. </Grid>
  1037. <Grid container>
  1038. <Grid item xs={12} md={6} >
  1039. <Stack spacing={1} sx={{ mr: { md: 1 } }}>
  1040. <Autocomplete
  1041. disablePortal
  1042. id="idDocType"
  1043. label={intl.formatMessage({ id: "idDocType" })}
  1044. //value={selectedIdDocType}
  1045. size="small"
  1046. options={idDocTypeComboList}
  1047. onBlur={formik.handleBlur}
  1048. filterOptions={(options) => options}
  1049. inputValue={selectedIdDocInputType}
  1050. getOptionLabel={(option) => option.label ? intl.formatMessage({ id: option.label }) : ""}
  1051. onChange={(event, newValue) => {
  1052. if (newValue != null) {
  1053. setSelectedIdDocInputType(intl.formatMessage({ id: newValue.label }));
  1054. setSelectedIdDocType(newValue);
  1055. if (newValue.type !== "HKID") {
  1056. formik.setFieldValue("checkDigit", "")
  1057. }
  1058. } else {
  1059. setSelectedIdDocInputType("");
  1060. setSelectedIdDocType({});
  1061. }
  1062. }}
  1063. sx={{
  1064. '& .MuiInputBase-root': { alignItems: 'center' },
  1065. '& .MuiAutocomplete-endAdornment': { top: '50%', transform: 'translateY(-50%)' },
  1066. '& .MuiOutlinedInput-root': { height: 40 }
  1067. }}
  1068. renderInput={(params) => <TextField
  1069. {...params}
  1070. error={formik.touched.idDocType && (selectedIdDocType === null || selectedIdDocType?.type == null)}
  1071. placeholder={intl.formatMessage({ id: 'idDocType' })}
  1072. />}
  1073. clearText={intl.formatMessage({ id: "muiClear" })}
  1074. closeText={intl.formatMessage({ id: "muiClose" })}
  1075. openText={intl.formatMessage({ id: "muiOpen" })}
  1076. noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
  1077. />
  1078. {formik.touched.idDocType && (
  1079. selectedIdDocType === null || selectedIdDocType?.type == null ?
  1080. <FormHelperText error id="helper-text-idDocType-signup" sx={{ fontSize: 16, fontWeight: 'bold', }}>
  1081. <FormattedMessage id="requireIdDocType" />
  1082. </FormHelperText> : ''
  1083. )}
  1084. </Stack>
  1085. </Grid>
  1086. {selectedIdDocType.type === "HKID" ?
  1087. <>
  1088. <Grid item xs={9} md={5}>
  1089. <Stack spacing={1} sx={{ mr: { md: 1 } }}>
  1090. <OutlinedInput
  1091. id="idNo-hkid-login"
  1092. type="text"
  1093. name="idNo"
  1094. value={formik.values.idNo}
  1095. onChange={async (e) => {
  1096. const ele = document.getElementById('idNo-hkid-login')
  1097. const startPos = ele.selectionStart
  1098. if (e.type === "change") {
  1099. if (!(e.target.value.match(/\s/g))) {
  1100. const newValue = await e.target.value.toUpperCase()
  1101. await formik.setFieldValue("idNo", newValue)
  1102. ele.setSelectionRange(startPos, startPos)
  1103. } else {
  1104. await formik.setFieldValue("idNo", formik.values.idNo)
  1105. ele.setSelectionRange(startPos - 1, startPos - 1)
  1106. }
  1107. }
  1108. }}
  1109. placeholder={intl.formatMessage({ id: 'idDocNumber' })}
  1110. fullWidth
  1111. sx={{ mr: 1 }}
  1112. error={Boolean(formik.touched.idNo && formik.errors.idNo || checkIdDocNumber)}
  1113. onBlur={formik.handleBlur}
  1114. inputProps={{
  1115. "aria-label": intl.formatMessage({ id: "idDocNumber" }),
  1116. "aria-describedby": 'helper-text-idNo-signup',
  1117. maxLength: selectedIdDocType.type === 'HKID' ? 8 : 18,
  1118. onKeyDown: (e) => {
  1119. // console.log(e)
  1120. if (e.key === 'Enter') {
  1121. e.preventDefault();
  1122. }
  1123. },
  1124. }}
  1125. />
  1126. {formik.touched.idNo && formik.errors.idNo && (
  1127. <FormHelperText error id="helper-text-idNo-signup">
  1128. {formik.errors.idNo}
  1129. </FormHelperText>
  1130. )}
  1131. {formik.touched.checkDigit && formik.errors.checkDigit && (
  1132. <FormHelperText error id="helper-text-checkDigit-signup">
  1133. {formik.errors.checkDigit}
  1134. </FormHelperText>
  1135. )}
  1136. {checkIdDocNumber && (
  1137. <FormHelperText error id="helper-text-idNo-signup">
  1138. <FormattedMessage id="idNoTaken" />
  1139. </FormHelperText>
  1140. )}
  1141. {checkHKIdDocWithCheckDigit && (
  1142. <FormHelperText error id="helper-text-idNo-checkdigit-signup">
  1143. <FormattedMessage id="requiredNumberInQuote" />
  1144. </FormHelperText>
  1145. )}
  1146. </Stack>
  1147. </Grid>
  1148. <Grid item xs={3} md={1}>
  1149. <Stack spacing={1}>
  1150. <OutlinedInput
  1151. id="checkDigit-login"
  1152. type="text"
  1153. value={formik.values.checkDigit.trim()}
  1154. name="checkDigit"
  1155. onChange={formik.handleChange}
  1156. //placeholder="( )"
  1157. // sx={{height:"53px"}}
  1158. startAdornment={<InputAdornment position="start">(</InputAdornment>}
  1159. endAdornment={<InputAdornment position="end">)</InputAdornment>}
  1160. sx={{
  1161. '& .MuiOutlinedInput-input': {
  1162. padding: '5px 2px 5px 2px', // Set the desired padding inline
  1163. },
  1164. }}
  1165. inputProps={{
  1166. maxLength: 1,
  1167. onKeyDown: (e) => {
  1168. if (e.key === 'Enter') {
  1169. e.preventDefault();
  1170. }
  1171. },
  1172. }}
  1173. fullWidth
  1174. error={Boolean(formik.touched.checkDigit && formik.errors.checkDigit || checkIdDocNumber)}
  1175. onBlur={formik.handleBlur}
  1176. />
  1177. </Stack>
  1178. </Grid>
  1179. </> :
  1180. <Grid item xs={12} md={6}>
  1181. <Stack spacing={1}>
  1182. <OutlinedInput
  1183. id="idNo-login"
  1184. type="text"
  1185. value={formik.values.idNo}
  1186. name="idNo"
  1187. onChange={async (e) => {
  1188. const ele = document.getElementById('idNo-login')
  1189. const startPos = ele.selectionStart
  1190. if (e.type === "change") {
  1191. if (!(e.target.value.match(/\s/g))) {
  1192. const newValue = await e.target.value.toUpperCase()
  1193. await formik.setFieldValue("idNo", newValue)
  1194. ele.setSelectionRange(startPos, startPos)
  1195. } else {
  1196. await formik.setFieldValue("idNo", formik.values.idNo)
  1197. ele.setSelectionRange(startPos - 1, startPos - 1)
  1198. }
  1199. }
  1200. }}
  1201. placeholder={intl.formatMessage({ id: 'idDocNumber' })}
  1202. fullWidth
  1203. sx={{ mr: 1 }}
  1204. error={Boolean(formik.touched.idNo && formik.errors.idNo || checkIdDocNumber)}
  1205. onBlur={formik.handleBlur}
  1206. inputProps={{
  1207. "aria-label": intl.formatMessage({ id: "idDocNumber" }),
  1208. "aria-describedby": 'helper-text-idNo-signup',
  1209. maxLength: 18,
  1210. onKeyDown: (e) => {
  1211. if (e.key === 'Enter') {
  1212. e.preventDefault();
  1213. }
  1214. },
  1215. }}
  1216. />
  1217. {formik.touched.idNo && formik.errors.idNo && (
  1218. <FormHelperText error id="helper-text-idNo-signup">
  1219. {formik.errors.idNo}
  1220. </FormHelperText>
  1221. )}
  1222. {checkIdDocNumber && (
  1223. <FormHelperText error id="helper-text-idNo-signup">
  1224. <FormattedMessage id="idNoTaken" />
  1225. </FormHelperText>
  1226. )}
  1227. </Stack>
  1228. </Grid>
  1229. }
  1230. </Grid>
  1231. </Grid>
  1232. <Grid item xs={12} md={12}>
  1233. <Typography variant="subtitle1">
  1234. <FormattedMessage id="registerNameLabel" />
  1235. </Typography>
  1236. </Grid>
  1237. <Grid item xs={12} md={6}>
  1238. <Stack spacing={1}>
  1239. <InputLabel htmlFor="enName-signup">
  1240. <Typography variant="pnspsFormHeader">
  1241. <FormattedMessage id="userEnglishName" />
  1242. {selectedIdDocType.type === "CNID" ? "" : <span style={{ color: '#B00020' }}></span>}
  1243. </Typography>
  1244. </InputLabel>
  1245. <OutlinedInput
  1246. id="enName-signup"
  1247. type="enName"
  1248. value={formik.values.enName}
  1249. name="enName"
  1250. onChange={formik.handleChange}
  1251. placeholder={intl.formatMessage({ id: 'sameAsYourIdDoc' })}
  1252. fullWidth
  1253. error={Boolean(formik.touched.enName && formik.errors.enName && selectedIdDocType.type !== "CNID")}
  1254. onBlur={formik.handleBlur}
  1255. inputProps={{
  1256. "aria-label": intl.formatMessage({ id: "userEnglishName" }),
  1257. "aria-describedby": 'helper-text-enName-signup',
  1258. onKeyDown: (e) => {
  1259. if (e.key === 'Enter') {
  1260. e.preventDefault();
  1261. }
  1262. },
  1263. }}
  1264. />
  1265. {formik.touched.enName && formik.errors.enName && selectedIdDocType.type !== "CNID" && (
  1266. <FormHelperText error id="helper-text-enName-signup">
  1267. {formik.errors.enName}
  1268. </FormHelperText>
  1269. )}
  1270. </Stack>
  1271. </Grid>
  1272. <Grid item xs={12} md={6}>
  1273. <Stack spacing={1}>
  1274. <InputLabel htmlFor="chName-signup">
  1275. <Typography variant="pnspsFormHeader">
  1276. <FormattedMessage id="userChineseName" />
  1277. <span style={{ color: '#B00020' }}></span>
  1278. </Typography>
  1279. </InputLabel>
  1280. <OutlinedInput
  1281. fullWidth
  1282. error={Boolean(formik.touched.chName && formik.errors.chName)}
  1283. id="chName-signup"
  1284. type="text"
  1285. value={formik.values.chName.trim()}
  1286. name="chName"
  1287. onChange={formik.handleChange}
  1288. placeholder={intl.formatMessage({ id: 'sameAsYourIdDoc' })}
  1289. onBlur={formik.handleBlur}
  1290. inputProps={{
  1291. "aria-label": intl.formatMessage({ id: "userChineseName" }),
  1292. "aria-describedby": 'helper-text-chName-signup',
  1293. maxLength: 6,
  1294. onKeyDown: (e) => {
  1295. if (e.key === 'Enter') {
  1296. e.preventDefault();
  1297. }
  1298. },
  1299. }}
  1300. />
  1301. {formik.touched.chName && formik.errors.chName && (
  1302. <FormHelperText error id="helper-text-chName-signup">
  1303. {formik.errors.chName}
  1304. </FormHelperText>
  1305. )}
  1306. </Stack>
  1307. </Grid>
  1308. <Grid item xs={12}>
  1309. <Stack spacing={1}>
  1310. <InputLabel htmlFor="address1-signup">
  1311. <Typography variant="pnspsFormHeader">
  1312. <FormattedMessage id="formAddress" />
  1313. <span style={{ color: '#B00020' }}>*</span>
  1314. </Typography>
  1315. </InputLabel>
  1316. <OutlinedInput
  1317. fullWidth
  1318. error={Boolean(formik.touched.address1 && formik.errors.address1)}
  1319. id="address1-signup"
  1320. value={formik.values.address1}
  1321. name="address1"
  1322. onChange={formik.handleChange}
  1323. placeholder={intl.formatMessage({ id: 'addressLine1' })}
  1324. onBlur={formik.handleBlur}
  1325. inputProps={{
  1326. "aria-label": intl.formatMessage({ id: "addressLine1" }),
  1327. onKeyDown: (e) => {
  1328. if (e.key === 'Enter') {
  1329. e.preventDefault();
  1330. }
  1331. },
  1332. }}
  1333. />
  1334. <OutlinedInput
  1335. fullWidth
  1336. error={Boolean(formik.touched.address2 && formik.errors.address2)}
  1337. id="address2-signup"
  1338. value={formik.values.address2}
  1339. name="address2"
  1340. onChange={formik.handleChange}
  1341. onBlur={formik.handleBlur}
  1342. placeholder={intl.formatMessage({ id: 'addressLine2' })}
  1343. inputProps={{
  1344. "aria-label": intl.formatMessage({ id: "addressLine2" }),
  1345. onKeyDown: (e) => {
  1346. if (e.key === 'Enter') {
  1347. e.preventDefault();
  1348. }
  1349. },
  1350. }}
  1351. />
  1352. <OutlinedInput
  1353. fullWidth
  1354. error={Boolean(formik.touched.address3 && formik.errors.address3)}
  1355. id="address3-signup"
  1356. value={formik.values.address3}
  1357. name="address3"
  1358. onChange={formik.handleChange}
  1359. onBlur={formik.handleBlur}
  1360. placeholder={intl.formatMessage({ id: 'addressLine3' })}
  1361. inputProps={{
  1362. "aria-label": intl.formatMessage({ id: "addressLine3" }),
  1363. onKeyDown: (e) => {
  1364. if (e.key === 'Enter') {
  1365. e.preventDefault();
  1366. }
  1367. },
  1368. }}
  1369. />
  1370. <Autocomplete
  1371. disablePortal
  1372. id="address4-combo"
  1373. value={selectedAddress4}
  1374. options={ComboData.district}
  1375. disabled={checkCountry}
  1376. // error={Boolean(districtErrStr != "")}
  1377. // onBlur={formik.handleBlur}
  1378. getOptionLabel={(option) => option.type ? intl.formatMessage({ id: option.type }) : ""}
  1379. onChange={(event, newValue) => {
  1380. setSelectedAddress4(newValue);
  1381. }}
  1382. sx={{
  1383. '& .MuiInputBase-root': { alignItems: 'center' },
  1384. '& .MuiAutocomplete-endAdornment': { top: '50%', transform: 'translateY(-50%)' },
  1385. '& .MuiOutlinedInput-root': { height: 40 }
  1386. }}
  1387. renderInput={(params) => <TextField error={checkDistrict} {...params} placeholder={intl.formatMessage({ id: 'region' })}
  1388. />}
  1389. clearText={intl.formatMessage({ id: "muiClear" })}
  1390. closeText={intl.formatMessage({ id: "muiClose" })}
  1391. openText={intl.formatMessage({ id: "muiOpen" })}
  1392. noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
  1393. />
  1394. <Autocomplete
  1395. disablePortal
  1396. id="address5-combo"
  1397. value={selectedAddress5}
  1398. options={ComboData.country}
  1399. disabled= {true}
  1400. getOptionLabel={(option) => option.type ? intl.formatMessage({ id: option.type }) : ""}
  1401. onChange={(event, newValue) => {
  1402. if (newValue !== null) {
  1403. setSelectedAddress5(newValue);
  1404. if (newValue.type === 'hongKong') {
  1405. setCheckCountry(false)
  1406. if(formik.values.phone==""){
  1407. formik.values.phoneCountryCode = "852";
  1408. }
  1409. if(formik.values.fax==""){
  1410. formik.values.faxCountryCode = "852";
  1411. }
  1412. } else {
  1413. if (newValue.type === 'mainland'){
  1414. if(formik.values.phone==""){
  1415. formik.values.phoneCountryCode = "86";
  1416. }
  1417. if(formik.values.fax==""){
  1418. formik.values.faxCountryCode = "86";
  1419. }
  1420. }else if(newValue.type === 'macau'){
  1421. if(formik.values.phone==""){
  1422. formik.values.phoneCountryCode = "853";
  1423. }
  1424. if(formik.values.fax==""){
  1425. formik.values.faxCountryCode = "853";
  1426. }
  1427. }
  1428. setSelectedAddress4("");
  1429. setCheckCountry(true)
  1430. }
  1431. } else {
  1432. setSelectedAddress4("");
  1433. setCheckCountry(true)
  1434. }
  1435. }}
  1436. sx={{
  1437. '& .MuiInputBase-root': { alignItems: 'center' },
  1438. '& .MuiAutocomplete-endAdornment': { top: '50%', transform: 'translateY(-50%)' },
  1439. '& .MuiOutlinedInput-root': { height: 40 }
  1440. }}
  1441. renderInput={(params) => <TextField {...params} placeholder={intl.formatMessage({ id: 'regionOrCountry' })} />}
  1442. clearText={intl.formatMessage({ id: "muiClear" })}
  1443. closeText={intl.formatMessage({ id: "muiClose" })}
  1444. openText={intl.formatMessage({ id: "muiOpen" })}
  1445. noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
  1446. />
  1447. {formik.touched.address1 && formik.errors.address1 && (
  1448. <FormHelperText error id="helper-text-address1-signup">
  1449. {formik.errors.address1}
  1450. </FormHelperText>
  1451. )}
  1452. {formik.touched.address2 && formik.errors.address2 && (
  1453. <FormHelperText error id="helper-text-address2-signup">
  1454. {formik.errors.address2}
  1455. </FormHelperText>
  1456. )}
  1457. {formik.touched.address3 && formik.errors.address3 && (
  1458. <FormHelperText error id="helper-text-address3-signup">
  1459. {formik.errors.address3}
  1460. </FormHelperText>
  1461. )}
  1462. {checkDistrict && (
  1463. <FormHelperText error >
  1464. {districtErrStr}
  1465. </FormHelperText>
  1466. )}
  1467. </Stack>
  1468. </Grid>
  1469. <Grid item xs={12} mt={1} mb={1}>
  1470. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1471. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>
  1472. <FormattedMessage id="yourContact" />
  1473. </Typography>
  1474. </Stack>
  1475. </Grid>
  1476. <Grid item xs={12} md={12}>
  1477. <Grid container>
  1478. <Grid item xs={12} md={6}>
  1479. <Stack spacing={1} sx={{ mr: { md: 1 }, mb: 1 }}>
  1480. <InputLabel htmlFor="email-signup">
  1481. <Typography variant="pnspsFormHeader">
  1482. <FormattedMessage id="userContactEmail" />
  1483. <span style={{ color: '#B00020' }}>*</span>
  1484. </Typography>
  1485. </InputLabel>
  1486. <OutlinedInput
  1487. fullWidth
  1488. error={Boolean((formik.touched.email && formik.errors.email) || checkEmail)}
  1489. id="email-signup"
  1490. type="email"
  1491. value={formik.values.email.trim()}
  1492. name="email"
  1493. onChange={formik.handleChange}
  1494. placeholder={intl.formatMessage({ id: 'userContactEmail' })}
  1495. onBlur={formik.handleBlur}
  1496. inputProps={{
  1497. "aria-label": intl.formatMessage({ id: "userContactEmail" }),
  1498. "aria-describedby": "helper-text-email-signup",
  1499. onKeyDown: (e) => {
  1500. if (e.key === 'Enter') {
  1501. e.preventDefault();
  1502. }
  1503. },
  1504. }}
  1505. />
  1506. {formik.touched.email && formik.errors.email && (
  1507. <FormHelperText error id="helper-text-email-signup">
  1508. {formik.errors.email}
  1509. </FormHelperText>
  1510. )}
  1511. {checkEmail && (
  1512. <FormHelperText error id="helper-text-email-signup">
  1513. <FormattedMessage id="emailUsed" />
  1514. </FormHelperText>
  1515. )}
  1516. </Stack>
  1517. </Grid>
  1518. <Grid item xs={12} md={6}>
  1519. <Stack spacing={1} >
  1520. <InputLabel htmlFor="emailConfirm-signup">
  1521. <Typography variant="pnspsFormHeader">
  1522. <FormattedMessage id="confirmEmail" />
  1523. <span style={{ color: '#B00020' }}>*</span>
  1524. </Typography>
  1525. </InputLabel>
  1526. <OutlinedInput
  1527. fullWidth
  1528. error={Boolean(formik.touched.emailConfirm && formik.errors.emailConfirm)}
  1529. id="emailConfirm-signup"
  1530. type="email"
  1531. value={formik.values.emailConfirm.trim()}
  1532. name="emailConfirm"
  1533. // onBlur={formik.handleBlur}
  1534. onChange={formik.handleChange}
  1535. placeholder={intl.formatMessage({ id: 'confirmEmail' })}
  1536. onBlur={formik.handleBlur}
  1537. onCut={handleCCPChange}
  1538. onCopy={handleCCPChange}
  1539. onPaste={handleCCPChange}
  1540. inputProps={{
  1541. "aria-label": intl.formatMessage({ id: "confirmEmail" }),
  1542. "aria-describedby": "helper-text-emailConfirm-signup",
  1543. onKeyDown: (e) => {
  1544. if (e.key === 'Enter') {
  1545. e.preventDefault();
  1546. }
  1547. },
  1548. }}
  1549. />
  1550. {formik.touched.emailConfirm && formik.errors.emailConfirm && (
  1551. <FormHelperText error id="helper-text-emailConfirm-signup">
  1552. {formik.errors.emailConfirm}
  1553. </FormHelperText>
  1554. )}
  1555. </Stack>
  1556. </Grid>
  1557. </Grid>
  1558. </Grid>
  1559. <Grid item xs={12} md={12}>
  1560. <Grid container>
  1561. <Grid item xs={12} md={6}>
  1562. <Grid container>
  1563. <Grid item xs={12} md={12}>
  1564. <Stack direction="column" spacing={1} sx={{ mr: { md: 1 }, mb: 1 }}>
  1565. <InputLabel htmlFor="phone-signup">
  1566. <Typography variant="pnspsFormHeader">
  1567. <FormattedMessage id="userContactNumber" />
  1568. <span style={{ color: '#B00020' }}>*</span>
  1569. </Typography>
  1570. </InputLabel>
  1571. <Stack direction="row">
  1572. <OutlinedInput
  1573. id="phoneCountryCode-signup"
  1574. type="phoneCountryCode"
  1575. value={formik.values.phoneCountryCode.trim()}
  1576. name="phoneCountryCode"
  1577. // onBlur={formik.handleBlur}
  1578. // onChange={formik.handleChange}
  1579. onChange={(event) => {
  1580. const value = event.target.value;
  1581. if (value.match(/[^0-9]/)) {
  1582. return event.preventDefault();
  1583. }
  1584. formik.setFieldValue("phoneCountryCode", value);
  1585. }}
  1586. placeholder={intl.formatMessage({ id: 'dialingCode' })}
  1587. error={Boolean(formik.touched.phone && formik.errors.phone)}
  1588. onBlur={formik.handleBlur}
  1589. endAdornment={<InputAdornment position="end">-</InputAdornment>}
  1590. inputProps={{
  1591. "aria-label": intl.formatMessage({ id: "dialingCode" }),
  1592. maxLength: 3,
  1593. onKeyDown: (e) => {
  1594. if (e.key === 'Enter') {
  1595. e.preventDefault();
  1596. }
  1597. },
  1598. }}
  1599. sx={{ width: '33%', mr: 1 }}
  1600. />
  1601. <OutlinedInput
  1602. id="phone-signup"
  1603. type="phone"
  1604. value={formik.values.phone.trim()}
  1605. name="phone"
  1606. // onBlur={formik.handleBlur}
  1607. // onChange={formik.handleChange}
  1608. onChange={(event) => {
  1609. const value = event.target.value;
  1610. if (value.match(/[^0-9]/)) {
  1611. return event.preventDefault();
  1612. }
  1613. formik.setFieldValue("phone", value);
  1614. }}
  1615. placeholder={intl.formatMessage({ id: 'userContactNumber' })}
  1616. error={Boolean(formik.touched.phone && formik.errors.phone)}
  1617. onBlur={formik.handleBlur}
  1618. inputProps={{
  1619. "aria-label": intl.formatMessage({ id: "userContactNumber" }),
  1620. "aria-describedby": 'helper-text-phone-signup',
  1621. maxLength: 11,
  1622. onKeyDown: (e) => {
  1623. if (e.key === 'Enter') {
  1624. e.preventDefault();
  1625. }
  1626. },
  1627. }}
  1628. sx={{ width: '66%' }}
  1629. />
  1630. </Stack>
  1631. {formik.touched.phone && formik.errors.phone && (
  1632. <FormHelperText error id="helper-text-phone-signup">
  1633. {formik.errors.phone}
  1634. </FormHelperText>
  1635. )}
  1636. </Stack>
  1637. </Grid>
  1638. </Grid>
  1639. </Grid>
  1640. <Grid item xs={12} md={6}>
  1641. <Grid container>
  1642. <Grid item xs={12} md={12}>
  1643. <Stack spacing={1} direction="column">
  1644. <InputLabel htmlFor="fax-signup">
  1645. <Typography variant="pnspsFormHeader">
  1646. <FormattedMessage id="userFaxNumber" />
  1647. </Typography>
  1648. </InputLabel>
  1649. <Stack direction="row">
  1650. <OutlinedInput
  1651. error={Boolean(formik.touched.fax && formik.errors.fax)}
  1652. id="faxCountryCode-signup"
  1653. type="faxCountryCode"
  1654. value={formik.values.faxCountryCode.trim()}
  1655. name="faxCountryCode"
  1656. // onChange={formik.handleChange}
  1657. onChange={(event) => {
  1658. const value = event.target.value;
  1659. if (value.match(/[^0-9]/)) {
  1660. return event.preventDefault();
  1661. }
  1662. formik.setFieldValue("faxCountryCode", value);
  1663. }}
  1664. placeholder={intl.formatMessage({ id: 'dialingCode' })}
  1665. onBlur={formik.handleBlur}
  1666. endAdornment={<InputAdornment position="end">-</InputAdornment>}
  1667. inputProps={{
  1668. "aria-label": intl.formatMessage({ id: "faxCountryCode" }),
  1669. maxLength: 3,
  1670. onKeyDown: (e) => {
  1671. if (e.key === 'Enter') {
  1672. e.preventDefault();
  1673. }
  1674. },
  1675. }}
  1676. sx={{ width: '33%', mr: 1 }}
  1677. />
  1678. <OutlinedInput
  1679. id="fax-signup"
  1680. type="fax"
  1681. value={formik.values.fax.trim()}
  1682. name="fax"
  1683. onBlur={formik.handleBlur}
  1684. // onChange={formik.handleChange}
  1685. onChange={(event) => {
  1686. const value = event.target.value;
  1687. if (value.match(/[^0-9]/)) {
  1688. return event.preventDefault();
  1689. }
  1690. formik.setFieldValue("fax", value);
  1691. }}
  1692. placeholder={intl.formatMessage({ id: 'userFaxNumber' })}
  1693. inputProps={{
  1694. "aria-label": intl.formatMessage({ id: "userFaxNumber" }),
  1695. maxLength: 8,
  1696. onKeyDown: (e) => {
  1697. if (e.key === 'Enter') {
  1698. e.preventDefault();
  1699. }
  1700. },
  1701. }}
  1702. sx={{ width: '66%' }}
  1703. />
  1704. </Stack>
  1705. </Stack>
  1706. </Grid>
  1707. </Grid>
  1708. </Grid>
  1709. </Grid>
  1710. </Grid>
  1711. <Grid item xs={12} md={12} mt={1} mb={1}>
  1712. <Grid container>
  1713. <Grid item xs={12} md={12}>
  1714. <Stack spacing={1} direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1715. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>
  1716. <FormattedMessage id="userIdDoc" />
  1717. <span style={{ color: '#B00020' }}>*</span></Typography>
  1718. <Typography display="inline" variant="subtitle1" sx={{ color: 'primary.primary' }}>
  1719. <FormattedMessage id="pleaseUploadIdDoc" />
  1720. </Typography>
  1721. <Typography display="inline" variant="subtitle1" sx={{ color: 'primary.primary' }}>
  1722. <FormattedMessage id="pleaseUploadIdDocSubTitle" />
  1723. </Typography>
  1724. <Stack mt={1} direction="row" justifyContent="flex-start" alignItems="center" spacing={2}>
  1725. <ThemeProvider theme={PNSPS_LONG_BUTTON_THEME}>
  1726. <Button
  1727. variant="contained"
  1728. sx={{ height: '40px' }}
  1729. type="button"
  1730. onClick={() => {
  1731. if (fileInputRef.current) {
  1732. fileInputRef.current.click();
  1733. }
  1734. }}
  1735. onKeyDown={(event) => {
  1736. if (event.key === 'Enter' || event.key === ' ') {
  1737. event.preventDefault();
  1738. if (fileInputRef.current) {
  1739. fileInputRef.current.click();
  1740. }
  1741. }
  1742. }}
  1743. >
  1744. <FormattedMessage id="uploadIdDoc" />
  1745. </Button>
  1746. <input
  1747. accept="image/png, .jpg, .bmp, .pdf"
  1748. //className={classes.input}
  1749. id="contained-button-file"
  1750. multiple
  1751. type="file"
  1752. onChange={handleFileUpload}
  1753. ref={fileInputRef}
  1754. style={{ display: 'none' }}
  1755. />
  1756. </ThemeProvider>
  1757. {/*<Typography xs={12} sm={9} md={3} display="inline" variant="subtitle1" sx={{ color: 'primary.primary' }}>如: 香港身份證; 護照; 中國內地身份證等</Typography>*/}
  1758. </Stack>
  1759. {fileList != null ?
  1760. <UploadFileTable key="uploadTable" recordList={fileListData} setUpdateRows={setUpdateRows} /> : null}
  1761. {/* <Stack mt={1} direction="row" justifyContent="flex-start" alignItems="center" spacing={2}>
  1762. <Button variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button>
  1763. <Button disabled={!formik.isValid} variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button>
  1764. </Stack> */}
  1765. </Stack>
  1766. </Grid>
  1767. </Grid>
  1768. </Grid>
  1769. </Grid>
  1770. <Grid item xs={12} md={12}>
  1771. <Grid container>
  1772. <Grid item xs={12} md={12}>
  1773. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>
  1774. <FormattedMessage id="termsAndCondition" />
  1775. <span style={{ color: '#B00020' }}>*</span>
  1776. </Typography>
  1777. </Grid>
  1778. <Grid item xs={12} md={12}>
  1779. <Grid container>
  1780. <Grid item xs={12} md={12}>
  1781. <Typography variant="h6" height="100%" sx={{ textAlign: "left", /*overflow: "scroll",*/ borderRadius: "inherit", borderStyle: "solid", borderWidth: "1px", borderColor: "#0C489E" }}>
  1782. <div style={{padding: 12}} dangerouslySetInnerHTML={{__html: intl.formatMessage({id: "termsAndCon"})}} />
  1783. </Typography>
  1784. </Grid>
  1785. </Grid>
  1786. <Grid item xs={12} s={12} md={12} lg={12}>
  1787. <Grid container>
  1788. <Grid item xs={6} sm={6} md={11} lg={11}>
  1789. <Grid container>
  1790. <Grid item sx={{ display: 'flex', alignItems: 'center' }}>
  1791. <Checkbox
  1792. checked={termsAndConAccept}
  1793. onChange={handleCheckBoxChange}
  1794. name="termsAndConAccept"
  1795. color="primary"
  1796. size="small"
  1797. inputProps={{
  1798. "aria-label": intl.formatMessage({ id: "iConfirm" })
  1799. }}
  1800. />
  1801. <Typography variant="pnspsFormHeader">
  1802. <FormattedMessage id="iConfirm" />
  1803. </Typography>
  1804. </Grid>
  1805. </Grid>
  1806. </Grid>
  1807. <Grid item xs={6} s={6} md={3} lg={3}>
  1808. <Grid container style={{ display: "none" }}>
  1809. <Grid item sx={{ display: 'flex', alignItems: 'center' }}>
  1810. <Checkbox
  1811. checked={termsAndConNotAccept}
  1812. onChange={handleCheckBoxChange}
  1813. name="termsAndConNotAccept"
  1814. color="primary"
  1815. size="small"
  1816. inputProps={{
  1817. "aria-label": intl.formatMessage({ id: "rejectTerms" })
  1818. }}
  1819. />
  1820. <Typography variant="pnspsFormHeader">
  1821. <FormattedMessage id="rejectTerms" />
  1822. </Typography>
  1823. </Grid>
  1824. </Grid>
  1825. </Grid>
  1826. </Grid>
  1827. </Grid>
  1828. </Grid>
  1829. </Grid>
  1830. </Grid>
  1831. <Grid item xs={12} lg={12}>
  1832. <Grid container>
  1833. <Stack direction="column">
  1834. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>
  1835. <FormattedMessage id="verify" />
  1836. <span style={{ color: '#B00020' }}>*</span>
  1837. </Typography>
  1838. <Stack spacing={1} direction="row">
  1839. <Grid item xs={5} lg={5} style={{ "border": "1px solid black" }}>
  1840. <img src={captchaImg} alt="" />
  1841. </Grid>
  1842. <Grid item xs={1} lg={1} style={{ "border": "0px solid black" }}>
  1843. <IconButton aria-label={intl.formatMessage({ id: 'ariaRefreshCaptcha' })} size="large" onClick={() => { onCaptchaChange() }}>
  1844. <LoopIcon fontSize="inherit" />
  1845. </IconButton>
  1846. </Grid>
  1847. <Grid item xs={6} lg={6}>
  1848. <OutlinedInput
  1849. fullWidth
  1850. id="captchaField"
  1851. type="text"
  1852. value={formik.values.captchaField.trim()}
  1853. onBlur={formik.handleBlur}
  1854. error={Boolean(formik.touched.captchaField && formik.errors.captchaField)}
  1855. name="captchaField"
  1856. onChange={(event) => {
  1857. const value = event.target.value;
  1858. props.setCheckCode(event.target.value);
  1859. setCheckCode(event.target.value);
  1860. formik.setFieldValue("captchaField", value);
  1861. }}
  1862. sx={{ width: '75%' }}
  1863. inputProps={{
  1864. "aria-label": intl.formatMessage({ id: "verify" }),
  1865. "aria-describedby": 'helper-text-captcha-signup'
  1866. }}
  1867. />
  1868. </Grid>
  1869. </Stack>
  1870. {formik.touched.captchaField && formik.errors.captchaField && (
  1871. <FormHelperText error id="helper-text-captcha-signup">
  1872. {formik.errors.captchaField}
  1873. </FormHelperText>
  1874. )}
  1875. <Stack spacing={1} direction="row" sx={{ mt: 0.25 }}>
  1876. <Button
  1877. variant="contained"
  1878. onClick={playCaptchaAudio}
  1879. aria-label={intl.formatMessage({ id: "captchaPlayAudio" })}
  1880. sx={{
  1881. backgroundColor: '#0C489E',
  1882. color: '#FFFFFF',
  1883. '&:hover': { backgroundColor: '#093A7A' },
  1884. }}
  1885. >
  1886. <FormattedMessage id="captchaPlayAudio" />
  1887. </Button>
  1888. </Stack>
  1889. </Stack>
  1890. </Grid>
  1891. </Grid>
  1892. </Grid>
  1893. </Grid>
  1894. </FormGroup>
  1895. {/* Preview Form */}
  1896. <FormGroup id={"previewForm"} sx={{ display: props.step === 1 ? "" : "none" }}>
  1897. <Grid container spacing={3}>
  1898. <Grid item xs={12} md={12}>
  1899. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1900. <div style={{ borderBottom: "3px solid #1A4399", width: "100%", margin_right: "15px" }}>
  1901. <Typography display="inline" variant="h3" sx={{ color: '#1A4399' }}>
  1902. <FormattedMessage id="becomeNewPersonalUser" />
  1903. </Typography>
  1904. </div>
  1905. {/* <Typography mt={0.25} variant="h6" sx={{ fontSize: 12,color: '#B00020'}}>註有*的項目必須輸入資料</Typography> */}
  1906. <Typography mt={0.25} variant="h4" sx={{ color: 'primary.primary' }}>
  1907. <FormattedMessage id="yourLoginInformation" />
  1908. </Typography>
  1909. {/* <Typography component={Link} to="/login" variant="body1" sx={{ textDecoration: 'none' }} color="primary">
  1910. Already have an account?
  1911. </Typography> */}
  1912. </Stack>
  1913. </Grid>
  1914. <Grid item xs={12} md={12}>
  1915. <Grid container spacing={2}>
  1916. <Grid item xs={12} >
  1917. <Stack spacing={2} direction="row">
  1918. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  1919. <FormattedMessage id="userLoginName" />:
  1920. </Typography>
  1921. <Typography variant="pnspsFormHeader" id="preview-username-login">
  1922. {formik.values.username}
  1923. </Typography>
  1924. </Stack>
  1925. </Grid>
  1926. <Grid item xs={12} mt={1} mb={1}>
  1927. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1928. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>
  1929. <FormattedMessage id="yourPersonalInformation" />
  1930. </Typography>
  1931. {/* <Typography component={Link} to="/login" variant="body1" sx={{ textDecoration: 'none' }} color="primary">
  1932. Already have an account?
  1933. </Typography> */}
  1934. </Stack>
  1935. </Grid>
  1936. {/* <Grid item xs={12} md={12} >
  1937. <Stack spacing={1}>
  1938. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  1939. <FormattedMessage id="userIdDoc" />
  1940. </Typography>
  1941. </Stack>
  1942. </Grid> */}
  1943. <Grid item xs={12} md={6} >
  1944. <Stack spacing={1} direction="row" >
  1945. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  1946. <FormattedMessage id="idDocType" />:
  1947. </Typography>
  1948. <Typography variant="pnspsFormHeader" name="preview-idDocType">
  1949. {selectedIdDocType?.label? intl.formatMessage({ id: selectedIdDocType.label}): " "}
  1950. </Typography>
  1951. </Stack>
  1952. </Grid>
  1953. <Grid item xs={12} md={6}>
  1954. <Stack direction="row" >
  1955. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]} sx={{mr:1}}>
  1956. <FormattedMessage id="idDocNumber" />:
  1957. </Typography>
  1958. <Typography variant="pnspsFormHeader" id="idNo-f4-login">
  1959. {formik.values.idNo.slice(0, 4)}
  1960. </Typography>
  1961. <Typography variant="pnspsFormHeader" id="idNo-exf4-login"
  1962. type={showId ? "text" : "password"}
  1963. >
  1964. {showId ?formik.values.idNo.slice(4):"****"}{showId ?selectedIdDocType.type == "HKID" ? '(' + formik.values.checkDigit + ')' : null:null}
  1965. </Typography>
  1966. <IconButton
  1967. aria-label={intl.formatMessage({ id: 'ariaToggleIdVisibility' })}
  1968. onClick={handleClickShowId}
  1969. onMouseDown={handleMouseDownId}
  1970. edge="end"
  1971. size="medium"
  1972. >
  1973. {showId ? <EyeOutlined /> : <EyeInvisibleOutlined />}
  1974. </IconButton>
  1975. </Stack>
  1976. </Grid>
  1977. <Grid item xs={12} md={6}>
  1978. <Stack spacing={1} direction="row">
  1979. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  1980. <FormattedMessage id="userEnglishName" />:
  1981. </Typography>
  1982. <Typography variant="pnspsFormHeader" id="preview-enName-signup">
  1983. {formik.values.enName}
  1984. </Typography>
  1985. </Stack>
  1986. </Grid>
  1987. <Grid item xs={12} md={6}>
  1988. <Stack spacing={1} direction="row">
  1989. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  1990. <FormattedMessage id="userChineseName" />:
  1991. </Typography>
  1992. <Typography variant="pnspsFormHeader" id="preview-chName-signup">
  1993. {formik.values.chName}
  1994. </Typography>
  1995. </Stack>
  1996. </Grid>
  1997. <Grid item xs={12}>
  1998. <Stack spacing={1} direction="column">
  1999. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  2000. <FormattedMessage id="formAddress" />:
  2001. </Typography>
  2002. <Stack spacing={1} direction="column">
  2003. <Typography variant="pnspsFormHeader" id="preview-address1-signup">
  2004. {formik.values.address1}
  2005. </Typography>
  2006. {formik.values.address2 != null ?
  2007. <Typography variant="pnspsFormHeader" id="preview-address2-signup">
  2008. {formik.values.address2}
  2009. </Typography>
  2010. : null}
  2011. {formik.values.address3 != null ?
  2012. <Typography variant="pnspsFormHeader" id="preview-address3-signup">
  2013. {formik.values.address3}
  2014. </Typography>
  2015. : null}
  2016. {selectedAddress5.type === "hongKong" ?
  2017. <Stack direction="column">
  2018. {/* <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]} id="preview-address4-signup">
  2019. <FormattedMessage id="region" />:
  2020. </Typography> */}
  2021. <Typography variant="pnspsFormHeader">
  2022. {!selectedAddress4 ? "" : intl.formatMessage({ id: selectedAddress4.type })}
  2023. </Typography>
  2024. </Stack>
  2025. : null}
  2026. <Stack direction="column">
  2027. {/* <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]} id="preview-address5-signup">
  2028. <FormattedMessage id="regionOrCountry" />:
  2029. </Typography> */}
  2030. <Typography variant="pnspsFormHeader">
  2031. {intl.formatMessage({ id: selectedAddress5.type })}
  2032. </Typography>
  2033. </Stack>
  2034. </Stack>
  2035. </Stack>
  2036. </Grid>
  2037. <Grid item xs={12} mt={1} mb={1}>
  2038. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  2039. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>
  2040. <FormattedMessage id="yourContact" />
  2041. </Typography>
  2042. </Stack>
  2043. </Grid>
  2044. <Grid item xs={12} md={12}>
  2045. <Stack spacing={1} direction="row">
  2046. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  2047. <FormattedMessage id="userContactEmail" />:
  2048. </Typography>
  2049. <Typography variant="pnspsFormHeader" id="preview-email-signup">
  2050. {formik.values.email}
  2051. </Typography>
  2052. </Stack>
  2053. </Grid>
  2054. <Grid item xs={12} md={6}>
  2055. <Stack spacing={1} direction="row">
  2056. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  2057. <FormattedMessage id="userContactNumber" />:
  2058. </Typography>
  2059. <Typography variant="pnspsFormHeader" id="preview-phone-signup">
  2060. +{formik.values.phoneCountryCode} {formik.values.phone}
  2061. </Typography>
  2062. </Stack>
  2063. </Grid>
  2064. {formik.values.faxCountryCode != "" && formik.values.fax != "" ?
  2065. <Grid item xs={12} md={6}>
  2066. <Stack spacing={1} direction="row">
  2067. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  2068. <FormattedMessage id="userFaxNumber" />:
  2069. </Typography>
  2070. <Typography variant="pnspsFormHeader" id="preview-fax-signup">
  2071. +{formik.values.faxCountryCode} {formik.values.fax}
  2072. </Typography>
  2073. </Stack>
  2074. </Grid>
  2075. : null}
  2076. <Grid item xs={12} md={12} mt={1} mb={1}>
  2077. <Grid container>
  2078. <Grid item xs={12} md={12}>
  2079. <Stack spacing={1} direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  2080. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>
  2081. <FormattedMessage id="userIdDoc" />
  2082. </Typography>
  2083. {fileList != null ?
  2084. <PreviewUploadFileTable key="previewTable" recordList={fileListData} /> : null}
  2085. </Stack>
  2086. </Grid>
  2087. </Grid>
  2088. </Grid>
  2089. </Grid>
  2090. </Grid>
  2091. </Grid>
  2092. </FormGroup>
  2093. {/* Submit page */}
  2094. <FormGroup id={"submitForm"} sx={{ display: props.step === 2 ? "" : "none" }}>
  2095. <Grid container spacing={3}>
  2096. {isLoading ?
  2097. <LoadingComponent /> :
  2098. <Grid item xs={12}>
  2099. {checkUpload ?
  2100. // SUCCESS page
  2101. <Stack mt={1} direction="column" justifyContent="flex-start" alignItems="center" spacing={2}>
  2102. <CheckCircleOutlineIcon color="success" sx={{ width: "200px", height: "200px" }} />
  2103. <Typography display="inline" variant="h4">
  2104. <FormattedMessage id="registerSubmitted" />
  2105. </Typography>
  2106. <Typography display="inline" variant="h4">
  2107. <FormattedMessage id="emailSent" />
  2108. </Typography>
  2109. <Button variant="outlined" component={Link} to="/login" ><Typography variant="pnspsFormHeader">
  2110. <FormattedMessage id="backToLogin" />
  2111. </Typography></Button>
  2112. </Stack>
  2113. :
  2114. // ERROR page
  2115. <Stack mt={1} direction="column" justifyContent="flex-start" alignItems="center" spacing={2}>
  2116. {/* <Button disabled={true} hidden={true} variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button> */}
  2117. <CancelOutlinedIcon color="error" sx={{ width: "200px", height: "200px" }} />
  2118. <Typography display="inline" variant="h4">
  2119. <FormattedMessage id="registerFail" />
  2120. </Typography>
  2121. <Button color="error" variant="outlined" component={Link} to="/login" ><Typography variant="pnspsFormHeader">
  2122. <FormattedMessage id="backToLogin" />
  2123. </Typography></Button>
  2124. </Stack>
  2125. }
  2126. </Grid>
  2127. }
  2128. </Grid>
  2129. </FormGroup>
  2130. </form>
  2131. </FormikProvider>
  2132. );
  2133. }
  2134. export default CustomFormWizard;