| @@ -74,10 +74,10 @@ function Header(props) { | |||||
| isGLDLoggedIn() ? | isGLDLoggedIn() ? | ||||
| <div id="adminContent"> | <div id="adminContent"> | ||||
| <li> | <li> | ||||
| <Link className="dashboard" to='/dashboard'><Typography variant={"headerTitle1"} sx={{ml:2}}>Dashboard</Typography></Link> | |||||
| <Link className="dashboard" to='/dashboard'><Typography variant={"headerTitle1"} sx={{ml:1}} >Dashboard</Typography></Link> | |||||
| </li> | </li> | ||||
| <li> | <li> | ||||
| <Link className="application" to='/application/search'><Typography variant={"headerTitle1"} sx={{ml:2}}>Application</Typography></Link> | |||||
| <Link className="application" to='/application/search'><Typography variant={"headerTitle1"} sx={{ml:1}}>Application</Typography></Link> | |||||
| </li> | </li> | ||||
| <li> | <li> | ||||
| <Link className="proof" to='/proof/search'><Typography variant={"headerTitle1"} sx={{ml:2}}>Proof</Typography></Link> | <Link className="proof" to='/proof/search'><Typography variant={"headerTitle1"} sx={{ml:2}}>Proof</Typography></Link> | ||||
| @@ -115,13 +115,13 @@ function Header(props) { | |||||
| <Link className="dashboard" to='/dashboard'><Typography variant={"headerTitle1"} sx={{ml:2}}>主頁</Typography></Link> | <Link className="dashboard" to='/dashboard'><Typography variant={"headerTitle1"} sx={{ml:2}}>主頁</Typography></Link> | ||||
| </li> | </li> | ||||
| <li> | <li> | ||||
| <Link className="myDocumet" to='/publicNotice'><Typography variant={"headerTitle1"} sx={{ml:2}}>我的公共啟事</Typography></Link> | |||||
| <Link className="myDocumet" to='/publicNotice'><Typography variant={"headerTitle1"} sx={{ml:0.5}}>我的公共啟事</Typography></Link> | |||||
| </li> | </li> | ||||
| <li> | <li> | ||||
| <Link className="documentRecord" to='/proof/search'><Typography variant={"headerTitle1"} sx={{ml:2}}>校對記錄</Typography></Link> | |||||
| <Link className="documentRecord" to='/proof/search'><Typography variant={"headerTitle1"} sx={{ml:1.5}}>校對記錄</Typography></Link> | |||||
| </li> | </li> | ||||
| <li> | <li> | ||||
| <Link className="paymentRecord" to='/paymentPage/search'><Typography variant={"headerTitle1"} sx={{ml:2}}>付款記錄</Typography></Link> | |||||
| <Link className="paymentRecord" to='/paymentPage/search'><Typography variant={"headerTitle1"} sx={{ml:1.5}}>付款記錄</Typography></Link> | |||||
| </li> | </li> | ||||
| <li> | <li> | ||||
| <Link className="userSetting" to='/dashboard'><Typography variant={"headerTitle1"} sx={{ml:2}}>設定</Typography><KeyboardArrowDownIcon /></Link> | <Link className="userSetting" to='/dashboard'><Typography variant={"headerTitle1"} sx={{ml:2}}>設定</Typography><KeyboardArrowDownIcon /></Link> | ||||
| @@ -165,7 +165,7 @@ const UserSearchForm = ({ applySearch }) => { | |||||
| textTransform: 'capitalize', | textTransform: 'capitalize', | ||||
| alignItems: 'end' | alignItems: 'end' | ||||
| }}> | }}> | ||||
| <AddCircleOutlineIcon sx={{mb:0.5}}/> | |||||
| <AddCircleOutlineIcon sx={{ mb: 0.5 }} /> | |||||
| <Typography sx={{ ml: 1 }} variant="h5">New User</Typography> | <Typography sx={{ ml: 1 }} variant="h5">New User</Typography> | ||||
| </Button> | </Button> | ||||
| </Grid> | </Grid> | ||||
| @@ -17,8 +17,11 @@ import VisibilityIcon from '@mui/icons-material/Visibility'; | |||||
| // project import | // project import | ||||
| import Loadable from 'components/Loadable'; | import Loadable from 'components/Loadable'; | ||||
| import { lazy } from 'react'; | import { lazy } from 'react'; | ||||
| import { notifyActionError } from 'utils/CommonFunction'; | |||||
| const CustomFormWizard = Loadable(lazy(() => import('./auth-forms/BusCustomFormWizard'))); | const CustomFormWizard = Loadable(lazy(() => import('./auth-forms/BusCustomFormWizard'))); | ||||
| const AuthWrapper = Loadable(lazy(() => import('./AuthWrapperCustom'))); | const AuthWrapper = Loadable(lazy(() => import('./AuthWrapperCustom'))); | ||||
| import axios from "axios"; | |||||
| import { GET_USERNAME } from "utils/ApiPathConst"; | |||||
| // import CustomFormWizard from './auth-forms/BusCustomFormWizard'; | // import CustomFormWizard from './auth-forms/BusCustomFormWizard'; | ||||
| // import AuthWrapper from './AuthWrapperCustom'; | // import AuthWrapper from './AuthWrapperCustom'; | ||||
| @@ -53,6 +56,7 @@ const BusRegister = () => { | |||||
| const [activeStep, setActiveStep] = useState(0); | const [activeStep, setActiveStep] = useState(0); | ||||
| const [completed, setCompleted] = useState([false]); | const [completed, setCompleted] = useState([false]); | ||||
| const [updateValid, setUpdateValid] = useState(false); | const [updateValid, setUpdateValid] = useState(false); | ||||
| const [username, setUsername] = useState("") | |||||
| const totalSteps = () => { | const totalSteps = () => { | ||||
| return steps.length; | return steps.length; | ||||
| @@ -70,15 +74,29 @@ const BusRegister = () => { | |||||
| return completedSteps() === totalSteps(); | return completedSteps() === totalSteps(); | ||||
| }; | }; | ||||
| const handleNext = () => { | |||||
| const newActiveStep = | |||||
| isLastStep() && !allStepsCompleted() | |||||
| ? // It's the last step, but not all steps have been completed, | |||||
| // find the first step that has been completed | |||||
| steps.findIndex((step, i) => !(i in completed)) | |||||
| : activeStep + 1; | |||||
| setActiveStep(newActiveStep); | |||||
| scrollToTop(); | |||||
| const handleCheckUsername = async () => { | |||||
| const response = await axios.get(`${GET_USERNAME}`, { | |||||
| params: { | |||||
| username: username, | |||||
| } | |||||
| }) | |||||
| return Number(response.data[0]) === 1 | |||||
| } | |||||
| const handleNext = async () => { | |||||
| const test = await handleCheckUsername() | |||||
| if (test) { | |||||
| notifyActionError("此用戶登入名稱已被注冊,請使用其他用戶登入名稱") | |||||
| } else { | |||||
| const newActiveStep = | |||||
| isLastStep() && !allStepsCompleted() | |||||
| ? // It's the last step, but not all steps have been completed, | |||||
| // find the first step that has been completed | |||||
| steps.findIndex((step, i) => !(i in completed)) | |||||
| : activeStep + 1; | |||||
| setActiveStep(newActiveStep); | |||||
| scrollToTop(); | |||||
| } | |||||
| }; | }; | ||||
| const handleBack = () => { | const handleBack = () => { | ||||
| @@ -133,7 +151,7 @@ const BusRegister = () => { | |||||
| ) : ( | ) : ( | ||||
| <React.Fragment> | <React.Fragment> | ||||
| <AuthWrapper> | <AuthWrapper> | ||||
| <CustomFormWizard setUpdateValid={setUpdateValid} step={activeStep} /> | |||||
| <CustomFormWizard setUpdateValid={setUpdateValid} step={activeStep} setUsername={setUsername} /> | |||||
| {/* <CustomFormWizard step={activeStep} /> */} | {/* <CustomFormWizard step={activeStep} /> */} | ||||
| </AuthWrapper> | </AuthWrapper> | ||||
| <Stack direction="row" sx={{ pb: 2 }}> | <Stack direction="row" sx={{ pb: 2 }}> | ||||
| @@ -15,10 +15,13 @@ import { | |||||
| Button, | Button, | ||||
| } from '@mui/material'; | } from '@mui/material'; | ||||
| import VisibilityIcon from '@mui/icons-material/Visibility'; | import VisibilityIcon from '@mui/icons-material/Visibility'; | ||||
| import { GET_USERNAME } from "utils/ApiPathConst"; | |||||
| // project import | // project import | ||||
| import Loadable from 'components/Loadable'; | import Loadable from 'components/Loadable'; | ||||
| import { lazy } from 'react'; | import { lazy } from 'react'; | ||||
| import { notifyActionError } from 'utils/CommonFunction'; | |||||
| import axios from "axios"; | |||||
| const CustomFormWizard = Loadable(lazy(() => import('./auth-forms/CustomFormWizard'))); | const CustomFormWizard = Loadable(lazy(() => import('./auth-forms/CustomFormWizard'))); | ||||
| const AuthWrapper = Loadable(lazy(() => import('./AuthWrapperCustom'))); | const AuthWrapper = Loadable(lazy(() => import('./AuthWrapperCustom'))); | ||||
| // ================================|| REGISTER ||================================ // | // ================================|| REGISTER ||================================ // | ||||
| @@ -52,6 +55,7 @@ const Register = () => { | |||||
| const [activeStep, setActiveStep] = useState(0); | const [activeStep, setActiveStep] = useState(0); | ||||
| const [completed, setCompleted] = useState([false]); | const [completed, setCompleted] = useState([false]); | ||||
| const [updateValid, setUpdateValid] = useState(false); | const [updateValid, setUpdateValid] = useState(false); | ||||
| const [username, setUsername] = useState(""); | |||||
| const totalSteps = () => { | const totalSteps = () => { | ||||
| return steps.length; | return steps.length; | ||||
| @@ -69,15 +73,29 @@ const Register = () => { | |||||
| return completedSteps() === totalSteps(); | return completedSteps() === totalSteps(); | ||||
| }; | }; | ||||
| const handleNext = () => { | |||||
| const newActiveStep = | |||||
| isLastStep() && !allStepsCompleted() | |||||
| ? // It's the last step, but not all steps have been completed, | |||||
| // find the first step that has been completed | |||||
| steps.findIndex((step, i) => !(i in completed)) | |||||
| : activeStep + 1; | |||||
| setActiveStep(newActiveStep); | |||||
| scrollToTop(); | |||||
| const handleCheckUsername = async () => { | |||||
| const response = await axios.get(`${GET_USERNAME}`, { | |||||
| params: { | |||||
| username: username, | |||||
| } | |||||
| }) | |||||
| return Number(response.data[0]) === 1 | |||||
| } | |||||
| const handleNext = async () => { | |||||
| const test = await handleCheckUsername() | |||||
| if (test) { | |||||
| notifyActionError("此用戶登入名稱已被注冊,請使用其他用戶登入名稱") | |||||
| } else { | |||||
| const newActiveStep = | |||||
| isLastStep() && !allStepsCompleted() | |||||
| ? // It's the last step, but not all steps have been completed, | |||||
| // find the first step that has been completed | |||||
| steps.findIndex((step, i) => !(i in completed)) | |||||
| : activeStep + 1; | |||||
| setActiveStep(newActiveStep); | |||||
| scrollToTop(); | |||||
| } | |||||
| }; | }; | ||||
| const handleBack = () => { | const handleBack = () => { | ||||
| @@ -132,7 +150,7 @@ const Register = () => { | |||||
| ) : ( | ) : ( | ||||
| <React.Fragment> | <React.Fragment> | ||||
| <AuthWrapper> | <AuthWrapper> | ||||
| <CustomFormWizard setUpdateValid={setUpdateValid} step={activeStep} /> | |||||
| <CustomFormWizard setUpdateValid={setUpdateValid} step={activeStep} setUsername={setUsername}/> | |||||
| {/* <CustomFormWizard step={activeStep} /> */} | {/* <CustomFormWizard step={activeStep} /> */} | ||||
| </AuthWrapper> | </AuthWrapper> | ||||
| <Stack direction="row" sx={{ pb: 2 }}> | <Stack direction="row" sx={{ pb: 2 }}> | ||||
| @@ -92,6 +92,7 @@ const BusCustomFormWizard = (props) => { | |||||
| const [termsAndConNotAccept, setTermsAndConNotAccept] = useState(false); | const [termsAndConNotAccept, setTermsAndConNotAccept] = useState(false); | ||||
| const [isValid, setisValid] = useState(false); | const [isValid, setisValid] = useState(false); | ||||
| const [checkCountry, setCheckCountry] = useState(false); | const [checkCountry, setCheckCountry] = useState(false); | ||||
| const [checkUsername, setCheckUsername] = useState(false); | |||||
| const address4ComboList = ComboData.district; | const address4ComboList = ComboData.district; | ||||
| const address5ComboList = ComboData.country; | const address5ComboList = ComboData.country; | ||||
| @@ -129,6 +130,18 @@ const BusCustomFormWizard = (props) => { | |||||
| }); | }); | ||||
| }, []); | }, []); | ||||
| const handleCheckUsername = async () => { | |||||
| if (values?.username) { | |||||
| const response = await axios.get(`${GET_USERNAME}`, { | |||||
| params: { | |||||
| username: values.username, | |||||
| } | |||||
| }) | |||||
| setCheckUsername((Number(response.data[0]) === 1)) | |||||
| return Number(response.data[0]) === 1 | |||||
| } | |||||
| } | |||||
| const onCaptchaChange = () => { | const onCaptchaChange = () => { | ||||
| HttpUtils.post({ | HttpUtils.post({ | ||||
| url: POST_CAPTCHA, | url: POST_CAPTCHA, | ||||
| @@ -167,7 +180,8 @@ const BusCustomFormWizard = (props) => { | |||||
| handleEmail(data.email) && | handleEmail(data.email) && | ||||
| handlePhone(data.phone) && | handlePhone(data.phone) && | ||||
| handleUserName(data.username) && | handleUserName(data.username) && | ||||
| handleCaptcha(data.captchaField) | |||||
| handleCaptcha(data.captchaField) && | |||||
| !checkUsername | |||||
| ) { | ) { | ||||
| setisValid(true) | setisValid(true) | ||||
| return isValid | return isValid | ||||
| @@ -528,6 +542,12 @@ const BusCustomFormWizard = (props) => { | |||||
| <Typography variant="h5"> | <Typography variant="h5"> | ||||
| 用戶登入名稱 | 用戶登入名稱 | ||||
| <span style={{ color: '#f10000' }}>*</span> | <span style={{ color: '#f10000' }}>*</span> | ||||
| <Button | |||||
| variant="contained" | |||||
| onClick={handleCheckUsername} | |||||
| sx={{ ml: 2, height: "40px" }}> | |||||
| <Typography variant="h6">檢查是否重覆</Typography> | |||||
| </Button> | |||||
| </Typography> | </Typography> | ||||
| </InputLabel> | </InputLabel> | ||||
| <OutlinedInput | <OutlinedInput | ||||
| @@ -535,7 +555,11 @@ const BusCustomFormWizard = (props) => { | |||||
| type="text" | type="text" | ||||
| value={formik.values.username.trim()} | value={formik.values.username.trim()} | ||||
| name="username" | name="username" | ||||
| onChange={formik.handleChange} | |||||
| onChange={(e) => { | |||||
| setCheckUsername(false) | |||||
| props.setUsername(e.target.value) | |||||
| formik.handleChange(e) | |||||
| }} | |||||
| placeholder="用戶登入名稱" | placeholder="用戶登入名稱" | ||||
| fullWidth | fullWidth | ||||
| error={Boolean(formik.touched.username && formik.errors.username)} | error={Boolean(formik.touched.username && formik.errors.username)} | ||||
| @@ -553,6 +577,11 @@ const BusCustomFormWizard = (props) => { | |||||
| {formik.errors.username} | {formik.errors.username} | ||||
| </FormHelperText> | </FormHelperText> | ||||
| )} | )} | ||||
| {checkUsername && ( | |||||
| <FormHelperText error id="helper-text-username-signup"> | |||||
| 此用戶登入名稱已被注冊,請使用其他用戶登入名稱 | |||||
| </FormHelperText> | |||||
| )} | |||||
| </Stack> | </Stack> | ||||
| </Grid> | </Grid> | ||||
| <Grid item xs={12} md={12}> | <Grid item xs={12} md={12}> | ||||
| @@ -64,7 +64,6 @@ const CustomFormWizard = (props) => { | |||||
| const [checkUpload, setCheckUpload] = useState(false); | const [checkUpload, setCheckUpload] = useState(false); | ||||
| const [isLoading, setLoding] = useState(true); | const [isLoading, setLoding] = useState(true); | ||||
| const [updateRows, setUpdateRows] = useState([]); | const [updateRows, setUpdateRows] = useState([]); | ||||
| const [userNameList, setUserNameList] = useState([]); | |||||
| const [captcha, setCaptcha] = useState([]); | const [captcha, setCaptcha] = useState([]); | ||||
| const [captchaImg, setCaptchaImage] = useState([]); | const [captchaImg, setCaptchaImage] = useState([]); | ||||
| @@ -94,6 +93,7 @@ const CustomFormWizard = (props) => { | |||||
| const [termsAndConNotAccept, setTermsAndConNotAccept] = useState(false); | const [termsAndConNotAccept, setTermsAndConNotAccept] = useState(false); | ||||
| const [isValid, setisValid] = useState(false); | const [isValid, setisValid] = useState(false); | ||||
| const [checkCountry, setCheckCountry] = useState(false); | const [checkCountry, setCheckCountry] = useState(false); | ||||
| const [checkUsername, setCheckUsername] = useState(false); | |||||
| const idDocTypeComboList = ComboData.idDocType; | const idDocTypeComboList = ComboData.idDocType; | ||||
| const address4ComboList = ComboData.district; | const address4ComboList = ComboData.district; | ||||
| @@ -111,18 +111,19 @@ const CustomFormWizard = (props) => { | |||||
| useEffect(() => { | useEffect(() => { | ||||
| changePassword(''); | changePassword(''); | ||||
| onCaptchaChange(); | onCaptchaChange(); | ||||
| axios.get(`${GET_USERNAME}`) | |||||
| .then((response) => { | |||||
| if (response.status === 200) { | |||||
| setUserNameList(response.data); | |||||
| } | |||||
| }, []); | |||||
| const handleCheckUsername = async () => { | |||||
| if (values?.username) { | |||||
| const response = await axios.get(`${GET_USERNAME}`, { | |||||
| params: { | |||||
| username: values.username, | |||||
| } | |||||
| }) | }) | ||||
| .catch(error => { | |||||
| console.log(error); | |||||
| return false; | |||||
| }); | |||||
| }, []); | |||||
| setCheckUsername((Number(response.data[0]) === 1)) | |||||
| return Number(response.data[0]) === 1 | |||||
| } | |||||
| } | |||||
| const onCaptchaChange = () => { | const onCaptchaChange = () => { | ||||
| HttpUtils.post({ | HttpUtils.post({ | ||||
| @@ -137,7 +138,6 @@ const CustomFormWizard = (props) => { | |||||
| }); | }); | ||||
| } | } | ||||
| const checkDataField = (data) => { | const checkDataField = (data) => { | ||||
| if (data.username !== "" && | if (data.username !== "" && | ||||
| data.password !== "" && | data.password !== "" && | ||||
| @@ -161,7 +161,8 @@ const CustomFormWizard = (props) => { | |||||
| handleIdNo(data.idNo, selectedIdDocType.type, data.checkDigit) && | handleIdNo(data.idNo, selectedIdDocType.type, data.checkDigit) && | ||||
| handlePhone(data.phone) && | handlePhone(data.phone) && | ||||
| handleUsername(data.username) && | handleUsername(data.username) && | ||||
| handleCaptcha(data.captchaField) | |||||
| handleCaptcha(data.captchaField) && | |||||
| !checkUsername | |||||
| ) { | ) { | ||||
| setisValid(true) | setisValid(true) | ||||
| return isValid | return isValid | ||||
| @@ -502,25 +503,15 @@ const CustomFormWizard = (props) => { | |||||
| captchaField: '' | captchaField: '' | ||||
| }), | }), | ||||
| validationSchema: yup.object().shape({ | validationSchema: yup.object().shape({ | ||||
| username: yup.string().min(6, displayErrorMsg('用戶名稱最少6位')).required(displayErrorMsg("請輸入用戶登入名稱")).test( | |||||
| "checkUserNameUsed", | |||||
| displayErrorMsg("此用戶登入名稱已被注冊,請使用其他用戶登入名稱"), | |||||
| function (value) { | |||||
| if (userNameList.some(item => item.username === value)) { | |||||
| return false | |||||
| } else { | |||||
| return true | |||||
| } | |||||
| } | |||||
| ) | |||||
| .matches(/^[aA-zZ0-9\s]+$/, {message: displayErrorMsg("用戶名稱不包含特殊字符")}) | |||||
| .matches(/^\S*$/, {message: displayErrorMsg("用戶名稱不包含空格")}), | |||||
| username: yup.string().min(6, displayErrorMsg('用戶名稱最少6位')).required(displayErrorMsg("請輸入用戶登入名稱")) | |||||
| .matches(/^[aA-zZ0-9\s]+$/, { message: displayErrorMsg("用戶名稱不包含特殊字符") }) | |||||
| .matches(/^\S*$/, { message: displayErrorMsg("用戶名稱不包含空格") }), | |||||
| password: yup.string().min(8, displayErrorMsg('請輸入最少8位密碼')).required(displayErrorMsg('請輸入密碼')) | password: yup.string().min(8, displayErrorMsg('請輸入最少8位密碼')).required(displayErrorMsg('請輸入密碼')) | ||||
| .matches(/^\S*$/, {message: displayErrorMsg('密碼不包含空格')}) | |||||
| .matches(/^(?=.*[a-z])/, {message: displayErrorMsg('請包括最少1個小寫字母')}) | |||||
| .matches(/^(?=.*[A-Z])/, {message: displayErrorMsg('請包括最少1個大寫字母')}) | |||||
| .matches(/^(?=.*[0-9])/, {message: displayErrorMsg('請包括最少1個數字')}) | |||||
| .matches(/^(?=.*[!@#%&])/, {message: displayErrorMsg('請包括最少1個特殊字符')}), | |||||
| .matches(/^\S*$/, { message: displayErrorMsg('密碼不包含空格') }) | |||||
| .matches(/^(?=.*[a-z])/, { message: displayErrorMsg('請包括最少1個小寫字母') }) | |||||
| .matches(/^(?=.*[A-Z])/, { message: displayErrorMsg('請包括最少1個大寫字母') }) | |||||
| .matches(/^(?=.*[0-9])/, { message: displayErrorMsg('請包括最少1個數字') }) | |||||
| .matches(/^(?=.*[!@#%&])/, { message: displayErrorMsg('請包括最少1個特殊字符') }), | |||||
| confirmPassword: yup.string().min(8, displayErrorMsg('請最少輸入8位密碼')).required(displayErrorMsg('請確認密碼')).oneOf([yup.ref('password'), null], displayErrorMsg('請輸入相同密碼')), | confirmPassword: yup.string().min(8, displayErrorMsg('請最少輸入8位密碼')).required(displayErrorMsg('請確認密碼')).oneOf([yup.ref('password'), null], displayErrorMsg('請輸入相同密碼')), | ||||
| enName: yup.string().max(255).required(displayErrorMsg('請輸入英文姓名')), | enName: yup.string().max(255).required(displayErrorMsg('請輸入英文姓名')), | ||||
| chName: yup.string().max(6).required(displayErrorMsg('請輸入中文姓名')), | chName: yup.string().max(6).required(displayErrorMsg('請輸入中文姓名')), | ||||
| @@ -530,8 +521,8 @@ const CustomFormWizard = (props) => { | |||||
| email: yup.string().email(displayErrorMsg('請輸入電郵格式')).max(255).required(displayErrorMsg('請輸入電郵')), | email: yup.string().email(displayErrorMsg('請輸入電郵格式')).max(255).required(displayErrorMsg('請輸入電郵')), | ||||
| emailConfirm: yup.string().email(displayErrorMsg('請輸入電郵格式')).max(255).required(displayErrorMsg('請輸入電郵')).oneOf([yup.ref('email'), null], displayErrorMsg('請輸入相同電郵')), | emailConfirm: yup.string().email(displayErrorMsg('請輸入電郵格式')).max(255).required(displayErrorMsg('請輸入電郵')).oneOf([yup.ref('email'), null], displayErrorMsg('請輸入相同電郵')), | ||||
| idNo: yup.string().required(displayErrorMsg(`請輸入${selectedIdDocInputType}號碼`)) | idNo: yup.string().required(displayErrorMsg(`請輸入${selectedIdDocInputType}號碼`)) | ||||
| .matches(/^[aA-zZ0-9\s]+$/, {message: displayErrorMsg(`${selectedIdDocInputType}號碼不包含特殊字符`)}) | |||||
| .matches(/^\S*$/, {message: displayErrorMsg(`${selectedIdDocInputType}號碼不包含空格`)}) | |||||
| .matches(/^[aA-zZ0-9\s]+$/, { message: displayErrorMsg(`${selectedIdDocInputType}號碼不包含特殊字符`) }) | |||||
| .matches(/^\S*$/, { message: displayErrorMsg(`${selectedIdDocInputType}號碼不包含空格`) }) | |||||
| .test('checkIDCardFormat', displayErrorMsg(`請輸入有效的${selectedIdDocInputType}號碼`), function (value) { | .test('checkIDCardFormat', displayErrorMsg(`請輸入有效的${selectedIdDocInputType}號碼`), function (value) { | ||||
| const idDocType = selectedIdDocType.type; | const idDocType = selectedIdDocType.type; | ||||
| var pattern_HKIDv1 = /^[A-Z]{1}[0-9]{6}$/; | var pattern_HKIDv1 = /^[A-Z]{1}[0-9]{6}$/; | ||||
| @@ -607,6 +598,7 @@ const CustomFormWizard = (props) => { | |||||
| }; | }; | ||||
| const { values } = formik | const { values } = formik | ||||
| useEffect(() => { | useEffect(() => { | ||||
| checkDataField(values) | checkDataField(values) | ||||
| }, [values]) | }, [values]) | ||||
| @@ -635,6 +627,12 @@ const CustomFormWizard = (props) => { | |||||
| <Typography variant="h5"> | <Typography variant="h5"> | ||||
| 用戶登入名稱 | 用戶登入名稱 | ||||
| <span style={{ color: '#f10000' }}>*</span> | <span style={{ color: '#f10000' }}>*</span> | ||||
| <Button | |||||
| variant="contained" | |||||
| onClick={handleCheckUsername} | |||||
| sx={{ ml: 2, height: "40px" }}> | |||||
| <Typography variant="h6">檢查是否重覆</Typography> | |||||
| </Button> | |||||
| </Typography> | </Typography> | ||||
| </InputLabel> | </InputLabel> | ||||
| <OutlinedInput | <OutlinedInput | ||||
| @@ -642,7 +640,11 @@ const CustomFormWizard = (props) => { | |||||
| type="text" | type="text" | ||||
| value={formik.values.username.trim()} | value={formik.values.username.trim()} | ||||
| name="username" | name="username" | ||||
| onChange={formik.handleChange} | |||||
| onChange={(e) => { | |||||
| setCheckUsername(false) | |||||
| props.setUsername(e.target.value) | |||||
| formik.handleChange(e) | |||||
| }} | |||||
| placeholder="用戶登入名稱" | placeholder="用戶登入名稱" | ||||
| fullWidth | fullWidth | ||||
| error={Boolean(formik.touched.username && formik.errors.username)} | error={Boolean(formik.touched.username && formik.errors.username)} | ||||
| @@ -660,6 +662,11 @@ const CustomFormWizard = (props) => { | |||||
| {formik.errors.username} | {formik.errors.username} | ||||
| </FormHelperText> | </FormHelperText> | ||||
| )} | )} | ||||
| {checkUsername && ( | |||||
| <FormHelperText error id="helper-text-username-signup"> | |||||
| 此用戶登入名稱已被注冊,請使用其他用戶登入名稱 | |||||
| </FormHelperText> | |||||
| )} | |||||
| </Stack> | </Stack> | ||||
| </Grid> | </Grid> | ||||
| <Grid item xs={12} md={12}> | <Grid item xs={12} md={12}> | ||||
| @@ -0,0 +1,20 @@ | |||||
| // ==============================|| OVERRIDES - FormHelperText ||============================== // | |||||
| export default function FormHelperText() { | |||||
| const fontSize = "1rem" | |||||
| const fontWeight = 600 | |||||
| const lineHeight = 1 | |||||
| return { | |||||
| MuiFormHelperText: { | |||||
| styleOverrides: { | |||||
| root: { | |||||
| fontSize: fontSize, | |||||
| fontWeight: fontWeight, | |||||
| lineHeight: lineHeight, | |||||
| }, | |||||
| } | |||||
| } | |||||
| }; | |||||
| } | |||||
| @@ -20,6 +20,7 @@ import Typography from './Typography'; | |||||
| import Textfield from './Textfield'; | import Textfield from './Textfield'; | ||||
| import DataGrid from './DataGrid'; | import DataGrid from './DataGrid'; | ||||
| import FormControlLabel from './FormControlLabel'; | import FormControlLabel from './FormControlLabel'; | ||||
| import FormHelperText from './FormHelperText'; | |||||
| // ==============================|| OVERRIDES - MAIN ||============================== // | // ==============================|| OVERRIDES - MAIN ||============================== // | ||||
| @@ -32,6 +33,7 @@ export default function ComponentsOverrides(theme) { | |||||
| Chip(theme), | Chip(theme), | ||||
| DataGrid(), | DataGrid(), | ||||
| FormControlLabel(), | FormControlLabel(), | ||||
| FormHelperText(), | |||||
| IconButton(theme), | IconButton(theme), | ||||
| InputLabel(theme), | InputLabel(theme), | ||||
| LinearProgress(), | LinearProgress(), | ||||
| @@ -162,6 +162,18 @@ export const notifyActionSuccess = (actionMsg) => { | |||||
| theme: "light", | theme: "light", | ||||
| })}; | })}; | ||||
| export const notifyActionError = (actionMsg) => { | |||||
| toast.error(`${actionMsg}`, { | |||||
| position: "bottom-right", | |||||
| autoClose: 5000, | |||||
| hideProgressBar: false, | |||||
| closeOnClick: true, | |||||
| pauseOnHover: true, | |||||
| draggable: true, | |||||
| progress: undefined, | |||||
| theme: "light", | |||||
| })}; | |||||
| export function prettyJson(json){ | export function prettyJson(json){ | ||||
| console.log(json); | console.log(json); | ||||
| console.log(JSON.stringify(json, null, 2)); | console.log(JSON.stringify(json, null, 2)); | ||||