| @@ -19,6 +19,7 @@ | |||||
| "@mui/lab": "^5.0.0-alpha.139", | "@mui/lab": "^5.0.0-alpha.139", | ||||
| "@mui/material": "^5.10.6", | "@mui/material": "^5.10.6", | ||||
| "@mui/x-data-grid": "^6.11.1", | "@mui/x-data-grid": "^6.11.1", | ||||
| "@mui/x-date-pickers": "^6.12.0", | |||||
| "@reduxjs/toolkit": "^1.8.5", | "@reduxjs/toolkit": "^1.8.5", | ||||
| "@testing-library/jest-dom": "^5.16.5", | "@testing-library/jest-dom": "^5.16.5", | ||||
| "@testing-library/react": "^13.4.0", | "@testing-library/react": "^13.4.0", | ||||
| @@ -48,6 +49,7 @@ | |||||
| "react-router-dom": "^6.4.1", | "react-router-dom": "^6.4.1", | ||||
| "react-scripts": "^5.0.1", | "react-scripts": "^5.0.1", | ||||
| "react-syntax-highlighter": "^15.5.0", | "react-syntax-highlighter": "^15.5.0", | ||||
| "react-to-print": "^2.14.13", | |||||
| "react-window": "^1.8.7", | "react-window": "^1.8.7", | ||||
| "redux": "^4.2.0", | "redux": "^4.2.0", | ||||
| "simplebar": "^5.3.8", | "simplebar": "^5.3.8", | ||||
| @@ -18407,6 +18409,15 @@ | |||||
| "react": ">= 0.14.0" | "react": ">= 0.14.0" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/react-to-print": { | |||||
| "version": "2.14.13", | |||||
| "resolved": "https://registry.npmjs.org/react-to-print/-/react-to-print-2.14.13.tgz", | |||||
| "integrity": "sha512-PqUGgTRZvkyBzWgaZHVBECWPX2nGEc3HOUy6WNXof6HT4yTFI92wtIkqQtr4jfvHbadqjwTgzgh6vgN8KXlWWw==", | |||||
| "peerDependencies": { | |||||
| "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", | |||||
| "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" | |||||
| } | |||||
| }, | |||||
| "node_modules/react-transition-group": { | "node_modules/react-transition-group": { | ||||
| "version": "4.4.5", | "version": "4.4.5", | ||||
| "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", | "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", | ||||
| @@ -45,6 +45,7 @@ | |||||
| "react-router-dom": "^6.4.1", | "react-router-dom": "^6.4.1", | ||||
| "react-scripts": "^5.0.1", | "react-scripts": "^5.0.1", | ||||
| "react-syntax-highlighter": "^15.5.0", | "react-syntax-highlighter": "^15.5.0", | ||||
| "react-to-print": "^2.14.13", | |||||
| "react-window": "^1.8.7", | "react-window": "^1.8.7", | ||||
| "redux": "^4.2.0", | "redux": "^4.2.0", | ||||
| "simplebar": "^5.3.8", | "simplebar": "^5.3.8", | ||||
| @@ -48,11 +48,7 @@ | |||||
| const BusRegister = () => { | const BusRegister = () => { | ||||
| const [activeStep, setActiveStep] = useState(0); | const [activeStep, setActiveStep] = useState(0); | ||||
| const [completed, setCompleted] = useState([false]); | const [completed, setCompleted] = useState([false]); | ||||
| const uploadStep = (value) => { | |||||
| setActiveStep(value); | |||||
| console.log(value) | |||||
| }; | |||||
| const [updateValid, setUpdateValid] = useState(false); | |||||
| const totalSteps = () => { | const totalSteps = () => { | ||||
| return steps.length; | return steps.length; | ||||
| @@ -71,7 +67,6 @@ | |||||
| }; | }; | ||||
| const handleNext = () => { | const handleNext = () => { | ||||
| console.log("test 1") | |||||
| const newActiveStep = | const newActiveStep = | ||||
| isLastStep() && !allStepsCompleted() | isLastStep() && !allStepsCompleted() | ||||
| ? // It's the last step, but not all steps have been completed, | ? // It's the last step, but not all steps have been completed, | ||||
| @@ -140,7 +135,7 @@ | |||||
| ) : ( | ) : ( | ||||
| <React.Fragment> | <React.Fragment> | ||||
| <AuthWrapper> | <AuthWrapper> | ||||
| <CustomFormWizard uploadStep={uploadStep} step={activeStep} /> | |||||
| <CustomFormWizard setUpdateValid={setUpdateValid} step={activeStep} /> | |||||
| {/* <CustomFormWizard step={activeStep} /> */} | {/* <CustomFormWizard step={activeStep} /> */} | ||||
| </AuthWrapper> | </AuthWrapper> | ||||
| <Stack direction="row" sx={{ pt: 2 }}> | <Stack direction="row" sx={{ pt: 2 }}> | ||||
| @@ -178,7 +173,7 @@ | |||||
| </Button> | </Button> | ||||
| ): | ): | ||||
| ( | ( | ||||
| <Button variant="outlined" onClick={handleNext} sx={{ mr: 1 }}> | |||||
| <Button disabled={!updateValid} variant="outlined" onClick={handleNext} sx={{ mr: 1 }}> | |||||
| 繼續 | 繼續 | ||||
| </Button> | </Button> | ||||
| ) | ) | ||||
| @@ -1,5 +1,7 @@ | |||||
| // import { Link } from 'react-router-dom'; | // import { Link } from 'react-router-dom'; | ||||
| import React,{useState} from 'react'; | |||||
| import React,{useState | |||||
| // ,useEffect | |||||
| } from 'react'; | |||||
| // material-ui | // material-ui | ||||
| import { | import { | ||||
| @@ -48,11 +50,7 @@ | |||||
| const Register = () => { | const Register = () => { | ||||
| const [activeStep, setActiveStep] = useState(0); | const [activeStep, setActiveStep] = useState(0); | ||||
| const [completed, setCompleted] = useState([false]); | const [completed, setCompleted] = useState([false]); | ||||
| const uploadStep = (value) => { | |||||
| setActiveStep(value); | |||||
| console.log(value) | |||||
| }; | |||||
| const [updateValid, setUpdateValid] = useState(false); | |||||
| const totalSteps = () => { | const totalSteps = () => { | ||||
| return steps.length; | return steps.length; | ||||
| @@ -71,7 +69,6 @@ | |||||
| }; | }; | ||||
| const handleNext = () => { | const handleNext = () => { | ||||
| console.log("test 1") | |||||
| const newActiveStep = | const newActiveStep = | ||||
| isLastStep() && !allStepsCompleted() | isLastStep() && !allStepsCompleted() | ||||
| ? // It's the last step, but not all steps have been completed, | ? // It's the last step, but not all steps have been completed, | ||||
| @@ -80,6 +77,7 @@ | |||||
| : activeStep + 1; | : activeStep + 1; | ||||
| setActiveStep(newActiveStep); | setActiveStep(newActiveStep); | ||||
| console.log(newActiveStep) | console.log(newActiveStep) | ||||
| }; | }; | ||||
| const handleBack = () => { | const handleBack = () => { | ||||
| @@ -140,11 +138,11 @@ | |||||
| ) : ( | ) : ( | ||||
| <React.Fragment> | <React.Fragment> | ||||
| <AuthWrapper> | <AuthWrapper> | ||||
| <CustomFormWizard uploadStep={uploadStep} step={activeStep} /> | |||||
| <CustomFormWizard setUpdateValid={setUpdateValid} step={activeStep} /> | |||||
| {/* <CustomFormWizard step={activeStep} /> */} | {/* <CustomFormWizard step={activeStep} /> */} | ||||
| </AuthWrapper> | </AuthWrapper> | ||||
| <Stack direction="row" sx={{ pt: 2 }}> | <Stack direction="row" sx={{ pt: 2 }}> | ||||
| { activeStep === totalSteps() - 1 ? ( | |||||
| { activeStep === 2|| activeStep === 0? ( | |||||
| <Button | <Button | ||||
| color="inherit" | color="inherit" | ||||
| disabled={true} | disabled={true} | ||||
| @@ -178,7 +176,7 @@ | |||||
| </Button> | </Button> | ||||
| ): | ): | ||||
| ( | ( | ||||
| <Button variant="outlined" onClick={handleNext} sx={{ mr: 1 }}> | |||||
| <Button disabled={!updateValid} variant="outlined" onClick={handleNext} sx={{ mr: 1 }}> | |||||
| 繼續 | 繼續 | ||||
| </Button> | </Button> | ||||
| ) | ) | ||||
| @@ -21,7 +21,7 @@ import Autocomplete from "@mui/material/Autocomplete"; | |||||
| // third party | // third party | ||||
| import { useFormik,FormikProvider } from 'formik'; | import { useFormik,FormikProvider } from 'formik'; | ||||
| import * as Yup from 'yup'; | |||||
| import * as yup from 'yup'; | |||||
| // import axios from "axios"; | // import axios from "axios"; | ||||
| // project import | // project import | ||||
| @@ -49,7 +49,6 @@ const BusCustomFormWizard = (props) => { | |||||
| const [showConfirmPassword, setshowConfirmPassword] = useState(false); | const [showConfirmPassword, setshowConfirmPassword] = useState(false); | ||||
| const [fileList, setFileList] = useState([]); | const [fileList, setFileList] = useState([]); | ||||
| const [fileListData, setFileListData] = useState([]); | const [fileListData, setFileListData] = useState([]); | ||||
| const [uploadStep, setUploadStep] = useState(0); | |||||
| const [checkUpload, setCheckUpload] = useState(false); | const [checkUpload, setCheckUpload] = useState(false); | ||||
| const handleClickShowPassword = () => { | const handleClickShowPassword = () => { | ||||
| @@ -72,33 +71,49 @@ const BusCustomFormWizard = (props) => { | |||||
| const [selectedAddress5, setSelectedAddress5] = useState("香港"); | const [selectedAddress5, setSelectedAddress5] = useState("香港"); | ||||
| const [termsAndConAccept, setTermsAndConAccept] = useState(false); | const [termsAndConAccept, setTermsAndConAccept] = useState(false); | ||||
| const [termsAndConNotAccept, setTermsAndConNotAccept] = useState(false); | const [termsAndConNotAccept, setTermsAndConNotAccept] = useState(false); | ||||
| const [isValid, setisValid] = useState(false); | |||||
| const address4ComboList = | const address4ComboList = | ||||
| ["北區","長洲區","大埔區","大嶼山區","東區","觀塘區","黃大仙區","九龍城區","葵青區","南區","南丫島區", | ["北區","長洲區","大埔區","大嶼山區","東區","觀塘區","黃大仙區","九龍城區","葵青區","南區","南丫島區", | ||||
| "坪洲區","荃灣區","沙田區","深水埗區","屯門區","灣仔區","西貢區","油尖旺區","元朗區","中西區"]; | "坪洲區","荃灣區","沙田區","深水埗區","屯門區","灣仔區","西貢區","油尖旺區","元朗區","中西區"]; | ||||
| const address5ComboList = ["香港","內地","澳門"]; | const address5ComboList = ["香港","內地","澳門"]; | ||||
| const termsAndCon = "Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy \n" | |||||
| +"Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy \n" | |||||
| +"Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy \n"+"Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy \n" | |||||
| +"Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy \n" | |||||
| +"Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy \n" | |||||
| +"Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy \n" | |||||
| +"Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy \n" | |||||
| const termsAndCon = "此網址由香港特別行政區政府物流服務署製作及管理。本署會盡力確保網址上的資料無誤,\n" | |||||
| + "但有絕對酌情權隨時刪除、暫停登載或編輯各項資料而無須給予任何理由。\n由於任何與網址" | |||||
| + "內資料有關的理由或原因,而導致出現申索、損失或損害,本署概不負責。\n使用者須自行評" | |||||
| + "估本網址所載或與本網址有關連的各項資料,並應在根據該等資料行事前,參照印行的香港" | |||||
| + "特別行政區憲報以核實該等資料,以及徵詢獨立意見。\n版權公告本網頁的內容,包括但不限" | |||||
| + "於所有文本、平面圖像、圖畫、圖片、照片以及數據或其他資料的匯編,均受版權保障。\n香" | |||||
| + "港特別行政區政府是本網頁內所有版權作品的擁有人,除非預先得到政府物流服務署的書面" | |||||
| + "授權,否則嚴禁複製、改編、分發、發布或向公眾提供該等版權作品。" | |||||
| useEffect(() => { | useEffect(() => { | ||||
| changePassword(''); | changePassword(''); | ||||
| }, []); | }, []); | ||||
| const checkDataField = (data)=> { | const checkDataField = (data)=> { | ||||
| if (data.username !=="", | |||||
| data.password !=="", | |||||
| data.enName !=="", | |||||
| data.email !=="", | |||||
| data.password !=="", | |||||
| data.password !=="" | |||||
| if (data.username !==""&& | |||||
| data.password !==""&& | |||||
| data.confirmPassword !==""&& | |||||
| data.password == data.confirmPassword&& | |||||
| data.enCompanyName !==""&& | |||||
| data.enName !==""&& | |||||
| data.address1 !==""&& | |||||
| data.email !==""&& | |||||
| data.emailConfirm !==""&& | |||||
| data.phone !==""&& | |||||
| data.phoneCountryCode !==""&& | |||||
| termsAndConAccept == true&& | |||||
| fileList.length!==0&& | |||||
| handlePassword(data.password)&& | |||||
| handleEmail(data.email)&& | |||||
| handlePhone(data.phone) | |||||
| ) | ) | ||||
| { | { | ||||
| return true | |||||
| setisValid(true) | |||||
| return isValid | |||||
| }else{ | |||||
| setisValid(false) | |||||
| return isValid | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -133,9 +148,17 @@ const BusCustomFormWizard = (props) => { | |||||
| setFileList(uploadFileList); | setFileList(uploadFileList); | ||||
| }; | }; | ||||
| useEffect(() => { | |||||
| props.setUpdateValid(isValid) | |||||
| }, [isValid]) | |||||
| useEffect(() => { | |||||
| checkDataField(values) | |||||
| }, [selectedAddress4,selectedAddress5, | |||||
| termsAndConAccept,termsAndConNotAccept,fileList]) | |||||
| useEffect(() => { | useEffect(() => { | ||||
| props.step ==2?_onSubmit():null; | props.step ==2?_onSubmit():null; | ||||
| setUploadStep(props.step) | |||||
| }, [props.step]) | }, [props.step]) | ||||
| const {handleSubmit} = useForm({}) | const {handleSubmit} = useForm({}) | ||||
| @@ -147,20 +170,14 @@ const BusCustomFormWizard = (props) => { | |||||
| "addressLine1":"", | "addressLine1":"", | ||||
| "addressLine2":"", | "addressLine2":"", | ||||
| "addressLine3":"", | "addressLine3":"", | ||||
| "district":"", | |||||
| "country":"" | "country":"" | ||||
| }; | }; | ||||
| if (values.address5=='香港'){ | |||||
| busUserAddress.addressLine1 = values.address1 | |||||
| busUserAddress.addressLine2 = values.address2 | |||||
| busUserAddress.addressLine3 = values.address3 | |||||
| busUserAddress.country = values.address5 | |||||
| }else{ | |||||
| busUserAddress.addressLine1 = values.address1 | |||||
| busUserAddress.addressLine2 = values.address2 | |||||
| busUserAddress.addressLine3 = values.address4 | |||||
| busUserAddress.country = values.address5 | |||||
| } | |||||
| busUserAddress.addressLine1 = values.address1 | |||||
| busUserAddress.addressLine2 = values.address2 | |||||
| busUserAddress.addressLine3 = values.address3 | |||||
| busUserAddress.district = values.address4 | |||||
| busUserAddress.country = values.address5 | |||||
| const userFaxNo = { | const userFaxNo = { | ||||
| "countryCode":values.faxCountryCode, | "countryCode":values.faxCountryCode, | ||||
| @@ -178,7 +195,7 @@ const BusCustomFormWizard = (props) => { | |||||
| tncFlag = false | tncFlag = false | ||||
| } | } | ||||
| if (checkDataField(values)){ | |||||
| if (isValid){ | |||||
| axios.post(`${apiPath}${POST_PUBLIC_USER_REGISTER}`, { | axios.post(`${apiPath}${POST_PUBLIC_USER_REGISTER}`, { | ||||
| username: values.username, | username: values.username, | ||||
| password: values.password, | password: values.password, | ||||
| @@ -188,7 +205,7 @@ const BusCustomFormWizard = (props) => { | |||||
| emailBus: values.email, | emailBus: values.email, | ||||
| brNo:values.brNo, | brNo:values.brNo, | ||||
| brExpiryDate:values.brExpiryDate, | brExpiryDate:values.brExpiryDate, | ||||
| faxNo:userFaxNo, | |||||
| userFaxNo:userFaxNo, | |||||
| busUserContactTel:busUserContactTel, | busUserContactTel:busUserContactTel, | ||||
| busUserAddress:busUserAddress, | busUserAddress:busUserAddress, | ||||
| contactPerson: values.enName, | contactPerson: values.enName, | ||||
| @@ -215,6 +232,43 @@ const BusCustomFormWizard = (props) => { | |||||
| } | } | ||||
| } | } | ||||
| function handlePhone(phone) { | |||||
| if (phone.length < 8) { | |||||
| return false; | |||||
| } else { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| function handlePassword(password) { | |||||
| let new_pass = password; | |||||
| // regular expressions to validate password | |||||
| var lowerCase = /[a-z]/g; | |||||
| var upperCase = /[A-Z]/g; | |||||
| var numbers = /[0-9]/g; | |||||
| if (!new_pass.match(lowerCase)) { | |||||
| return false; | |||||
| } else if (!new_pass.match(upperCase)) { | |||||
| return false; | |||||
| } else if (!new_pass.match(numbers)) { | |||||
| return false; | |||||
| } else if (new_pass.length < 8) { | |||||
| return false; | |||||
| } else { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| function handleEmail(email) { | |||||
| var reg = /^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$/; | |||||
| var result = reg.test(email); | |||||
| if (result == false) { | |||||
| return false; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| const formik = useFormik({ | const formik = useFormik({ | ||||
| initialValues:({ | initialValues:({ | ||||
| username:'', | username:'', | ||||
| @@ -235,34 +289,51 @@ const BusCustomFormWizard = (props) => { | |||||
| brExpiryDate:'', | brExpiryDate:'', | ||||
| brNo:'', | brNo:'', | ||||
| }), | }), | ||||
| validationSchema:Yup.object().shape({ | |||||
| username: Yup.string().max(255).required('請輸入用戶名稱'), | |||||
| password: Yup.string().max(255).required('請輸入密碼'), | |||||
| confirmPassword: Yup.string().max(255).required('請確認密碼'), | |||||
| enName: Yup.string().max(255).required('請輸入英文姓名'), | |||||
| chName: Yup.string().max(255).required('請輸入中文姓名'), | |||||
| address1: Yup.string().max(255).required('請輸入第一行地址'), | |||||
| address2: Yup.string().max(255).required('請輸入第二行地址'), | |||||
| address3: Yup.string().max(255).required('請輸入第三行地址'), | |||||
| email: Yup.string().email('Must be a valid email').max(255).required('Email is required'), | |||||
| idNo: Yup.string().max(255).required('請輸入證件號碼'), | |||||
| checkDigit:Yup.string().max(1).required('請輸入證件號碼'), | |||||
| idType: Yup.string().max(255).required('請輸入第三行地址')}) | |||||
| validationSchema:yup.object().shape({ | |||||
| username: yup.string().max(255).required('請輸入用戶名稱'), | |||||
| password: yup.string().min(8,'請輸入最少8位密碼').required('請輸入密碼') | |||||
| .matches(/^(?=.*[a-z])/, '請包括最少1個小寫字母') | |||||
| .matches(/^(?=.*[A-Z])/, '請包括最少1個大寫字母') | |||||
| .matches(/^(?=.*[0-9])/, '請包括最少1個數字') | |||||
| .matches(/^(?=.*[!@#%&])/, '請包括最少1個特殊字符'), | |||||
| confirmPassword: yup.string().min(8,'請最少輸入8位密碼').required('請確認密碼').oneOf([yup.ref('password'), null], '請輸入相同密碼'), | |||||
| enName: yup.string().max(255).required('請輸入英文姓名'), | |||||
| enCompanyName: yup.string().max(255).required('請輸入英文名稱'), | |||||
| chName: yup.string().max(255).required('請輸入中文姓名'), | |||||
| address1: yup.string().max(255).required('請輸入第一行地址'), | |||||
| address2: yup.string().max(255).required('請輸入第二行地址'), | |||||
| address3: yup.string().max(255).required('請輸入第三行地址'), | |||||
| email: yup.string().email('請輸入電郵格式').max(255).required('請輸入電郵'), | |||||
| emailConfirm: yup.string().email('請輸入電郵格式').max(255).required('請輸入電郵').oneOf([yup.ref('email'), null], '請輸入相同電郵'), | |||||
| phoneCountryCode: yup.string().min(3,'請輸入3位數字').required('請輸入國際區號'), | |||||
| faxCountryCode: yup.string().min(3,'請輸入3位數字'), | |||||
| phone: yup.string().min(8,'請輸入8位數字').required('請輸入聯絡電話'), | |||||
| fax: yup.string().min(8,'請輸入8位數字'), | |||||
| brExpiryDate: yup.string().min(8,'請輸入商業登記證有效日期'), | |||||
| brNo: yup.string().min(8,'請輸入商業登記證號碼'), | |||||
| }) | |||||
| }); | }); | ||||
| const handleReset = (resetForm) => { | |||||
| resetForm(); | |||||
| setSelectedAddress4("") | |||||
| }; | |||||
| const { values } = formik | const { values } = formik | ||||
| useEffect(() => { | useEffect(() => { | ||||
| checkDataField(values) | |||||
| }, [values]) | }, [values]) | ||||
| return ( | return ( | ||||
| <FormikProvider value={formik}> | <FormikProvider value={formik}> | ||||
| <form onSubmit={handleSubmit(_onSubmit)}> | <form onSubmit={handleSubmit(_onSubmit)}> | ||||
| {/* Input Form */} | {/* Input Form */} | ||||
| <FormGroup id={"inputForm"} sx={{ display: uploadStep === 0 ? "" : "none" }}> | |||||
| <FormGroup id={"inputForm"} sx={{ display: props.step === 0 ? "" : "none" }}> | |||||
| <Grid container spacing={3}> | <Grid container spacing={3}> | ||||
| <Grid item xs={12} md={12}> | <Grid item xs={12} md={12}> | ||||
| <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}> | <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}> | ||||
| <Button variant="outlined" type="reset" onClick={handleReset.bind(null, formik.resetForm)} sx={{ fontSize: 16,height:'30px'}}>重置</Button> | |||||
| <div style={{borderBottom: "3px solid #1A4399", width:"100%", margin_right: "15px"}}> | <div style={{borderBottom: "3px solid #1A4399", width:"100%", margin_right: "15px"}}> | ||||
| <Typography display="inline" variant="h3" sx={{ color: '#1A4399'}}>成為新的機構/公司用戶</Typography> | <Typography display="inline" variant="h3" sx={{ color: '#1A4399'}}>成為新的機構/公司用戶</Typography> | ||||
| </div> | </div> | ||||
| @@ -289,6 +360,7 @@ const BusCustomFormWizard = (props) => { | |||||
| placeholder="用戶登入名稱" | placeholder="用戶登入名稱" | ||||
| fullWidth | fullWidth | ||||
| error={Boolean(formik.touched.username && formik.errors.username)} | error={Boolean(formik.touched.username && formik.errors.username)} | ||||
| onBlur={formik.handleBlur} | |||||
| inputProps={{ | inputProps={{ | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| if (e.key === 'Enter') { | if (e.key === 'Enter') { | ||||
| @@ -377,9 +449,10 @@ const BusCustomFormWizard = (props) => { | |||||
| type={showConfirmPassword ? 'text' : 'password'} | type={showConfirmPassword ? 'text' : 'password'} | ||||
| value={formik.values.confirmPassword} | value={formik.values.confirmPassword} | ||||
| name="confirmPassword" | name="confirmPassword" | ||||
| onBlur={formik.handleBlur} | |||||
| onChange={(e) => { | onChange={(e) => { | ||||
| formik.handleChange(e); | formik.handleChange(e); | ||||
| changePassword(e.target.value); | |||||
| // changePassword(e.target.value); | |||||
| }} | }} | ||||
| inputProps={{ | inputProps={{ | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| @@ -437,6 +510,7 @@ const BusCustomFormWizard = (props) => { | |||||
| placeholder="與與商業登記證相同如有" | placeholder="與與商業登記證相同如有" | ||||
| fullWidth | fullWidth | ||||
| error={Boolean(formik.touched.enCompanyName && formik.errors.enCompanyName)} | error={Boolean(formik.touched.enCompanyName && formik.errors.enCompanyName)} | ||||
| onBlur={formik.handleBlur} | |||||
| inputProps={{ | inputProps={{ | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| if (e.key === 'Enter') { | if (e.key === 'Enter') { | ||||
| @@ -546,6 +620,7 @@ const BusCustomFormWizard = (props) => { | |||||
| name="address1" | name="address1" | ||||
| onChange={formik.handleChange} | onChange={formik.handleChange} | ||||
| placeholder="第一行" | placeholder="第一行" | ||||
| onBlur={formik.handleBlur} | |||||
| inputProps={{ | inputProps={{ | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| if (e.key === 'Enter') { | if (e.key === 'Enter') { | ||||
| @@ -650,6 +725,7 @@ const BusCustomFormWizard = (props) => { | |||||
| placeholder="與你的身份證明文件相同" | placeholder="與你的身份證明文件相同" | ||||
| fullWidth | fullWidth | ||||
| error={Boolean(formik.touched.enName && formik.errors.enName)} | error={Boolean(formik.touched.enName && formik.errors.enName)} | ||||
| onBlur={formik.handleBlur} | |||||
| inputProps={{ | inputProps={{ | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| if (e.key === 'Enter') { | if (e.key === 'Enter') { | ||||
| @@ -681,6 +757,7 @@ const BusCustomFormWizard = (props) => { | |||||
| name="email" | name="email" | ||||
| onChange={formik.handleChange} | onChange={formik.handleChange} | ||||
| placeholder="電郵" | placeholder="電郵" | ||||
| onBlur={formik.handleBlur} | |||||
| inputProps={{ | inputProps={{ | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| if (e.key === 'Enter') { | if (e.key === 'Enter') { | ||||
| @@ -711,6 +788,7 @@ const BusCustomFormWizard = (props) => { | |||||
| // onBlur={formik.handleBlur} | // onBlur={formik.handleBlur} | ||||
| onChange={formik.handleChange} | onChange={formik.handleChange} | ||||
| placeholder="確認電郵" | placeholder="確認電郵" | ||||
| onBlur={formik.handleBlur} | |||||
| inputProps={{ | inputProps={{ | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| if (e.key === 'Enter') { | if (e.key === 'Enter') { | ||||
| @@ -747,6 +825,7 @@ const BusCustomFormWizard = (props) => { | |||||
| onChange={formik.handleChange} | onChange={formik.handleChange} | ||||
| placeholder="eg:852" | placeholder="eg:852" | ||||
| error={Boolean(formik.touched.phone && formik.errors.phone)} | error={Boolean(formik.touched.phone && formik.errors.phone)} | ||||
| onBlur={formik.handleBlur} | |||||
| inputProps={{ | inputProps={{ | ||||
| maxLength: 3, | maxLength: 3, | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| @@ -762,7 +841,7 @@ const BusCustomFormWizard = (props) => { | |||||
| type="phone" | type="phone" | ||||
| value={formik.values.phone} | value={formik.values.phone} | ||||
| name="phone" | name="phone" | ||||
| // onBlur={formik.handleBlur} | |||||
| onBlur={formik.handleBlur} | |||||
| onChange={formik.handleChange} | onChange={formik.handleChange} | ||||
| placeholder="聯絡電話" | placeholder="聯絡電話" | ||||
| error={Boolean(formik.touched.phone && formik.errors.phone)} | error={Boolean(formik.touched.phone && formik.errors.phone)} | ||||
| @@ -776,12 +855,12 @@ const BusCustomFormWizard = (props) => { | |||||
| }} | }} | ||||
| sx={{width:'75%'}} | sx={{width:'75%'}} | ||||
| /> | /> | ||||
| {formik.touched.phone && formik.errors.phone && ( | |||||
| <FormHelperText error id="helper-text-phone-signup"> | |||||
| {formik.errors.phone} | |||||
| </FormHelperText> | |||||
| )} | |||||
| </Stack> | </Stack> | ||||
| {formik.touched.phone && formik.errors.phone && ( | |||||
| <FormHelperText error id="helper-text-phone-signup"> | |||||
| {formik.errors.phone} | |||||
| </FormHelperText> | |||||
| )} | |||||
| </Stack> | </Stack> | ||||
| </Grid> | </Grid> | ||||
| </Grid> | </Grid> | ||||
| @@ -925,7 +1004,7 @@ const BusCustomFormWizard = (props) => { | |||||
| </Grid> | </Grid> | ||||
| </FormGroup> | </FormGroup> | ||||
| {/* Preview Form */} | {/* Preview Form */} | ||||
| <FormGroup id={"previewForm"} sx={{ display: uploadStep === 1 ? "" : "none"}}> | |||||
| <FormGroup id={"previewForm"} sx={{ display: props.step === 1 ? "" : "none"}}> | |||||
| <Grid container spacing={2}> | <Grid container spacing={2}> | ||||
| <Grid item xs={12}> | <Grid item xs={12}> | ||||
| <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}> | <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}> | ||||
| @@ -984,7 +1063,7 @@ const BusCustomFormWizard = (props) => { | |||||
| <Grid item xs={12} md={12} > | <Grid item xs={12} md={12} > | ||||
| <Stack spacing={1}> | <Stack spacing={1}> | ||||
| <Typography> | <Typography> | ||||
| 商業登記證: | |||||
| 商業登記證 | |||||
| </Typography> | </Typography> | ||||
| </Stack> | </Stack> | ||||
| </Grid> | </Grid> | ||||
| @@ -1019,17 +1098,23 @@ const BusCustomFormWizard = (props) => { | |||||
| <Typography id="preview-address1-signup"> | <Typography id="preview-address1-signup"> | ||||
| {formik.values.address1} | {formik.values.address1} | ||||
| </Typography> | </Typography> | ||||
| <Typography id="preview-address2-signup"> | |||||
| {formik.values.address2} | |||||
| </Typography> | |||||
| {formik.values.address2!=null? | |||||
| <Typography id="preview-address2-signup"> | |||||
| {formik.values.address2} | |||||
| </Typography> | |||||
| :null} | |||||
| {formik.values.address3!=null? | |||||
| <Typography id="preview-address3-signup"> | <Typography id="preview-address3-signup"> | ||||
| {formik.values.address3} | {formik.values.address3} | ||||
| </Typography> | </Typography> | ||||
| <Typography id="preview-address4-signup"> | |||||
| {formik.values.address4} | |||||
| </Typography> | |||||
| :null} | |||||
| {selectedAddress5==("香港")? | |||||
| <Typography id="preview-address4-signup"> | |||||
| 區域 (只適用於香港): {selectedAddress4} | |||||
| </Typography> | |||||
| :null} | |||||
| <Typography id="preview-address5-signup"> | <Typography id="preview-address5-signup"> | ||||
| {formik.values.address5} | |||||
| 國家/地區: {selectedAddress5} | |||||
| </Typography> | </Typography> | ||||
| </Stack> | </Stack> | ||||
| </Stack> | </Stack> | ||||
| @@ -1085,13 +1170,12 @@ const BusCustomFormWizard = (props) => { | |||||
| </Grid> | </Grid> | ||||
| </FormGroup> | </FormGroup> | ||||
| {/* Submit page */} | {/* Submit page */} | ||||
| <FormGroup id={"submitForm"} sx={{ display: uploadStep === 2 ? "" : "none"}}> | |||||
| <FormGroup id={"submitForm"} sx={{ display: props.step === 2 ? "" : "none"}}> | |||||
| <Grid container spacing={3}> | <Grid container spacing={3}> | ||||
| <Grid item xs={12}> | <Grid item xs={12}> | ||||
| {checkUpload? | {checkUpload? | ||||
| // SUCCESS page | // SUCCESS page | ||||
| <Stack mt={1} direction="column" justifyContent="flex-start" alignItems="center" spacing={2}> | <Stack mt={1} direction="column" justifyContent="flex-start" alignItems="center" spacing={2}> | ||||
| {/* <Button disabled={true} hidden={true} variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button> */} | |||||
| <CheckCircleOutlineIcon color="success" sx={{width:"200px",height:"200px"}}/> | <CheckCircleOutlineIcon color="success" sx={{width:"200px",height:"200px"}}/> | ||||
| <Typography display="inline" variant="h4">完成申請,請登入帳戶</Typography> | <Typography display="inline" variant="h4">完成申請,請登入帳戶</Typography> | ||||
| <Button variant="outlined" component={Link} to="/login" sx={{ fontSize: 20,height:'60px'}}>返回登入頁面</Button> | <Button variant="outlined" component={Link} to="/login" sx={{ fontSize: 20,height:'60px'}}>返回登入頁面</Button> | ||||
| @@ -48,7 +48,6 @@ const CustomFormWizard = (props) => { | |||||
| const [showConfirmPassword, setshowConfirmPassword] = useState(false); | const [showConfirmPassword, setshowConfirmPassword] = useState(false); | ||||
| const [fileList, setFileList] = useState([]); | const [fileList, setFileList] = useState([]); | ||||
| const [fileListData, setFileListData] = useState([]); | const [fileListData, setFileListData] = useState([]); | ||||
| const [uploadStep, setUploadStep] = useState(0); | |||||
| const [checkUpload, setCheckUpload] = useState(false); | const [checkUpload, setCheckUpload] = useState(false); | ||||
| const handleClickShowPassword = () => { | const handleClickShowPassword = () => { | ||||
| @@ -72,39 +71,56 @@ const CustomFormWizard = (props) => { | |||||
| const [selectedAddress5, setSelectedAddress5] = useState("香港"); | const [selectedAddress5, setSelectedAddress5] = useState("香港"); | ||||
| const [termsAndConAccept, setTermsAndConAccept] = useState(false); | const [termsAndConAccept, setTermsAndConAccept] = useState(false); | ||||
| const [termsAndConNotAccept, setTermsAndConNotAccept] = useState(false); | const [termsAndConNotAccept, setTermsAndConNotAccept] = useState(false); | ||||
| const [isValid, setisValid] = useState(false); | |||||
| const idDocTypeComboList = ["passport","HKID","CNID","BR","otherCert"]; | const idDocTypeComboList = ["passport","HKID","CNID","BR","otherCert"]; | ||||
| const address4ComboList = | const address4ComboList = | ||||
| ["北區","長洲區","大埔區","大嶼山區","東區","觀塘區","黃大仙區","九龍城區","葵青區","南區","南丫島區", | ["北區","長洲區","大埔區","大嶼山區","東區","觀塘區","黃大仙區","九龍城區","葵青區","南區","南丫島區", | ||||
| "坪洲區","荃灣區","沙田區","深水埗區","屯門區","灣仔區","西貢區","油尖旺區","元朗區","中西區"]; | "坪洲區","荃灣區","沙田區","深水埗區","屯門區","灣仔區","西貢區","油尖旺區","元朗區","中西區"]; | ||||
| const address5ComboList = ["香港","內地","澳門"]; | const address5ComboList = ["香港","內地","澳門"]; | ||||
| const termsAndCon = "Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy \n" | |||||
| +"Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy \n" | |||||
| +"Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy \n"+"Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy \n" | |||||
| +"Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy \n" | |||||
| +"Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy \n" | |||||
| +"Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy \n" | |||||
| +"Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy Dummy \n" | |||||
| const termsAndCon = "此網址由香港特別行政區政府物流服務署製作及管理。本署會盡力確保網址上的資料無誤,\n" | |||||
| + "但有絕對酌情權隨時刪除、暫停登載或編輯各項資料而無須給予任何理由。\n由於任何與網址" | |||||
| + "內資料有關的理由或原因,而導致出現申索、損失或損害,本署概不負責。\n使用者須自行評" | |||||
| + "估本網址所載或與本網址有關連的各項資料,並應在根據該等資料行事前,參照印行的香港" | |||||
| + "特別行政區憲報以核實該等資料,以及徵詢獨立意見。\n版權公告本網頁的內容,包括但不限" | |||||
| + "於所有文本、平面圖像、圖畫、圖片、照片以及數據或其他資料的匯編,均受版權保障。\n香" | |||||
| + "港特別行政區政府是本網頁內所有版權作品的擁有人,除非預先得到政府物流服務署的書面" | |||||
| + "授權,否則嚴禁複製、改編、分發、發布或向公眾提供該等版權作品。" | |||||
| useEffect(() => { | useEffect(() => { | ||||
| changePassword(''); | changePassword(''); | ||||
| }, []); | }, []); | ||||
| const checkDataField = (data)=> { | const checkDataField = (data)=> { | ||||
| if (data.username !=="", | |||||
| data.password !=="", | |||||
| data.enName !=="", | |||||
| data.email !=="", | |||||
| data.password !=="", | |||||
| data.password !=="" | |||||
| if (data.username !==""&& | |||||
| data.password !==""&& | |||||
| data.confirmPassword !==""&& | |||||
| data.password == data.confirmPassword&& | |||||
| selectedIdDocType !==""&& | |||||
| data.idNo !==""&& | |||||
| data.enName !==""&& | |||||
| data.address1 !==""&& | |||||
| data.email !==""&& | |||||
| data.emailConfirm !==""&& | |||||
| data.phone !==""&& | |||||
| data.phoneCountryCode !==""&& | |||||
| termsAndConAccept == true&& | |||||
| fileList.length!==0&& | |||||
| handlePassword(data.password)&& | |||||
| handleEmail(data.email)&& | |||||
| handleIdNo(data.idNo,selectedIdDocType)&& | |||||
| handlePhone(data.phone) | |||||
| ) | ) | ||||
| { | { | ||||
| return true | |||||
| setisValid(true) | |||||
| return isValid | |||||
| }else{ | |||||
| setisValid(false) | |||||
| return isValid | |||||
| } | } | ||||
| }; | }; | ||||
| const handleCheckBoxChange = (event) => { | const handleCheckBoxChange = (event) => { | ||||
| console.log (event.target) | |||||
| if(event.target.name == 'termsAndConAccept'){ | if(event.target.name == 'termsAndConAccept'){ | ||||
| setTermsAndConAccept(event.target.checked) | setTermsAndConAccept(event.target.checked) | ||||
| setTermsAndConNotAccept(!event.target.checked) | setTermsAndConNotAccept(!event.target.checked) | ||||
| @@ -134,9 +150,17 @@ const CustomFormWizard = (props) => { | |||||
| setFileList(uploadFileList); | setFileList(uploadFileList); | ||||
| }; | }; | ||||
| useEffect(() => { | |||||
| props.setUpdateValid(isValid) | |||||
| }, [isValid]) | |||||
| useEffect(() => { | |||||
| checkDataField(values) | |||||
| }, [selectedIdDocType,selectedAddress4,selectedAddress5, | |||||
| termsAndConAccept,termsAndConNotAccept,fileList]) | |||||
| useEffect(() => { | useEffect(() => { | ||||
| props.step ==2?_onSubmit():null; | props.step ==2?_onSubmit():null; | ||||
| setUploadStep(props.step) | |||||
| }, [props.step]) | }, [props.step]) | ||||
| const {handleSubmit} = useForm({}) | const {handleSubmit} = useForm({}) | ||||
| @@ -144,26 +168,19 @@ const CustomFormWizard = (props) => { | |||||
| values.idDocType = selectedIdDocType | values.idDocType = selectedIdDocType | ||||
| values.address4 = selectedAddress4 | values.address4 = selectedAddress4 | ||||
| values.address5 = selectedAddress5 | values.address5 = selectedAddress5 | ||||
| console.log(values) | |||||
| const userAddress = { | const userAddress = { | ||||
| "addressLine1":"", | "addressLine1":"", | ||||
| "addressLine2":"", | "addressLine2":"", | ||||
| "addressLine3":"", | "addressLine3":"", | ||||
| "district":"", | |||||
| "country":"" | "country":"" | ||||
| }; | }; | ||||
| if (values.address5=='香港'){ | |||||
| userAddress.addressLine1 = values.address1 | |||||
| userAddress.addressLine2 = values.address2 | |||||
| userAddress.addressLine3 = values.address3 | |||||
| userAddress.country = values.address5 | |||||
| }else{ | |||||
| userAddress.addressLine1 = values.address1 | |||||
| userAddress.addressLine2 = values.address2 | |||||
| userAddress.addressLine3 = values.address4 | |||||
| userAddress.country = values.address5 | |||||
| } | |||||
| userAddress.addressLine1 = values.address1 | |||||
| userAddress.addressLine2 = values.address2 | |||||
| userAddress.addressLine3 = values.address3 | |||||
| userAddress.district = values.address4 | |||||
| userAddress.country = values.address5 | |||||
| const userFaxNo = { | const userFaxNo = { | ||||
| "countryCode":values.faxCountryCode, | "countryCode":values.faxCountryCode, | ||||
| "faxNumber":values.fax, | "faxNumber":values.fax, | ||||
| @@ -179,8 +196,8 @@ const CustomFormWizard = (props) => { | |||||
| if (termsAndConNotAccept){ | if (termsAndConNotAccept){ | ||||
| tncFlag = false | tncFlag = false | ||||
| } | } | ||||
| if (checkDataField(values)){ | |||||
| if (isValid){ | |||||
| axios.post(`${apiPath}${POST_PUBLIC_USER_REGISTER}`, { | axios.post(`${apiPath}${POST_PUBLIC_USER_REGISTER}`, { | ||||
| username: values.username, | username: values.username, | ||||
| password: values.password, | password: values.password, | ||||
| @@ -217,12 +234,62 @@ const CustomFormWizard = (props) => { | |||||
| } | } | ||||
| } | } | ||||
| function handlePhone(phone) { | |||||
| if (phone.length < 8) { | |||||
| return false; | |||||
| } else { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| function handleIdNo(idNo,selectedIdDocType) { | |||||
| var upperCase = /[A-Z]/g; | |||||
| if (!idNo.match(upperCase)&&selectedIdDocType=="HKID") { | |||||
| return false; | |||||
| } | |||||
| else if (idNo.length < 7) { | |||||
| return false; | |||||
| } else { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| function handlePassword(password) { | |||||
| let new_pass = password; | |||||
| // regular expressions to validate password | |||||
| var lowerCase = /[a-z]/g; | |||||
| var upperCase = /[A-Z]/g; | |||||
| var numbers = /[0-9]/g; | |||||
| if (!new_pass.match(lowerCase)) { | |||||
| return false; | |||||
| } else if (!new_pass.match(upperCase)) { | |||||
| return false; | |||||
| } else if (!new_pass.match(numbers)) { | |||||
| return false; | |||||
| } else if (new_pass.length < 8) { | |||||
| return false; | |||||
| } else { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| function handleEmail(email) { | |||||
| var reg = /^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$/; | |||||
| var result = reg.test(email); | |||||
| if (result == false) { | |||||
| return false; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| const formik = useFormik({ | const formik = useFormik({ | ||||
| initialValues:({ | initialValues:({ | ||||
| username:'', | username:'', | ||||
| enName: '', | enName: '', | ||||
| chName: '', | chName: '', | ||||
| email: '', | email: '', | ||||
| emailConfirm: '', | |||||
| address1: '', | address1: '', | ||||
| address2: '', | address2: '', | ||||
| address3: '', | address3: '', | ||||
| @@ -235,56 +302,58 @@ const CustomFormWizard = (props) => { | |||||
| submit: null, | submit: null, | ||||
| fax:'', | fax:'', | ||||
| faxCountryCode:'852', | faxCountryCode:'852', | ||||
| idDocType:selectedIdDocType | |||||
| }), | }), | ||||
| validationSchema:yup.object().shape({ | validationSchema:yup.object().shape({ | ||||
| username: yup.string().max(255).required('請輸入用戶名稱'), | username: yup.string().max(255).required('請輸入用戶名稱'), | ||||
| password: yup.string().max(255).required('請輸入密碼'), | |||||
| confirmPassword: yup.string().max(255).required('請確認密碼'), | |||||
| password: yup.string().min(8,'請輸入最少8位密碼').required('請輸入密碼') | |||||
| .matches(/^(?=.*[a-z])/, '請包括最少1個小寫字母') | |||||
| .matches(/^(?=.*[A-Z])/, '請包括最少1個大寫字母') | |||||
| .matches(/^(?=.*[0-9])/, '請包括最少1個數字') | |||||
| .matches(/^(?=.*[!@#%&])/, '請包括最少1個特殊字符'), | |||||
| confirmPassword: yup.string().min(8,'請最少輸入8位密碼').required('請確認密碼').oneOf([yup.ref('password'), null], '請輸入相同密碼'), | |||||
| enName: yup.string().max(255).required('請輸入英文姓名'), | enName: yup.string().max(255).required('請輸入英文姓名'), | ||||
| chName: yup.string().max(255).required('請輸入中文姓名'), | chName: yup.string().max(255).required('請輸入中文姓名'), | ||||
| address1: yup.string().max(255).required('請輸入第一行地址'), | address1: yup.string().max(255).required('請輸入第一行地址'), | ||||
| address2: yup.string().max(255).required('請輸入第二行地址'), | address2: yup.string().max(255).required('請輸入第二行地址'), | ||||
| address3: yup.string().max(255).required('請輸入第三行地址'), | address3: yup.string().max(255).required('請輸入第三行地址'), | ||||
| email: yup.string().email('Must be a valid email').max(255).required('Email is required'), | |||||
| idNo: yup.string().max(255).required('請輸入證件號碼'), | |||||
| checkDigit:yup.string().max(1).required('請輸入證件號碼'), | |||||
| idType: yup.string().max(255).required('請輸入第三行地址')}), | |||||
| email: yup.string().email('請輸入電郵格式').max(255).required('請輸入電郵'), | |||||
| emailConfirm: yup.string().email('請輸入電郵格式').max(255).required('請輸入電郵').oneOf([yup.ref('email'), null], '請輸入相同電郵'), | |||||
| idNo: yup.string().min(7,"請輸入證件號碼").required('請輸入證件號碼'), | |||||
| checkDigit:yup.string().max(1).required('請輸入括號內的數字或字母'), | |||||
| idDocType: yup.string().max(255).required('請輸入證件類別'), | |||||
| phoneCountryCode: yup.string().min(3,'請輸入3位數字').required('請輸入國際區號'), | |||||
| faxCountryCode: yup.string().min(3,'請輸入3位數字'), | |||||
| phone: yup.string().min(8,'請輸入8位數字').required('請輸入聯絡電話'), | |||||
| fax: yup.string().min(8,'請輸入8位數字'), | |||||
| }), | |||||
| }); | }); | ||||
| // const validationSchema =yup.object().shape({ | |||||
| // username: yup.string().max(255).required('請輸入用戶名稱'), | |||||
| // password: yup.string().max(255).required('請輸入密碼'), | |||||
| // confirmPassword: yup.string().max(255).required('請確認密碼'), | |||||
| // enName: yup.string().max(255).required('請輸入英文姓名'), | |||||
| // chName: yup.string().max(255).required('請輸入中文姓名'), | |||||
| // address1: yup.string().max(255).required('請輸入第一行地址'), | |||||
| // address2: yup.string().max(255).required('請輸入第二行地址'), | |||||
| // address3: yup.string().max(255).required('請輸入第三行地址'), | |||||
| // email: yup.string().email('Must be a valid email').max(255).required('Email is required'), | |||||
| // idNo: yup.string().max(255).required('請輸入證件號碼'), | |||||
| // checkDigit:yup.string().max(1).required('請輸入證件號碼'), | |||||
| // idType: yup.string().max(255).required('請輸入第三行地址')}); | |||||
| const handleReset = (resetForm) => { | |||||
| resetForm(); | |||||
| setSelectedAddress4("") | |||||
| setSelectedIdDocType("") | |||||
| }; | |||||
| const { values } = formik | const { values } = formik | ||||
| useEffect(() => { | useEffect(() => { | ||||
| checkDataField(values) | |||||
| }, [values]) | }, [values]) | ||||
| return ( | return ( | ||||
| <FormikProvider value={formik}> | <FormikProvider value={formik}> | ||||
| <form onSubmit={handleSubmit(_onSubmit)}> | <form onSubmit={handleSubmit(_onSubmit)}> | ||||
| {/* Input Form */} | {/* Input Form */} | ||||
| <FormGroup id={"inputForm"} sx={{ display: uploadStep === 0 ? "" : "none" }}> | |||||
| <FormGroup id={"inputForm"} sx={{ display: props.step === 0 ? "" : "none" }}> | |||||
| <Grid container spacing={3}> | <Grid container spacing={3}> | ||||
| <Grid item xs={12} md={12}> | <Grid item xs={12} md={12}> | ||||
| <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}> | <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}> | ||||
| <Button variant="outlined" type="reset" onClick={handleReset.bind(null, formik.resetForm)} sx={{ fontSize: 16,height:'30px'}}>重置</Button> | |||||
| <div style={{borderBottom: "3px solid #1A4399", width:"100%", margin_right: "15px"}}> | <div style={{borderBottom: "3px solid #1A4399", width:"100%", margin_right: "15px"}}> | ||||
| <Typography display="inline" variant="h3" sx={{ color: '#1A4399'}}>成為新的個人用戶</Typography> | |||||
| <Typography display="inline" variant="h3" sx={{ color: '#1A4399'}}>成為新的個人用戶</Typography> | |||||
| </div> | </div> | ||||
| <Typography mt={0.25} variant="h6" sx={{ fontSize: 12,color: '#f10000'}}>註有*的項目必須輸入資料</Typography> | <Typography mt={0.25} variant="h6" sx={{ fontSize: 12,color: '#f10000'}}>註有*的項目必須輸入資料</Typography> | ||||
| <Typography mt={0.25} variant="h4" sx={{ color: 'primary.primary'}}>你的登入資料</Typography> | <Typography mt={0.25} variant="h4" sx={{ color: 'primary.primary'}}>你的登入資料</Typography> | ||||
| {/* <Typography component={Link} to="/login" variant="body1" sx={{ textDecoration: 'none' }} color="primary"> | |||||
| Already have an account? | |||||
| </Typography> */} | |||||
| </Stack> | </Stack> | ||||
| </Grid> | </Grid> | ||||
| <Grid item xs={12} md={12}> | <Grid item xs={12} md={12}> | ||||
| @@ -370,16 +439,16 @@ const CustomFormWizard = (props) => { | |||||
| )} | )} | ||||
| </Stack> | </Stack> | ||||
| <FormControl fullWidth sx={{ mt: 2 }}> | <FormControl fullWidth sx={{ mt: 2 }}> | ||||
| <Grid container spacing={2} alignItems="center"> | |||||
| <Grid item> | |||||
| <Box sx={{ bgcolor: level?.color, width: 85, height: 8, borderRadius: '7px' }} /> | |||||
| </Grid> | |||||
| <Grid item> | |||||
| <Typography variant="subtitle1" fontSize="0.75rem"> | |||||
| {level?.label} | |||||
| </Typography> | |||||
| <Grid container spacing={2} alignItems="center"> | |||||
| <Grid item> | |||||
| <Box sx={{ bgcolor: level?.color, width: 85, height: 8, borderRadius: '7px' }} /> | |||||
| </Grid> | |||||
| <Grid item> | |||||
| <Typography variant="subtitle1" fontSize="0.75rem"> | |||||
| {level?.label} | |||||
| </Typography> | |||||
| </Grid> | |||||
| </Grid> | </Grid> | ||||
| </Grid> | |||||
| </FormControl> | </FormControl> | ||||
| </Grid> | </Grid> | ||||
| <Grid item xs={12} md={6} > | <Grid item xs={12} md={6} > | ||||
| @@ -395,7 +464,7 @@ const CustomFormWizard = (props) => { | |||||
| onBlur={formik.handleBlur} | onBlur={formik.handleBlur} | ||||
| onChange={(e) => { | onChange={(e) => { | ||||
| formik.handleChange(e); | formik.handleChange(e); | ||||
| changePassword(e.target.value); | |||||
| // changePassword(e.target.value); | |||||
| }} | }} | ||||
| inputProps={{ | inputProps={{ | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| @@ -457,17 +526,22 @@ const CustomFormWizard = (props) => { | |||||
| <Stack spacing={1} sx={{mr:{md:1},mb:{xs:0.5}}}> | <Stack spacing={1} sx={{mr:{md:1},mb:{xs:0.5}}}> | ||||
| <Autocomplete | <Autocomplete | ||||
| disablePortal | disablePortal | ||||
| id="idDocType-combo" | |||||
| value={selectedIdDocType === null ? null : selectedIdDocType} | |||||
| id="idDocType" | |||||
| value={selectedIdDocType} | |||||
| options={idDocTypeComboList} | options={idDocTypeComboList} | ||||
| onBlur={formik.handleBlur} | |||||
| onChange={(event, newValue) => { | onChange={(event, newValue) => { | ||||
| if (newValue !== null){ | |||||
| setSelectedIdDocType(newValue); | |||||
| } | |||||
| setSelectedIdDocType(newValue); | |||||
| }} | }} | ||||
| sx={{"& .MuiInputBase-root": { height: "41px" },"#idDocType-combo":{padding: "0px 0px 0px 0px"}, "& .MuiAutocomplete-endAdornment": { top: "auto" },}} | |||||
| sx={{"& .MuiInputBase-root": { height: "41px" },"#idDocType":{padding: "0px 0px 0px 0px"}, "& .MuiAutocomplete-endAdornment": { top: "auto" },}} | |||||
| renderInput={(params) => <TextField {...params} placeholder="證件類別"/>} | renderInput={(params) => <TextField {...params} placeholder="證件類別"/>} | ||||
| /> | /> | ||||
| {formik.touched.idDocType && ( | |||||
| selectedIdDocType===null? | |||||
| <FormHelperText error id="helper-text-idDocType-signup"> | |||||
| 請輸入證件類別 | |||||
| </FormHelperText>:'' | |||||
| )} | |||||
| </Stack> | </Stack> | ||||
| </Grid> | </Grid> | ||||
| {selectedIdDocType =="HKID"? | {selectedIdDocType =="HKID"? | ||||
| @@ -495,10 +569,15 @@ const CustomFormWizard = (props) => { | |||||
| }} | }} | ||||
| /> | /> | ||||
| {formik.touched.idNo && formik.errors.idNo && ( | {formik.touched.idNo && formik.errors.idNo && ( | ||||
| <FormHelperText error id="helper-text-enName-signup"> | |||||
| <FormHelperText error id="helper-text-idNo-signup"> | |||||
| {formik.errors.idNo} | {formik.errors.idNo} | ||||
| </FormHelperText> | </FormHelperText> | ||||
| )} | )} | ||||
| {formik.touched.checkDigit && formik.errors.checkDigit && ( | |||||
| <FormHelperText error id="helper-text-checkDigit-signup"> | |||||
| {formik.errors.checkDigit} | |||||
| </FormHelperText> | |||||
| )} | |||||
| </Stack> | </Stack> | ||||
| </Grid> | </Grid> | ||||
| <Grid item xs={2} md={1}> | <Grid item xs={2} md={1}> | ||||
| @@ -521,12 +600,8 @@ const CustomFormWizard = (props) => { | |||||
| }} | }} | ||||
| fullWidth | fullWidth | ||||
| error={Boolean(formik.touched.checkDigit && formik.errors.checkDigit)} | error={Boolean(formik.touched.checkDigit && formik.errors.checkDigit)} | ||||
| onBlur={formik.handleBlur} | |||||
| /> | /> | ||||
| {formik.touched.checkDigit && formik.errors.checkDigit && ( | |||||
| <FormHelperText error id="helper-text-enName-signup"> | |||||
| {formik.errors.checkDigit} | |||||
| </FormHelperText> | |||||
| )} | |||||
| </Stack> | </Stack> | ||||
| </Grid> | </Grid> | ||||
| </>: | </>: | ||||
| @@ -542,6 +617,7 @@ const CustomFormWizard = (props) => { | |||||
| fullWidth | fullWidth | ||||
| sx={{mr:1}} | sx={{mr:1}} | ||||
| error={Boolean(formik.touched.idNo && formik.errors.idNo)} | error={Boolean(formik.touched.idNo && formik.errors.idNo)} | ||||
| onBlur={formik.handleBlur} | |||||
| inputProps={{ | inputProps={{ | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| if (e.key === 'Enter') { | if (e.key === 'Enter') { | ||||
| @@ -551,7 +627,7 @@ const CustomFormWizard = (props) => { | |||||
| }} | }} | ||||
| /> | /> | ||||
| {formik.touched.idNo && formik.errors.idNo && ( | {formik.touched.idNo && formik.errors.idNo && ( | ||||
| <FormHelperText error id="helper-text-enName-signup"> | |||||
| <FormHelperText error id="helper-text-idNo-signup"> | |||||
| {formik.errors.idNo} | {formik.errors.idNo} | ||||
| </FormHelperText> | </FormHelperText> | ||||
| )} | )} | ||||
| @@ -574,6 +650,7 @@ const CustomFormWizard = (props) => { | |||||
| placeholder="與你的身份證明文件相同" | placeholder="與你的身份證明文件相同" | ||||
| fullWidth | fullWidth | ||||
| error={Boolean(formik.touched.enName && formik.errors.enName)} | error={Boolean(formik.touched.enName && formik.errors.enName)} | ||||
| onBlur={formik.handleBlur} | |||||
| inputProps={{ | inputProps={{ | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| if (e.key === 'Enter') { | if (e.key === 'Enter') { | ||||
| @@ -629,6 +706,7 @@ const CustomFormWizard = (props) => { | |||||
| name="address1" | name="address1" | ||||
| onChange={formik.handleChange} | onChange={formik.handleChange} | ||||
| placeholder="第一行" | placeholder="第一行" | ||||
| onBlur={formik.handleBlur} | |||||
| inputProps={{ | inputProps={{ | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| if (e.key === 'Enter') { | if (e.key === 'Enter') { | ||||
| @@ -672,12 +750,10 @@ const CustomFormWizard = (props) => { | |||||
| <Autocomplete | <Autocomplete | ||||
| disablePortal | disablePortal | ||||
| id="address4-combo" | id="address4-combo" | ||||
| value={selectedAddress4 === null ? null : selectedAddress4} | |||||
| value={selectedAddress4} | |||||
| options={address4ComboList} | options={address4ComboList} | ||||
| onChange={(event, newValue) => { | onChange={(event, newValue) => { | ||||
| if (newValue !== null){ | |||||
| setSelectedAddress4(newValue); | |||||
| } | |||||
| setSelectedAddress4(newValue); | |||||
| }} | }} | ||||
| sx={{"& .MuiInputBase-root": { height: "41px" },"#address4-combo":{padding: "0px 0px 0px 0px"}, "& .MuiAutocomplete-endAdornment": { top: "auto" },}} | sx={{"& .MuiInputBase-root": { height: "41px" },"#address4-combo":{padding: "0px 0px 0px 0px"}, "& .MuiAutocomplete-endAdornment": { top: "auto" },}} | ||||
| @@ -689,9 +765,7 @@ const CustomFormWizard = (props) => { | |||||
| value={selectedAddress5} | value={selectedAddress5} | ||||
| options={address5ComboList} | options={address5ComboList} | ||||
| onChange={(event, newValue) => { | onChange={(event, newValue) => { | ||||
| if (newValue !== null){ | |||||
| setSelectedAddress5(newValue); | |||||
| } | |||||
| setSelectedAddress5(newValue); | |||||
| }} | }} | ||||
| sx={{"& .MuiInputBase-root": { height: "41px" },"#address5-combo":{padding: "0px 0px 0px 0px"}, "& .MuiAutocomplete-endAdornment": { top: "auto" },}} | sx={{"& .MuiInputBase-root": { height: "41px" },"#address5-combo":{padding: "0px 0px 0px 0px"}, "& .MuiAutocomplete-endAdornment": { top: "auto" },}} | ||||
| @@ -735,6 +809,7 @@ const CustomFormWizard = (props) => { | |||||
| name="email" | name="email" | ||||
| onChange={formik.handleChange} | onChange={formik.handleChange} | ||||
| placeholder="電郵" | placeholder="電郵" | ||||
| onBlur={formik.handleBlur} | |||||
| inputProps={{ | inputProps={{ | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| if (e.key === 'Enter') { | if (e.key === 'Enter') { | ||||
| @@ -765,6 +840,7 @@ const CustomFormWizard = (props) => { | |||||
| // onBlur={formik.handleBlur} | // onBlur={formik.handleBlur} | ||||
| onChange={formik.handleChange} | onChange={formik.handleChange} | ||||
| placeholder="確認電郵" | placeholder="確認電郵" | ||||
| onBlur={formik.handleBlur} | |||||
| inputProps={{ | inputProps={{ | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| if (e.key === 'Enter') { | if (e.key === 'Enter') { | ||||
| @@ -801,6 +877,7 @@ const CustomFormWizard = (props) => { | |||||
| onChange={formik.handleChange} | onChange={formik.handleChange} | ||||
| placeholder="eg:852" | placeholder="eg:852" | ||||
| error={Boolean(formik.touched.phone && formik.errors.phone)} | error={Boolean(formik.touched.phone && formik.errors.phone)} | ||||
| onBlur={formik.handleBlur} | |||||
| inputProps={{ | inputProps={{ | ||||
| maxLength: 3, | maxLength: 3, | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| @@ -820,6 +897,7 @@ const CustomFormWizard = (props) => { | |||||
| onChange={formik.handleChange} | onChange={formik.handleChange} | ||||
| placeholder="聯絡電話" | placeholder="聯絡電話" | ||||
| error={Boolean(formik.touched.phone && formik.errors.phone)} | error={Boolean(formik.touched.phone && formik.errors.phone)} | ||||
| onBlur={formik.handleBlur} | |||||
| inputProps={{ | inputProps={{ | ||||
| maxLength: 8, | maxLength: 8, | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| @@ -830,12 +908,12 @@ const CustomFormWizard = (props) => { | |||||
| }} | }} | ||||
| sx={{width:'75%'}} | sx={{width:'75%'}} | ||||
| /> | /> | ||||
| {formik.touched.phone && formik.errors.phone && ( | |||||
| <FormHelperText error id="helper-text-phone-signup"> | |||||
| {formik.errors.phone} | |||||
| </FormHelperText> | |||||
| )} | |||||
| </Stack> | </Stack> | ||||
| {formik.touched.phone && formik.errors.phone && ( | |||||
| <FormHelperText error id="helper-text-phone-signup"> | |||||
| {formik.errors.phone} | |||||
| </FormHelperText> | |||||
| )} | |||||
| </Stack> | </Stack> | ||||
| </Grid> | </Grid> | ||||
| </Grid> | </Grid> | ||||
| @@ -852,9 +930,9 @@ const CustomFormWizard = (props) => { | |||||
| type="faxCountryCode" | type="faxCountryCode" | ||||
| value={formik.values.faxCountryCode} | value={formik.values.faxCountryCode} | ||||
| name="faxCountryCode" | name="faxCountryCode" | ||||
| // onBlur={formik.handleBlur} | |||||
| onChange={formik.handleChange} | onChange={formik.handleChange} | ||||
| placeholder="eg:852" | placeholder="eg:852" | ||||
| onBlur={formik.handleBlur} | |||||
| inputProps={{ | inputProps={{ | ||||
| maxLength: 3, | maxLength: 3, | ||||
| onKeyDown: (e) => { | onKeyDown: (e) => { | ||||
| @@ -870,7 +948,7 @@ const CustomFormWizard = (props) => { | |||||
| type="fax" | type="fax" | ||||
| value={formik.values.fax} | value={formik.values.fax} | ||||
| name="fax" | name="fax" | ||||
| // onBlur={formik.handleBlur} | |||||
| onBlur={formik.handleBlur} | |||||
| onChange={formik.handleChange} | onChange={formik.handleChange} | ||||
| placeholder="傳真號碼" | placeholder="傳真號碼" | ||||
| inputProps={{ | inputProps={{ | ||||
| @@ -977,7 +1055,7 @@ const CustomFormWizard = (props) => { | |||||
| </Grid> | </Grid> | ||||
| </FormGroup> | </FormGroup> | ||||
| {/* Preview Form */} | {/* Preview Form */} | ||||
| <FormGroup id={"previewForm"} sx={{ display: uploadStep === 1 ? "" : "none"}}> | |||||
| <FormGroup id={"previewForm"} sx={{ display: props.step === 1 ? "" : "none"}}> | |||||
| <Grid container spacing={2}> | <Grid container spacing={2}> | ||||
| <Grid item xs={12}> | <Grid item xs={12}> | ||||
| <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}> | <Stack direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}> | ||||
| @@ -1127,7 +1205,7 @@ const CustomFormWizard = (props) => { | |||||
| </Stack> | </Stack> | ||||
| </Grid> | </Grid> | ||||
| :null} | :null} | ||||
| <Grid item xs={12} mt={1} mb={1}> | |||||
| {/* <Grid item xs={12} mt={1} mb={1}> | |||||
| <Stack spacing={1} direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}> | <Stack spacing={1} direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}> | ||||
| <Typography display="inline" variant="h4" sx={{ color: 'primary.primary'}}>身份證明文件</Typography> | <Typography display="inline" variant="h4" sx={{ color: 'primary.primary'}}>身份證明文件</Typography> | ||||
| <Typography display="inline" variant="h6" sx={{ fontSize: 12,color: 'primary.primary'}}>請上傳你的 有效身份證明文件 的數碼檔案,以驗證你的身份。</Typography> | <Typography display="inline" variant="h6" sx={{ fontSize: 12,color: 'primary.primary'}}>請上傳你的 有效身份證明文件 的數碼檔案,以驗證你的身份。</Typography> | ||||
| @@ -1139,13 +1217,13 @@ const CustomFormWizard = (props) => { | |||||
| <Typography display="inline" variant="h6" sx={{ fontSize: 12, color: 'primary.primary'}}>如: 香港身份證; 護照; 中國內地身份證等</Typography> | <Typography display="inline" variant="h6" sx={{ fontSize: 12, color: 'primary.primary'}}>如: 香港身份證; 護照; 中國內地身份證等</Typography> | ||||
| </Stack> | </Stack> | ||||
| </Stack> | </Stack> | ||||
| </Grid> | |||||
| </Grid> */} | |||||
| </Grid> | </Grid> | ||||
| </Grid> | </Grid> | ||||
| </Grid> | </Grid> | ||||
| </FormGroup> | </FormGroup> | ||||
| {/* Submit page */} | {/* Submit page */} | ||||
| <FormGroup id={"submitForm"} sx={{ display: uploadStep === 2 ? "" : "none"}}> | |||||
| <FormGroup id={"submitForm"} sx={{ display: props.step === 2 ? "" : "none"}}> | |||||
| <Grid container spacing={3}> | <Grid container spacing={3}> | ||||
| <Grid item xs={12}> | <Grid item xs={12}> | ||||
| {checkUpload? | {checkUpload? | ||||
| @@ -78,7 +78,7 @@ export default function UploadFileTable({recordList}) { | |||||
| paginationModel: {page: 0, pageSize: 5}, | paginationModel: {page: 0, pageSize: 5}, | ||||
| }, | }, | ||||
| }} | }} | ||||
| // pageSizeOptions={[5, 10]} | |||||
| pageSizeOptions={[5, 10]} | |||||
| autoHeight | autoHeight | ||||
| /> | /> | ||||
| </Box> | </Box> | ||||
| @@ -8866,6 +8866,11 @@ react-syntax-highlighter@^15.5.0: | |||||
| prismjs "^1.27.0" | prismjs "^1.27.0" | ||||
| refractor "^3.6.0" | refractor "^3.6.0" | ||||
| react-to-print@^2.14.13: | |||||
| version "2.14.13" | |||||
| resolved "https://registry.npmjs.org/react-to-print/-/react-to-print-2.14.13.tgz" | |||||
| integrity sha512-PqUGgTRZvkyBzWgaZHVBECWPX2nGEc3HOUy6WNXof6HT4yTFI92wtIkqQtr4jfvHbadqjwTgzgh6vgN8KXlWWw== | |||||
| react-transition-group@^4.0.0, react-transition-group@^4.4.0, react-transition-group@^4.4.5: | react-transition-group@^4.0.0, react-transition-group@^4.4.0, react-transition-group@^4.4.5: | ||||
| version "4.4.5" | version "4.4.5" | ||||
| resolved "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz" | resolved "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz" | ||||