您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 

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