diff --git a/src/pages/User/SearchPage/UserSearchForm.js b/src/pages/User/SearchPage/UserSearchForm.js index 9e2ea78..f172c32 100644 --- a/src/pages/User/SearchPage/UserSearchForm.js +++ b/src/pages/User/SearchPage/UserSearchForm.js @@ -165,7 +165,7 @@ const UserSearchForm = ({ applySearch }) => { textTransform: 'capitalize', alignItems: 'end' }}> - + New User diff --git a/src/pages/authentication/BusRegister.js b/src/pages/authentication/BusRegister.js index 7d083e2..3fde0d9 100644 --- a/src/pages/authentication/BusRegister.js +++ b/src/pages/authentication/BusRegister.js @@ -17,8 +17,11 @@ import VisibilityIcon from '@mui/icons-material/Visibility'; // project import import Loadable from 'components/Loadable'; import { lazy } from 'react'; +import { notifyActionError } from 'utils/CommonFunction'; const CustomFormWizard = Loadable(lazy(() => import('./auth-forms/BusCustomFormWizard'))); const AuthWrapper = Loadable(lazy(() => import('./AuthWrapperCustom'))); +import axios from "axios"; +import { GET_USERNAME } from "utils/ApiPathConst"; // import CustomFormWizard from './auth-forms/BusCustomFormWizard'; // import AuthWrapper from './AuthWrapperCustom'; @@ -53,6 +56,7 @@ const BusRegister = () => { const [activeStep, setActiveStep] = useState(0); const [completed, setCompleted] = useState([false]); const [updateValid, setUpdateValid] = useState(false); + const [username, setUsername] = useState("") const totalSteps = () => { return steps.length; @@ -70,15 +74,29 @@ const BusRegister = () => { 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 = () => { @@ -133,7 +151,7 @@ const BusRegister = () => { ) : ( - + {/* */} diff --git a/src/pages/authentication/Register.js b/src/pages/authentication/Register.js index 1d1efa8..7422578 100644 --- a/src/pages/authentication/Register.js +++ b/src/pages/authentication/Register.js @@ -15,10 +15,13 @@ import { Button, } from '@mui/material'; import VisibilityIcon from '@mui/icons-material/Visibility'; +import { GET_USERNAME } from "utils/ApiPathConst"; // project import import Loadable from 'components/Loadable'; import { lazy } from 'react'; +import { notifyActionError } from 'utils/CommonFunction'; +import axios from "axios"; const CustomFormWizard = Loadable(lazy(() => import('./auth-forms/CustomFormWizard'))); const AuthWrapper = Loadable(lazy(() => import('./AuthWrapperCustom'))); // ================================|| REGISTER ||================================ // @@ -52,6 +55,7 @@ const Register = () => { const [activeStep, setActiveStep] = useState(0); const [completed, setCompleted] = useState([false]); const [updateValid, setUpdateValid] = useState(false); + const [username, setUsername] = useState(""); const totalSteps = () => { return steps.length; @@ -69,15 +73,29 @@ const Register = () => { 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 = () => { @@ -132,7 +150,7 @@ const Register = () => { ) : ( - + {/* */} diff --git a/src/pages/authentication/auth-forms/BusCustomFormWizard.js b/src/pages/authentication/auth-forms/BusCustomFormWizard.js index 9a3e264..b96fbc6 100644 --- a/src/pages/authentication/auth-forms/BusCustomFormWizard.js +++ b/src/pages/authentication/auth-forms/BusCustomFormWizard.js @@ -92,6 +92,7 @@ const BusCustomFormWizard = (props) => { const [termsAndConNotAccept, setTermsAndConNotAccept] = useState(false); const [isValid, setisValid] = useState(false); const [checkCountry, setCheckCountry] = useState(false); + const [checkUsername, setCheckUsername] = useState(false); const address4ComboList = ComboData.district; 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 = () => { HttpUtils.post({ url: POST_CAPTCHA, @@ -167,7 +180,8 @@ const BusCustomFormWizard = (props) => { handleEmail(data.email) && handlePhone(data.phone) && handleUserName(data.username) && - handleCaptcha(data.captchaField) + handleCaptcha(data.captchaField) && + !checkUsername ) { setisValid(true) return isValid @@ -528,6 +542,12 @@ const BusCustomFormWizard = (props) => { 用戶登入名稱 * + { type="text" value={formik.values.username.trim()} name="username" - onChange={formik.handleChange} + onChange={(e) => { + setCheckUsername(false) + props.setUsername(e.target.value) + formik.handleChange(e) + }} placeholder="用戶登入名稱" fullWidth error={Boolean(formik.touched.username && formik.errors.username)} @@ -553,6 +577,11 @@ const BusCustomFormWizard = (props) => { {formik.errors.username} )} + {checkUsername && ( + + 此用戶登入名稱已被注冊,請使用其他用戶登入名稱 + + )} diff --git a/src/pages/authentication/auth-forms/CustomFormWizard.js b/src/pages/authentication/auth-forms/CustomFormWizard.js index e73c819..143e700 100644 --- a/src/pages/authentication/auth-forms/CustomFormWizard.js +++ b/src/pages/authentication/auth-forms/CustomFormWizard.js @@ -64,7 +64,6 @@ const CustomFormWizard = (props) => { const [checkUpload, setCheckUpload] = useState(false); const [isLoading, setLoding] = useState(true); const [updateRows, setUpdateRows] = useState([]); - const [userNameList, setUserNameList] = useState([]); const [captcha, setCaptcha] = useState([]); const [captchaImg, setCaptchaImage] = useState([]); @@ -94,6 +93,7 @@ const CustomFormWizard = (props) => { const [termsAndConNotAccept, setTermsAndConNotAccept] = useState(false); const [isValid, setisValid] = useState(false); const [checkCountry, setCheckCountry] = useState(false); + const [checkUsername, setCheckUsername] = useState(false); const idDocTypeComboList = ComboData.idDocType; const address4ComboList = ComboData.district; @@ -111,18 +111,19 @@ const CustomFormWizard = (props) => { useEffect(() => { changePassword(''); 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 = () => { HttpUtils.post({ @@ -137,7 +138,6 @@ const CustomFormWizard = (props) => { }); } - const checkDataField = (data) => { if (data.username !== "" && data.password !== "" && @@ -161,7 +161,8 @@ const CustomFormWizard = (props) => { handleIdNo(data.idNo, selectedIdDocType.type, data.checkDigit) && handlePhone(data.phone) && handleUsername(data.username) && - handleCaptcha(data.captchaField) + handleCaptcha(data.captchaField) && + !checkUsername ) { setisValid(true) return isValid @@ -502,25 +503,15 @@ const CustomFormWizard = (props) => { captchaField: '' }), 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('請輸入密碼')) - .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('請輸入相同密碼')), enName: yup.string().max(255).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('請輸入電郵')), emailConfirm: yup.string().email(displayErrorMsg('請輸入電郵格式')).max(255).required(displayErrorMsg('請輸入電郵')).oneOf([yup.ref('email'), null], displayErrorMsg('請輸入相同電郵')), 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) { const idDocType = selectedIdDocType.type; var pattern_HKIDv1 = /^[A-Z]{1}[0-9]{6}$/; @@ -607,6 +598,7 @@ const CustomFormWizard = (props) => { }; const { values } = formik + useEffect(() => { checkDataField(values) }, [values]) @@ -635,6 +627,12 @@ const CustomFormWizard = (props) => { 用戶登入名稱 * + { type="text" value={formik.values.username.trim()} name="username" - onChange={formik.handleChange} + onChange={(e) => { + setCheckUsername(false) + props.setUsername(e.target.value) + formik.handleChange(e) + }} placeholder="用戶登入名稱" fullWidth error={Boolean(formik.touched.username && formik.errors.username)} @@ -660,6 +662,11 @@ const CustomFormWizard = (props) => { {formik.errors.username} )} + {checkUsername && ( + + 此用戶登入名稱已被注冊,請使用其他用戶登入名稱 + + )} diff --git a/src/themes/overrides/FormHelperText.js b/src/themes/overrides/FormHelperText.js new file mode 100644 index 0000000..9a488cb --- /dev/null +++ b/src/themes/overrides/FormHelperText.js @@ -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, + }, + } + } + }; +} diff --git a/src/themes/overrides/index.js b/src/themes/overrides/index.js index bb2888c..6e9461d 100644 --- a/src/themes/overrides/index.js +++ b/src/themes/overrides/index.js @@ -20,6 +20,7 @@ import Typography from './Typography'; import Textfield from './Textfield'; import DataGrid from './DataGrid'; import FormControlLabel from './FormControlLabel'; +import FormHelperText from './FormHelperText'; // ==============================|| OVERRIDES - MAIN ||============================== // @@ -32,6 +33,7 @@ export default function ComponentsOverrides(theme) { Chip(theme), DataGrid(), FormControlLabel(), + FormHelperText(), IconButton(theme), InputLabel(theme), LinearProgress(), diff --git a/src/utils/CommonFunction.js b/src/utils/CommonFunction.js index 2101d28..aef31ea 100644 --- a/src/utils/CommonFunction.js +++ b/src/utils/CommonFunction.js @@ -162,6 +162,18 @@ export const notifyActionSuccess = (actionMsg) => { 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){ console.log(json); console.log(JSON.stringify(json, null, 2));