diff --git a/src/pages/pnspsUserDetailPage_Individual/UserInformationCard_Individual.js b/src/pages/pnspsUserDetailPage_Individual/UserInformationCard_Individual.js index 11ac6cc..51d82f2 100644 --- a/src/pages/pnspsUserDetailPage_Individual/UserInformationCard_Individual.js +++ b/src/pages/pnspsUserDetailPage_Individual/UserInformationCard_Individual.js @@ -79,6 +79,8 @@ const UserInformationCard_Individual = ({userData,userFile, loadDataFun}) => { userData["faxNumber"] = userData.faxNo?.faxNumber; userData["fax_countryCode"] = userData.faxNo?.countryCode; + userData["lastLoginDate"] = userData.lastLogin?DateUtils.datetimeStr(userData.lastLogin):""; + setIdDocType(userData.idDocType); setDistrict(userData.district); setCountry(userData.country); @@ -645,11 +647,8 @@ const UserInformationCard_Individual = ({userData,userFile, loadDataFun}) => { diff --git a/src/pages/pnspsUserDetailPage_Organization/UserInformationCard_Organization.js b/src/pages/pnspsUserDetailPage_Organization/UserInformationCard_Organization.js index 54b2391..87f3310 100644 --- a/src/pages/pnspsUserDetailPage_Organization/UserInformationCard_Organization.js +++ b/src/pages/pnspsUserDetailPage_Organization/UserInformationCard_Organization.js @@ -1,6 +1,7 @@ // material-ui import { - Grid, TextField, Typography, Button + Grid, TextField, Typography, Button, + OutlinedInput, FormHelperText } from '@mui/material'; import MainCard from "../../components/MainCard"; import * as React from "react"; @@ -10,6 +11,9 @@ import * as DateUtils from '../../utils/DateUtils'; import * as HttpUtils from '../../utils/HttpUtils'; import * as UrlUtils from "../../utils/ApiPathConst"; +import { useFormik,FormikProvider } from 'formik'; +import * as yup from 'yup'; + // ==============================|| DASHBOARD - DEFAULT ||============================== // @@ -19,10 +23,33 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => { const [editMode, setEditMode] = useState(false); const [locked, setLocked] = useState(false); - const from = useForm({defaultValues: userData}); const {register,reset, handleSubmit} = from; + + const formik = useFormik({ + initialValues:(currentUserData), + validationSchema:yup.object().shape({ + + 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,'請輸入商業登記證號碼'), + }) + + }); + + useEffect(() => { let createDate = DateUtils.datetimeStr(userData.created); let modifiedBy = DateUtils.datetimeStr(userData.modified)+", "+userData.modifiedBy; @@ -51,29 +78,36 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => { }, [currentUserData]); - function onSubmitForm(_formData) { + + function onSubmitForm() { HttpUtils.post({ url: UrlUtils.POST_IND_USER+"/"+userData.id, params: { - chName: _formData.chName, - enName: _formData.enName, + chName: formik.values.chName, + enName: formik.values.enName, contactTel: { - countryCode: _formData.tel_countryCode, - phoneNumber: _formData.phoneNumber + countryCode: formik.values.tel_countryCode, + phoneNumber: formik.values.phoneNumber }, faxNo: { - countryCode: _formData.fax_countryCode, - faxNumber: _formData.faxNumber + countryCode: formik.values.fax_countryCode, + faxNumber: formik.values.faxNumber }, addressBus: { - country: _formData.country, - district: _formData.district, - addressLine1: _formData.addressLine1, - addressLine2: _formData.addressLine2, - addressLine3: _formData.addressLine3, + country: formik.values.country, + district: formik.values.district, + addressLine1: formik.values.addressLine1, + addressLine2: formik.values.addressLine2, + addressLine3: formik.values.addressLine3, }, - identification: _formData.identification, - emailBus:_formData.emailBus, + identification: formik.values.identification, + emailBus:formik.values.emailBus, + contactPerson: formik.values.contactPerson, + enCompanyName: formik.values.enCompanyName, + chCompanyName: formik.values.chCompanyName, + brNo: formik.values.brNo, + brExpiryDate: formik.values.brExpiryDate, + }, onSuccess: function(){ loadDataFun(); @@ -89,6 +123,15 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => { window.open("/org/fromUser/"+userData.id, "_blank", "noreferrer"); }; + const onVerifiedClick = () => { + HttpUtils.get({ + url: UrlUtils.GET_IND_USER_VERIFY+"/"+userData.id, + onSuccess: function(){ + loadDataFun(); + } + }); + }; + const doLock = () => { HttpUtils.get({ url: UrlUtils.GET_USER_LOCK+"/"+userData.id, @@ -107,6 +150,7 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => { }); }; + return ( { Information +
{/*top button*/} @@ -302,10 +347,7 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => { @@ -325,8 +367,8 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => { @@ -341,8 +383,9 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => { Verified: + { - currentUserData.verified || editMode? + currentUserData.verifiedBy || editMode? { textTransform: 'capitalize', alignItems: 'end' }} + onClick={onVerifiedClick} > Verify } + + { fullWidth {...register("chCompanyName")} id='chCompanyName' - disabled + disabled={!editMode} /> @@ -597,12 +643,30 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => { - + { + if (e.key === 'Enter') { + e.preventDefault(); + } + }, + }} + /> + {formik.touched.brExpiryDate && formik.errors.brExpiryDate && ( + + {formik.errors.brExpiryDate} + + )} @@ -617,28 +681,19 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => { @@ -685,6 +740,8 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
+ +
); }; diff --git a/src/pages/pnspsUserDetailPage_Organization/index.js b/src/pages/pnspsUserDetailPage_Organization/index.js index a4ac7ce..b3041e0 100644 --- a/src/pages/pnspsUserDetailPage_Organization/index.js +++ b/src/pages/pnspsUserDetailPage_Organization/index.js @@ -30,7 +30,7 @@ const UserMaintainPage_Organization = () => { HttpUtils.get({ url: `${UrlUtils.GET_ORG_USER_PATH}/${params.id}`, onSuccess: function(response){ - response.data["addressBus"] = JSON.parse(response.data["address"]); + response.data["addressBus"] = JSON.parse(response.data["addressBus"]); response.data["contactTel"] = JSON.parse(response.data["contactTel"]); response.data["faxNo"] = JSON.parse(response.data["faxNo"]); setUserData(response.data) diff --git a/src/pages/pnspsUserSearchPage_Individual/UserSearchForm_Individual.js b/src/pages/pnspsUserSearchPage_Individual/UserSearchForm_Individual.js index ca0d9ff..07c5876 100644 --- a/src/pages/pnspsUserSearchPage_Individual/UserSearchForm_Individual.js +++ b/src/pages/pnspsUserSearchPage_Individual/UserSearchForm_Individual.js @@ -1,15 +1,13 @@ // material-ui import { Button, - CardContent, FormControlLabel, + CardContent, Grid, TextField, - Typography + Autocomplete } from '@mui/material'; import MainCard from "../../components/MainCard"; import {useForm} from "react-hook-form"; - import { useState} from "react"; -import Checkbox from "@mui/material/Checkbox"; import * as React from "react"; // ==============================|| DASHBOARD - DEFAULT ||============================== // @@ -17,8 +15,7 @@ import * as React from "react"; const UserSearchForm_Individual = ({applySearch}) => { const [type, setType] = useState([]); - const [locked, setLocked] = useState(false); - + const [accountFilter, setAccountFilter] = useState("Active"); const { reset, register, handleSubmit } = useForm() const onSubmit = (data) => { @@ -34,14 +31,13 @@ const UserSearchForm_Individual = ({applySearch}) => { fullName: data.fullName, email: data.email, phone: data.phone, - locked: locked, + accountFilter: accountFilter, }; applySearch(temp); }; function resetForm(){ setType([]); - setLocked(false); reset(); } @@ -97,18 +93,23 @@ const UserSearchForm_Individual = ({applySearch}) => { - setLocked(event.target.checked)} - name="checked" - color="primary" - size="small" + { + if (newValue !== null){ + setAccountFilter(newValue); + } + }} + renderInput={(params) => ( + + )} /> - } - label={Locked} - /> {/**/} {/* { + if(params.value){ + let tel = JSON.parse(params.value); + return "+"+tel.countryCode+ " "+tel.phoneNumber; + } + + } + }, + { + id: 'emailAddress', + field: 'emailAddress', headerName: 'Email', flex: 1, }, + { + id: 'lastLogin', + field: 'lastLogin', + headerName: 'Last Login', + flex: 1, + valueGetter:(params)=>{ + if(params.value){ + return DateUtils.datetimeStr(params.value); + } + + } + }, { id: 'locked', field: 'locked', - type: 'bool', - headerName: 'Locked', + headerName: 'Status', flex: 1, - renderCell: (params) => { - return ( - - ); + valueGetter:(params)=>{ + if(params.value){ + return "Locked"; + }else{ + return "Active"; + } + + } + }, + { + field: 'verifiedDate', + type: 'actions', + headerName: 'Verified', + width: 100, + cellClassName: 'actions', + getActions: (params) => { + if(params.row.verifiedDate) + return [ + } + color="success" + />]; + return [ + } + color="error" + />]; }, }, ]; diff --git a/src/pages/pnspsUserSearchPage_Organization/UserSearchForm_Organization.js b/src/pages/pnspsUserSearchPage_Organization/UserSearchForm_Organization.js index 2a6505f..a17e3e6 100644 --- a/src/pages/pnspsUserSearchPage_Organization/UserSearchForm_Organization.js +++ b/src/pages/pnspsUserSearchPage_Organization/UserSearchForm_Organization.js @@ -1,15 +1,13 @@ // material-ui import { Button, - CardContent, FormControlLabel, - Grid, TextField, - Typography + CardContent, Autocomplete, + Grid, TextField } from '@mui/material'; import MainCard from "../../components/MainCard"; import {useForm} from "react-hook-form"; import { useState} from "react"; -import Checkbox from "@mui/material/Checkbox"; import * as React from "react"; // ==============================|| DASHBOARD - DEFAULT ||============================== // @@ -17,7 +15,7 @@ import * as React from "react"; const UserSearchForm_Organization = ({applySearch}) => { const [type, setType] = useState([]); - const [locked, setLocked] = useState(false); + const [accountFilter, setAccountFilter] = useState("Active"); const { reset, register, handleSubmit } = useForm() @@ -34,14 +32,15 @@ const UserSearchForm_Organization = ({applySearch}) => { fullName: data.fullName, email: data.email, phone: data.phone, - locked: locked, + brNoStr: data.brNoStr, + orgName: data.orgName, + accountFilter: accountFilter, }; applySearch(temp); }; function resetForm(){ setType([]); - setLocked(false); reset(); } @@ -60,6 +59,25 @@ const UserSearchForm_Organization = ({applySearch}) => { {/*row 2*/} + + + + + + + + + { - setLocked(event.target.checked)} - name="checked" - color="primary" - size="small" + { + if (newValue !== null){ + setAccountFilter(newValue); + } + }} + renderInput={(params) => ( + + )} /> - } - label={Locked} - /> {/**/} {/* { + if(params.value){ + return DateUtils.datetimeStr(params.value); + } + + } + }, { id: 'locked', field: 'locked', - type: 'bool', - headerName: 'Locked', + headerName: 'Status', flex: 1, - renderCell: (params) => { - return ( - - ); + valueGetter:(params)=>{ + if(params.value){ + return "Locked"; + }else{ + return "Active"; + } + + } + }, + { + field: 'verifiedDate', + type: 'actions', + headerName: 'Verified', + width: 100, + cellClassName: 'actions', + getActions: (params) => { + if(params.row.verifiedDate) + return [ + } + color="success" + />]; + return [ + } + color="error" + />]; }, }, ]; diff --git a/src/utils/ComboData.js b/src/utils/ComboData.js index a3d50ed..96bc236 100644 --- a/src/utils/ComboData.js +++ b/src/utils/ComboData.js @@ -1,32 +1,7 @@ -import * as yup from 'yup'; export const idDocType = ["passport","HKID","CNID","BR","otherCert"]; export const district = ["北區","長洲區","大埔區","大嶼山區","東區","觀塘區","黃大仙區","九龍城區","葵青區","南區","南丫島區", "坪洲區","荃灣區","沙田區","深水埗區","屯門區","灣仔區","西貢區","油尖旺區","元朗區","中西區"]; export const country = ["香港","內地","澳門"]; -export const validationSchema = ()=>{ - return yup.object().shape({ - username: yup.string().min(8,"用戶名稱最少8位").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('請輸入英文姓名'), - 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], '請輸入相同電郵'), - 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位數字'), - }); -} \ No newline at end of file +export const accountFilter = [{display:"Active", value:"active"},{display:"Locked", value:"locked"},{display:"Not verified", value:"notVerified"}]; diff --git a/src/utils/IconUtils.js b/src/utils/IconUtils.js index f8b633c..0226144 100644 --- a/src/utils/IconUtils.js +++ b/src/utils/IconUtils.js @@ -3,8 +3,12 @@ import DeleteIcon from '@mui/icons-material/DeleteForever'; import EditIcon from '@mui/icons-material/Edit'; import ViewIcon from '@mui/icons-material/Visibility'; import DownloadICon from '@mui/icons-material/Download'; +import VaildIcon from '@mui/icons-material/CheckCircleOutline'; +import InVaildIcon from '@mui/icons-material/HighlightOff'; export const Delete = DeleteIcon; export const Edit = EditIcon; export const View = ViewIcon; -export const Download = DownloadICon; \ No newline at end of file +export const Download = DownloadICon; +export const Vaild = VaildIcon; +export const Invaild = InVaildIcon; \ No newline at end of file