Alex Cheung 2 years ago
parent
commit
0adb790e55
15 changed files with 530 additions and 322 deletions
  1. +28
    -27
      src/pages/OrganizationDetailPage_FromUser/OrganizationCard_loadFromUser.js
  2. +2
    -3
      src/pages/OrganizationDetailPage_FromUser/index.js
  3. +1
    -1
      src/pages/OrganizationSearchPage/OrganizationTable.js
  4. +16
    -16
      src/pages/pnspsUserDetailPage_Individual/UserInformationCard_Individual.js
  5. +0
    -1
      src/pages/pnspsUserDetailPage_Individual/index.js
  6. +269
    -162
      src/pages/pnspsUserDetailPage_Organization/UserInformationCard_Organization.js
  7. +4
    -2
      src/pages/pnspsUserDetailPage_Organization/index.js
  8. +20
    -19
      src/pages/pnspsUserSearchPage_Individual/UserSearchForm_Individual.js
  9. +70
    -22
      src/pages/pnspsUserSearchPage_Individual/UserTable_Individual.js
  10. +41
    -18
      src/pages/pnspsUserSearchPage_Organization/UserSearchForm_Organization.js
  11. +68
    -22
      src/pages/pnspsUserSearchPage_Organization/UserTable_Organization.js
  12. +1
    -1
      src/routes/SettingRoutes.js
  13. +1
    -26
      src/utils/ComboData.js
  14. +4
    -1
      src/utils/DateUtils.js
  15. +5
    -1
      src/utils/IconUtils.js

src/pages/OrganizationDetailPage/OrganizationCard_loadFromUser.js → src/pages/OrganizationDetailPage_FromUser/OrganizationCard_loadFromUser.js View File

@@ -17,11 +17,11 @@ import {useNavigate} from "react-router-dom";
// ==============================|| DASHBOARD - DEFAULT ||============================== // // ==============================|| DASHBOARD - DEFAULT ||============================== //




const OrganizationCard = ({userData, id}) => {
const OrganizationCard_loadFromUser = ({userData, id}) => {


const [currentUserData, setCurrentUserData] = useState(userData); const [currentUserData, setCurrentUserData] = useState(userData);
const from = useForm({defaultValues: userData});
const {register,reset, handleSubmit} = from;
const form = useForm({defaultValues: userData});
const {register,reset, handleSubmit} = form;


const navigate = useNavigate(); const navigate = useNavigate();


@@ -57,7 +57,8 @@ const OrganizationCard = ({userData, id}) => {
}, [currentUserData]); }, [currentUserData]);




function onSubmitForm(_formData) {
const onSubmitForm=(_formData)=>{
console.log(_formData);
HttpUtils.post({ HttpUtils.post({
url: UrlUtils.POST_ORG_SAVE_PATH, url: UrlUtils.POST_ORG_SAVE_PATH,
params: { params: {
@@ -101,10 +102,29 @@ const OrganizationCard = ({userData, id}) => {
Information Information
</Typography> </Typography>


<form onSubmit={handleSubmit(onSubmitForm)}>
<form id="_form" onSubmit={handleSubmit(onSubmitForm)}>


<Grid container spacing={1}> <Grid container spacing={1}>
{/*bottom top*/}
<Grid item s={12} md={12} lg={12} sx={{mb: 3}} alignItems={"start"} justifyContent="center">

<Grid item sx={{ml: 3, mr: 3}}>
<Button
size="large"
variant="contained"
type="submit"
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}
>
Create
</Button>
</Grid>
</Grid>
{/*bottom top*/}
<Grid item lg={4} > <Grid item lg={4} >
<Grid container alignItems={"center"}> <Grid container alignItems={"center"}>
<Grid item xs={4} s={4} md={4} lg={4} <Grid item xs={4} s={4} md={4} lg={4}
@@ -340,30 +360,11 @@ const OrganizationCard = ({userData, id}) => {


</Grid> </Grid>


{/*bottom button*/}
<Grid item s={12} md={12} lg={12} sx={{mb: 3}} alignItems={"end"} justifyContent="center">
<Grid container maxWidth justifyContent="flex-end">

<Grid item sx={{ml: 3, mr: 3}}>
<Button
size="large"
variant="contained"
type="submit"
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}
>
Create
</Button>
</Grid>
</Grid>
</Grid>


</form> </form>
</MainCard> </MainCard>
); );
}; };


export default OrganizationCard;
export default OrganizationCard_loadFromUser;

src/pages/OrganizationDetailPage/index_loadFormUser.js → src/pages/OrganizationDetailPage_FromUser/index.js View File

@@ -12,7 +12,7 @@ import * as UrlUtils from "../../utils/ApiPathConst";
// ==============================|| DASHBOARD - DEFAULT ||============================== // // ==============================|| DASHBOARD - DEFAULT ||============================== //




const OrganizationDetailPage = () => {
const OrganizationDetailPage_FromUser = () => {
const params = useParams(); const params = useParams();
const [formData, setFormData] = useState({}) const [formData, setFormData] = useState({})
const [isLoading, setLoding] = useState(true); const [isLoading, setLoding] = useState(true);
@@ -57,7 +57,6 @@ const OrganizationDetailPage = () => {
<Grid item xs={12} md={12} lg={12}> <Grid item xs={12} md={12} lg={12}>
<InfoCard <InfoCard
userData={formData} userData={formData}
loadDataFun={loadData}
id={params.id} id={params.id}
/> />
</Grid> </Grid>
@@ -70,4 +69,4 @@ const OrganizationDetailPage = () => {
}; };




export default OrganizationDetailPage;
export default OrganizationDetailPage_FromUser;

+ 1
- 1
src/pages/OrganizationSearchPage/OrganizationTable.js View File

@@ -19,7 +19,7 @@ export default function OrganizationTable({recordList}) {
}, [recordList]); }, [recordList]);


const handleActionClick = (id) => () => { const handleActionClick = (id) => () => {
navigate('/orgUser/'+ id);
navigate('/org/'+ id);
}; };


const columns = [ const columns = [


+ 16
- 16
src/pages/pnspsUserDetailPage_Individual/UserInformationCard_Individual.js View File

@@ -79,6 +79,8 @@ const UserInformationCard_Individual = ({userData,userFile, loadDataFun}) => {
userData["faxNumber"] = userData.faxNo?.faxNumber; userData["faxNumber"] = userData.faxNo?.faxNumber;
userData["fax_countryCode"] = userData.faxNo?.countryCode; userData["fax_countryCode"] = userData.faxNo?.countryCode;


userData["lastLoginDate"] = userData.lastLogin?DateUtils.datetimeStr(userData.lastLogin):"";

setIdDocType(userData.idDocType); setIdDocType(userData.idDocType);
setDistrict(userData.district); setDistrict(userData.district);
setCountry(userData.country); setCountry(userData.country);
@@ -92,31 +94,32 @@ const UserInformationCard_Individual = ({userData,userFile, loadDataFun}) => {
}, [currentUserData]); }, [currentUserData]);




function onSubmitForm() {
function onSubmitForm(_data) {

HttpUtils.post({ HttpUtils.post({
url: UrlUtils.POST_IND_USER+"/"+userData.id, url: UrlUtils.POST_IND_USER+"/"+userData.id,
params: { params: {
prefix: formik.values.prefix,
prefix: _data.prefix,
enName: formik.values.enName, enName: formik.values.enName,
chName: formik.values.chName,
chName: _data.chName,
idDocType: idDocType, idDocType: idDocType,
contactTel: { contactTel: {
countryCode: formik.values.tel_countryCode,
phoneNumber: formik.values.phoneNumber
countryCode: _data.tel_countryCode,
phoneNumber: _data.phoneNumber
}, },
identification: formik.values.identification, identification: formik.values.identification,
checkDigit: formik.values.checkDigit, checkDigit: formik.values.checkDigit,
faxNo:{ faxNo:{
countryCode: formik.values.fax_countryCode,
faxNumber: formik.values.faxNumber
countryCode: _data.fax_countryCode,
faxNumber: _data.faxNumber
}, },
emailAddress:formik.values.emailAddress,
emailAddress:_data.emailAddress,
address:{ address:{
country:country, country:country,
district:district, district:district,
addressLine1: formik.values.addressLine1,
addressLine2: formik.values.addressLine2,
addressLine3: formik.values.addressLine3,
addressLine1: _data.addressLine1,
addressLine2: _data.addressLine2,
addressLine3: _data.addressLine3,
}, },
}, },
onSuccess: function(){ onSuccess: function(){
@@ -645,11 +648,8 @@ const UserInformationCard_Individual = ({userData,userFile, loadDataFun}) => {


<TextField <TextField
fullWidth fullWidth
{...register("lastLogin",
{
value: currentUserData?.lastLogin,
})}
id='lastLogin'
{...register("lastLoginDate")}
id='lastLoginDate'
disabled disabled
> >
</TextField> </TextField>


+ 0
- 1
src/pages/pnspsUserDetailPage_Individual/index.js View File

@@ -20,7 +20,6 @@ const UserMaintainPage_Individual = () => {




useEffect(()=>{ useEffect(()=>{
console.log(userData);
loadData(); loadData();
},[]); },[]);




+ 269
- 162
src/pages/pnspsUserDetailPage_Organization/UserInformationCard_Organization.js View File

@@ -1,6 +1,7 @@
// material-ui // material-ui
import { import {
Grid, TextField, Typography, Button
Grid, TextField, Typography, Button,
OutlinedInput, FormHelperText, Autocomplete
} from '@mui/material'; } from '@mui/material';
import MainCard from "../../components/MainCard"; import MainCard from "../../components/MainCard";
import * as React from "react"; import * as React from "react";
@@ -9,6 +10,10 @@ import {useEffect, useState} from "react";
import * as DateUtils from '../../utils/DateUtils'; import * as DateUtils from '../../utils/DateUtils';
import * as HttpUtils from '../../utils/HttpUtils'; import * as HttpUtils from '../../utils/HttpUtils';
import * as UrlUtils from "../../utils/ApiPathConst"; import * as UrlUtils from "../../utils/ApiPathConst";
import * as ComboData from "../../utils/ComboData";

import { useFormik,FormikProvider } from 'formik';
import * as yup from 'yup';


// ==============================|| DASHBOARD - DEFAULT ||============================== // // ==============================|| DASHBOARD - DEFAULT ||============================== //


@@ -19,28 +24,62 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
const [editMode, setEditMode] = useState(false); const [editMode, setEditMode] = useState(false);
const [locked, setLocked] = useState(false); const [locked, setLocked] = useState(false);


const [district, setDistrict] = useState(null);
const [country, setCountry] = useState(ComboData.country[0]);


const from = useForm({defaultValues: userData}); const from = useForm({defaultValues: userData});
const {register,reset, handleSubmit} = from; 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(() => { useEffect(() => {
let createDate = DateUtils.datetimeStr(userData.created); let createDate = DateUtils.datetimeStr(userData.created);
let modifiedBy = DateUtils.datetimeStr(userData.modified)+", "+userData.modifiedBy; let modifiedBy = DateUtils.datetimeStr(userData.modified)+", "+userData.modifiedBy;
userData["createDate"] = createDate; userData["createDate"] = createDate;
userData["modifieDate"] = modifiedBy; userData["modifieDate"] = modifiedBy;
userData["verifiedStatus"] = userData.verifiedBy? "Not verify yet":DateUtils.datetimeStr(userData.verifiedDate)+", "+userData.verifiedByName;
userData["verifiedStatus"] = userData.verifiedBy? DateUtils.datetimeStr(userData.verifiedDate)+", "+userData.verifiedByName: "Not verify yet";

userData["lastLoginDate"] = userData.lastLogin?DateUtils.datetimeStr(lastLoginDate):"";


userData["country"] = userData.address?.country;
userData["district"] = userData.address?.district;
userData["addressLine1"] = userData.address?.addressLine1;
userData["addressLine2"] = userData.address?.addressLine2;
userData["addressLine3"] = userData.address?.addressLine3;
userData["country"] = userData.addressBus?.country;
userData["district"] = userData.addressBus?.district;
userData["addressLine1"] = userData.addressBus?.addressLine1;
userData["addressLine2"] = userData.addressBus?.addressLine2;
userData["addressLine3"] = userData.addressBus?.addressLine3;


userData["phoneNumber"] = userData.contactTel?.phoneNumber; userData["phoneNumber"] = userData.contactTel?.phoneNumber;
userData["tel_countryCode"] = userData.contactTel?.countryCode; userData["tel_countryCode"] = userData.contactTel?.countryCode;


userData["faxNumber"] = userData.faxNo?.faxNumber; userData["faxNumber"] = userData.faxNo?.faxNumber;
userData["fax_countryCode"] = userData.faxNo?.countryCode; userData["fax_countryCode"] = userData.faxNo?.countryCode;

userData["brExpiryDate"] = userData.brExpiryDate?DateUtils.convertToDate(brExpiryDate):"";


setDistrict(userData.district);
setCountry(userData.country);
setCurrentUserData(userData); setCurrentUserData(userData);
}, [userData]); }, [userData]);
@@ -51,29 +90,36 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
}, [currentUserData]); }, [currentUserData]);




function onSubmitForm(_formData) {

function onSubmitForm(_data) {
HttpUtils.post({ HttpUtils.post({
url: UrlUtils.POST_IND_USER+"/"+userData.id, url: UrlUtils.POST_IND_USER+"/"+userData.id,
params: { params: {
chName: _formData.chName,
enName: _formData.enName,
chName: _data.chName,
enName: _data.enName,
contactTel: { contactTel: {
countryCode: _formData.tel_countryCode,
phoneNumber: _formData.phoneNumber
countryCode: _data.tel_countryCode,
phoneNumber: _data.phoneNumber
}, },
faxNo: { faxNo: {
countryCode: _formData.fax_countryCode,
faxNumber: _formData.faxNumber
countryCode: _data.fax_countryCode,
faxNumber: _data.faxNumber
}, },
addressBus: { addressBus: {
country: _formData.country,
district: _formData.district,
addressLine1: _formData.addressLine1,
addressLine2: _formData.addressLine2,
addressLine3: _formData.addressLine3,
country: country,
district: district,
addressLine1: _data.addressLine1,
addressLine2: _data.addressLine2,
addressLine3: _data.addressLine3,
}, },
identification: _formData.identification,
emailBus:_formData.emailBus,
identification: _data.identification,
emailBus:_data.emailBus,
contactPerson: _data.contactPerson,
enCompanyName: _data.enCompanyName,
chCompanyName: _data.chCompanyName,
brNo: _data.brNo,
brExpiryDate: formik.values.brExpiryDate,

}, },
onSuccess: function(){ onSuccess: function(){
loadDataFun(); loadDataFun();
@@ -89,6 +135,15 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
window.open("/org/fromUser/"+userData.id, "_blank", "noreferrer"); 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 = () => { const doLock = () => {
HttpUtils.get({ HttpUtils.get({
url: UrlUtils.GET_USER_LOCK+"/"+userData.id, url: UrlUtils.GET_USER_LOCK+"/"+userData.id,
@@ -107,6 +162,7 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
}); });
}; };


return ( return (
<MainCard elevation={0} <MainCard elevation={0}
border={false} border={false}
@@ -116,7 +172,67 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
Information Information
</Typography> </Typography>


<FormikProvider value={formik}>
<form onSubmit={handleSubmit(onSubmitForm)}> <form onSubmit={handleSubmit(onSubmitForm)}>

{/*top button*/}
<Grid item s={12} md={12} lg={12} sx={{mb: 3}} alignItems={"start"} justifyContent="center">
<Grid container maxWidth justifyContent="flex-start">
{editMode?
<>
<Grid item sx={{ml: 3, mr: 3}}>
<Button
size="large"
variant="contained"
onClick={loadDataFun}
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}
>
Cancel Edit
</Button>
</Grid>
<Grid item sx={{ml: 3, mr: 3}}>
<Button
size="large"
variant="contained"
type="submit"
color="success"
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}
>
Save
</Button>
</Grid>
</>
:
<>
<Grid item sx={{ml: 3, mr: 3}}>
<Button
size="large"
variant="contained"
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}
onClick={onEditClick}
>
Edit
</Button>
</Grid>
</>
}
</Grid>
</Grid>
{/*end top button*/}
<Grid container spacing={1}> <Grid container spacing={1}>
<Grid item lg={4} > <Grid item lg={4} >
@@ -243,10 +359,7 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {


<Grid item xs={7} s={7} md={7} lg={6} > <Grid item xs={7} s={7} md={7} lg={6} >
<TextField <TextField
{...register("identification",
{
value: currentUserData?.identification,
})}
{...register("identification")}
id='identification' id='identification'
disabled={!editMode} disabled={!editMode}
/> />
@@ -266,8 +379,8 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
<Grid item xs={7} s={7} md={7} lg={6}> <Grid item xs={7} s={7} md={7} lg={6}>
<TextField <TextField
fullWidth fullWidth
{...register("emailAddress")}
id='emailAddress'
{...register("emailBus")}
id='emailBus'
disabled={!editMode} disabled={!editMode}
/> />
</Grid> </Grid>
@@ -282,8 +395,9 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
Verified: Verified:
</Grid> </Grid>


{ {
currentUserData.verified || editMode?
currentUserData.verifiedBy || editMode?
<Grid item xs={6}> <Grid item xs={6}>
<TextField <TextField
fullWidth fullWidth
@@ -310,17 +424,20 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
textTransform: 'capitalize', textTransform: 'capitalize',
alignItems: 'end' alignItems: 'end'
}} }}
onClick={onVerifiedClick}
> >
Verified
Verify
</Button> </Button>
</Grid> </Grid>
</> </>
} }
</Grid> </Grid>
</Grid> </Grid>







<Grid item lg={4}> <Grid item lg={4}>
<Grid container alignItems={"center"}> <Grid container alignItems={"center"}>
<Grid item xs={4} s={4} md={4} lg={4} <Grid item xs={4} s={4} md={4} lg={4}
@@ -332,11 +449,8 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {


<TextField <TextField
fullWidth fullWidth
{...register("lastLogin",
{
value: currentUserData?.lastLogin,
})}
id='lastLogin'
{...register("lastLoginDate")}
id='lastLoginDate'
disabled disabled
> >
</TextField> </TextField>
@@ -352,106 +466,69 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
sx={{ml: 3, mr: 3, display: 'flex', alignItems: 'center'}}> sx={{ml: 3, mr: 3, display: 'flex', alignItems: 'center'}}>
Status: Status:
</Grid> </Grid>
{
editMode?
<Grid item xs={7} s={7} md={7} lg={6}>
<TextField
fullWidth
{...register("status")}
id='status'
disabled
/>
</Grid>
:
<>

<Grid item lg={4}>
<TextField
fullWidth
{...register("status")}
id='status'
disabled
/>
</Grid>
{locked?
<Grid lg={1}>
<Button
size="large"
variant="contained"
color="success"
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}
onClick={doUnlock}
>
Active
</Button>
</Grid>
:
<Grid item lg={1}>
<Button
size="large"
variant="contained"
color="error"
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}
onClick={doLock}
>
Lock
</Button>
</Grid>
}

</>
}



<Grid item xs={7} s={7} md={7} lg={6}>
<TextField
fullWidth
{...register("status")}
id='status'
disabled
/>
</Grid>
</Grid> </Grid>
</Grid> </Grid>


</Grid> </Grid>


{/*bottom button*/}
<Grid item s={12} md={12} lg={12} sx={{mb: 3}} alignItems={"end"} justifyContent="center">
<Grid container maxWidth justifyContent="flex-end">
{editMode?
<>
<Grid item sx={{ml: 3, mr: 3}}>
<Button
size="large"
variant="contained"
type="submit"
color="success"
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}
>
Save
</Button>
</Grid>
<Grid item sx={{ml: 3, mr: 3}}>
<Button
size="large"
variant="contained"
onClick={loadDataFun}
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}
>
Cancel & Back
</Button>
</Grid>
</>
:
<>
{locked?
<Grid item sx={{ml: 3, mr: 3}}>
<Button
size="large"
variant="contained"
color="primary"
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}
onClick={doUnlock}
>
Unlock
</Button>
</Grid>
:
<Grid item sx={{ml: 3, mr: 3}}>
<Button
size="large"
variant="contained"
color="primary"
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}
onClick={doLock}
>
Lock
</Button>
</Grid>
}
<Grid item sx={{ml: 3, mr: 3}}>
<Button
size="large"
variant="contained"
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}
onClick={onEditClick}
>
Edit
</Button>
</Grid>
</>
}
</Grid>
</Grid>


<Grid container spacing={1}> <Grid container spacing={1}>
<Grid item lg={1} > <Grid item lg={1} >
@@ -500,7 +577,7 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
fullWidth fullWidth
{...register("chCompanyName")} {...register("chCompanyName")}
id='chCompanyName' id='chCompanyName'
disabled
disabled={!editMode}
/> />
</Grid> </Grid>
</Grid> </Grid>
@@ -535,7 +612,7 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
<TextField <TextField
fullWidth fullWidth
{...register("contactPerson")} {...register("contactPerson")}
id='brExpiryDateTemp'
id='contactPerson'
disabled={!editMode} disabled={!editMode}
/> />
</Grid> </Grid>
@@ -575,12 +652,31 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
</Grid> </Grid>


<Grid item xs={7} s={7} md={7} lg={6}> <Grid item xs={7} s={7} md={7} lg={6}>
<TextField
fullWidth
{...register("brExpiryDateTemp")}
id='brExpiryDateTemp'
disabled={!editMode}
/>
<OutlinedInput
fullWidth
disabled={!editMode}
{...register("brExpiryDate")}
error={Boolean(formik.touched.brExpiryDate && formik.errors.brExpiryDate)}
id="brExpiryDate"
type="date"
value={formik.values.brExpiryDate}
format="dd/MM/yyyy"
name="brExpiryDate"
onChange={formik.handleChange}
placeholder="與與商業登記證相同如有"
inputProps={{
onKeyDown: (e) => {
if (e.key === 'Enter') {
e.preventDefault();
}
},
}}
/>
{formik.touched.brExpiryDate && formik.errors.brExpiryDate && (
<FormHelperText error id="brExpiryDate">
{formik.errors.brExpiryDate}
</FormHelperText>
)}
</Grid> </Grid>
</Grid> </Grid>
</Grid> </Grid>
@@ -595,28 +691,19 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
<Grid item xs={7} s={7} md={12} lg={6}> <Grid item xs={7} s={7} md={12} lg={6}>
<TextField <TextField
fullWidth fullWidth
{...register("addressLine1",
{
value: currentUserData?.address?.addressLine1,
})}
{...register("addressLine1")}
id='addressLine1' id='addressLine1'
disabled={!editMode} disabled={!editMode}
/> />
<TextField <TextField
fullWidth fullWidth
{...register("addressLine2",
{
value: currentUserData?.address?.addressLine2,
})}
{...register("addressLine2")}
id='addressLine2' id='addressLine2'
disabled={!editMode} disabled={!editMode}
/> />
<TextField <TextField
fullWidth fullWidth
{...register("addressLine3",
{
value: currentUserData?.address?.addressLine3,
})}
{...register("addressLine3")}
id='addressLine3' id='addressLine3'
disabled={!editMode} disabled={!editMode}
/> />
@@ -624,7 +711,7 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
</Grid> </Grid>
</Grid> </Grid>


<Grid item lg={4} >
<Grid item lg={4}>
<Grid container alignItems={"center"}> <Grid container alignItems={"center"}>
<Grid item xs={4} s={4} md={4} lg={4} <Grid item xs={4} s={4} md={4} lg={4}
sx={{ml: 3, mr: 3, display: 'flex', alignItems: 'center'}}> sx={{ml: 3, mr: 3, display: 'flex', alignItems: 'center'}}>
@@ -632,17 +719,25 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
</Grid> </Grid>


<Grid item xs={7} s={7} md={7} lg={6}> <Grid item xs={7} s={7} md={7} lg={6}>
<TextField
fullWidth
{...register("district")}
id='district'
disabled={!editMode}
/>
<Autocomplete
fullWidth
disablePortal
id="district"
{...register("district")}
value={district}
options={ComboData.district}
onChange={(event, newValue) => {
setDistrict(newValue);
}}
disabled={!editMode}
sx={{"& .MuiInputBase-root": { height: "41px" },"#district":{padding: "0px 0px 0px 0px"}, "& .MuiAutocomplete-endAdornment": { top: "auto" },}}
renderInput={(params) => <TextField {...params} placeholder="區域 (只適用於香港)"/>}
/>
</Grid> </Grid>
</Grid> </Grid>
</Grid> </Grid>

<Grid item lg={4} >
<Grid item lg={4}>
<Grid container alignItems={"center"}> <Grid container alignItems={"center"}>
<Grid item xs={4} s={4} md={4} lg={4} <Grid item xs={4} s={4} md={4} lg={4}
sx={{ml: 3, mr: 3, display: 'flex', alignItems: 'center'}}> sx={{ml: 3, mr: 3, display: 'flex', alignItems: 'center'}}>
@@ -650,19 +745,31 @@ const UserInformationCard_Organization = ({userData, loadDataFun}) => {
</Grid> </Grid>


<Grid item xs={7} s={7} md={7} lg={6}> <Grid item xs={7} s={7} md={7} lg={6}>
<TextField
fullWidth
{...register("country")}
id='country'
<Autocomplete
fullWidth
disablePortal
disabled={!editMode} disabled={!editMode}
id="country"
value={country}
options={ComboData.country}
{...register("country")}
onChange={(event, newValue) => {
setCountry(newValue);
}}
sx={{"& .MuiInputBase-root": { height: "41px" },"#country":{padding: "0px 0px 0px 0px"}, "& .MuiAutocomplete-endAdornment": { top: "auto" },}}
renderInput={(params) => <TextField {...params} placeholder="國家/地區"/>}
/> />
</Grid> </Grid>

</Grid> </Grid>
</Grid> </Grid>

</Grid> </Grid>


</form> </form>

</FormikProvider>
</MainCard> </MainCard>
); );
}; };


+ 4
- 2
src/pages/pnspsUserDetailPage_Organization/index.js View File

@@ -4,7 +4,6 @@ import {useEffect, useState} from "react";
import * as React from "react"; import * as React from "react";
//import axios from "axios"; //import axios from "axios";
import * as HttpUtils from "../../utils/HttpUtils"; import * as HttpUtils from "../../utils/HttpUtils";
import {apiPath} from "../../auth/utils";
import {useParams} from "react-router-dom"; import {useParams} from "react-router-dom";
import FileList from "../../components/FileList" import FileList from "../../components/FileList"
import MainCard from "../../components/MainCard"; import MainCard from "../../components/MainCard";
@@ -29,8 +28,11 @@ const UserMaintainPage_Organization = () => {
const loadData = ()=>{ const loadData = ()=>{
setLoding(true); setLoding(true);
HttpUtils.get({ HttpUtils.get({
url: `${apiPath}${UrlUtils.GET_USER_PATH}/${params.id}`,
url: `${UrlUtils.GET_ORG_USER_PATH}/${params.id}`,
onSuccess: function(response){ onSuccess: function(response){
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) setUserData(response.data)
} }
}); });


+ 20
- 19
src/pages/pnspsUserSearchPage_Individual/UserSearchForm_Individual.js View File

@@ -1,15 +1,13 @@
// material-ui // material-ui
import { import {
Button, Button,
CardContent, FormControlLabel,
CardContent,
Grid, TextField, Grid, TextField,
Typography
Autocomplete
} from '@mui/material'; } from '@mui/material';
import MainCard from "../../components/MainCard"; import MainCard from "../../components/MainCard";
import {useForm} from "react-hook-form"; import {useForm} from "react-hook-form";

import { useState} from "react"; import { useState} from "react";
import Checkbox from "@mui/material/Checkbox";
import * as React from "react"; import * as React from "react";
// ==============================|| DASHBOARD - DEFAULT ||============================== // // ==============================|| DASHBOARD - DEFAULT ||============================== //


@@ -17,8 +15,7 @@ import * as React from "react";
const UserSearchForm_Individual = ({applySearch}) => { const UserSearchForm_Individual = ({applySearch}) => {


const [type, setType] = useState([]); const [type, setType] = useState([]);
const [locked, setLocked] = useState(false);

const [accountFilter, setAccountFilter] = useState("Active");


const { reset, register, handleSubmit } = useForm() const { reset, register, handleSubmit } = useForm()
const onSubmit = (data) => { const onSubmit = (data) => {
@@ -34,14 +31,13 @@ const UserSearchForm_Individual = ({applySearch}) => {
fullName: data.fullName, fullName: data.fullName,
email: data.email, email: data.email,
phone: data.phone, phone: data.phone,
locked: locked,
accountFilter: accountFilter,
}; };
applySearch(temp); applySearch(temp);
}; };


function resetForm(){ function resetForm(){
setType([]); setType([]);
setLocked(false);
reset(); reset();
} }


@@ -97,18 +93,23 @@ const UserSearchForm_Individual = ({applySearch}) => {
</Grid> </Grid>


<Grid item xs={9} s={6} md={5} lg={3} sx={{ml:3, mr:3, mb:3}}> <Grid item xs={9} s={6} md={5} lg={3} sx={{ml:3, mr:3, mb:3}}>
<FormControlLabel
control={
<Checkbox
checked={locked}
onChange={(event) => setLocked(event.target.checked)}
name="checked"
color="primary"
size="small"
<Autocomplete
{...register("accountFilter")}
disablePortal
id="accountFilter"
options={["Active","Locked","Not verified"]}
value={accountFilter}
onChange={(event, newValue) => {
if (newValue !== null){
setAccountFilter(newValue);
}
}}
renderInput={(params) => (
<TextField {...params}
label="Status"
/>
)}
/> />
}
label={<Typography variant="h6">Locked</Typography>}
/>
</Grid> </Grid>
{/*<Grid item xs={9} s={6} md={5} lg={3} sx={{ml:3, mr:3, mb:3}}>*/} {/*<Grid item xs={9} s={6} md={5} lg={3} sx={{ml:3, mr:3, mb:3}}>*/}
{/* <TextField*/} {/* <TextField*/}


+ 70
- 22
src/pages/pnspsUserSearchPage_Individual/UserTable_Individual.js View File

@@ -2,19 +2,19 @@
import * as React from 'react'; import * as React from 'react';
import { import {
DataGrid, DataGrid,
GridActionsCellItem,
GridActionsCellItem
} from "@mui/x-data-grid"; } from "@mui/x-data-grid";
import VisibilityIcon from '@mui/icons-material/Visibility'; import VisibilityIcon from '@mui/icons-material/Visibility';
import HighlightOff from '@mui/icons-material/HighlightOff';
import CheckCircleOutline from '@mui/icons-material/CheckCircleOutline';
import {useEffect} from "react"; import {useEffect} from "react";
import {useNavigate} from "react-router-dom"; import {useNavigate} from "react-router-dom";
import { useTheme } from '@mui/material/styles';
import Checkbox from '@mui/material/Checkbox';
import * as DateUtils from "../../utils/DateUtils";
// ==============================|| EVENT TABLE ||============================== // // ==============================|| EVENT TABLE ||============================== //


export default function UserTable_Individual({recordList}) { export default function UserTable_Individual({recordList}) {
const [rows, setRows] = React.useState(recordList); const [rows, setRows] = React.useState(recordList);
const [rowModesModel] = React.useState({}); const [rowModesModel] = React.useState({});
const theme = useTheme();


const navigate = useNavigate() const navigate = useNavigate()


@@ -52,34 +52,82 @@ export default function UserTable_Individual({recordList}) {
flex: 1, flex: 1,
}, },
{ {
id: 'name',
field: 'name',
headerName: 'Full Name',
id: 'enName',
field: 'enName',
headerName: 'Name (Eng)',
flex: 1, flex: 1,
}, },
{ {
id: 'email',
field: 'email',
id: 'chName',
field: 'chName',
headerName: 'Name (Ch)',
flex: 1,
},
{
id: 'contactTel',
field: 'contactTel',
headerName: 'Tel.',
flex: 1,
valueGetter:(params)=>{
if(params.value){
let tel = JSON.parse(params.value);
return "+"+tel.countryCode+ " "+tel.phoneNumber;
}
}
},
{
id: 'emailAddress',
field: 'emailAddress',
headerName: 'Email', headerName: 'Email',
flex: 1, flex: 1,
}, },
{
id: 'lastLogin',
field: 'lastLogin',
headerName: 'Last Login',
flex: 1,
valueGetter:(params)=>{
if(params.value){
return DateUtils.datetimeStr(params.value);
}
}
},
{ {
id: 'locked', id: 'locked',
field: 'locked', field: 'locked',
type: 'bool',
headerName: 'Locked',
headerName: 'Status',
flex: 1, flex: 1,
renderCell: (params) => {
return (
<Checkbox
theme={theme}
key="locked"
checked={params.row.locked}
color="primary"
size="small"
//onChange={handleChange}
/>
);
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 [
<GridActionsCellItem
key=""
icon={<CheckCircleOutline/>}
color="success"
/>];
return [
<GridActionsCellItem
key=""
icon={<HighlightOff/>}
color="error"
/>];
}, },
}, },
]; ];


+ 41
- 18
src/pages/pnspsUserSearchPage_Organization/UserSearchForm_Organization.js View File

@@ -1,15 +1,13 @@
// material-ui // material-ui
import { import {
Button, Button,
CardContent, FormControlLabel,
Grid, TextField,
Typography
CardContent, Autocomplete,
Grid, TextField
} from '@mui/material'; } from '@mui/material';
import MainCard from "../../components/MainCard"; import MainCard from "../../components/MainCard";
import {useForm} from "react-hook-form"; import {useForm} from "react-hook-form";


import { useState} from "react"; import { useState} from "react";
import Checkbox from "@mui/material/Checkbox";
import * as React from "react"; import * as React from "react";
// ==============================|| DASHBOARD - DEFAULT ||============================== // // ==============================|| DASHBOARD - DEFAULT ||============================== //


@@ -17,7 +15,7 @@ import * as React from "react";
const UserSearchForm_Organization = ({applySearch}) => { const UserSearchForm_Organization = ({applySearch}) => {


const [type, setType] = useState([]); const [type, setType] = useState([]);
const [locked, setLocked] = useState(false);
const [accountFilter, setAccountFilter] = useState("Active");




const { reset, register, handleSubmit } = useForm() const { reset, register, handleSubmit } = useForm()
@@ -34,14 +32,15 @@ const UserSearchForm_Organization = ({applySearch}) => {
fullName: data.fullName, fullName: data.fullName,
email: data.email, email: data.email,
phone: data.phone, phone: data.phone,
locked: locked,
brNoStr: data.brNoStr,
orgName: data.orgName,
accountFilter: accountFilter,
}; };
applySearch(temp); applySearch(temp);
}; };


function resetForm(){ function resetForm(){
setType([]); setType([]);
setLocked(false);
reset(); reset();
} }


@@ -60,6 +59,25 @@ const UserSearchForm_Organization = ({applySearch}) => {


{/*row 2*/} {/*row 2*/}
<Grid container alignItems={"center"}> <Grid container alignItems={"center"}>

<Grid item xs={9} s={6} md={5} lg={3} sx={{ml:3, mr:3, mb:3}}>
<TextField
fullWidth
{...register("orgName")}
id="orgName"
label="Org Name"
/>
</Grid>

<Grid item xs={9} s={6} md={5} lg={3} sx={{ml:3, mr:3, mb:3}}>
<TextField
fullWidth
{...register("brNoStr")}
id="brNoStr"
label="BR No."
/>
</Grid>

<Grid item xs={9} s={6} md={5} lg={3} sx={{ml:3, mr:3, mb:3}}> <Grid item xs={9} s={6} md={5} lg={3} sx={{ml:3, mr:3, mb:3}}>
<TextField <TextField
fullWidth fullWidth
@@ -97,18 +115,23 @@ const UserSearchForm_Organization = ({applySearch}) => {
</Grid> </Grid>


<Grid item xs={9} s={6} md={5} lg={3} sx={{ml:3, mr:3, mb:3}}> <Grid item xs={9} s={6} md={5} lg={3} sx={{ml:3, mr:3, mb:3}}>
<FormControlLabel
control={
<Checkbox
checked={locked}
onChange={(event) => setLocked(event.target.checked)}
name="checked"
color="primary"
size="small"
<Autocomplete
{...register("accountFilter")}
disablePortal
id="accountFilter"
options={["Active","Locked","Not verified"]}
value={accountFilter}
onChange={(event, newValue) => {
if (newValue !== null){
setAccountFilter(newValue);
}
}}
renderInput={(params) => (
<TextField {...params}
label="Status"
/>
)}
/> />
}
label={<Typography variant="h6">Locked</Typography>}
/>
</Grid> </Grid>
{/*<Grid item xs={9} s={6} md={5} lg={3} sx={{ml:3, mr:3, mb:3}}>*/} {/*<Grid item xs={9} s={6} md={5} lg={3} sx={{ml:3, mr:3, mb:3}}>*/}
{/* <TextField*/} {/* <TextField*/}


+ 68
- 22
src/pages/pnspsUserSearchPage_Organization/UserTable_Organization.js View File

@@ -7,14 +7,13 @@ import {
import VisibilityIcon from '@mui/icons-material/Visibility'; import VisibilityIcon from '@mui/icons-material/Visibility';
import {useEffect} from "react"; import {useEffect} from "react";
import {useNavigate} from "react-router-dom"; import {useNavigate} from "react-router-dom";
import { useTheme } from '@mui/material/styles';
import Checkbox from '@mui/material/Checkbox';
import HighlightOff from '@mui/icons-material/HighlightOff';
import CheckCircleOutline from '@mui/icons-material/CheckCircleOutline';
// ==============================|| EVENT TABLE ||============================== // // ==============================|| EVENT TABLE ||============================== //


export default function UserTable_Organization({recordList}) { export default function UserTable_Organization({recordList}) {
const [rows, setRows] = React.useState(recordList); const [rows, setRows] = React.useState(recordList);
const [rowModesModel] = React.useState({}); const [rowModesModel] = React.useState({});
const theme = useTheme();


const navigate = useNavigate() const navigate = useNavigate()


@@ -52,34 +51,81 @@ export default function UserTable_Organization({recordList}) {
flex: 1, flex: 1,
}, },
{ {
id: 'name',
field: 'name',
headerName: 'Full Name',
id: 'enName',
field: 'enName',
headerName: 'Name (Eng)',
flex: 1, flex: 1,
}, },
{ {
id: 'email',
field: 'email',
headerName: 'Email',
id: 'chName',
field: 'chName',
headerName: 'Name (Ch)',
flex: 1, flex: 1,
}, },
{
id: 'enCompanyName',
field: 'enCompanyName',
headerName: 'Company(Eng)',
flex: 1,
},
{
id: 'chCompanyName',
field: 'chCompanyName',
headerName: 'Company(Ch)',
flex: 1,
},
{
id: 'brNo',
field: 'brNo',
headerName: 'Br No',
flex: 1,
},
{
id: 'lastLogin',
field: 'lastLogin',
headerName: 'Last Login',
flex: 1,
valueGetter:(params)=>{
if(params.value){
return DateUtils.datetimeStr(params.value);
}
}
},
{ {
id: 'locked', id: 'locked',
field: 'locked', field: 'locked',
type: 'bool',
headerName: 'Locked',
headerName: 'Status',
flex: 1, flex: 1,
renderCell: (params) => {
return (
<Checkbox
theme={theme}
key="locked"
checked={params.row.locked}
color="primary"
size="small"
//onChange={handleChange}
/>
);
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 [
<GridActionsCellItem
key=""
icon={<CheckCircleOutline/>}
color="success"
/>];
return [
<GridActionsCellItem
key=""
icon={<HighlightOff/>}
color="error"
/>];
}, },
}, },
]; ];


+ 1
- 1
src/routes/SettingRoutes.js View File

@@ -17,7 +17,7 @@ const UserGroupSearchPage = Loadable(lazy(() => import('pages/pnspsUserGroupSear
const UserGroupDetailPage = Loadable(lazy(() => import('pages/pnspsUserGroupDetailPage'))); const UserGroupDetailPage = Loadable(lazy(() => import('pages/pnspsUserGroupDetailPage')));
const OrganizationSearchPage = Loadable(lazy(() => import('pages/OrganizationSearchPage'))); const OrganizationSearchPage = Loadable(lazy(() => import('pages/OrganizationSearchPage')));
const OrganizationDetailPage = Loadable(lazy(() => import('pages/OrganizationDetailPage'))); const OrganizationDetailPage = Loadable(lazy(() => import('pages/OrganizationDetailPage')));
const OrganizationDetailPage_fromUser = Loadable(lazy(() => import('pages/OrganizationDetailPage/index_loadFormUser')));
const OrganizationDetailPage_fromUser = Loadable(lazy(() => import('pages/OrganizationDetailPage_FromUser')));




// ==============================|| AUTH ROUTING ||============================== // // ==============================|| AUTH ROUTING ||============================== //


+ 1
- 26
src/utils/ComboData.js View File

@@ -1,32 +1,7 @@
import * as yup from 'yup';


export const idDocType = ["passport","HKID","CNID","BR","otherCert"]; export const idDocType = ["passport","HKID","CNID","BR","otherCert"];
export const district = ["北區","長洲區","大埔區","大嶼山區","東區","觀塘區","黃大仙區","九龍城區","葵青區","南區","南丫島區", export const district = ["北區","長洲區","大埔區","大嶼山區","東區","觀塘區","黃大仙區","九龍城區","葵青區","南區","南丫島區",
"坪洲區","荃灣區","沙田區","深水埗區","屯門區","灣仔區","西貢區","油尖旺區","元朗區","中西區"]; "坪洲區","荃灣區","沙田區","深水埗區","屯門區","灣仔區","西貢區","油尖旺區","元朗區","中西區"];
export const country = ["中國香港","中國","中國澳門"]; 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位數字'),
});
}
export const accountFilter = [{display:"Active", value:"active"},{display:"Locked", value:"locked"},{display:"Not verified", value:"notVerified"}];

+ 4
- 1
src/utils/DateUtils.js View File

@@ -10,9 +10,12 @@ export const dateStr = (date) =>{
return dayjs(date).format("DD-MM-YYYY") return dayjs(date).format("DD-MM-YYYY")
}; };


const convertToDate = (date)=>{
export const convertToDate = (date)=>{
if(Array.isArray(date)){ if(Array.isArray(date)){
return new Date(date[0],date[1],date[2],date[3],date[4],date[5]); return new Date(date[0],date[1],date[2],date[3],date[4],date[5]);
} }
if(typeof date == 'number'){
return new Date(date);
}
return date; return date;
} }

+ 5
- 1
src/utils/IconUtils.js View File

@@ -3,8 +3,12 @@ import DeleteIcon from '@mui/icons-material/DeleteForever';
import EditIcon from '@mui/icons-material/Edit'; import EditIcon from '@mui/icons-material/Edit';
import ViewIcon from '@mui/icons-material/Visibility'; import ViewIcon from '@mui/icons-material/Visibility';
import DownloadICon from '@mui/icons-material/Download'; 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 Delete = DeleteIcon;
export const Edit = EditIcon; export const Edit = EditIcon;
export const View = ViewIcon; export const View = ViewIcon;
export const Download = DownloadICon;
export const Download = DownloadICon;
export const Vaild = VaildIcon;
export const Invaild = InVaildIcon;

Loading…
Cancel
Save