iamjpcbau
iamjpcbau

Reputation: 404

React.js material-table: How to disable action icon on load?

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

Answers (1)

NicoE
NicoE

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

Related Questions