Reputation: 404
I would like to disable all actions in material-table per row depending on status
column
e.g. if the value of status in row 1 is REJECTED
, all action icons should be disabled
I know I should use disabled
attribute. However, I want to achieve this upon load of page
import React, { useState, useEffect, forwardRef, useCallback } from "react";
import useStyles from "./styles";
import {
Paper,
Button,
Grid,
FormControl,
InputLabel,
Select,
MenuItem,
TextField,
InputAdornment,
} from "@material-ui/core";
import { DropzoneDialog } from "material-ui-dropzone";
import MaterialTable from "material-table";
import {
AddBox,
ArrowDownward,
Check,
ChevronLeft,
ChevronRight,
Clear,
DeleteOutline,
Edit,
FilterList,
FirstPage,
LastPage,
Remove,
SaveAlt,
Search,
Settings,
ViewColumn,
Publish,
RemoveCircle,
Undo,
} from "@material-ui/icons";
import InwardService from "../../services/InwardService";
import { store } from "react-notifications-component";
import { trackPromise } from "react-promise-tracker";
import { green, red } from "@material-ui/core/colors";
import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent";
import DialogTitle from "@material-ui/core/DialogTitle";
import { USER_PROFILE_ID_SESSION_ATTRIBUTE } from "../../services/AuthenticationService";
import ProfileMaintenanceService from "../../services/ProfileMaintenanceService";
import Moment from "moment";
export default function Inward() {
const tableIcons = {
Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />),
Check: forwardRef((props, ref) => <Check {...props} ref={ref} />),
Clear: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
Delete: forwardRef((props, ref) => <DeleteOutline {...props} ref={ref} />),
DetailPanel: forwardRef((props, ref) => (
<ChevronRight {...props} ref={ref} />
)),
Edit: forwardRef((props, ref) => <Edit {...props} ref={ref} />),
Export: forwardRef((props, ref) => <SaveAlt {...props} ref={ref} />),
Filter: forwardRef((props, ref) => <FilterList {...props} ref={ref} />),
FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />),
LastPage: forwardRef((props, ref) => <LastPage {...props} ref={ref} />),
NextPage: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
PreviousPage: forwardRef((props, ref) => (
<ChevronLeft {...props} ref={ref} />
)),
ResetSearch: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
Search: forwardRef((props, ref) => <Search {...props} ref={ref} />),
SortArrow: forwardRef((props, ref) => (
<ArrowDownward {...props} ref={ref} />
)),
ThirdStateCheck: forwardRef((props, ref) => (
<Remove {...props} ref={ref} />
)),
ViewColumn: forwardRef((props, ref) => <ViewColumn {...props} ref={ref} />),
};
var classes = useStyles();
const PESONET_FILE_EXT = process.env.REACT_APP_INWARD_UPLOAD_PESONET;
const PDDTS_FILE_EXT = process.env.REACT_APP_INWARD_UPLOAD_PDDTS;
const profileList = sessionStorage.getItem(USER_PROFILE_ID_SESSION_ATTRIBUTE); // string
const [profileDetails, setProfileDetails] = useState([]);
const [profileModules, setProfileModules] = useState([]);
const [profileActions, setProfileActions] = useState([]);
const [isDropzoneOpen, setIsDropzoneOpen] = useState(false);
const [files, setFiles] = useState([]);
const [fileExtensions, setFileExtensions] = useState([]);
const [product, setProduct] = useState([]);
const [inwardData, setInwardData] = useState([]); // change variable name
const [isMakerRole, setIsMakerRole] = useState(false);
const [isApproverRole, setIsApproverRole] = useState(false);
const [statusMap, setStatusMap] = useState([]);
const [recordToUpdate, setRecordToUpdate] = useState({
action: "",
batchRef: "",
product: "",
rowDataStatus: [],
});
const [disabled, setDisabled] = useState({
productDropdown: true,
pesonetOption: true,
pddtsOption: true,
uploadBtn: true,
});
const [isHidden, setIsHidden] = useState({
returnAction: true,
rejectAction: true,
processAction: true,
approveAction: true,
excludeAction: true,
});
const [open, setOpen] = useState(false);
const [fullWidth] = useState(true);
const [maxWidth] = useState("lg");
const [curTime] = useState(new Date().toLocaleString());
const notification = {
title: "CPEX",
message: "Configurable",
type: "success",
insert: "top",
container: "top-right",
animationIn: ["animated", "fadeIn"],
animationOut: ["animated", "fadeOut"],
dismiss: {
duration: 5000,
},
};
useEffect(() => {
retrieveProfileDetails();
// retrieveInwardData();
}, []);
useEffect(() => {
if (product.length > 0 && isMakerRole == true) {
setDisabled({
...disabled,
uploadBtn: false,
});
}
if (fileExtensions.length > 0) {
fileExtensions.splice(fileExtensions, 1);
}
switch (product) {
case "PESONET":
return setFileExtensions(fileExtensions.concat(PESONET_FILE_EXT));
case "PDDTS":
return setFileExtensions(fileExtensions.concat(PDDTS_FILE_EXT));
default:
return setDisabled({ ...disabled, uploadBtn: true });
}
}, [product]);
useEffect(() => {
console.log("06122020 profileDetails ", profileDetails);
const modules = profileDetails.map((module) => module.module);
const actions = profileDetails
.map((item) => item.actions.map((action) => action.action))
.flat();
setProfileModules(profileModules.concat(modules));
setProfileActions(profileActions.concat(actions));
}, [profileDetails]);
useEffect(() => {
// could change depending on how profile layout
console.log("06122020 profileModules ", profileModules);
profileModules.forEach((profileModulesMap) => {
const productRoleMap = profileModulesMap.split(" ");
if (productRoleMap.length > 0) {
console.log("06122020 productRoleMap[0] ", productRoleMap[0]);
switch (productRoleMap[0]) {
case "Pesonet": {
// change to PESONET
// case sensitive
if (productRoleMap[1] == "Maker") {
console.log("06122020 Pesonet maker");
setDisabled({
...disabled,
productDropdown: false,
pesonetOption: false,
pddtsOption: true,
});
setIsHidden({
...isHidden,
returnAction: true,
rejectAction: false,
processAction: false,
approveAction: false,
excludeAction: false,
});
setIsMakerRole(true);
setIsApproverRole(false);
return;
} else if (productRoleMap[1] == "Approver") {
console.log("06122020 Pesonet approver");
setDisabled({
...disabled,
pesonetOption: false,
pddtsOption: true,
});
setIsHidden({
...isHidden,
returnAction: false,
rejectAction: false,
processAction: true,
approveAction: false,
excludeAction: true,
});
setIsMakerRole(false);
setIsApproverRole(true);
return;
}
}
case "PDDTS": {
if (productRoleMap[1] == "Maker") {
console.log("06122020 PDDTS maker");
setDisabled({
...disabled,
productDropdown: false,
pesonetOption: true,
pddtsOption: false,
});
setIsHidden({
...isHidden,
returnAction: true,
rejectAction: false,
processAction: false,
approveAction: false,
excludeAction: false,
});
setIsMakerRole(true);
setIsApproverRole(false);
return;
} else if (productRoleMap[1] == "Approver") {
console.log("06122020 PDDTS approver");
setDisabled({
...disabled,
pesonetOption: true,
pddtsOption: false,
});
setIsHidden({
...isHidden,
returnAction: false,
rejectAction: false,
processAction: true,
approveAction: false,
excludeAction: true,
});
setIsMakerRole(false);
setIsApproverRole(true);
return;
}
}
}
}
});
}, [profileModules]);
useEffect(() => {
console.log("~~~ useEffect profileActions ", profileActions);
}, [profileActions]);
useEffect(() => {
if (isMakerRole == true) {
statusMap.splice(statusMap, statusMap.length);
// setStatusMap(statusMap.concat("PENDING"));
setStatusMap(statusMap.concat("PENDING", "REJECTED")); // final
}
}, [isMakerRole]);
useEffect(() => {
if (isApproverRole == true) {
statusMap.splice(statusMap, statusMap.length);
setStatusMap(statusMap.concat("AUTHORIZE", "REJECTED", "COMPLETED"));
}
}, [isApproverRole]);
useEffect(() => {
if (statusMap.length > 0) {
retrieveInwardData();
}
}, [statusMap]);
useEffect(() => {
if (recordToUpdate.rowDataStatus.length > 0) {
trackPromise(
InwardService.updateInwardStatus(
recordToUpdate.action,
recordToUpdate.batchRef,
recordToUpdate.product,
recordToUpdate.rowDataStatus
).then((response) => {
if (response.data.success != "") {
store.addNotification({
...notification,
message: response.data.success,
dismiss: {
duration: 5000,
},
});
return InwardService.retrieveInwardData(statusMap);
}
})
).catch((error) => {
if (error.response) {
if (
error.response.data.error !== undefined &&
error.response.data.error != ""
) {
store.addNotification({
...notification,
type: "danger",
message: error.response.data.error,
dismiss: {
duration: 5000,
},
});
} else {
store.addNotification({
...notification,
type: "danger",
message: "Server did not respond with a status code of 200",
dismiss: {
duration: 5000,
},
});
}
} else if (error.request) {
// if API is down
store.addNotification({
...notification,
type: "danger",
message: "Request was made but no response was received",
dismiss: {
duration: 5000,
},
});
}
});
}
}, [recordToUpdate]);
const retrieveProfileDetails = useCallback(() => {
const profileListArr = profileList.split(",");
console.log("06122020 profileListArr ", profileListArr);
profileListArr.forEach((profileListArrMap) => {
ProfileMaintenanceService.retrieveProfileDetails(profileListArrMap).then(
(response) => {
setProfileDetails(response.data);
}
);
});
});
const retrieveInwardData = useCallback(() => {
InwardService.retrieveInwardData(statusMap) // status depends on profile, might transfer to useeffect of statusMap
// InwardService.retrieveInwardData("PENDING")
.then((response) => {
setInwardData(response.data);
})
.catch((error) => {
if (error.response) {
if (
error.response.data.error !== undefined &&
error.response.data.error != ""
) {
store.addNotification({
...notification,
type: "danger",
message: error.response.data.error,
dismiss: {
duration: 5000,
},
});
} else {
store.addNotification({
...notification,
type: "danger",
message: "Server did not respond with a status code of 200",
dismiss: {
duration: 5000,
},
});
}
} else if (error.request) {
// if API is down
store.addNotification({
...notification,
type: "danger",
message: "Request was made but no response was received",
dismiss: {
duration: 5000,
},
});
}
});
});
const columnsInwardNew = [
{
title: "Batch Reference No.",
field: "batchRef",
cellStyle: {
width: 190,
minWidth: 190,
},
headerStyle: {
width: 190,
minWidth: 190,
},
},
{
title: "Total Records",
field: "totalRecords",
filtering: false,
},
{
title: "Total Amount",
field: "totalAmount",
filtering: false,
},
{
title: "Total Excluded Records",
field: "totalRecordsExcluded",
filtering: false,
},
{
title: "Product",
field: "product",
},
{
title: "Status",
field: "status",
},
];
const columnsInwardProcessNew = [
{ title: "Total Count for Payroll", field: "totalCountForPayroll" },
{ title: "Total Amount for Payroll", field: "totalAmountForPayroll" },
{
title: "Total Count for Non-Payroll",
field: "totalCountForNonPayroll",
},
{
title: "Total Amount for Non-Payroll",
field: "totalAmountForNonPayroll",
},
{ title: "Total Count for CP", field: "totalCountForCP" },
{ title: "Total Amount for CP", field: "totalAmountForCP" },
];
const data = [
{
batchRef: "PD-000000",
totalRecords: "0",
totalAmount: "0",
totalRecordsExcluded: "0",
product: "PDDTS",
status: "COMPLETED",
},
];
const returnRecord = useCallback((event, rowData) => {
recordToUpdate.rowDataStatus.splice(
recordToUpdate.rowDataStatus,
recordToUpdate.rowDataStatus.length
);
setRecordToUpdate({
...recordToUpdate,
action: "RETURNED", // should be from env file
batchRef: rowData.batchRef,
product: rowData.product,
rowDataStatus: recordToUpdate.rowDataStatus.concat("PENDING"), // should be from env file
});
});
const rejectRecord = useCallback((event, rowData) => {
recordToUpdate.rowDataStatus.splice(
recordToUpdate.rowDataStatus,
recordToUpdate.rowDataStatus.length
);
setRecordToUpdate({
...recordToUpdate,
action: "REJECTED", // should be from env file
batchRef: rowData.batchRef,
product: rowData.product,
rowDataStatus: recordToUpdate.rowDataStatus.concat("REJECTED"),
});
});
const processRecord = useCallback((event, rowData) => {
setOpen(true);
});
const approveRecord = useCallback((event, rowData) => {
if (isMakerRole == true) {
recordToUpdate.rowDataStatus.splice(
recordToUpdate.rowDataStatus,
recordToUpdate.rowDataStatus.length
);
setRecordToUpdate({
...recordToUpdate,
action: "AUTHORIZE", // should be from env file
batchRef: rowData.batchRef,
product: rowData.product,
rowDataStatus: recordToUpdate.rowDataStatus.concat("AUTHORIZE"), // should be from env file
});
} else if (isApproverRole == true) {
recordToUpdate.rowDataStatus.splice(
recordToUpdate.rowDataStatus,
recordToUpdate.rowDataStatus.length
);
setRecordToUpdate({
...recordToUpdate,
action: "APPROVED", // should be from env file
batchRef: rowData.batchRef,
product: rowData.product,
rowDataStatus: recordToUpdate.rowDataStatus.concat("COMPLETED"), // should be from env file
});
InwardService.downloadFile(
rowData.batchRef,
rowData.transactioDate,
rowData.product
).then((response) => {
const url = window.URL.createObjectURL(
new Blob([response.data.fileContent])
);
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", response.data.filename); // timestamp could be from backend service
document.body.appendChild(link);
link.click();
});
}
});
const excludeRecord = useCallback((event, rowData) => {});
const handleOnSaveDropzoneDialog = (files) => {
setFiles(files);
let formData = new FormData();
for (var i = 0; i < files.length; i++) {
let file = files[i];
formData.append("file", file);
}
trackPromise(
InwardService.uploadFile(formData, product).then((response) => {
if (response.data.success != "") {
store.addNotification({
...notification,
type: "success",
message: response.data.success,
dismiss: {
duration: 5000,
},
});
return InwardService.retrieveInwardData(statusMap); // status depends on profile
}
})
).catch((error) => {
if (error.response) {
if (
error.response.data.error !== undefined &&
error.response.data.error != ""
) {
store.addNotification({
...notification,
type: "danger",
message: error.response.data.error,
dismiss: {
duration: 5000,
},
});
} else {
store.addNotification({
...notification,
type: "danger",
message: "Server did not respond with a status code of 200",
dismiss: {
duration: 5000,
},
});
}
} else if (error.request) {
store.addNotification({
...notification,
type: "danger",
message: "Request was made but no response was received",
dismiss: {
duration: 5000,
},
});
}
});
};
const handleChange = (event) => {
setProduct(event.target.value);
};
const handleClose = () => {
setOpen(false);
};
return (
<React.Fragment>
<Dialog
fullWidth={fullWidth}
maxWidth={maxWidth}
open={open}
onClose={handleClose}
aria-labelledby="max-width-dialog-title"
>
<DialogTitle id="max-width-dialog-title">Process</DialogTitle>
<DialogContent>
<MaterialTable
icons={tableIcons}
columns={columnsInwardProcessNew}
data={inwardData} // temp, final should be inwardData
title=""
options={{
actionsColumnIndex: -1,
headerStyle: {
backgroundColor: "#78909c",
color: "#fff",
},
search: true,
}}
actions={[
{
icon: () => <RemoveCircle style={{ color: red[500] }} />,
tooltip: "Exclude",
onClick: (event, rowData) => excludeRecord(event, rowData),
hidden: isHidden.excludeAction,
// hidden: false,
},
]}
/>
<br />
<TextField
type="search"
variant="outlined"
margin="normal"
placeholder="Search by OFI..."
style={{ float: "right", width: 300 }} // width is tentative
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Search />
</InputAdornment>
),
classes: { input: classes.textfield1 },
}}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} style={{ color: red[500] }}>
Close
</Button>
<Button onClick={handleClose} color="primary">
Submit
</Button>
</DialogActions>
</Dialog>
<Paper classes={{ root: classes.paperRoot }}>
<MaterialTable
icons={tableIcons}
columns={columnsInwardNew}
data={inwardData} // final should be inwardData
title=""
options={{
exportButton: true,
filtering: true,
actionsColumnIndex: -1,
headerStyle: {
backgroundColor: "#78909c",
color: "#fff",
},
}}
actions={[
{
icon: Undo,
tooltip: "Return",
onClick: (event, rowData) => returnRecord(event, rowData),
hidden: isHidden.returnAction,
// hidden: false,
},
{
icon: () => <Clear style={{ color: red[500] }} />,
tooltip: "Reject",
onClick: (event, rowData) => rejectRecord(event, rowData),
hidden: isHidden.rejectAction,
// hidden: false,
},
{
icon: Settings,
tooltip: "Process",
onClick: (event, rowData) => processRecord(event, rowData),
hidden: isHidden.processAction,
disabled: true,
// hidden: false,
},
{
icon: () => <Check style={{ color: green[500] }} />,
tooltip: "Approve",
onClick: (event, rowData) => approveRecord(event, rowData),
hidden: isHidden.approveAction,
// hidden: false,
},
]}
/>
<Grid item xs={6}>
<br />
<FormControl
variant="outlined"
size="small"
className={classes.formControl}
>
<InputLabel id="simple-select-outlined-label">Product</InputLabel>
<Select
labelId="simple-select-outlined-label"
id="simple-select-outlined"
value={product}
onChange={handleChange}
label="Product"
disabled={disabled.productDropdown}
>
<MenuItem value="product" disabled>
Product
</MenuItem>
{/* to change to pesonetoption */}
<MenuItem value="PESONET" disabled={true}>
PESONet
</MenuItem>
{/* to change to pddtsoption */}
<MenuItem value="PDDTS" disabled={false}>
PDDTS
</MenuItem>
</Select>
</FormControl>
<Button
variant="contained"
color="default"
className={classes.button}
startIcon={<Publish />}
onClick={() => setIsDropzoneOpen(true)}
disabled={disabled.uploadBtn}
>
Upload File
</Button>
</Grid>
<DropzoneDialog
acceptedFiles={fileExtensions}
cancelButtonText={"cancel"}
submitButtonText={"submit"}
maxFileSize={5000000}
open={isDropzoneOpen}
onClose={() => setIsDropzoneOpen(false)}
onSave={(files) => {
handleOnSaveDropzoneDialog(files);
setIsDropzoneOpen(false);
}}
showPreviews={true}
showFileNamesInPreview={true}
/>
</Paper>
</React.Fragment>
);
}
Upvotes: 0
Views: 4127
Reputation: 4853
You could define each action as a function that takes rowdata as parameter, for example:
actions={[
(rowdata) => ({
icon: () => <SettingsPower />,
tooltip: "Activate",
onClick: (rowData) => {
let serviceInfo = {
serviceId: rowData.id,
serviceType: rowData.service_type,
};
this.props.onClickedAction("terminate", serviceInfo);
},
disabled:
(rowdata.originalServState !== "activated" &&
rowdata.originalServState !== "registered")
}),
]}
The example at the docs goes like this:
actions={[
{
icon: 'save',
tooltip: 'Save User',
onClick: (event, rowData) => alert("You saved " + rowData.name)
},
rowData => ({
icon: 'delete',
tooltip: 'Delete User',
onClick: (event, rowData) => confirm("You want to delete " + rowData.name),
disabled: rowData.birthYear < 2000
})
]}
Upvotes: 1