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.
 
 

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