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.
 
 

1545 lines
93 KiB

  1. import { useEffect, useState, } from 'react';
  2. // material-ui
  3. import {
  4. Box,
  5. Button,
  6. FormControl,
  7. FormHelperText,
  8. Grid, IconButton,
  9. InputAdornment,
  10. InputLabel, OutlinedInput,
  11. Stack,
  12. Typography,
  13. FormGroup,
  14. TextField,
  15. Checkbox
  16. // MenuItem
  17. } from '@mui/material';
  18. import {useForm,} from 'react-hook-form'
  19. import Autocomplete from "@mui/material/Autocomplete";
  20. // third party
  21. import { useFormik,FormikProvider } from 'formik';
  22. import * as yup from 'yup';
  23. // import axios from "axios";
  24. // project import
  25. // import AnimateButton from 'components/@extended/AnimateButton';
  26. import { strengthColorChi, strengthIndicator } from 'utils/password-strength';
  27. // import {apiPath} from "auth/utils";
  28. import axios from "axios";
  29. import {POST_PUBLIC_USER_REGISTER,POST_CAPTCHA, GET_USERNAME} from "utils/ApiPathConst";
  30. // import * as HttpUtils from 'utils/HttpUtils';
  31. import * as ComboData from "utils/ComboData";
  32. import Loadable from 'components/Loadable';
  33. import { lazy } from 'react';
  34. const UploadFileTable = Loadable(lazy(() => import('./UploadFileTable')));
  35. const PreviewUploadFileTable = Loadable(lazy(() => import('./PreviewUploadFileTable')));
  36. const LoadingComponent = Loadable(lazy(() => import('../../extra-pages/LoadingComponent')));
  37. // import UploadFileTable from './UploadFileTable';
  38. // import LoadingComponent from "../../extra-pages/LoadingComponent";
  39. // assets
  40. import { EyeInvisibleOutlined, EyeOutlined } from '@ant-design/icons';
  41. // import { Paper } from '../../../../node_modules/@mui/material/index';
  42. import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
  43. import CancelOutlinedIcon from '@mui/icons-material/CancelOutlined';
  44. import { Link } from 'react-router-dom';
  45. import * as HttpUtils from "../../../utils/HttpUtils";
  46. import LoopIcon from '@mui/icons-material/Loop';
  47. // ============================|| FIREBASE - REGISTER ||============================ //
  48. const CustomFormWizard = (props) => {
  49. const [level, setLevel] = useState();
  50. const [showPassword, setShowPassword] = useState(false);
  51. const [showConfirmPassword, setshowConfirmPassword] = useState(false);
  52. const [fileList, setFileList] = useState([]);
  53. const [fileListData, setFileListData] = useState([]);
  54. const [checkUpload, setCheckUpload] = useState(false);
  55. const [isLoading, setLoding] = useState(true);
  56. const [updateRows, setUpdateRows] = useState([]);
  57. const [userNameList, setUserNameList] = useState();
  58. const [captcha, setCaptcha] = useState([]);
  59. const [captchaImg, setCaptchaImage] = useState([]);
  60. const handleClickShowPassword = () => {
  61. setShowPassword(!showPassword);
  62. };
  63. const handleClickShowConfirmPassword = () => {
  64. setshowConfirmPassword(!showConfirmPassword);
  65. };
  66. const handleMouseDownPassword = (event) => {
  67. event.preventDefault();
  68. };
  69. const changePassword = (value) => {
  70. const temp = strengthIndicator(value);
  71. setLevel(strengthColorChi(temp));
  72. };
  73. const [selectedIdDocType, setSelectedIdDocType] = useState({});
  74. const [selectedIdDocInputType, setSelectedIdDocInputType] = useState("");
  75. // const [selectedIdDocLabel, setSelectedIdDocLabel] = useState(null);
  76. const [selectedAddress4, setSelectedAddress4] = useState(null);
  77. const [selectedAddress5, setSelectedAddress5] = useState(ComboData.country[0]);
  78. const [termsAndConAccept, setTermsAndConAccept] = useState(false);
  79. const [termsAndConNotAccept, setTermsAndConNotAccept] = useState(false);
  80. const [isValid, setisValid] = useState(false);
  81. const [checkCountry, setCheckCountry] = useState(false);
  82. const idDocTypeComboList = ComboData.idDocType;
  83. const address4ComboList = ComboData.district;
  84. const address5ComboList = ComboData.country;
  85. const termsAndCon = "此網址由香港特別行政區政府物流服務署製作及管理。本署會盡力確保網址上的資料無誤,\n"
  86. + "但有絕對酌情權隨時刪除、暫停登載或編輯各項資料而無須給予任何理由。\n由於任何與網址"
  87. + "內資料有關的理由或原因,而導致出現申索、損失或損害,本署概不負責。\n使用者須自行評"
  88. + "估本網址所載或與本網址有關連的各項資料,並應在根據該等資料行事前,參照印行的香港"
  89. + "特別行政區憲報以核實該等資料,以及徵詢獨立意見。\n版權公告本網頁的內容,包括但不限"
  90. + "於所有文本、平面圖像、圖畫、圖片、照片以及數據或其他資料的匯編,均受版權保障。\n香"
  91. + "港特別行政區政府是本網頁內所有版權作品的擁有人,除非預先得到政府物流服務署的書面"
  92. + "授權,否則嚴禁複製、改編、分發、發布或向公眾提供該等版權作品。"
  93. const refType = "identification";
  94. useEffect(() => {
  95. changePassword('');
  96. onCaptchaChange();
  97. axios.get(`${GET_USERNAME}`)
  98. .then((response) => {
  99. if (response.status === 200) {
  100. setUserNameList(response.data);
  101. }
  102. })
  103. .catch(error => {
  104. console.log(error);
  105. return false;
  106. });
  107. }, []);
  108. const onCaptchaChange = ()=>{
  109. HttpUtils.post({
  110. url: POST_CAPTCHA,
  111. params:{width: 130, height: 40},
  112. onSuccess:(responseData)=>{
  113. localStorage.setItem("checkCode",responseData.checkCode);
  114. localStorage.setItem("base64Url",responseData.base64Url);
  115. setCaptcha(localStorage.getItem('checkCode'));
  116. setCaptchaImage(localStorage.getItem('base64Url'));
  117. }
  118. });
  119. }
  120. const checkDataField = (data)=> {
  121. if (data.username !==""&&
  122. data.password !==""&&
  123. data.confirmPassword !==""&&
  124. data.password == data.confirmPassword&&
  125. selectedIdDocType.type !==""&&
  126. data.idNo !==""&&
  127. (data.enName !=="" || selectedIdDocType.type === "CNID")&&
  128. data.chName !==""&&
  129. data.address1 !==""&&
  130. data.email !==""&&
  131. data.emailConfirm !==""&&
  132. data.email == data.emailConfirm&&
  133. data.phone !==""&&
  134. data.phoneCountryCode !==""&&
  135. termsAndConAccept == true&&
  136. fileList.length!==0&&
  137. data.captchaField&&
  138. handlePassword(data.password)&&
  139. handleEmail(data.email)&&
  140. handleIdNo(data.idNo,selectedIdDocType.type,data.checkDigit)&&
  141. handlePhone(data.phone)&&
  142. handleUsername(data.username)&&
  143. handleCaptcha(data.captchaField)
  144. )
  145. {
  146. setisValid(true)
  147. return isValid
  148. }else{
  149. setisValid(false)
  150. return isValid
  151. }
  152. };
  153. const handleCheckBoxChange = (event) => {
  154. if(event.target.name == 'termsAndConAccept'){
  155. setTermsAndConAccept(event.target.checked)
  156. setTermsAndConNotAccept(!event.target.checked)
  157. }
  158. if(event.target.name == 'termsAndConNotAccept'){
  159. setTermsAndConNotAccept(event.target.checked)
  160. setTermsAndConAccept(!event.target.checked)
  161. }
  162. };
  163. useEffect(() => {
  164. let updateRowList = new DataTransfer();
  165. var updateRowsIndex = updateRows.length;
  166. const saveFileList = [];
  167. if (updateRowsIndex!=null){
  168. for (let i = 0; i < updateRowsIndex; i++){
  169. const file = updateRows[i]
  170. file.id = i;
  171. updateRowList.items.add(file);
  172. saveFileList.push(file);
  173. }
  174. let updatedFileList = updateRowList.files;
  175. setFileList(updatedFileList);
  176. setFileListData(saveFileList)
  177. }
  178. }, [updateRows]);
  179. const handleFileUpload = (event)=>{
  180. let updateList = new DataTransfer();
  181. let currentFileList = fileListData;
  182. const uploadFileList = event.target.files;
  183. const saveFileList = [];
  184. var currentIndex = 0;
  185. if (currentFileList.length!=null){
  186. currentIndex = currentFileList.length;
  187. for (let i = 0; i < currentIndex; i++){
  188. const file = currentFileList[i]
  189. // file.id = currentIndex;
  190. updateList.items.add(file);
  191. saveFileList.push(file);
  192. }
  193. }
  194. for (let i = 0; i < uploadFileList.length && currentIndex<5; i++){
  195. const file = event.target.files[i]
  196. let isDuplicate = false;
  197. // Check if the file name already exists in saveFileList
  198. for (let j = 0; j < saveFileList.length; j++) {
  199. if (saveFileList[j].name === file.name) {
  200. isDuplicate = true;
  201. break;
  202. }
  203. }
  204. if (!isDuplicate && i+currentIndex<5) {
  205. file.id = currentIndex+i
  206. saveFileList.push(file)
  207. updateList.items.add(file);
  208. }
  209. }
  210. let updatedFileList = updateList.files;
  211. setFileListData(saveFileList)
  212. setFileList(updatedFileList);
  213. };
  214. useEffect(() => {
  215. props.setUpdateValid(isValid)
  216. }, [isValid])
  217. useEffect(() => {
  218. checkDataField(values)
  219. }, [
  220. selectedIdDocType,
  221. selectedAddress4,selectedAddress5,
  222. termsAndConAccept,termsAndConNotAccept,fileList])
  223. useEffect(() => {
  224. props.step ==2?_onSubmit():null;
  225. onCaptchaChange();
  226. checkDataField(values)
  227. }, [props.step])
  228. const {handleSubmit} = useForm({})
  229. const _onSubmit = () => {
  230. setLoding(true);
  231. values.idDocType = selectedIdDocType.type
  232. values.address4 = selectedAddress4
  233. values.address5 = selectedAddress5
  234. const userAddress = {
  235. "addressLine1":"",
  236. "addressLine2":"",
  237. "addressLine3":"",
  238. "district":"",
  239. "country":""
  240. };
  241. userAddress.addressLine1 = values.address1
  242. userAddress.addressLine2 = values.address2
  243. userAddress.addressLine3 = values.address3
  244. userAddress.district = values.address4
  245. userAddress.country = values.address5
  246. const userFaxNo = {
  247. "countryCode":values.faxCountryCode,
  248. "faxNumber":values.fax,
  249. };
  250. const userMobileNumber = {
  251. "countryCode":values.phoneCountryCode,
  252. "phoneNumber":values.phone,
  253. };
  254. let tncFlag = false;
  255. if (termsAndConAccept){
  256. tncFlag = true
  257. }
  258. if (termsAndConNotAccept){
  259. tncFlag = false
  260. }
  261. const user = {
  262. username: values.username,
  263. password: values.password,
  264. name: values.username,
  265. enName: values.enName,
  266. chName: values.chName,
  267. emailAddress: values.email,
  268. idDocType:values.idDocType,
  269. identification:values.idNo,
  270. checkDigit:values.checkDigit,
  271. tncFlag:tncFlag,
  272. type:"IND",
  273. };
  274. var formData = new FormData();
  275. for (let i = 0; i < fileListData.length; i++){
  276. const file = fileListData[i]
  277. formData.append("multipartFileList", file);
  278. }
  279. formData.append("refType", refType);
  280. for (const [key, value] of Object.entries(user)) {
  281. formData.append(key, value);
  282. }
  283. formData.append("userFaxNo", JSON.stringify(userFaxNo));
  284. formData.append("userMobileNumber", JSON.stringify(userMobileNumber));
  285. formData.append("userAddress", JSON.stringify(userAddress));
  286. // if(refCode){
  287. // formData.append("refCode", refCode);
  288. // }
  289. if (isValid){
  290. axios.post(POST_PUBLIC_USER_REGISTER, formData,{
  291. headers: {
  292. "Content-Type":"multipart/form-data"
  293. }
  294. })
  295. .then((response) => {
  296. console.log(response)
  297. setCheckUpload(true)
  298. setLoding(false);
  299. })
  300. .catch(error => {
  301. console.error(error);
  302. setLoding(false);
  303. });
  304. }else{
  305. setLoding(false);
  306. }
  307. }
  308. function handlePhone(phone) {
  309. if (phone.length < 8) {
  310. return false;
  311. } else {
  312. // console.log("Phone true")
  313. return true;
  314. }
  315. }
  316. function handleUsername(username) {
  317. var symbol = /^(?=.*[!@#%&])/;
  318. var space = /\s/;
  319. if (username.length < 6) {
  320. return false;
  321. } else if (username.match(symbol)) {
  322. return false;
  323. }else if (username.match(space)) {
  324. return false;
  325. } else {
  326. return true;
  327. }
  328. }
  329. function handleCaptcha(captchaField) {
  330. return captchaField == captcha;
  331. }
  332. function handleIdNo(idNo,selectedIdDocType,checkDigit) {
  333. var pattern = /^[A-Z][0-9]*$/;
  334. var space = /\s/;
  335. if (!idNo.match(pattern)) {
  336. return false;
  337. }else if
  338. (selectedIdDocType=="HKID"&&checkDigit==""){
  339. return false;
  340. }
  341. else if (idNo.match(space)) {
  342. return false;
  343. }else if (idNo.length < 7) {
  344. return false;
  345. } else {
  346. // console.log("IdNo true")
  347. return true;
  348. }
  349. }
  350. function handlePassword(password) {
  351. let new_pass = password;
  352. // regular expressions to validate password
  353. var lowerCase = /[a-z]/g;
  354. var upperCase = /[A-Z]/g;
  355. var numbers = /[0-9]/g;
  356. var symbol = /^(?=.*[!@#%&])/;
  357. var space = /\s/;
  358. if (!new_pass.match(lowerCase)) {
  359. return false;
  360. } else if (!new_pass.match(upperCase)) {
  361. return false;
  362. } else if (!new_pass.match(numbers)) {
  363. return false;
  364. } else if (!new_pass.match(symbol)) {
  365. return false;
  366. } else if (new_pass.length < 8) {
  367. return false;
  368. }
  369. else if (new_pass.match(space)) {
  370. return false;
  371. }else {
  372. // console.log("password true")
  373. return true;
  374. }
  375. }
  376. function handleEmail(email) {
  377. var validRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
  378. if (!email.match(validRegex)) {
  379. return false;
  380. }else{
  381. return true;
  382. }
  383. }
  384. const formik = useFormik({
  385. initialValues:({
  386. username:'',
  387. enName: '',
  388. chName: '',
  389. email: '',
  390. emailConfirm: '',
  391. address1: '',
  392. address2: '',
  393. address3: '',
  394. password: '',
  395. confirmPassword: '',
  396. phone:'',
  397. phoneCountryCode:'852',
  398. idNo:'',
  399. checkDigit:'',
  400. submit: null,
  401. fax:'',
  402. faxCountryCode:'852',
  403. idDocType:'',
  404. captchaField:''
  405. }),
  406. validationSchema:yup.object().shape({
  407. username: yup.string().min(6,'用戶名稱最少6位').required('請輸入用戶名稱').test(
  408. "checkUserNameUsed",
  409. "此用戶登入名稱已被注冊,請使用其他用戶登入名稱",
  410. function(value) {
  411. if (userNameList.some(item => item.username === value)) {
  412. return false
  413. } else {
  414. return true
  415. }
  416. }
  417. )
  418. .matches(/^[aA-zZ0-9\s]+$/, "用戶名稱不包含特殊字符")
  419. .matches(/^\S*$/, '用戶名稱不包含空格'),
  420. password: yup.string().min(8,'請輸入最少8位密碼').required('請輸入密碼')
  421. .matches(/^\S*$/, '密碼不包含空格')
  422. .matches(/^(?=.*[a-z])/, '請包括最少1個小寫字母')
  423. .matches(/^(?=.*[A-Z])/, '請包括最少1個大寫字母')
  424. .matches(/^(?=.*[0-9])/, '請包括最少1個數字')
  425. .matches(/^(?=.*[!@#%&])/, '請包括最少1個特殊字符'),
  426. confirmPassword: yup.string().min(8,'請最少輸入8位密碼').required('請確認密碼').oneOf([yup.ref('password'), null], '請輸入相同密碼'),
  427. enName: yup.string().max(255).required('請輸入英文姓名'),
  428. chName: yup.string().max(6).required('請輸入中文姓名'),
  429. address1: yup.string().max(255).required('請輸入第一行地址'),
  430. address2: yup.string().max(255).required('請輸入第二行地址'),
  431. address3: yup.string().max(255).required('請輸入第三行地址'),
  432. email: yup.string().email('請輸入電郵格式').max(255).required('請輸入電郵'),
  433. emailConfirm: yup.string().email('請輸入電郵格式').max(255).required('請輸入電郵').oneOf([yup.ref('email'), null], '請輸入相同電郵'),
  434. idNo: yup.string().required('請輸入證件號碼')
  435. .matches(/^[aA-zZ0-9\s]+$/, "證件號碼不包含特殊字符")
  436. .matches(/^\S*$/, '證件號碼不包含空格')
  437. .test('checkIDCardFormat', '請輸入香港身份證號碼', function(value) {
  438. const idDocType = selectedIdDocType.type;
  439. var pattern = /^[A-Z][0-9]*$/;
  440. if(value!==undefined){
  441. if (!value.match(pattern)&&idDocType=="HKID"&&value.length<7) {
  442. return false
  443. } else {
  444. return true
  445. }
  446. }
  447. }),
  448. checkDigit:yup.string().max(1).required('請輸入括號內的數字或字母'),
  449. idDocType: yup.string().max(255).required('請輸入證件類別'),
  450. phoneCountryCode: yup.string().min(2,'請輸入最少2位數字').required('請輸入國際區號'),
  451. // faxCountryCode: yup.string().min(3,'請輸入3位數字'),
  452. phone: yup.string().min(8,'請輸入最少8位數字').required('請輸入聯絡電話'),
  453. // fax: yup.string().min(8,'請輸入8位數字'),
  454. captchaField: yup.string().required('請輸入驗證').oneOf([captcha], '請輸入有效驗證'),
  455. }),
  456. });
  457. const handleReset = (resetForm) => {
  458. resetForm();
  459. setSelectedAddress4("")
  460. setSelectedAddress5(ComboData.country[0])
  461. setCheckCountry(false)
  462. setSelectedIdDocType({})
  463. setSelectedIdDocInputType("");
  464. setFileList([])
  465. setFileListData([])
  466. onCaptchaChange()
  467. // setSelectedIdDocLabel("")
  468. };
  469. const { values } = formik
  470. useEffect(() => {
  471. checkDataField(values)
  472. }, [values])
  473. return (
  474. <FormikProvider value={formik}>
  475. <form onSubmit={handleSubmit(_onSubmit)}>
  476. {/* Input Form */}
  477. <FormGroup id={"inputForm"} sx={{ display: props.step === 0 ? "" : "none" }}>
  478. <Grid container spacing={3}>
  479. <Grid item xs={12} md={12}>
  480. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  481. <Button variant="outlined" type="reset" onClick={handleReset.bind(null, formik.resetForm)} sx={{ fontSize: 16,height:'30px'}}>重置</Button>
  482. <div style={{borderBottom: "3px solid #1A4399", width:"100%", margin_right: "15px"}}>
  483. <Typography display="inline" variant="h3" sx={{ color: '#1A4399'}}>成為新的個人用戶</Typography>
  484. </div>
  485. <Typography mt={0.25} variant="h6" sx={{ fontSize: 12,color: '#f10000'}}>註有*的項目必須輸入資料</Typography>
  486. <Typography mt={0.25} variant="h4" sx={{ color: 'primary.primary'}}>你的登入資料</Typography>
  487. </Stack>
  488. </Grid>
  489. <Grid item xs={12} md={12}>
  490. <Grid container spacing={1}>
  491. <Grid item xs={12} md={12} >
  492. <Stack spacing={1}>
  493. <InputLabel htmlFor="username-signup">用戶登入名稱
  494. <span style={{color: '#f10000'}}>*</span>
  495. </InputLabel>
  496. <OutlinedInput
  497. id="username-login"
  498. type="text"
  499. value={formik.values.username.trim()}
  500. name="username"
  501. onChange={formik.handleChange}
  502. placeholder="用戶登入名稱"
  503. fullWidth
  504. error={Boolean(formik.touched.username && formik.errors.username)}
  505. onBlur={formik.handleBlur}
  506. inputProps={{
  507. onKeyDown: (e) => {
  508. if (e.key === 'Enter') {
  509. e.preventDefault();
  510. }
  511. },
  512. }}
  513. />
  514. {formik.touched.username && formik.errors.username && (
  515. <FormHelperText error id="helper-text-username-signup">
  516. {formik.errors.username}
  517. </FormHelperText>
  518. )}
  519. </Stack>
  520. </Grid>
  521. <Grid item xs={12} md={12}>
  522. <Grid container>
  523. <Grid item xs={12} md={6} >
  524. <Stack spacing={1} sx={{mr:{md:1},mb:1}}>
  525. <Stack direction="row" justifyContent="space-between">
  526. <InputLabel htmlFor="password-signup">密碼
  527. <span style={{color: '#f10000'}}>*</span>
  528. </InputLabel>
  529. </Stack>
  530. <OutlinedInput
  531. fullWidth
  532. error={Boolean(formik.touched.password && formik.errors.password)}
  533. id="password-signup"
  534. type={showPassword ? 'text' : 'password'}
  535. value={formik.values.password.trim()}
  536. name="password"
  537. onChange={(e) => {
  538. formik.handleChange(e);
  539. changePassword(e.target.value);
  540. }}
  541. endAdornment={
  542. <InputAdornment position="end">
  543. <IconButton
  544. aria-label="toggle password visibility"
  545. onClick={handleClickShowPassword}
  546. onMouseDown={handleMouseDownPassword}
  547. edge="end"
  548. size="large"
  549. >
  550. {showPassword ? <EyeOutlined /> : <EyeInvisibleOutlined />}
  551. </IconButton>
  552. </InputAdornment>
  553. }
  554. placeholder="密碼"
  555. onBlur={formik.handleBlur}
  556. inputProps={{
  557. onKeyDown: (e) => {
  558. if (e.key === 'Enter') {
  559. e.preventDefault();
  560. }
  561. },
  562. }}
  563. />
  564. {formik.touched.password && formik.errors.password && (
  565. <FormHelperText error id="helper-text-password-signup">
  566. {formik.errors.password}
  567. </FormHelperText>
  568. )}
  569. </Stack>
  570. <FormControl fullWidth sx={{ mt: 2 }}>
  571. <Grid container spacing={2} alignItems="center">
  572. <Grid item>
  573. <Box sx={{ bgcolor: level?.color, width: 85, height: 8, borderRadius: '7px' }} />
  574. </Grid>
  575. <Grid item>
  576. <Typography variant="subtitle1" fontSize="0.75rem">
  577. {level?.label}
  578. </Typography>
  579. </Grid>
  580. </Grid>
  581. </FormControl>
  582. </Grid>
  583. <Grid item xs={12} md={6} >
  584. <Stack spacing={1}>
  585. <InputLabel htmlFor="confirmPassword-signup">確認密碼
  586. <span style={{color: '#f10000'}}>*</span>
  587. </InputLabel>
  588. <OutlinedInput
  589. id="confirmPassword-login"
  590. type={showConfirmPassword ? 'text' : 'password'}
  591. value={formik.values.confirmPassword.trim()}
  592. name="confirmPassword"
  593. onBlur={formik.handleBlur}
  594. onChange={(e) => {
  595. formik.handleChange(e);
  596. // changePassword(e.target.value);
  597. }}
  598. inputProps={{
  599. onKeyDown: (e) => {
  600. if (e.key === 'Enter') {
  601. e.preventDefault();
  602. }
  603. },
  604. }}
  605. endAdornment={
  606. <InputAdornment position="end">
  607. <IconButton
  608. aria-label="toggle password visibility"
  609. onClick={handleClickShowConfirmPassword}
  610. onMouseDown={handleMouseDownPassword}
  611. edge="end"
  612. size="large"
  613. >
  614. {showConfirmPassword ? <EyeOutlined /> : <EyeInvisibleOutlined />}
  615. </IconButton>
  616. </InputAdornment>
  617. }
  618. placeholder="確認密碼"
  619. fullWidth
  620. error={Boolean(formik.touched.confirmPassword && formik.errors.confirmPassword)}
  621. />
  622. {formik.touched.confirmPassword && formik.errors.confirmPassword && (
  623. <FormHelperText error id="helper-text-confirmPassword-signup">
  624. {formik.errors.confirmPassword}
  625. </FormHelperText>
  626. )}
  627. </Stack>
  628. <Grid container spacing={2} alignItems="center">
  629. <Grid item>
  630. <Typography fontSize="0.75rem">
  631. <br/>
  632. •至少8個字元,字元越多越好 <br/>
  633. •字母和數字的混合<br/>
  634. •英文字母大寫與小寫的混合<br/>
  635. •至少包含一個特殊符號,例如,@ # ?
  636. </Typography>
  637. </Grid>
  638. </Grid>
  639. </Grid>
  640. </Grid>
  641. </Grid>
  642. <Grid item xs={12} mt={1} mb={1}>
  643. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  644. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary'}}>你的個人資料</Typography>
  645. {/* <Typography component={Link} to="/login" variant="body1" sx={{ textDecoration: 'none' }} color="primary">
  646. Already have an account?
  647. </Typography> */}
  648. </Stack>
  649. </Grid>
  650. <Grid item xs={12} md={12} >
  651. <Grid container sx={{mb:1}}>
  652. <Stack spacing={1}>
  653. <InputLabel htmlFor="idDocType-signup">身份證明文件
  654. <span style={{color: '#f10000'}}>*</span>
  655. </InputLabel>
  656. {/* {formik.touched.enName && formik.errors.enName && (
  657. <FormHelperText error id="helper-text-enName-signup">
  658. {formik.errors.enName}
  659. </FormHelperText>
  660. )} */}
  661. </Stack>
  662. </Grid>
  663. <Grid container>
  664. <Grid item xs={12} md={6} >
  665. <Stack spacing={1} sx={{mr:{md:1},mb:{xs:0.5}}}>
  666. <Autocomplete
  667. disablePortal
  668. id="idDocType"
  669. //value={selectedIdDocType}
  670. options={idDocTypeComboList}
  671. // getOptionLabel={(idDocTypeComboList) => idDocTypeComboList.label}
  672. onBlur={formik.handleBlur}
  673. filterOptions={(options)=>options}
  674. inputValue={selectedIdDocInputType}
  675. onChange={(event, newValue) => {
  676. if (newValue!=null && newValue != {}){
  677. setSelectedIdDocInputType(newValue.label);
  678. setSelectedIdDocType(newValue);
  679. if (newValue.type!="HKID"){
  680. formik.setFieldValue("checkDigit","")
  681. }
  682. }else{
  683. setSelectedIdDocInputType("");
  684. }
  685. }}
  686. sx={{"& .MuiInputBase-root": { height: "41px" },"#idDocType":{padding: "0px 0px 0px 0px"}, "& .MuiAutocomplete-endAdornment": { top: "auto" },}}
  687. renderInput={(params) => <TextField {...params} placeholder="證件類別"/>}
  688. />
  689. {formik.touched.idDocType && (
  690. selectedIdDocType===null?
  691. <FormHelperText error id="helper-text-idDocType-signup">
  692. 請輸入證件類別
  693. </FormHelperText>:''
  694. )}
  695. </Stack>
  696. </Grid>
  697. {selectedIdDocType.type=="HKID"?
  698. <>
  699. <Grid item xs={10} md={5}>
  700. <Stack spacing={1}>
  701. <OutlinedInput
  702. id="idNo-login"
  703. type="text"
  704. value={formik.values.idNo.toUpperCase().trim()}
  705. name="idNo"
  706. onChange={formik.handleChange}
  707. placeholder="證件號碼"
  708. fullWidth
  709. sx={{mr:1}}
  710. error={Boolean(formik.touched.idNo && formik.errors.idNo)}
  711. onBlur={formik.handleBlur}
  712. inputProps={{
  713. maxLength: selectedIdDocType.type =='HKID'?7:18,
  714. onKeyDown: (e) => {
  715. if (e.key === 'Enter') {
  716. e.preventDefault();
  717. }
  718. },
  719. }}
  720. />
  721. {formik.touched.idNo && formik.errors.idNo && (
  722. <FormHelperText error id="helper-text-idNo-signup">
  723. {formik.errors.idNo}
  724. </FormHelperText>
  725. )}
  726. {formik.touched.checkDigit && formik.errors.checkDigit && (
  727. <FormHelperText error id="helper-text-checkDigit-signup">
  728. {formik.errors.checkDigit}
  729. </FormHelperText>
  730. )}
  731. </Stack>
  732. </Grid>
  733. <Grid item xs={2} md={1}>
  734. <Stack spacing={1}>
  735. <OutlinedInput
  736. id="checkDigit-login"
  737. type="text"
  738. value={formik.values.checkDigit.trim()}
  739. name="checkDigit"
  740. onChange={formik.handleChange}
  741. placeholder="( )"
  742. // sx={{height:"53px"}}
  743. inputProps={{
  744. maxLength: 1,
  745. onKeyDown: (e) => {
  746. if (e.key === 'Enter') {
  747. e.preventDefault();
  748. }
  749. },
  750. }}
  751. fullWidth
  752. error={Boolean(formik.touched.checkDigit && formik.errors.checkDigit)}
  753. onBlur={formik.handleBlur}
  754. />
  755. </Stack>
  756. </Grid>
  757. </>:
  758. <Grid item xs={12} md={6}>
  759. <Stack spacing={1}>
  760. <OutlinedInput
  761. id="idNo-login"
  762. type="text"
  763. value={formik.values.idNo.trim()}
  764. name="idNo"
  765. onChange={formik.handleChange}
  766. placeholder="證件號碼"
  767. fullWidth
  768. sx={{mr:1}}
  769. error={Boolean(formik.touched.idNo && formik.errors.idNo)}
  770. onBlur={formik.handleBlur}
  771. inputProps={{
  772. maxLength: 18,
  773. onKeyDown: (e) => {
  774. if (e.key === 'Enter') {
  775. e.preventDefault();
  776. }
  777. },
  778. }}
  779. />
  780. {formik.touched.idNo && formik.errors.idNo && (
  781. <FormHelperText error id="helper-text-idNo-signup">
  782. {formik.errors.idNo}
  783. </FormHelperText>
  784. )}
  785. </Stack>
  786. </Grid>
  787. }
  788. </Grid>
  789. </Grid>
  790. <Grid item xs={12} md={6}>
  791. <Stack spacing={1}>
  792. <InputLabel htmlFor="enName-signup">英文姓名
  793. {selectedIdDocType.type === "CNID" ? "" : <span style={{color: '#f10000'}}>*</span>}
  794. </InputLabel>
  795. <OutlinedInput
  796. id="enName-login"
  797. type="enName"
  798. value={formik.values.enName}
  799. name="enName"
  800. onChange={formik.handleChange}
  801. placeholder="與你的身份證明文件相同"
  802. fullWidth
  803. error={Boolean(formik.touched.enName && formik.errors.enName && selectedIdDocType.type !== "CNID")}
  804. onBlur={formik.handleBlur}
  805. inputProps={{
  806. onKeyDown: (e) => {
  807. if (e.key === 'Enter') {
  808. e.preventDefault();
  809. }
  810. },
  811. }}
  812. />
  813. {formik.touched.enName && formik.errors.enName && selectedIdDocType.type !== "CNID" && (
  814. <FormHelperText error id="helper-text-enName-signup">
  815. {formik.errors.enName}
  816. </FormHelperText>
  817. )}
  818. </Stack>
  819. </Grid>
  820. <Grid item xs={12} md={6}>
  821. <Stack spacing={1}>
  822. <InputLabel htmlFor="chName-signup">
  823. 中文姓名
  824. <span style={{color: '#f10000'}}>*</span>
  825. </InputLabel>
  826. <OutlinedInput
  827. fullWidth
  828. error={Boolean(formik.touched.chName && formik.errors.chName)}
  829. id="chName-signup"
  830. type="text"
  831. value={formik.values.chName.trim()}
  832. name="chName"
  833. onChange={formik.handleChange}
  834. placeholder="與你的身份證明文件相同"
  835. onBlur={formik.handleBlur}
  836. inputProps={{
  837. maxLength: 6,
  838. onKeyDown: (e) => {
  839. if (e.key === 'Enter') {
  840. e.preventDefault();
  841. }
  842. },
  843. }}
  844. />
  845. {formik.touched.chName && formik.errors.chName && (
  846. <FormHelperText error id="helper-text-chName-signup">
  847. {formik.errors.chName}
  848. </FormHelperText>
  849. )}
  850. </Stack>
  851. </Grid>
  852. <Grid item xs={12}>
  853. <Stack spacing={1}>
  854. <InputLabel htmlFor="address1-signup">地址
  855. <span style={{color: '#f10000'}}>*</span>
  856. </InputLabel>
  857. <OutlinedInput
  858. fullWidth
  859. error={Boolean(formik.touched.address1 && formik.errors.address1)}
  860. id="address1-signup"
  861. value={formik.values.address1}
  862. name="address1"
  863. onChange={formik.handleChange}
  864. placeholder="第一行"
  865. onBlur={formik.handleBlur}
  866. inputProps={{
  867. onKeyDown: (e) => {
  868. if (e.key === 'Enter') {
  869. e.preventDefault();
  870. }
  871. },
  872. }}
  873. />
  874. <OutlinedInput
  875. fullWidth
  876. error={Boolean(formik.touched.address2 && formik.errors.address2)}
  877. id="address2-signup"
  878. value={formik.values.address2}
  879. name="address2"
  880. onChange={formik.handleChange}
  881. placeholder="第二行"
  882. inputProps={{
  883. onKeyDown: (e) => {
  884. if (e.key === 'Enter') {
  885. e.preventDefault();
  886. }
  887. },
  888. }}
  889. />
  890. <OutlinedInput
  891. fullWidth
  892. error={Boolean(formik.touched.address3 && formik.errors.address3)}
  893. id="address3-signup"
  894. value={formik.values.address3}
  895. name="address3"
  896. onChange={formik.handleChange}
  897. placeholder="第三行"
  898. inputProps={{
  899. onKeyDown: (e) => {
  900. if (e.key === 'Enter') {
  901. e.preventDefault();
  902. }
  903. },
  904. }}
  905. />
  906. <Autocomplete
  907. disablePortal
  908. id="address4-combo"
  909. value={selectedAddress4}
  910. options={address4ComboList}
  911. disabled={checkCountry}
  912. onChange={(event, newValue) => {
  913. setSelectedAddress4(newValue);
  914. }}
  915. sx={{"& .MuiInputBase-root": { height: "41px" },"#address4-combo":{padding: "0px 0px 0px 0px"}, "& .MuiAutocomplete-endAdornment": { top: "auto" },}}
  916. renderInput={(params) => <TextField {...params} placeholder="區域 (只適用於香港)"/>}
  917. />
  918. <Autocomplete
  919. disablePortal
  920. id="address5-combo"
  921. value={selectedAddress5}
  922. options={address5ComboList}
  923. onChange={(event, newValue) => {
  924. if (newValue !== null){
  925. setSelectedAddress5(newValue);
  926. if(newValue=='香港'){
  927. setCheckCountry(false)
  928. }else{
  929. setSelectedAddress4("");
  930. setCheckCountry(true)
  931. }
  932. }else{
  933. setSelectedAddress4("");
  934. setCheckCountry(true)
  935. }
  936. }}
  937. sx={{"& .MuiInputBase-root": { height: "41px" },"#address5-combo":{padding: "0px 0px 0px 0px"}, "& .MuiAutocomplete-endAdornment": { top: "auto" },}}
  938. renderInput={(params) => <TextField {...params} placeholder="國家/地區"/>}
  939. />
  940. {formik.touched.address1 && formik.errors.address1 && (
  941. <FormHelperText error id="helper-text-address1-signup">
  942. {formik.errors.address1}
  943. </FormHelperText>
  944. )}
  945. {formik.touched.address2 && formik.errors.address2 && (
  946. <FormHelperText error id="helper-text-address2-signup">
  947. {formik.errors.address2}
  948. </FormHelperText>
  949. )}
  950. {formik.touched.address3 && formik.errors.address3 && (
  951. <FormHelperText error id="helper-text-address3-signup">
  952. {formik.errors.address3}
  953. </FormHelperText>
  954. )}
  955. </Stack>
  956. </Grid>
  957. <Grid item xs={12} mt={1} mb={1}>
  958. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  959. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary'}}>你的聯絡資料</Typography>
  960. </Stack>
  961. </Grid>
  962. <Grid item xs={12} md={12}>
  963. <Grid container>
  964. <Grid item xs={12} md={6}>
  965. <Stack spacing={1} sx={{mr:{md:1},mb:1}}>
  966. <InputLabel htmlFor="email-signup">電郵
  967. <span style={{color: '#f10000'}}>*</span>
  968. </InputLabel>
  969. <OutlinedInput
  970. fullWidth
  971. error={Boolean(formik.touched.email && formik.errors.email)}
  972. id="email-login"
  973. type="email"
  974. value={formik.values.email.trim()}
  975. name="email"
  976. onChange={formik.handleChange}
  977. placeholder="電郵"
  978. onBlur={formik.handleBlur}
  979. inputProps={{
  980. onKeyDown: (e) => {
  981. if (e.key === 'Enter') {
  982. e.preventDefault();
  983. }
  984. },
  985. }}
  986. />
  987. {formik.touched.email && formik.errors.email && (
  988. <FormHelperText error id="helper-text-email-signup">
  989. {formik.errors.email}
  990. </FormHelperText>
  991. )}
  992. </Stack>
  993. </Grid>
  994. <Grid item xs={12} md={6}>
  995. <Stack spacing={1} >
  996. <InputLabel htmlFor="emailConfirm-signup">確認電郵
  997. <span style={{color: '#f10000'}}>*</span>
  998. </InputLabel>
  999. <OutlinedInput
  1000. fullWidth
  1001. error={Boolean(formik.touched.emailConfirm && formik.errors.emailConfirm)}
  1002. id="emailConfirm-login"
  1003. type="email"
  1004. value={formik.values.emailConfirm.trim()}
  1005. name="emailConfirm"
  1006. // onBlur={formik.handleBlur}
  1007. onChange={formik.handleChange}
  1008. placeholder="確認電郵"
  1009. onBlur={formik.handleBlur}
  1010. inputProps={{
  1011. onKeyDown: (e) => {
  1012. if (e.key === 'Enter') {
  1013. e.preventDefault();
  1014. }
  1015. },
  1016. }}
  1017. />
  1018. {formik.touched.emailConfirm && formik.errors.emailConfirm && (
  1019. <FormHelperText error id="helper-text-emailConfirm-signup">
  1020. {formik.errors.emailConfirm}
  1021. </FormHelperText>
  1022. )}
  1023. </Stack>
  1024. </Grid>
  1025. </Grid>
  1026. </Grid>
  1027. <Grid item xs={12} md={12}>
  1028. <Grid container>
  1029. <Grid item xs={12} md={6}>
  1030. <Grid container>
  1031. <Grid item xs={12} md={12}>
  1032. <Stack direction="column" spacing={1} sx={{mr:{md:1},mb:1}}>
  1033. <InputLabel htmlFor="phone-signup">聯絡電話
  1034. <span style={{color: '#f10000'}}>*</span>
  1035. </InputLabel>
  1036. <Stack direction="row">
  1037. <OutlinedInput
  1038. id="phoneCountryCode-login"
  1039. type="phoneCountryCode"
  1040. value={formik.values.phoneCountryCode.trim()}
  1041. name="phoneCountryCode"
  1042. // onBlur={formik.handleBlur}
  1043. // onChange={formik.handleChange}
  1044. onChange={(event) => {
  1045. const value = event.target.value;
  1046. if (value.match(/[^0-9]/)) {
  1047. return event.preventDefault();
  1048. }
  1049. formik.setFieldValue("phoneCountryCode",value);
  1050. }}
  1051. placeholder="國際區號"
  1052. error={Boolean(formik.touched.phone && formik.errors.phone)}
  1053. onBlur={formik.handleBlur}
  1054. inputProps={{
  1055. maxLength: 3,
  1056. onKeyDown: (e) => {
  1057. if (e.key === 'Enter') {
  1058. e.preventDefault();
  1059. }
  1060. },
  1061. }}
  1062. sx={{width:'25%'}}
  1063. />
  1064. <OutlinedInput
  1065. id="phone-login"
  1066. type="phone"
  1067. value={formik.values.phone.trim()}
  1068. name="phone"
  1069. // onBlur={formik.handleBlur}
  1070. // onChange={formik.handleChange}
  1071. onChange={(event) => {
  1072. const value = event.target.value;
  1073. if (value.match(/[^0-9]/)) {
  1074. return event.preventDefault();
  1075. }
  1076. formik.setFieldValue("phone",value);
  1077. }}
  1078. placeholder="聯絡電話"
  1079. error={Boolean(formik.touched.phone && formik.errors.phone)}
  1080. onBlur={formik.handleBlur}
  1081. inputProps={{
  1082. maxLength: 11,
  1083. onKeyDown: (e) => {
  1084. if (e.key === 'Enter') {
  1085. e.preventDefault();
  1086. }
  1087. },
  1088. }}
  1089. sx={{width:'75%'}}
  1090. />
  1091. </Stack>
  1092. {formik.touched.phone && formik.errors.phone && (
  1093. <FormHelperText error id="helper-text-phone-signup">
  1094. {formik.errors.phone}
  1095. </FormHelperText>
  1096. )}
  1097. </Stack>
  1098. </Grid>
  1099. </Grid>
  1100. </Grid>
  1101. <Grid item xs={12} md={6}>
  1102. <Grid container>
  1103. <Grid item xs={12} md={12}>
  1104. <Stack spacing={1} direction="column">
  1105. <InputLabel htmlFor="fax-signup">傳真號碼</InputLabel>
  1106. <Stack direction="row">
  1107. <OutlinedInput
  1108. error={Boolean(formik.touched.fax && formik.errors.fax)}
  1109. id="faxCountryCode-login"
  1110. type="faxCountryCode"
  1111. value={formik.values.faxCountryCode.trim()}
  1112. name="faxCountryCode"
  1113. // onChange={formik.handleChange}
  1114. onChange={(event) => {
  1115. const value = event.target.value;
  1116. if (value.match(/[^0-9]/)) {
  1117. return event.preventDefault();
  1118. }
  1119. formik.setFieldValue("faxCountryCode",value);
  1120. }}
  1121. placeholder="國際區號"
  1122. onBlur={formik.handleBlur}
  1123. inputProps={{
  1124. maxLength: 3,
  1125. onKeyDown: (e) => {
  1126. if (e.key === 'Enter') {
  1127. e.preventDefault();
  1128. }
  1129. },
  1130. }}
  1131. sx={{width:'25%'}}
  1132. />
  1133. <OutlinedInput
  1134. id="fax-login"
  1135. type="fax"
  1136. value={formik.values.fax.trim()}
  1137. name="fax"
  1138. onBlur={formik.handleBlur}
  1139. // onChange={formik.handleChange}
  1140. onChange={(event) => {
  1141. const value = event.target.value;
  1142. if (value.match(/[^0-9]/)) {
  1143. return event.preventDefault();
  1144. }
  1145. formik.setFieldValue("fax",value);
  1146. }}
  1147. placeholder="傳真號碼"
  1148. inputProps={{
  1149. maxLength: 8,
  1150. onKeyDown: (e) => {
  1151. if (e.key === 'Enter') {
  1152. e.preventDefault();
  1153. }
  1154. },
  1155. }}
  1156. sx={{width:'75%'}}
  1157. />
  1158. </Stack>
  1159. </Stack>
  1160. </Grid>
  1161. </Grid>
  1162. </Grid>
  1163. </Grid>
  1164. </Grid>
  1165. <Grid item xs={12} md={12} mt={1} mb={1}>
  1166. <Grid container>
  1167. <Grid item xs={12} md={12}>
  1168. <Stack spacing={1} direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1169. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary'}}>身份證明文件<span style={{color: '#f10000'}}>*</span></Typography>
  1170. <Typography display="inline" variant="h6" sx={{ fontSize: 12,color: 'primary.primary'}}>請上傳你的 有效身份證明文件 的數碼檔案,以驗證你的身份。</Typography>
  1171. <Typography display="inline" variant="h6" sx={{ fontSize: 12,color: 'primary.primary'}}>如: 香港身份證; 護照; 中國內地身份證; 專業執業証書等</Typography>
  1172. <Stack mt={1} direction="row" justifyContent="flex-start" alignItems="center" spacing={2}>
  1173. <Button variant="contained" component="label" sx={{ fontSize: 12,height:'40px'}}>上傳身份證明文件
  1174. <input
  1175. accept="image/png, .jpg, .bmp, .pdf"
  1176. //className={classes.input}
  1177. id="contained-button-file"
  1178. multiple
  1179. type="file"
  1180. onChange={handleFileUpload}
  1181. style={{display: 'none'}}
  1182. />
  1183. </Button>
  1184. <Typography display="inline" variant="h6" sx={{ fontSize: 12, color: 'primary.primary'}}>如: 香港身份證; 護照; 中國內地身份證等</Typography>
  1185. </Stack>
  1186. {fileList !=null?
  1187. <UploadFileTable key="uploadTable" recordList={fileListData} setUpdateRows={setUpdateRows}/>:null}
  1188. {/* <Stack mt={1} direction="row" justifyContent="flex-start" alignItems="center" spacing={2}>
  1189. <Button variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button>
  1190. <Button disabled={!formik.isValid} variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button>
  1191. </Stack> */}
  1192. </Stack>
  1193. </Grid>
  1194. </Grid>
  1195. </Grid>
  1196. </Grid>
  1197. <Grid item xs={12} md={12}>
  1198. <Grid container>
  1199. <Grid item xs={12} md={12}>
  1200. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary'}}>
  1201. 條款和條件
  1202. <span style={{color: '#f10000'}}>*</span>
  1203. </Typography>
  1204. </Grid>
  1205. <Grid item xs={12} md={12}>
  1206. <Grid container>
  1207. <Grid item xs={12} md={12}>
  1208. <Typography height="80%" sx={{textAlign: "left",overflow: "scroll",borderRadius: "inherit", borderStyle: "solid",borderWidth: "1px",borderColor: "#0C489E"}}>
  1209. {termsAndCon}
  1210. </Typography>
  1211. </Grid>
  1212. </Grid>
  1213. <Grid item xs={12} s={12} md={12} lg={12}>
  1214. <Grid container>
  1215. <Grid item xs={6} s={6} md={2} lg={2}>
  1216. <Grid container>
  1217. <Grid item sx={{display: 'flex', alignItems: 'center'}}>
  1218. <Checkbox
  1219. checked={termsAndConAccept}
  1220. onChange={handleCheckBoxChange}
  1221. name="termsAndConAccept"
  1222. color="primary"
  1223. size="small"
  1224. />
  1225. <Typography>我接受</Typography>
  1226. </Grid>
  1227. </Grid>
  1228. </Grid>
  1229. <Grid item xs={6} s={6} md={2} lg={2}>
  1230. <Grid container>
  1231. <Grid item sx={{display: 'flex', alignItems: 'center'}}>
  1232. <Checkbox
  1233. checked={termsAndConNotAccept}
  1234. onChange={handleCheckBoxChange}
  1235. name="termsAndConNotAccept"
  1236. color="primary"
  1237. size="small"
  1238. />
  1239. <Typography>我不接受</Typography>
  1240. </Grid>
  1241. </Grid>
  1242. </Grid>
  1243. </Grid>
  1244. </Grid>
  1245. </Grid>
  1246. </Grid>
  1247. </Grid>
  1248. <Grid item xs={12} lg={12}>
  1249. <Grid container>
  1250. <Stack direction="column">
  1251. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary'}}>
  1252. 驗證
  1253. <span style={{color: '#f10000'}}>*</span>
  1254. </Typography>
  1255. <Stack spacing={1} direction="row">
  1256. <Grid item xs={5} lg={5} style={{"border":"1px solid black"}}>
  1257. <img src={captchaImg} alt=""/>
  1258. </Grid>
  1259. <Grid item xs={1} lg={1} style={{"border":"0px solid black"}}>
  1260. <IconButton aria-label="refrashCaptcha" size="large" onClick={()=>{onCaptchaChange()}}>
  1261. <LoopIcon fontSize="inherit" />
  1262. </IconButton>
  1263. </Grid>
  1264. <Grid item xs={6} lg={6}>
  1265. <OutlinedInput
  1266. fullWidth
  1267. id="captchaField"
  1268. type="text"
  1269. value={formik.values.captchaField.trim()}
  1270. onBlur={formik.handleBlur}
  1271. error={Boolean(formik.touched.captchaField && formik.errors.captchaField)}
  1272. name="captchaField"
  1273. onChange={(event) => {
  1274. const value = event.target.value;
  1275. formik.setFieldValue("captchaField",value);
  1276. }}
  1277. sx={{width:'75%'}}
  1278. />
  1279. </Grid>
  1280. </Stack>
  1281. {formik.touched.captchaField && formik.errors.captchaField && (
  1282. <FormHelperText error id="helper-text-captcha-signup">
  1283. {formik.errors.captchaField}
  1284. </FormHelperText>
  1285. )}
  1286. </Stack>
  1287. </Grid>
  1288. </Grid>
  1289. </Grid>
  1290. </Grid>
  1291. </FormGroup>
  1292. {/* Preview Form */}
  1293. <FormGroup id={"previewForm"} sx={{ display: props.step === 1 ? "" : "none"}}>
  1294. <Grid container spacing={3}>
  1295. <Grid item xs={12} md={12}>
  1296. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1297. <div style={{borderBottom: "3px solid #1A4399", width:"100%", margin_right: "15px"}}>
  1298. <Typography display="inline" variant="h3" sx={{ color: '#1A4399'}}>成為新的個人用戶</Typography>
  1299. </div>
  1300. {/* <Typography mt={0.25} variant="h6" sx={{ fontSize: 12,color: '#f10000'}}>註有*的項目必須輸入資料</Typography> */}
  1301. <Typography mt={0.25} variant="h4" sx={{ color: 'primary.primary'}}>你的登入資料</Typography>
  1302. {/* <Typography component={Link} to="/login" variant="body1" sx={{ textDecoration: 'none' }} color="primary">
  1303. Already have an account?
  1304. </Typography> */}
  1305. </Stack>
  1306. </Grid>
  1307. <Grid item xs={12} md={12}>
  1308. <Grid container spacing={2}>
  1309. <Grid item xs={12} >
  1310. <Stack spacing={2} direction="row">
  1311. <Typography>
  1312. 用戶登入名稱:
  1313. </Typography>
  1314. <Typography id="preview-username-login">
  1315. {formik.values.username}
  1316. </Typography>
  1317. </Stack>
  1318. </Grid>
  1319. <Grid item xs={12} mt={1} mb={1}>
  1320. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1321. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary'}}>你的個人資料</Typography>
  1322. {/* <Typography component={Link} to="/login" variant="body1" sx={{ textDecoration: 'none' }} color="primary">
  1323. Already have an account?
  1324. </Typography> */}
  1325. </Stack>
  1326. </Grid>
  1327. <Grid item xs={12} md={12} >
  1328. <Stack spacing={1}>
  1329. <Typography>
  1330. 身份證明文件
  1331. </Typography>
  1332. </Stack>
  1333. </Grid>
  1334. <Grid item xs={12} md={6} >
  1335. <Stack spacing={1} direction="row">
  1336. <Typography>
  1337. 證件類別:
  1338. </Typography>
  1339. <Typography name = "preview-idDocType">
  1340. {selectedIdDocType.label}
  1341. </Typography>
  1342. </Stack>
  1343. </Grid>
  1344. <Grid item xs={12} md={6}>
  1345. <Stack spacing={1} direction="row">
  1346. <Typography>
  1347. 證件號碼:
  1348. </Typography>
  1349. <Typography id="idNo-login">
  1350. {formik.values.idNo} {selectedIdDocType.type=="HKID"?'('+formik.values.checkDigit+')':null}
  1351. </Typography>
  1352. </Stack>
  1353. </Grid>
  1354. <Grid item xs={12} md={6}>
  1355. <Stack spacing={1} direction="row">
  1356. <Typography>
  1357. 英文姓名:
  1358. </Typography>
  1359. <Typography id="preview-enName-signup">
  1360. {formik.values.enName}
  1361. </Typography>
  1362. </Stack>
  1363. </Grid>
  1364. <Grid item xs={12} md={6}>
  1365. <Stack spacing={1} direction="row">
  1366. <Typography>
  1367. 中文姓名:
  1368. </Typography>
  1369. <Typography id="preview-chName-signup">
  1370. {formik.values.chName}
  1371. </Typography>
  1372. </Stack>
  1373. </Grid>
  1374. <Grid item xs={12}>
  1375. <Stack spacing={1} direction="row">
  1376. <Typography>
  1377. 地址:
  1378. </Typography>
  1379. <Stack spacing={1} direction="column">
  1380. <Typography id="preview-address1-signup">
  1381. {formik.values.address1}
  1382. </Typography>
  1383. {formik.values.address2!=null?
  1384. <Typography id="preview-address2-signup">
  1385. {formik.values.address2}
  1386. </Typography>
  1387. :null}
  1388. {formik.values.address3!=null?
  1389. <Typography id="preview-address3-signup">
  1390. {formik.values.address3}
  1391. </Typography>
  1392. :null}
  1393. {selectedAddress5==("香港")?
  1394. <Typography id="preview-address4-signup">
  1395. 區域 (只適用於香港): {selectedAddress4}
  1396. </Typography>
  1397. :null}
  1398. <Typography id="preview-address5-signup">
  1399. 國家/地區: {selectedAddress5}
  1400. </Typography>
  1401. </Stack>
  1402. </Stack>
  1403. </Grid>
  1404. <Grid item xs={12} mt={1} mb={1}>
  1405. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1406. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary'}}>你的聯絡資料</Typography>
  1407. </Stack>
  1408. </Grid>
  1409. <Grid item xs={12} md={12}>
  1410. <Stack spacing={1} direction="row">
  1411. <Typography>
  1412. 電郵:
  1413. </Typography>
  1414. <Typography id="preview-email-signup">
  1415. {formik.values.email}
  1416. </Typography>
  1417. </Stack>
  1418. </Grid>
  1419. <Grid item xs={12} md={6}>
  1420. <Stack spacing={1} direction="row">
  1421. <Typography>
  1422. 聯絡電話:
  1423. </Typography>
  1424. <Typography id="preview-phone-signup">
  1425. +{formik.values.phoneCountryCode} {formik.values.phone}
  1426. </Typography>
  1427. </Stack>
  1428. </Grid>
  1429. {formik.values.faxCountryCode!=""&&formik.values.fax!=""?
  1430. <Grid item xs={12} md={6}>
  1431. <Stack spacing={1} direction="row">
  1432. <Typography>
  1433. 傳真號碼:
  1434. </Typography>
  1435. <Typography id="preview-fax-signup">
  1436. +{formik.values.faxCountryCode} {formik.values.fax}
  1437. </Typography>
  1438. </Stack>
  1439. </Grid>
  1440. :null}
  1441. <Grid item xs={12} md={12} mt={1} mb={1}>
  1442. <Grid container>
  1443. <Grid item xs={12} md={12}>
  1444. <Stack spacing={1} direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1445. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary'}}>身份證明文件</Typography>
  1446. {fileList !=null?
  1447. <PreviewUploadFileTable key="previewTable" recordList={fileListData} />:null}
  1448. </Stack>
  1449. </Grid>
  1450. </Grid>
  1451. </Grid>
  1452. </Grid>
  1453. </Grid>
  1454. </Grid>
  1455. </FormGroup>
  1456. {/* Submit page */}
  1457. <FormGroup id={"submitForm"} sx={{ display: props.step === 2 ? "" : "none"}}>
  1458. <Grid container spacing={3}>
  1459. {isLoading ?
  1460. <LoadingComponent/>:
  1461. <Grid item xs={12}>
  1462. {checkUpload?
  1463. // SUCCESS page
  1464. <Stack mt={1} direction="column" justifyContent="flex-start" alignItems="center" spacing={2}>
  1465. <CheckCircleOutlineIcon color="success" sx={{width:"200px",height:"200px"}}/>
  1466. <Typography display="inline" variant="h4">帳戶申請已成功提交。</Typography>
  1467. <Typography display="inline" variant="h4">驗證電郵將發送到你的電郵地址,請要指示完成驗證及登入系統。</Typography>
  1468. <Button variant="outlined" component={Link} to="/login" sx={{ fontSize: 20,height:'60px'}}>返回登入頁面</Button>
  1469. </Stack>
  1470. :
  1471. // ERROR page
  1472. <Stack mt={1} direction="column" justifyContent="flex-start" alignItems="center" spacing={2}>
  1473. {/* <Button disabled={true} hidden={true} variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button> */}
  1474. <CancelOutlinedIcon color="error" sx={{width:"200px",height:"200px"}}/>
  1475. <Typography display="inline" variant="h4">申請失敗,請稍後嘗試</Typography>
  1476. <Button color="error" variant="outlined" component={Link} to="/login" sx={{ fontSize: 20,height:'60px'}}>返回登入頁面</Button>
  1477. </Stack>
  1478. }
  1479. </Grid>
  1480. }
  1481. </Grid>
  1482. </FormGroup>
  1483. </form>
  1484. </FormikProvider>
  1485. );
  1486. }
  1487. export default CustomFormWizard;