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

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