Browse Source

fix file upload and add alert window for password error

master
Alex Cheung 2 years ago
parent
commit
ebf4b375c8
8 changed files with 298 additions and 68 deletions
  1. +1
    -1
      src/pages/authentication/BusRegister.js
  2. +1
    -1
      src/pages/authentication/Register.js
  3. +20
    -14
      src/pages/authentication/auth-forms/AuthLoginCustom.js
  4. +79
    -31
      src/pages/authentication/auth-forms/BusCustomFormWizard.js
  5. +39
    -15
      src/pages/authentication/auth-forms/CustomFormWizard.js
  6. +48
    -0
      src/pages/authentication/auth-forms/PasswordAlertDialog.js
  7. +107
    -0
      src/pages/authentication/auth-forms/PreviewUploadFileTable.js
  8. +3
    -6
      src/pages/authentication/auth-forms/UploadFileTable.js

+ 1
- 1
src/pages/authentication/BusRegister.js View File

@@ -125,7 +125,7 @@
<Typography sx={{ mt: 2, mb: 1 }}>
All steps completed - you&apos;re finished
</Typography>
<Stack direction="row" sx={{ pt: 2 }}>
<Stack direction="row" sx={{ pb: 2 }}>
<Stack sx={{ flex: '1 1 auto' }} />
<Button onClick={handleReset}>Reset</Button>
</Stack>


+ 1
- 1
src/pages/authentication/Register.js View File

@@ -141,7 +141,7 @@ const AuthWrapper = Loadable(lazy(() => import('./AuthWrapperCustom')));
<CustomFormWizard setUpdateValid={setUpdateValid} step={activeStep} />
{/* <CustomFormWizard step={activeStep} /> */}
</AuthWrapper>
<Stack direction="row" sx={{ pt: 2 }}>
<Stack direction="row" sx={{ pb: 2 }}>
{ activeStep === 2|| activeStep === 0? (
<Button
color="inherit"


+ 20
- 14
src/pages/authentication/auth-forms/AuthLoginCustom.js View File

@@ -1,6 +1,8 @@
import React, {
useEffect,
useState} from 'react';
useState,
lazy
} from 'react';
import { Link as RouterLink } from 'react-router-dom';
import {useNavigate} from 'react-router-dom';
import {useForm,} from 'react-hook-form'
@@ -29,6 +31,8 @@ import { useFormik,FormikProvider } from 'formik';
// project import
//import FirebaseSocial from './FirebaseSocial';
import AnimateButton from 'components/@extended/AnimateButton';
import Loadable from 'components/Loadable';
const PasswordAlertDialog = Loadable(lazy(() => import('./PasswordAlertDialog')));

// assets
import { EyeOutlined, EyeInvisibleOutlined } from '@ant-design/icons';
@@ -51,9 +55,9 @@ const AuthLoginCustom = () => {

// let [posts, setPosts] = useState([]);
const [isValid, setisValid] = useState(false);
const [isSuccess, setSuccess] = useState();
const [isSumitting, setSumitting] = useState();
// const [isSuccess, setSuccess] = useState();
// const [isSumitting, setSumitting] = useState();
const [open, setOpen] = React.useState(false);
// useEffect(() => {
// // console.log("POST: " + posts.accessToken);
// },[posts]);
@@ -64,7 +68,7 @@ const AuthLoginCustom = () => {

const tryLogin = () => {
if(isValid){
setSumitting(true)
// setSumitting(true)
useJwt
.login({username: values.username, password: values.password})
.then((response) => {
@@ -77,16 +81,18 @@ const AuthLoginCustom = () => {
//avatar: require('src/assets/images/users/avatar-3.png').default,
}
const data = {...userData, accessToken: response.data.accessToken, refreshToken: response.data.refreshToken}
setSuccess(true)
// setSuccess(true)
dispatch(handleLogin(data))
navigate('/dashboard');
setSumitting(false)
console.log(isSuccess)
// setSumitting(false)
})
.catch((error) => {
setSuccess(false)
// setSuccess(false)
setOpen(true)
console.error(error)
});
}else{
setOpen(true)
}
}

@@ -149,6 +155,10 @@ const AuthLoginCustom = () => {
// }
// }

const handleClose = () => {
setOpen(false);
};

const { values } = formik
useEffect(() => {
checkDataField(values)
@@ -162,11 +172,6 @@ const AuthLoginCustom = () => {
<Grid container spacing={3}>
<Grid item xs={12}>
<Stack spacing={1}>
{!isSuccess && isSumitting && (
<FormHelperText error id="standard-weight-helper-text-username-login">
用戶登入名稱或密碼錯誤
</FormHelperText>
)}
<InputLabel htmlFor="email-login">用戶登入名稱</InputLabel>
<OutlinedInput
id="username"
@@ -269,6 +274,7 @@ const AuthLoginCustom = () => {
{/* <FirebaseSocial />*/}
{/*</Grid> */}
</Grid>
<PasswordAlertDialog open={open} handleClose={handleClose}/>
</form>
</FormikProvider>
);


+ 79
- 31
src/pages/authentication/auth-forms/BusCustomFormWizard.js View File

@@ -28,15 +28,16 @@ import * as yup from 'yup';
// import AnimateButton from 'components/@extended/AnimateButton';

import { strengthColorChi, strengthIndicator } from 'utils/password-strength';
import {apiPath} from "auth/utils";
// import {apiPath} from "auth/utils";
import axios from "axios";
import {POST_PUBLIC_USER_REGISTER} from "utils/ApiPathConst";
import * as HttpUtils from 'utils/HttpUtils';
// import * as HttpUtils from 'utils/HttpUtils';

import Loadable from 'components/Loadable';
import { lazy } from 'react';
const UploadFileTable = Loadable(lazy(() => import('./UploadFileTable')));
const LoadingComponent = Loadable(lazy(() => import('../../extra-pages/LoadingComponent')));
const PreviewUploadFileTable = Loadable(lazy(() => import('./PreviewUploadFileTable')));
// import UploadFileTable from './UploadFileTable';
// import LoadingComponent from "../../extra-pages/LoadingComponent";

@@ -57,6 +58,7 @@ const BusCustomFormWizard = (props) => {
const [fileListData, setFileListData] = useState([]);
const [checkUpload, setCheckUpload] = useState(false);
const [isLoading, setLoding] = useState(true);
const [updateRows, setUpdateRows] = useState([]);

const handleClickShowPassword = () => {
setShowPassword(!showPassword);
@@ -92,7 +94,7 @@ const BusCustomFormWizard = (props) => {
+ "於所有文本、平面圖像、圖畫、圖片、照片以及數據或其他資料的匯編,均受版權保障。\n香"
+ "港特別行政區政府是本網頁內所有版權作品的擁有人,除非預先得到政府物流服務署的書面"
+ "授權,否則嚴禁複製、改編、分發、發布或向公眾提供該等版權作品。"
// const refType = "identification";
const refType = "identification";

useEffect(() => {
changePassword('');
@@ -186,12 +188,13 @@ const BusCustomFormWizard = (props) => {
break;
}
}
if (!isDuplicate) {
if (!isDuplicate && i+currentIndex<5) {
file.id = currentIndex+i
saveFileList.push(file)
updateList.items.add(file);
}
console.log("currentIndex")
console.log(currentIndex)
}
let updatedFileList = updateList.files;

@@ -247,9 +250,8 @@ const BusCustomFormWizard = (props) => {
tncFlag = false
}

if (isValid){
axios.post(`${apiPath}${POST_PUBLIC_USER_REGISTER}`, {
username: values.username,
const user = {
username: values.username,
password: values.password,
name: values.username,
enCompanyName: values.enCompanyName,
@@ -257,27 +259,36 @@ const BusCustomFormWizard = (props) => {
emailBus: values.email,
brNo:values.brNo,
brExpiryDate:values.brExpiryDate,
userFaxNo:userFaxNo,
busUserContactTel:busUserContactTel,
busUserAddress:busUserAddress,
contactPerson: values.enName,
tncFlag:tncFlag,
type:"ORG"
};

var formData = new FormData();
for (let i = 0; i < fileListData.length; i++){
const file = fileListData[i]
formData.append("multipartFileList", file);
}
formData.append("refType", refType);
for (const [key, value] of Object.entries(user)) {
formData.append(key, value);
}
formData.append("userFaxNo", JSON.stringify(userFaxNo));
formData.append("busUserContactTel", JSON.stringify(busUserContactTel));
formData.append("busUserAddress", JSON.stringify(busUserAddress));

if (isValid){
axios.post(POST_PUBLIC_USER_REGISTER, formData,{
headers: {
"Content-Type":"multipart/form-data"
}
})
.then((response) => {
console.log(response)
setCheckUpload(true)
HttpUtils.fileUpload(
{
refType:"brFile",
refId: response.data.id,
file: fileList[0],
onSuccess: (response)=>{
console.log(response);
setLoding(false);
// setOpen(true);
}
}
);
setLoding(false);
})
.catch(error => {
console.error(error);
@@ -319,7 +330,6 @@ const BusCustomFormWizard = (props) => {
var validRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
// var result = reg.test(email);
var result = email.match(validRegex);
console.log("test1: "+result)
if (result == false) {
return false;
}
@@ -879,7 +889,14 @@ const BusCustomFormWizard = (props) => {
value={formik.values.phoneCountryCode}
name="phoneCountryCode"
// onBlur={formik.handleBlur}
onChange={formik.handleChange}
// onChange={formik.handleChange}
onChange={(event) => {
const value = event.target.value;
if (value.match(/[^0-9]/)) {
return event.preventDefault();
}
formik.setFieldValue("phoneCountryCode",value);
}}
placeholder="國際區號"
error={Boolean(formik.touched.phone && formik.errors.phone)}
onBlur={formik.handleBlur}
@@ -899,7 +916,14 @@ const BusCustomFormWizard = (props) => {
value={formik.values.phone}
name="phone"
onBlur={formik.handleBlur}
onChange={formik.handleChange}
// onChange={formik.handleChange}
onChange={(event) => {
const value = event.target.value;
if (value.match(/[^0-9]/)) {
return event.preventDefault();
}
formik.setFieldValue("phone",value);
}}
placeholder="聯絡電話"
error={Boolean(formik.touched.phone && formik.errors.phone)}
inputProps={{
@@ -935,7 +959,14 @@ const BusCustomFormWizard = (props) => {
value={formik.values.faxCountryCode}
name="faxCountryCode"
// onBlur={formik.handleBlur}
onChange={formik.handleChange}
// onChange={formik.handleChange}
onChange={(event) => {
const value = event.target.value;
if (value.match(/[^0-9]/)) {
return event.preventDefault();
}
formik.setFieldValue("faxCountryCode",value);
}}
placeholder="國際區號"
inputProps={{
maxLength: 3,
@@ -953,7 +984,14 @@ const BusCustomFormWizard = (props) => {
value={formik.values.fax}
name="fax"
// onBlur={formik.handleBlur}
onChange={formik.handleChange}
// onChange={formik.handleChange}
onChange={(event) => {
const value = event.target.value;
if (value.match(/[^0-9]/)) {
return event.preventDefault();
}
formik.setFieldValue("fax",value);
}}
placeholder="傳真號碼"
inputProps={{
maxLength: 8,
@@ -980,7 +1018,7 @@ const BusCustomFormWizard = (props) => {
<span style={{color: '#f10000'}}>*</span>
</Typography>
<Typography display="inline" variant="h6" sx={{ fontSize: 12,color: 'primary.primary'}}>請上傳你的 有效商業登記證及其他文件 的數碼檔案,以驗證你的身份。</Typography>
<Typography display="inline" variant="h6" sx={{ fontSize: 12,color: 'primary.primary'}}>如: 香港身份證; 護照; 中國內地身份證等</Typography>
{/* <Typography display="inline" variant="h6" sx={{ fontSize: 12,color: 'primary.primary'}}>如: 香港身份證; 護照; 中國內地身份證等</Typography> */}
<Stack mt={1} direction="row" justifyContent="flex-start" alignItems="center" spacing={2}>
<Button variant="contained" component="label" sx={{ fontSize: 12,height:'40px'}}>上傳商業登記證及其他文件
<input
@@ -996,7 +1034,7 @@ const BusCustomFormWizard = (props) => {
{/* <Typography display="inline" variant="h6" sx={{ fontSize: 12, color: 'primary.primary'}}></Typography> */}
</Stack>
{fileList !=null?
<UploadFileTable recordList={fileListData} />:null}
<UploadFileTable key="uploadTable" recordList={fileListData} setUpdateRows={setUpdateRows}/>:null}
{/* <Stack mt={1} direction="row" justifyContent="flex-start" alignItems="center" spacing={2}>
<Button variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button>
<Button disabled={!formik.isValid} variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button>
@@ -1221,7 +1259,17 @@ const BusCustomFormWizard = (props) => {
</Typography>
</Stack>
</Grid>
<Grid item xs={12} md={12} mt={1} mb={1}>
<Grid container>
<Grid item xs={12} md={12}>
<Stack spacing={1} direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
<Typography display="inline" variant="h4" sx={{ color: 'primary.primary'}}>身份證明文件</Typography>
{fileList !=null?
<PreviewUploadFileTable key="previewTable" recordList={fileListData} />:null}
</Stack>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>


+ 39
- 15
src/pages/authentication/auth-forms/CustomFormWizard.js View File

@@ -36,6 +36,7 @@ import * as ComboData from "../../../utils/ComboData";
import Loadable from 'components/Loadable';
import { lazy } from 'react';
const UploadFileTable = Loadable(lazy(() => import('./UploadFileTable')));
const PreviewUploadFileTable = Loadable(lazy(() => import('./PreviewUploadFileTable')));
const LoadingComponent = Loadable(lazy(() => import('../../extra-pages/LoadingComponent')));
// import UploadFileTable from './UploadFileTable';
// import LoadingComponent from "../../extra-pages/LoadingComponent";
@@ -58,6 +59,7 @@ const CustomFormWizard = (props) => {
const [fileList, setFileList] = useState([]);
const [fileListData, setFileListData] = useState([]);
const [checkUpload, setCheckUpload] = useState(false);
const [isLoading, setLoding] = useState(true);
const [updateRows, setUpdateRows] = useState([]);

const handleClickShowPassword = () => {
@@ -83,7 +85,6 @@ const CustomFormWizard = (props) => {
const [termsAndConAccept, setTermsAndConAccept] = useState(false);
const [termsAndConNotAccept, setTermsAndConNotAccept] = useState(false);
const [isValid, setisValid] = useState(false);
const [isLoading, setLoding] = useState(true);

const idDocTypeComboList = ComboData.idDocType;
const address4ComboList = ComboData.district;
@@ -191,7 +192,7 @@ const CustomFormWizard = (props) => {
break;
}
}
if (!isDuplicate) {
if (!isDuplicate && i+currentIndex<5) {
file.id = currentIndex+i
saveFileList.push(file)
updateList.items.add(file);
@@ -287,9 +288,6 @@ const CustomFormWizard = (props) => {
// formData.append("refCode", refCode);
// }

console.log("formData:")
console.log(formData)

if (isValid){
axios.post(POST_PUBLIC_USER_REGISTER, formData,{
headers: {
@@ -399,9 +397,9 @@ const CustomFormWizard = (props) => {
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位數字'),
// faxCountryCode: yup.string().min(3,'請輸入3位數字'),
phone: yup.string().min(8,'請輸入8位數字').required('請輸入聯絡電話'),
fax: yup.string().min(8,'請輸入8位數字'),
// fax: yup.string().min(8,'請輸入8位數字'),
}),
});

@@ -959,7 +957,14 @@ const CustomFormWizard = (props) => {
value={formik.values.phoneCountryCode}
name="phoneCountryCode"
// onBlur={formik.handleBlur}
onChange={formik.handleChange}
// onChange={formik.handleChange}
onChange={(event) => {
const value = event.target.value;
if (value.match(/[^0-9]/)) {
return event.preventDefault();
}
formik.setFieldValue("phoneCountryCode",value);
}}
placeholder="國際區號"
error={Boolean(formik.touched.phone && formik.errors.phone)}
onBlur={formik.handleBlur}
@@ -979,7 +984,14 @@ const CustomFormWizard = (props) => {
value={formik.values.phone}
name="phone"
// onBlur={formik.handleBlur}
onChange={formik.handleChange}
// onChange={formik.handleChange}
onChange={(event) => {
const value = event.target.value;
if (value.match(/[^0-9]/)) {
return event.preventDefault();
}
formik.setFieldValue("phone",value);
}}
placeholder="聯絡電話"
error={Boolean(formik.touched.phone && formik.errors.phone)}
onBlur={formik.handleBlur}
@@ -1015,7 +1027,14 @@ const CustomFormWizard = (props) => {
type="faxCountryCode"
value={formik.values.faxCountryCode}
name="faxCountryCode"
onChange={formik.handleChange}
// onChange={formik.handleChange}
onChange={(event) => {
const value = event.target.value;
if (value.match(/[^0-9]/)) {
return event.preventDefault();
}
formik.setFieldValue("faxCountryCode",value);
}}
placeholder="國際區號"
onBlur={formik.handleBlur}
inputProps={{
@@ -1034,7 +1053,14 @@ const CustomFormWizard = (props) => {
value={formik.values.fax}
name="fax"
onBlur={formik.handleBlur}
onChange={formik.handleChange}
// onChange={formik.handleChange}
onChange={(event) => {
const value = event.target.value;
if (value.match(/[^0-9]/)) {
return event.preventDefault();
}
formik.setFieldValue("fax",value);
}}
placeholder="傳真號碼"
inputProps={{
maxLength: 8,
@@ -1075,7 +1101,7 @@ const CustomFormWizard = (props) => {
<Typography display="inline" variant="h6" sx={{ fontSize: 12, color: 'primary.primary'}}>如: 香港身份證; 護照; 中國內地身份證等</Typography>
</Stack>
{fileList !=null?
<UploadFileTable recordList={fileListData} setUpdateRows={setUpdateRows} disableDelete={false}/>:null}
<UploadFileTable key="uploadTable" recordList={fileListData} setUpdateRows={setUpdateRows}/>:null}
{/* <Stack mt={1} direction="row" justifyContent="flex-start" alignItems="center" spacing={2}>
<Button variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button>
<Button disabled={!formik.isValid} variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button>
@@ -1296,13 +1322,11 @@ const CustomFormWizard = (props) => {
<Stack spacing={1} direction="column" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
<Typography display="inline" variant="h4" sx={{ color: 'primary.primary'}}>身份證明文件</Typography>
{fileList !=null?
<UploadFileTable recordList={fileListData} updateRows={updateRows} disableDelete={true}/>:null}
<PreviewUploadFileTable key="previewTable" recordList={fileListData} />:null}
</Stack>
</Grid>
</Grid>
</Grid>

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


+ 48
- 0
src/pages/authentication/auth-forms/PasswordAlertDialog.js View File

@@ -0,0 +1,48 @@
import React, {
// useEffect,
// useState
} from 'react';

// material-ui
import {
Button,
// Link,
Stack,
Typography,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle
} from '@mui/material';
import CancelOutlinedIcon from '@mui/icons-material/CancelOutlined';

const PasswordAlertDialog = (props) => {
return (
<Dialog
open={props.open}
onClose={props.handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
<Stack mt={1} mr={4} direction="row" justifyContent="flex-start" alignItems="center" spacing={2}>
<CancelOutlinedIcon color="error" sx={{width:"35px",height:"40px"}}/>
<Typography display="inline" variant="h4">用戶名或密碼錯誤</Typography>
</Stack>
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
{""}
</DialogContentText>
</DialogContent>
<DialogActions>
<Button variant="contained" color="error" onClick={props.handleClose} autoFocus>
關閉
</Button>
</DialogActions>
</Dialog>
);
};

export default PasswordAlertDialog;

+ 107
- 0
src/pages/authentication/auth-forms/PreviewUploadFileTable.js View File

@@ -0,0 +1,107 @@
// material-ui
import * as React from 'react';
import {
DataGrid,
// GridActionsCellItem,
// GridRowModes
} from "@mui/x-data-grid";
// import RemoveCircleOutlineIcon from '@mui/icons-material/RemoveCircleOutline';
import {useEffect} from "react";
// import {useNavigate} from "react-router-dom";
// import { useTheme } from '@mui/material/styles';
import {
Box,
Stack
} from '@mui/material';
// ==============================|| EVENT TABLE ||============================== //

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

// const navigate = useNavigate()

useEffect(() => {
setRows(recordList);
}, [recordList]);

function NoRowsOverlay() {
return (
<Stack height="100%" alignItems="center" justifyContent="center">
沒有上傳檔案
{/* <pre>(rows=&#123;[]&#125;)</pre> */}
</Stack>
);
}

// const handleCancelClick = (id) => () => {
// setRowModesModel({
// ...rowModesModel,
// [id]: { mode: GridRowModes.View, ignoreModifications: true },
// });
// console.log("Starting Delete")
// const editedRow = rows.find((row) => row.id === id);
// console.log(editedRow)
// console.log(editedRow.isNew)
// setUpdateRows(rows.filter((row) => row.id !== id));
// setRows(rows.filter((row) => row.id !== id));
// }

const columns = [
// {
// field: 'actions',
// type: 'actions',
// headerName: '',
// width: 30,
// cellClassName: 'actions',
// getActions: ({id}) => {
// return [
// <GridActionsCellItem
// key="OutSave"
// icon={<RemoveCircleOutlineIcon/>}
// label="delete"
// className="textPrimary"
// onClick={handleCancelClick(id)}
// color="error"
// />]
// },
// },
{
id: 'name',
field: 'name',
headerName: '檔案名稱',
flex: 1,
},
{
id: 'size',
field: 'size',
headerName: '檔案大小',
valueGetter: (params) => {
// console.log(params)
return Math.ceil(params.value/1024)+" KB";
},
flex: 1,
},
];

return (
<Box style={{ height: '200px', width: '100%' }}>
<DataGrid
rows={rows}
columns={columns}
editMode="row"
sx={{border:1}}
rowModesModel={rowModesModel}
disablePagination
components={{ NoRowsOverlay, }}
// hideFooterPagination={true}
disableSelectionOnClick
disableColumnMenu
disableColumnSelector
hideFooter
/>
</Box>
);
}

+ 3
- 6
src/pages/authentication/auth-forms/UploadFileTable.js View File

@@ -15,7 +15,7 @@ import {
} from '@mui/material';
// ==============================|| EVENT TABLE ||============================== //

export default function UploadFileTable({recordList, setUpdateRows, disableDelete}) {
export default function UploadFileTable({recordList, setUpdateRows,}) {
const [rows, setRows] = React.useState(recordList);
const [rowModesModel,setRowModesModel] = React.useState({});
@@ -25,12 +25,9 @@ export default function UploadFileTable({recordList, setUpdateRows, disableDelet

useEffect(() => {
setRows(recordList);
// console.log(disableDelete);
}, [recordList]);

// useEffect(() => {
// console.log(updateRows);
// }, [updateRows]);

function NoRowsOverlay() {
return (
<Stack height="100%" alignItems="center" justifyContent="center">
@@ -60,7 +57,7 @@ export default function UploadFileTable({recordList, setUpdateRows, disableDelet
headerName: '',
width: 30,
cellClassName: 'actions',
hide:{disableDelete},
// hide:true,
getActions: ({id}) => {
return [
<GridActionsCellItem


Loading…
Cancel
Save