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.
 
 

1627 lines
99 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' }}>
  515. <FormattedMessage id="becomeNewBusinessUser"/>
  516. </Typography>
  517. </div>
  518. <Typography mt={0.25} variant="h6" sx={{ color: '#f10000' }}>註有*的項目必須輸入資料</Typography>
  519. <Typography mt={0.25} variant="h4" sx={{ color: 'primary.primary' }}>你的登入資料</Typography>
  520. {/* <Typography component={Link} to="/login" variant="body1" sx={{ textDecoration: 'none' }} color="primary">
  521. Already have an account?
  522. </Typography> */}
  523. </Stack>
  524. </Grid>
  525. <Grid item xs={12} md={12}>
  526. <Grid container spacing={1}>
  527. <Grid item xs={12} md={12} >
  528. <Stack spacing={1}>
  529. <InputLabel htmlFor="username-signup">
  530. <Typography variant="pnspsFormHeader">
  531. <FormattedMessage id="userLoginName"/>
  532. <span style={{ color: '#f10000' }}>*</span>
  533. {/* <Button
  534. variant="contained"
  535. onClick={handleCheckUsername}
  536. sx={{ ml: 2, height: "40px" }}>
  537. <Typography variant="h6">檢查是否重覆</Typography>
  538. </Button> */}
  539. </Typography>
  540. </InputLabel>
  541. <OutlinedInput
  542. id="username-login"
  543. type="text"
  544. value={formik.values.username.trim()}
  545. name="username"
  546. onChange={(e) => {
  547. setCheckUsername(false)
  548. props.setUsername(e.target.value)
  549. formik.handleChange(e)
  550. }}
  551. placeholder={intl.formatMessage({id: 'userLoginName'})}
  552. fullWidth
  553. error={Boolean((formik.touched.username && formik.errors.username) || checkUsername)}
  554. onBlur={formik.handleBlur}
  555. inputProps={{
  556. onKeyDown: (e) => {
  557. if (e.key === 'Enter') {
  558. e.preventDefault();
  559. }
  560. },
  561. }}
  562. />
  563. {formik.touched.username && formik.errors.username && (
  564. <FormHelperText error id="helper-text-username-signup">
  565. {formik.errors.username}
  566. </FormHelperText>
  567. )}
  568. {checkUsername && (
  569. <FormHelperText error id="helper-text-username-signup">
  570. 此用戶登入名稱已被注冊,請使用其他用戶登入名稱
  571. </FormHelperText>
  572. )}
  573. </Stack>
  574. </Grid>
  575. <Grid item xs={12} md={12}>
  576. <Grid container>
  577. <Grid item xs={12} md={6} >
  578. <Stack spacing={1} sx={{ mr: { md: 1 }, mb: 1 }}>
  579. <Stack direction="row" justifyContent="space-between">
  580. <InputLabel htmlFor="password-signup">
  581. <Typography variant="pnspsFormHeader">
  582. <FormattedMessage id="userPassword"/>
  583. <span style={{ color: '#f10000' }}>*</span>
  584. </Typography>
  585. </InputLabel>
  586. </Stack>
  587. <OutlinedInput
  588. fullWidth
  589. error={Boolean(formik.touched.password && formik.errors.password)}
  590. id="password-signup"
  591. type={showPassword ? 'text' : 'password'}
  592. value={formik.values.password.trim()}
  593. name="password"
  594. onChange={(e) => {
  595. formik.handleChange(e);
  596. changePassword(e.target.value);
  597. }}
  598. endAdornment={
  599. <InputAdornment position="end">
  600. <IconButton
  601. aria-label="toggle password visibility"
  602. onClick={handleClickShowPassword}
  603. onMouseDown={handleMouseDownPassword}
  604. edge="end"
  605. size="large"
  606. >
  607. {showPassword ? <EyeOutlined /> : <EyeInvisibleOutlined />}
  608. </IconButton>
  609. </InputAdornment>
  610. }
  611. placeholder={intl.formatMessage({id: 'userPassword'})}
  612. onBlur={formik.handleBlur}
  613. inputProps={{
  614. onKeyDown: (e) => {
  615. if (e.key === 'Enter') {
  616. e.preventDefault();
  617. }
  618. },
  619. }}
  620. />
  621. {formik.touched.password && formik.errors.password && (
  622. <FormHelperText error id="helper-text-password-signup">
  623. {formik.errors.password}
  624. </FormHelperText>
  625. )}
  626. </Stack>
  627. <FormControl fullWidth sx={{ mt: 2 }}>
  628. <Grid container spacing={2} alignItems="center">
  629. <Grid item>
  630. <Box sx={{ bgcolor: level?.color, width: 85, height: 8, borderRadius: '7px' }} />
  631. </Grid>
  632. <Grid item>
  633. <Typography variant="subtitle1">
  634. {level?.label}
  635. </Typography>
  636. </Grid>
  637. </Grid>
  638. </FormControl>
  639. </Grid>
  640. <Grid item xs={12} md={6} >
  641. <Stack spacing={1}>
  642. <InputLabel htmlFor="confirmPassword-signup">
  643. <Typography variant="pnspsFormHeader">
  644. 確認密碼
  645. <span style={{ color: '#f10000' }}>*</span>
  646. </Typography>
  647. </InputLabel>
  648. <OutlinedInput
  649. id="confirmPassword-login"
  650. type={showConfirmPassword ? 'text' : 'password'}
  651. value={formik.values.confirmPassword.trim()}
  652. name="confirmPassword"
  653. onBlur={formik.handleBlur}
  654. onChange={(e) => {
  655. formik.handleChange(e);
  656. // changePassword(e.target.value);
  657. }}
  658. inputProps={{
  659. onKeyDown: (e) => {
  660. if (e.key === 'Enter') {
  661. e.preventDefault();
  662. }
  663. },
  664. }}
  665. endAdornment={
  666. <InputAdornment position="end">
  667. <IconButton
  668. aria-label="toggle password visibility"
  669. onClick={handleClickShowConfirmPassword}
  670. onMouseDown={handleMouseDownPassword}
  671. edge="end"
  672. size="large"
  673. >
  674. {showConfirmPassword ? <EyeOutlined /> : <EyeInvisibleOutlined />}
  675. </IconButton>
  676. </InputAdornment>
  677. }
  678. placeholder="確認密碼"
  679. fullWidth
  680. error={Boolean(formik.touched.confirmPassword && formik.errors.confirmPassword)}
  681. />
  682. {formik.touched.confirmPassword && formik.errors.confirmPassword && (
  683. <FormHelperText error id="helper-text-confirmPassword-signup">
  684. {formik.errors.confirmPassword}
  685. </FormHelperText>
  686. )}
  687. </Stack>
  688. <Grid container spacing={2} alignItems="center">
  689. <Grid item sx={{mt:1}}>
  690. <Typography variant="subtitle1">
  691. •至少8個字元,字元越多越好 <br />
  692. •字母和數字的混合<br />
  693. •英文字母大寫與小寫的混合<br />
  694. •至少包含一個特殊符號,例如,@ # ?
  695. </Typography>
  696. </Grid>
  697. </Grid>
  698. </Grid>
  699. </Grid>
  700. </Grid>
  701. <Grid item xs={12} mt={1} mb={1}>
  702. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  703. <Typography display="inline" variant="h4" /*sx={{ color: '#1A4399' }}*/>你的機構/公司資料</Typography>
  704. {/* <Typography component={Link} to="/login" variant="body1" sx={{ textDecoration: 'none' }} color="primary">
  705. Already have an account?
  706. </Typography> */}
  707. </Stack>
  708. </Grid>
  709. <Grid item xs={12} md={12}>
  710. <Typography variant="subtitle1">
  711. •請輸入機構/公司英文名稱或中文名稱<br />
  712. •Please enter the English/Chinese name of the organisation/company
  713. </Typography>
  714. </Grid>
  715. <Grid item xs={12} md={6}>
  716. <Stack spacing={1}>
  717. <InputLabel htmlFor="enCompanyName-signup">
  718. <Typography variant="pnspsFormHeader">
  719. 機構/公司英文名稱
  720. </Typography>
  721. </InputLabel>
  722. <OutlinedInput
  723. id="enCompanyName-login"
  724. type="enCompanyName"
  725. value={formik.values.enCompanyName}
  726. name="enCompanyName"
  727. onChange={formik.handleChange}
  728. placeholder="與商業登記證相同"
  729. fullWidth
  730. error={Boolean(formik.touched.enCompanyName && formik.errors.enCompanyName && selectedAddress5 !== "內地")}
  731. onBlur={formik.handleBlur}
  732. inputProps={{
  733. onKeyDown: (e) => {
  734. if (e.key === 'Enter') {
  735. e.preventDefault();
  736. }
  737. },
  738. }}
  739. />
  740. {formik.touched.enCompanyName && formik.errors.enCompanyName && selectedAddress5 !== "內地" && (
  741. <FormHelperText error id="helper-text-enCompanyName-signup">
  742. {formik.errors.enCompanyName}
  743. </FormHelperText>
  744. )}
  745. </Stack>
  746. </Grid>
  747. <Grid item xs={12} md={6}>
  748. <Stack spacing={1}>
  749. <InputLabel htmlFor="chCompanyName-signup">
  750. <Typography variant="pnspsFormHeader">
  751. 機構/公司中文名稱
  752. </Typography>
  753. </InputLabel>
  754. <OutlinedInput
  755. fullWidth
  756. error={Boolean(formik.touched.chCompanyName && formik.errors.chCompanyName)}
  757. id="chCompanyName-signup"
  758. type="text"
  759. value={formik.values.chCompanyName.trim()}
  760. name="chCompanyName"
  761. onChange={formik.handleChange}
  762. placeholder="與商業登記證相同"
  763. onBlur={formik.handleBlur}
  764. inputProps={{
  765. onKeyDown: (e) => {
  766. if (e.key === 'Enter') {
  767. e.preventDefault();
  768. }
  769. },
  770. }}
  771. />
  772. {formik.touched.chCompanyName && formik.errors.chCompanyName && (
  773. <FormHelperText error id="helper-text-chCompanyName-signup">
  774. {formik.errors.chCompanyName}
  775. </FormHelperText>
  776. )}
  777. </Stack>
  778. </Grid>
  779. <Grid item xs={12} md={6}>
  780. <Stack spacing={1}>
  781. <InputLabel htmlFor="brNo-signup" sx={{ whiteSpace: 'pre-wrap', wordWrap: 'break-word' }}>
  782. <Typography variant="pnspsFormHeader">
  783. 商業登記證號碼 (e.g. 12341234)
  784. <span style={{ color: '#f10000' }}>*</span>
  785. </Typography>
  786. </InputLabel>
  787. <OutlinedInput
  788. fullWidth
  789. error={Boolean(formik.touched.brNo && formik.errors.brNo)}
  790. id="brNo-signup"
  791. type="text"
  792. value={formik.values.brNo.trim()}
  793. name="brNo"
  794. onChange={formik.handleChange}
  795. onBlur={formik.handleBlur}
  796. placeholder="與商業登記證相同"
  797. inputProps={{
  798. onKeyDown: (e) => {
  799. if (e.key === 'Enter') {
  800. e.preventDefault();
  801. }
  802. },
  803. }}
  804. />
  805. {formik.touched.brNo && formik.errors.brNo && (
  806. <FormHelperText error id="helper-text-brNo-signup">
  807. {formik.errors.brNo}
  808. </FormHelperText>
  809. )}
  810. </Stack>
  811. </Grid>
  812. <Grid item xs={12} md={6}>
  813. <Stack spacing={1}>
  814. <InputLabel htmlFor="brExpiryDate-signup">
  815. <Typography variant="pnspsFormHeader">
  816. 商業登記證有效日期
  817. <span style={{ color: '#f10000' }}>*</span>
  818. </Typography>
  819. </InputLabel>
  820. <OutlinedInput
  821. fullWidth
  822. error={Boolean(formik.touched.brExpiryDate && formik.errors.brExpiryDate)}
  823. id="brExpiryDate-signup"
  824. type="date"
  825. value={formik.values.brExpiryDate}
  826. name="brExpiryDate"
  827. onChange={formik.handleChange}
  828. onBlur={formik.handleBlur}
  829. placeholder="與商業登記證相同"
  830. inputProps={{
  831. max: "2099-12-31",
  832. min: new Date().toISOString().split("T")[0],
  833. onKeyDown: (e) => {
  834. if (e.key === 'Enter') {
  835. e.preventDefault();
  836. }
  837. },
  838. }}
  839. />
  840. {formik.touched.brExpiryDate && formik.errors.brExpiryDate && (
  841. <FormHelperText error id="helper-text-brExpiryDate-signup">
  842. {formik.errors.brExpiryDate}
  843. </FormHelperText>
  844. )}
  845. </Stack>
  846. </Grid>
  847. <Grid item xs={12}>
  848. <Stack spacing={1}>
  849. <InputLabel htmlFor="address1-signup">
  850. <Typography variant="pnspsFormHeader">
  851. 地址
  852. <span style={{ color: '#f10000' }}>*</span>
  853. </Typography>
  854. </InputLabel>
  855. <OutlinedInput
  856. fullWidth
  857. error={Boolean(formik.touched.address1 && formik.errors.address1)}
  858. id="address1-signup"
  859. value={formik.values.address1}
  860. name="address1"
  861. onChange={formik.handleChange}
  862. placeholder="第一行"
  863. onBlur={formik.handleBlur}
  864. inputProps={{
  865. onKeyDown: (e) => {
  866. if (e.key === 'Enter') {
  867. e.preventDefault();
  868. }
  869. },
  870. }}
  871. />
  872. <OutlinedInput
  873. fullWidth
  874. error={Boolean(formik.touched.address2 && formik.errors.address2)}
  875. id="address2-signup"
  876. value={formik.values.address2}
  877. name="address2"
  878. onChange={formik.handleChange}
  879. placeholder="第二行"
  880. inputProps={{
  881. onKeyDown: (e) => {
  882. if (e.key === 'Enter') {
  883. e.preventDefault();
  884. }
  885. },
  886. }}
  887. />
  888. <OutlinedInput
  889. fullWidth
  890. error={Boolean(formik.touched.address3 && formik.errors.address3)}
  891. id="address3-signup"
  892. value={formik.values.address3}
  893. name="address3"
  894. onChange={formik.handleChange}
  895. placeholder="第三行"
  896. inputProps={{
  897. onKeyDown: (e) => {
  898. if (e.key === 'Enter') {
  899. e.preventDefault();
  900. }
  901. },
  902. }}
  903. />
  904. <Autocomplete
  905. disablePortal
  906. id="address4-combo"
  907. value={selectedAddress4}
  908. options={address4ComboList}
  909. disabled={checkCountry}
  910. onChange={(event, newValue) => {
  911. setSelectedAddress4(newValue);
  912. }}
  913. sx={{ "& .MuiInputBase-root": { height: "41px" }, "#address4-combo": { padding: "0px 0px 0px 3px" }, "& .MuiAutocomplete-endAdornment": { top: "auto" }, }}
  914. renderInput={(params) => <TextField {...params} placeholder="區域 (只適用於香港)" />}
  915. />
  916. <Autocomplete
  917. disablePortal
  918. id="address5-combo"
  919. value={selectedAddress5}
  920. options={address5ComboList}
  921. onChange={(event, newValue) => {
  922. if (newValue !== null) {
  923. setSelectedAddress5(newValue);
  924. if (newValue === '香港') {
  925. setCheckCountry(false)
  926. } else {
  927. setSelectedAddress4("");
  928. setCheckCountry(true)
  929. }
  930. } else {
  931. setSelectedAddress4("");
  932. setCheckCountry(true)
  933. }
  934. }}
  935. sx={{ "& .MuiInputBase-root": { height: "41px" }, "#address5-combo": { padding: "0px 0px 0px 3px" }, "& .MuiAutocomplete-endAdornment": { top: "auto" }, }}
  936. renderInput={(params) => <TextField {...params} placeholder="國家/地區" />}
  937. />
  938. {formik.touched.address1 && formik.errors.address1 && (
  939. <FormHelperText error id="helper-text-address1-signup">
  940. {formik.errors.address1}
  941. </FormHelperText>
  942. )}
  943. {formik.touched.address2 && formik.errors.address2 && (
  944. <FormHelperText error id="helper-text-address2-signup">
  945. {formik.errors.address2}
  946. </FormHelperText>
  947. )}
  948. {formik.touched.address3 && formik.errors.address3 && (
  949. <FormHelperText error id="helper-text-address3-signup">
  950. {formik.errors.address3}
  951. </FormHelperText>
  952. )}
  953. </Stack>
  954. </Grid>
  955. <Grid item xs={12} mt={1} mb={1}>
  956. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  957. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>你的聯絡資料</Typography>
  958. </Stack>
  959. </Grid>
  960. <Grid item xs={12} md={12}>
  961. <Stack spacing={1}>
  962. <InputLabel htmlFor="enName-signup">
  963. <Typography variant="pnspsFormHeader">
  964. 姓名
  965. <span style={{ color: '#f10000' }}>*</span>
  966. </Typography>
  967. </InputLabel>
  968. <OutlinedInput
  969. id="enName-login"
  970. type="enName"
  971. value={formik.values.enName}
  972. name="enName"
  973. onChange={formik.handleChange}
  974. placeholder=""
  975. fullWidth
  976. error={Boolean(formik.touched.enName && formik.errors.enName)}
  977. onBlur={formik.handleBlur}
  978. inputProps={{
  979. onKeyDown: (e) => {
  980. if (e.key === 'Enter') {
  981. e.preventDefault();
  982. }
  983. },
  984. }}
  985. />
  986. {formik.touched.enName && formik.errors.enName && (
  987. <FormHelperText error id="helper-text-enName-signup">
  988. {formik.errors.enName}
  989. </FormHelperText>
  990. )}
  991. </Stack>
  992. </Grid>
  993. <Grid item xs={12} md={12}>
  994. <Grid container>
  995. <Grid item xs={12} md={6}>
  996. <Stack spacing={1} sx={{ mr: { md: 1 }, mb: 1 }}>
  997. <InputLabel htmlFor="email-signup">
  998. <Typography variant="pnspsFormHeader">
  999. 電郵
  1000. <span style={{ color: '#f10000' }}>*</span>
  1001. </Typography>
  1002. </InputLabel>
  1003. <OutlinedInput
  1004. fullWidth
  1005. error={Boolean((formik.touched.email && formik.errors.email) || checkEmail)}
  1006. id="email-login"
  1007. type="email"
  1008. value={formik.values.email.trim()}
  1009. name="email"
  1010. onChange={formik.handleChange}
  1011. placeholder="電郵"
  1012. onBlur={formik.handleBlur}
  1013. inputProps={{
  1014. onKeyDown: (e) => {
  1015. if (e.key === 'Enter') {
  1016. e.preventDefault();
  1017. }
  1018. },
  1019. }}
  1020. />
  1021. {formik.touched.email && formik.errors.email && (
  1022. <FormHelperText error id="helper-text-email-signup">
  1023. {formik.errors.email}
  1024. </FormHelperText>
  1025. )}
  1026. {checkEmail && (
  1027. <FormHelperText error id="helper-text-email-signup">
  1028. 此電郵已被注冊,請使用其他電郵
  1029. </FormHelperText>
  1030. )}
  1031. </Stack>
  1032. </Grid>
  1033. <Grid item xs={12} md={6}>
  1034. <Stack spacing={1} >
  1035. <InputLabel htmlFor="emailConfirm-signup">
  1036. <Typography variant="pnspsFormHeader">
  1037. 確認電郵
  1038. <span style={{ color: '#f10000' }}>*</span>
  1039. </Typography>
  1040. </InputLabel>
  1041. <OutlinedInput
  1042. fullWidth
  1043. error={Boolean(formik.touched.emailConfirm && formik.errors.emailConfirm)}
  1044. id="emailConfirm-login"
  1045. type="email"
  1046. value={formik.values.emailConfirm.trim()}
  1047. name="emailConfirm"
  1048. // onBlur={formik.handleBlur}
  1049. onChange={formik.handleChange}
  1050. placeholder="確認電郵"
  1051. onBlur={formik.handleBlur}
  1052. inputProps={{
  1053. onKeyDown: (e) => {
  1054. if (e.key === 'Enter') {
  1055. e.preventDefault();
  1056. }
  1057. },
  1058. }}
  1059. />
  1060. {formik.touched.emailConfirm && formik.errors.emailConfirm && (
  1061. <FormHelperText error id="helper-text-emailConfirm-signup">
  1062. {formik.errors.emailConfirm}
  1063. </FormHelperText>
  1064. )}
  1065. </Stack>
  1066. </Grid>
  1067. </Grid>
  1068. </Grid>
  1069. <Grid item xs={12} md={12}>
  1070. <Grid container>
  1071. <Grid item xs={12} md={6}>
  1072. <Grid container>
  1073. <Grid item xs={12} md={12}>
  1074. <Stack direction="column" spacing={1} sx={{ mr: { md: 1 }, mb: 1 }}>
  1075. <InputLabel htmlFor="phone-signup">
  1076. <Typography variant="pnspsFormHeader">
  1077. 聯絡電話
  1078. <span style={{ color: '#f10000' }}>*</span>
  1079. </Typography>
  1080. </InputLabel>
  1081. <Stack direction="row">
  1082. <OutlinedInput
  1083. id="phoneCountryCode-login"
  1084. type="phoneCountryCode"
  1085. value={formik.values.phoneCountryCode.trim()}
  1086. name="phoneCountryCode"
  1087. // onBlur={formik.handleBlur}
  1088. // onChange={formik.handleChange}
  1089. onChange={(event) => {
  1090. const value = event.target.value;
  1091. if (value.match(/[^0-9]/)) {
  1092. return event.preventDefault();
  1093. }
  1094. formik.setFieldValue("phoneCountryCode", value);
  1095. }}
  1096. endAdornment={<InputAdornment position="end">-</InputAdornment>}
  1097. placeholder="國際區號"
  1098. error={Boolean(formik.touched.phone && formik.errors.phone)}
  1099. onBlur={formik.handleBlur}
  1100. inputProps={{
  1101. maxLength: 3,
  1102. onKeyDown: (e) => {
  1103. if (e.key === 'Enter') {
  1104. e.preventDefault();
  1105. }
  1106. },
  1107. }}
  1108. sx={{ width: '33%', mr:1 }}
  1109. />
  1110. <OutlinedInput
  1111. id="phone-login"
  1112. type="phone"
  1113. value={formik.values.phone.trim()}
  1114. name="phone"
  1115. onBlur={formik.handleBlur}
  1116. // onChange={formik.handleChange}
  1117. onChange={(event) => {
  1118. const value = event.target.value;
  1119. if (value.match(/[^0-9]/)) {
  1120. return event.preventDefault();
  1121. }
  1122. formik.setFieldValue("phone", value);
  1123. }}
  1124. placeholder="聯絡電話"
  1125. error={Boolean(formik.touched.phone && formik.errors.phone)}
  1126. inputProps={{
  1127. maxLength: 11,
  1128. onKeyDown: (e) => {
  1129. if (e.key === 'Enter') {
  1130. e.preventDefault();
  1131. }
  1132. },
  1133. }}
  1134. sx={{ width: '66%' }}
  1135. />
  1136. </Stack>
  1137. {formik.touched.phone && formik.errors.phone && (
  1138. <FormHelperText error id="helper-text-phone-signup">
  1139. {formik.errors.phone}
  1140. </FormHelperText>
  1141. )}
  1142. </Stack>
  1143. </Grid>
  1144. </Grid>
  1145. </Grid>
  1146. <Grid item xs={12} md={6}>
  1147. <Grid container>
  1148. <Grid item xs={12} md={12}>
  1149. <Stack spacing={1} direction="column">
  1150. <InputLabel htmlFor="fax-signup">
  1151. <Typography variant="pnspsFormHeader">
  1152. 傳真號碼
  1153. </Typography>
  1154. </InputLabel>
  1155. <Stack direction="row">
  1156. <OutlinedInput
  1157. error={Boolean(formik.touched.fax && formik.errors.fax)}
  1158. id="faxCountryCode-login"
  1159. type="faxCountryCode"
  1160. value={formik.values.faxCountryCode.trim()}
  1161. name="faxCountryCode"
  1162. // onBlur={formik.handleBlur}
  1163. // onChange={formik.handleChange}
  1164. onChange={(event) => {
  1165. const value = event.target.value;
  1166. if (value.match(/[^0-9]/)) {
  1167. return event.preventDefault();
  1168. }
  1169. formik.setFieldValue("faxCountryCode", value);
  1170. }}
  1171. placeholder="國際區號"
  1172. endAdornment={<InputAdornment position="end">-</InputAdornment>}
  1173. inputProps={{
  1174. maxLength: 3,
  1175. onKeyDown: (e) => {
  1176. if (e.key === 'Enter') {
  1177. e.preventDefault();
  1178. }
  1179. },
  1180. }}
  1181. sx={{ width: '33%', mr:1 }}
  1182. />
  1183. <OutlinedInput
  1184. id="fax-login"
  1185. type="fax"
  1186. value={formik.values.fax.trim()}
  1187. name="fax"
  1188. // onBlur={formik.handleBlur}
  1189. // onChange={formik.handleChange}
  1190. onChange={(event) => {
  1191. const value = event.target.value;
  1192. if (value.match(/[^0-9]/)) {
  1193. return event.preventDefault();
  1194. }
  1195. formik.setFieldValue("fax", value);
  1196. }}
  1197. placeholder="傳真號碼"
  1198. inputProps={{
  1199. maxLength: 8,
  1200. onKeyDown: (e) => {
  1201. if (e.key === 'Enter') {
  1202. e.preventDefault();
  1203. }
  1204. },
  1205. }}
  1206. sx={{ width: '66%' }}
  1207. />
  1208. </Stack>
  1209. </Stack>
  1210. </Grid>
  1211. </Grid>
  1212. </Grid>
  1213. </Grid>
  1214. </Grid>
  1215. <Grid item xs={12} md={12} mt={1} mb={1}>
  1216. <Grid container>
  1217. <Grid item xs={12} md={12}>
  1218. <Stack spacing={1} direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1219. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>商業登記證及其他文件
  1220. <span style={{ color: '#f10000' }}>*</span>
  1221. </Typography>
  1222. <Typography display="inline" variant="h6" sx={{ color: 'primary.primary' }}>請上傳你的 有效商業登記證及其他文件 的數碼檔案,以驗證你的身份。</Typography>
  1223. {/* <Typography display="inline" variant="h6" sx={{ fontSize: 12,color: 'primary.primary'}}>如: 香港身份證; 護照; 中國內地身份證等</Typography> */}
  1224. <Stack mt={1} direction="row" justifyContent="flex-start" alignItems="center" spacing={2}>
  1225. <ThemeProvider theme={PNSPS_LONG_BUTTON_THEME}>
  1226. <Button variant="contained" component="label" sx={{ height: '40px' }}>
  1227. 上傳商業登記證及其他文件
  1228. <input
  1229. accept="image/png, .jpg, .bmp, .pdf"
  1230. //className={classes.input}
  1231. id="contained-button-file"
  1232. multiple
  1233. type="file"
  1234. onChange={handleFileUpload}
  1235. style={{ display: 'none' }}
  1236. />
  1237. </Button>
  1238. </ThemeProvider>
  1239. {/* <Typography display="inline" variant="h6" sx={{ fontSize: 12, color: 'primary.primary'}}></Typography> */}
  1240. </Stack>
  1241. {fileList != null ?
  1242. <UploadFileTable key="uploadTable" recordList={fileListData} setUpdateRows={setUpdateRows} /> : null}
  1243. {/* <Stack mt={1} direction="row" justifyContent="flex-start" alignItems="center" spacing={2}>
  1244. <Button variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button>
  1245. <Button disabled={!formik.isValid} variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button>
  1246. </Stack> */}
  1247. </Stack>
  1248. </Grid>
  1249. </Grid>
  1250. </Grid>
  1251. </Grid>
  1252. <Grid item xs={12} md={12}>
  1253. <Grid container>
  1254. <Grid item xs={12} md={12}>
  1255. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>
  1256. 條款和條件
  1257. <span style={{ color: '#f10000' }}>*</span>
  1258. </Typography>
  1259. </Grid>
  1260. <Grid item xs={12} md={12}>
  1261. <Grid container>
  1262. <Grid item xs={12} md={12}>
  1263. <Typography variant="h6" height="100%" sx={{ textAlign: "left", /*overflow: "scroll",*/ borderRadius: "inherit", borderStyle: "solid", borderWidth: "1px", borderColor: "#0C489E" }}>
  1264. {termsAndCon}
  1265. </Typography>
  1266. </Grid>
  1267. </Grid>
  1268. <Grid item xs={12} s={12} md={12} lg={12}>
  1269. <Grid container>
  1270. <Grid item xs={6} s={6} md={2} lg={2}>
  1271. <Grid container>
  1272. <Grid item sx={{ display: 'flex', alignItems: 'center' }}>
  1273. <Checkbox
  1274. checked={termsAndConAccept}
  1275. onChange={handleCheckBoxChange}
  1276. name="termsAndConAccept"
  1277. color="primary"
  1278. size="small"
  1279. />
  1280. <Typography variant="pnspsFormHeader">我接受</Typography>
  1281. </Grid>
  1282. </Grid>
  1283. </Grid>
  1284. <Grid item xs={6} s={6} md={2} lg={2}>
  1285. <Grid container>
  1286. <Grid item sx={{ display: 'flex', alignItems: 'center' }}>
  1287. <Checkbox
  1288. checked={termsAndConNotAccept}
  1289. onChange={handleCheckBoxChange}
  1290. name="termsAndConNotAccept"
  1291. color="primary"
  1292. size="small"
  1293. />
  1294. <Typography variant="pnspsFormHeader">我不接受</Typography>
  1295. </Grid>
  1296. </Grid>
  1297. </Grid>
  1298. </Grid>
  1299. </Grid>
  1300. </Grid>
  1301. </Grid>
  1302. </Grid>
  1303. <Grid item xs={12} lg={12}>
  1304. <Grid container>
  1305. <Stack direction="column">
  1306. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>
  1307. 驗證
  1308. <span style={{ color: '#f10000' }}>*</span>
  1309. </Typography>
  1310. <Stack spacing={1} direction="row">
  1311. <Grid item xs={5} lg={5} style={{ "border": "1px solid black" }}>
  1312. <img src={captchaImg} alt="" />
  1313. </Grid>
  1314. <Grid item xs={1} lg={1} style={{ "border": "0px solid black" }}>
  1315. <IconButton aria-label="refrashCaptcha" size="large" onClick={() => { onCaptchaChange() }}>
  1316. <LoopIcon fontSize="inherit" />
  1317. </IconButton>
  1318. </Grid>
  1319. <Grid item xs={6} lg={6}>
  1320. <OutlinedInput
  1321. fullWidth
  1322. id="captchaField"
  1323. type="text"
  1324. value={formik.values.captchaField.trim()}
  1325. onBlur={formik.handleBlur}
  1326. error={Boolean(formik.touched.captchaField && formik.errors.captchaField)}
  1327. name="captchaField"
  1328. onChange={(event) => {
  1329. const value = event.target.value;
  1330. props.setCheckCode(event.target.value);
  1331. formik.setFieldValue("captchaField", value);
  1332. }}
  1333. sx={{ width: '75%' }}
  1334. />
  1335. </Grid>
  1336. </Stack>
  1337. {formik.touched.captchaField && formik.errors.captchaField && (
  1338. <FormHelperText error id="helper-text-captcha-signup">
  1339. {formik.errors.captchaField}
  1340. </FormHelperText>
  1341. )}
  1342. </Stack>
  1343. </Grid>
  1344. </Grid>
  1345. </Grid>
  1346. </Grid>
  1347. </FormGroup>
  1348. {/* Preview Form */}
  1349. <FormGroup id={"previewForm"} sx={{ display: props.step === 1 ? "" : "none" }}>
  1350. <Grid container spacing={2}>
  1351. <Grid item xs={12}>
  1352. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1353. <div style={{ borderBottom: "3px solid #1A4399", width: "100%", margin_right: "15px" }}>
  1354. <Typography display="inline" variant="h3" sx={{ color: '#1A4399' }}>
  1355. <FormattedMessage id="becomeNewBusinessUser"/>
  1356. </Typography>
  1357. </div>
  1358. {/* <Typography mt={0.25} variant="h6" sx={{ fontSize: 12,color: '#f10000'}}>註有*的項目必須輸入資料</Typography> */}
  1359. <Typography mt={0.25} variant="h4" sx={{ color: 'primary.primary' }}>你的登入資料</Typography>
  1360. {/* <Typography component={Link} to="/login" variant="body1" sx={{ textDecoration: 'none' }} color="primary">
  1361. Already have an account?
  1362. </Typography> */}
  1363. </Stack>
  1364. </Grid>
  1365. <Grid item xs={12}>
  1366. <Grid container spacing={1}>
  1367. <Grid item xs={12} >
  1368. <Stack spacing={1} direction="row">
  1369. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  1370. {intl.formatMessage({id: 'userLoginName'})}:
  1371. </Typography>
  1372. <Typography variant="pnspsFormHeader" id="preview-username-login">
  1373. {formik.values.username}
  1374. </Typography>
  1375. </Stack>
  1376. </Grid>
  1377. <Grid item xs={12} mt={1} mb={1}>
  1378. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1379. <Typography display="inline" variant="h4" /*sx={{ color: '#1A4399' }}*/>你的機構/公司資料</Typography>
  1380. {/* <Typography component={Link} to="/login" variant="body1" sx={{ textDecoration: 'none' }} color="primary">
  1381. Already have an account?
  1382. </Typography> */}
  1383. </Stack>
  1384. </Grid>
  1385. <Grid item xs={12} md={6}>
  1386. <Stack spacing={1} direction="row">
  1387. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  1388. 機構/公司英文名稱:
  1389. </Typography>
  1390. <Typography variant="pnspsFormHeader" id="preview-enCompanyName-signup">
  1391. {formik.values.enCompanyName}
  1392. </Typography>
  1393. </Stack>
  1394. </Grid>
  1395. <Grid item xs={12} md={6}>
  1396. <Stack spacing={1} direction="row">
  1397. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  1398. 機構/公司中文名稱:
  1399. </Typography>
  1400. <Typography variant="pnspsFormHeader" id="preview-chCompanyName-signup">
  1401. {formik.values.chCompanyName}
  1402. </Typography>
  1403. </Stack>
  1404. </Grid>
  1405. <Grid item xs={12} md={12} >
  1406. <Stack spacing={1}>
  1407. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  1408. 商業登記證
  1409. </Typography>
  1410. </Stack>
  1411. </Grid>
  1412. <Grid item xs={12} md={6}>
  1413. <Stack spacing={1} direction="row">
  1414. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  1415. 商業登記證號碼:
  1416. </Typography>
  1417. <Typography variant="pnspsFormHeader" id="brNo-login">
  1418. {formik.values.brNo}
  1419. </Typography>
  1420. </Stack>
  1421. </Grid>
  1422. <Grid item xs={12} md={6}>
  1423. <Stack spacing={1} direction="row">
  1424. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  1425. 商業登記證有效日期:
  1426. </Typography>
  1427. <Typography variant="pnspsFormHeader" id="brExpiryDate-login">
  1428. {formik.values.brExpiryDate}
  1429. </Typography>
  1430. </Stack>
  1431. </Grid>
  1432. <Grid item xs={12}>
  1433. <Stack spacing={1} direction="row">
  1434. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  1435. 地址:
  1436. </Typography>
  1437. <Stack spacing={1} direction="column">
  1438. <Typography variant="pnspsFormHeader" id="preview-address1-signup">
  1439. {formik.values.address1}
  1440. </Typography>
  1441. {formik.values.address2 != null ?
  1442. <Typography variant="pnspsFormHeader" id="preview-address2-signup">
  1443. {formik.values.address2}
  1444. </Typography>
  1445. : null}
  1446. {formik.values.address3 != null ?
  1447. <Typography variant="pnspsFormHeader" id="preview-address3-signup">
  1448. {formik.values.address3}
  1449. </Typography>
  1450. : null}
  1451. {selectedAddress5 === "香港" ?
  1452. <Stack direction="row">
  1453. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]} id="preview-address4-signup">
  1454. 區域 (只適用於香港):
  1455. </Typography>
  1456. <Typography variant="pnspsFormHeader">
  1457. {selectedAddress4}
  1458. </Typography>
  1459. </Stack>
  1460. : null}
  1461. <Stack direction="row">
  1462. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]} id="preview-address5-signup">
  1463. 國家/地區:
  1464. </Typography>
  1465. <Typography variant="pnspsFormHeader">
  1466. {selectedAddress5}
  1467. </Typography>
  1468. </Stack>
  1469. </Stack>
  1470. </Stack>
  1471. </Grid>
  1472. <Grid item xs={12} mt={1} mb={1}>
  1473. <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1474. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>你的聯絡資料</Typography>
  1475. </Stack>
  1476. </Grid>
  1477. <Grid item xs={12} md={12}>
  1478. <Stack spacing={1} direction="row">
  1479. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  1480. 英文名稱:
  1481. </Typography>
  1482. <Typography variant="pnspsFormHeader" id="preview-enName-signup">
  1483. {formik.values.enName}
  1484. </Typography>
  1485. </Stack>
  1486. </Grid>
  1487. <Grid item xs={12} md={12}>
  1488. <Stack spacing={1} direction="row">
  1489. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  1490. 電郵:
  1491. </Typography>
  1492. <Typography variant="pnspsFormHeader" id="preview-email-signup">
  1493. {formik.values.email}
  1494. </Typography>
  1495. </Stack>
  1496. </Grid>
  1497. <Grid item xs={12} md={6}>
  1498. <Stack spacing={1} direction="row">
  1499. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  1500. 聯絡電話:
  1501. </Typography>
  1502. <Typography variant="pnspsFormHeader" id="preview-phone-signup">
  1503. +{formik.values.phoneCountryCode} {formik.values.phone}
  1504. </Typography>
  1505. </Stack>
  1506. </Grid>
  1507. <Grid item xs={12} md={6}>
  1508. <Stack spacing={1} direction="row">
  1509. <Typography variant="pnspsFormHeader" color={theme.palette.grey[600]}>
  1510. 傳真號碼:
  1511. </Typography>
  1512. <Typography variant="pnspsFormHeader" id="preview-fax-signup">
  1513. +{formik.values.faxCountryCode} {formik.values.fax}
  1514. </Typography>
  1515. </Stack>
  1516. </Grid>
  1517. <Grid item xs={12} md={12} mt={1} mb={1}>
  1518. <Grid container>
  1519. <Grid item xs={12} md={12}>
  1520. <Stack spacing={1} direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
  1521. <Typography display="inline" variant="h4" sx={{ color: 'primary.primary' }}>身份證明文件</Typography>
  1522. {fileList != null ?
  1523. <PreviewUploadFileTable key="previewTable" recordList={fileListData} /> : null}
  1524. </Stack>
  1525. </Grid>
  1526. </Grid>
  1527. </Grid>
  1528. </Grid>
  1529. </Grid>
  1530. </Grid>
  1531. </FormGroup>
  1532. {/* Submit page */}
  1533. <FormGroup id={"submitForm"} sx={{ display: props.step === 2 ? "" : "none" }}>
  1534. <Grid container spacing={3}>
  1535. {isLoading ?
  1536. <LoadingComponent /> :
  1537. <Grid item xs={12}>
  1538. {checkUpload ?
  1539. // SUCCESS page
  1540. <Stack mt={1} direction="column" justifyContent="flex-start" alignItems="center" spacing={2}>
  1541. <CheckCircleOutlineIcon color="success" sx={{ width: "200px", height: "200px" }} />
  1542. <Typography display="inline" variant="h4">帳戶申請已成功提交。</Typography>
  1543. <Typography display="inline" variant="h4">驗證電郵將發送到你的電郵地址,請依指示完成驗證及登入系統。</Typography>
  1544. <Button variant="outlined" component={Link} to="/login" sx={{ fontSize: 20, height: '60px' }}><Typography variant="pnspsFormHeader">返回登入頁面</Typography></Button>
  1545. </Stack>
  1546. :
  1547. // ERROR page
  1548. <Stack mt={1} direction="column" justifyContent="flex-start" alignItems="center" spacing={2}>
  1549. {/* <Button disabled={true} hidden={true} variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button> */}
  1550. <CancelOutlinedIcon color="error" sx={{ width: "200px", height: "200px" }} />
  1551. <Typography display="inline" variant="h4">申請失敗,請稍後嘗試</Typography>
  1552. <Button color="error" variant="outlined" component={Link} to="/login" sx={{ fontSize: 20, height: '60px' }}><Typography variant="pnspsFormHeader">返回登入頁面</Typography></Button>
  1553. </Stack>
  1554. }
  1555. </Grid>
  1556. }
  1557. </Grid>
  1558. </FormGroup>
  1559. </form>
  1560. </FormikProvider>
  1561. );
  1562. }
  1563. export default BusCustomFormWizard;