mui / mui-x

MUI X: Build complex and data-rich applications using a growing list of advanced React components, like the Data Grid, Date and Time Pickers, Charts, and more!
https://mui.com/x/
4.51k stars 1.31k forks source link

[data grid] How to apply conditional cell color and cell selection color at the same time #14374

Closed mahammahmood closed 2 months ago

mahammahmood commented 2 months ago

The problem in depth

I want that in my RD_Start_F and RD_Complete_F where the cell is yellow to apply conditional cell color and cell selection color at the same time.

Screenshot 2024-08-28 175440

Here is a live demo of my problem DEMO

Your environment

`npx @mui/envinfo` ``` Don't forget to mention which browser you used. Output from `npx @mui/envinfo` goes here. ```

Search keywords: Data, Grid, Premium, cell, selection, color Order ID: 91010

michelengelen commented 2 months ago

Hey @mahammahmood ... could you elaborate a bit on how this should look like? Its not clear from your description what should happen if the cell is selected. Should the color change or should they mix? 🤷🏼

mahammahmood commented 2 months ago

In the screenshot below, when I select the cell, the colored cell becomes darker to indicate that it is selected Screenshot 2024-08-29 101924

But when I select the yellow cell, it does not show the selection. Screenshot 2024-08-29 102213

The code for the red and green cells is provided below.

 {
      field: "RAD_Start_A",
      headerName: "RAD START(A)",
      editable: true,
      minWidth: 150,
      flex: 0.1,
      display: "flex",
      type: "date",
      cellClassName: "editable-Date",
      renderHeader: () => {
        return (
          <>
            <Typography variant="subtitle2" fontWeight={600}>
              {"START(A)"}
            </Typography>
          </>
        );
      },
      renderCell: (params: any) => (
        <>
          <Box>{formatCustomCompleteDate(params.value, storedDateFormat)}</Box>
        </>
      ),
    },
    {
      field: "RAD_Complete_A",
      headerName: "RAD COMPLETE(A)",
      editable: true,
      minWidth: 150,
      flex: 0.1,
      display: "flex",
      type: "date",
      cellClassName: "editable-Date",
      renderHeader: () => {
        return (
          <>
            <Typography variant="subtitle2" fontWeight={600}>
              {"COMPLETE(A)"}
            </Typography>
          </>
        );
      },
      renderCell: (params: any) => (
        <>
          <Box>{formatCustomCompleteDate(params.value, storedDateFormat)}</Box>
        </>
      ),
    },
  <Box
      sx={{
        height: 500,
        width: "100%",
        [`.${gridClasses.cell}.red`]: {
          backgroundColor: "#FFE7E5",
          color: "#FF2D1E",
          ["&.Mui-selected"]: {
            backgroundColor: "#ffd5d1",
            ["&:hover"]: {
              backgroundColor: "#ffc3bd",
            },
          },
        },
        [`.${gridClasses.cell}.green`]: {
          backgroundColor: "#CAFFE4",
          color: "#139B57",
          ["&.Mui-selected"]: {
            backgroundColor: "#b8ffd9",
            ["&:hover"]: {
              backgroundColor: "#a3ffce",
            },
          },
        },
      }}
    >
      <DataGridPremium
        rows={rowsDate}
        columns={DateColumns}
        checkboxSelection
        disableRowSelectionOnClick
        ignoreValueFormatterDuringExport
        cellSelection
        getCellClassName={(params) => {
          if (params.field === "RAD_Start_A") {
            return params.row.RAD_Start_F < params.row.RAD_Start_A
              ? "red"
              : "green";
          }

          if (params.field === "RAD_Complete_A") {
            return params.row.RAD_Complete_F < params.row.RAD_Complete_A
              ? "red"
              : "green";
          }

          return "";
        }}
        onCellEditStop={(params: GridCellEditStopParams, event: MuiEvent) => {
          if (params.reason === GridCellEditStopReasons.cellFocusOut) {
            event.defaultMuiPrevented = true;
          }
        }}
      />
    </Box>

The code for the yellow-colored cell is here

 {
      field: "RD_Start_F",
      headerName: "RD START(F)",
      editable: true,
      minWidth: 150,
      flex: 0.1,
      display: "flex",
      type: "date",
      cellClassName: "editable-Date",
      renderHeader: () => {
        return (
          <>
            <Typography variant="subtitle2" fontWeight={600}>
              {"START(F)"}
            </Typography>
          </>
        );
      },
      renderCell: (params: any) => (
        <>
          <Box
            px="10px"
            sx={{
              backgroundColor: isWithinNextSevenDays(
                params.row.RD_Start_F,
                referenceDate,
                nextSevenDays
              )
                ? "#FFFA94"
                : "transparent",
              height: "100%",
              width: "100%",
            }}
          >
            <Stack
              justifyContent="center"
              sx={{
                height: "100%",
                width: "100%",
                color: isWithinNextThreeDays(
                  params.row.RD_Start_F,
                  referenceThreeDate,
                  nextThreeDays
                )
                  ? "error.main"
                  : "inherit",
                fontWeight: isWithinNextSevenDays(
                  params.row.RD_Start_F,
                  referenceDate,
                  nextSevenDays
                )
                  ? "600"
                  : "400",
              }}
            >
              {formatCustomCompleteDate(params.value, storedDateFormat)}
            </Stack>
          </Box>
        </>
      ),
    },
    {
      field: "RD_Complete_F",
      headerName: "RD COMPLETE(F)",
      editable: true,
      minWidth: 150,
      flex: 0.1,
      display: "flex",
      type: "date",
      cellClassName: "editable-Date",
      renderHeader: () => {
        return (
          <>
            <Typography variant="subtitle2" fontWeight={600}>
              {"COMPLETE(F)"}
            </Typography>
          </>
        );
      },
      renderCell: (params: any) => (
        <>
          <Box
            px="10px"
            sx={{
              backgroundColor: isWithinNextSevenDays(
                params.row.RD_Complete_F,
                referenceDate,
                nextSevenDays
              )
                ? "#FFFA94"
                : "transparent",
              height: "100%",
              width: "100%",
            }}
          >
            <Stack
              justifyContent="center"
              sx={{
                height: "100%",
                width: "100%",
                color: isWithinNextThreeDays(
                  params.row.RD_Complete_F,
                  referenceThreeDate,
                  nextThreeDays
                )
                  ? "error.main"
                  : "inherit",
                fontWeight: isWithinNextSevenDays(
                  params.row.RD_Complete_F,
                  referenceDate,
                  nextSevenDays
                )
                  ? "600"
                  : "400",
              }}
            >
              {formatCustomCompleteDate(params.value, storedDateFormat)}
            </Stack>
          </Box>
        </>
      ),
    },

Here is my full code. The demo link I provided is not up to date; this code is the updated version.

export const rowsDate = [
  {
    id: 0,
    color: 1,
    locationId: "GA104D",
    RAD_Start_F: new Date("5/22/2024"),
    RAD_Complete_F: new Date("5/26/2024"),
    RAD_Start_A: new Date("5/25/2024"),
    RAD_Complete_A: new Date("5/25/2024"),
    RFDS_Start_F: new Date("6/8/2024"),
    RFDS_Complete_F: new Date("6/11/2024"),
    RD_Start_F: new Date("9/17/2024"),
    RD_Complete_F: new Date("9/18/2024"),
  },
  {
    id: 1,
    color: 0,
    locationId: "MI101H",
    RAD_Start_F: new Date("5/23/2024"),
    RAD_Complete_F: new Date("5/24/2024"),
    RAD_Start_A: new Date("5/26/2024"),
    RAD_Complete_A: new Date("5/26/2024"),
    RFDS_Start_F: new Date("6/9/2024"),
    RFDS_Complete_F: new Date("6/12/2024"),
    RD_Start_F: new Date("9/18/2024"),
    RD_Complete_F: new Date("9/19/2024"),
  },
  {
    id: 2,
    color: 1,
    locationId: "GA103D",
    RAD_Start_F: new Date("5/24/2024"),
    RAD_Complete_F: new Date("5/25/2024"),
    RAD_Start_A: new Date("5/27/2024"),
    RAD_Complete_A: new Date("5/27/2024"),
    RFDS_Start_F: new Date("6/10/2024"),
    RFDS_Complete_F: new Date("6/13/2024"),
    RD_Start_F: new Date("9/19/2024"),
    RD_Complete_F: new Date("9/20/2024"),
  },
  {
    id: 3,
    color: 0,
    locationId: "SC100B",
    RAD_Start_F: new Date("5/25/2024"),
    RAD_Complete_F: new Date("5/26/2024"),
    RAD_Start_A: new Date("5/28/2024"),
    RAD_Complete_A: new Date("5/28/2024"),
    RFDS_Start_F: new Date("6/11/2024"),
    RFDS_Complete_F: new Date("6/14/2024"),
    RD_Start_F: new Date("9/16/2024"),
    RD_Complete_F: new Date("9/17/2024"),
  },
];
export default function ClipboardPaste() {
  const storedDateFormat = "USA (MM/DD/YYYY)";
  const formatCustomCompleteDate = (
    date: Date | string | undefined,
    dateFormat: string
  ): string => {
    if (!date) {
      return "";
    }

    // Convert string date to Date object if necessary
    if (typeof date === "string") {
      date = new Date(date);
    }

    // Check if date is a valid Date object
    if (isNaN(date.getTime())) {
      return "";
    }

    const month = date.getMonth() + 1; // getMonth() is zero-based
    const day = date.getDate();
    const year = date.getFullYear();

    const shortMonthName = date.toLocaleString("default", { month: "short" }); // Get abbreviated month name
    const dayName = [
      "Sunday",
      "Monday",
      "Tuesday",
      "Wednesday",
      "Thursday",
      "Friday",
      "Saturday",
    ][date.getDay()];

    switch (dateFormat) {
      case "EUR (DD/MM/YYYY)":
        return `${day}/${month}/${year}`;
      case "USA (MM/DD/YYYY)":
        return `${month}/${day}/${year}`;
      case "JIS (YYYY/MM/DD)":
        return `${year}/${month}/${day}`;
      case "DMY (Day, month, year)":
        return `${dayName}, ${day} ${shortMonthName} ${year}`;
      case "MDY (Month, day, year)":
        return `${shortMonthName} ${day}, ${year}`;
      case "YMD (Year, Month, Day)":
        return `${year}, ${shortMonthName} ${day}`;
      default:
        // Assuming default is 'USA (MM/DD/YYYY)' if the format doesn't match any case
        return `${month}/${day}/${year}`;
    }
  };

  const referenceDate = new Date(
    formatCustomCompleteDate("9/15/2024", storedDateFormat)
  );
  const nextSevenDaysInitial = new Date(
    referenceDate.getTime() + 7 * 24 * 60 * 60 * 1000
  );
  const nextSevenDays = new Date(
    formatCustomCompleteDate(nextSevenDaysInitial, storedDateFormat)
  );
  const isWithinNextSevenDays = (
    date: Date,
    referenceDate: Date,
    nextSevenDays: Date
  ) => {
    return date >= referenceDate && date <= nextSevenDays;
  };

  const referenceThreeDate = new Date(
    formatCustomCompleteDate("9/19/2024", storedDateFormat)
  );
  const nextThreeDaysInitial = new Date(
    referenceThreeDate.getTime() + 3 * 24 * 60 * 60 * 1000
  );
  const nextThreeDays = new Date(
    formatCustomCompleteDate(nextThreeDaysInitial, storedDateFormat)
  );
  const isWithinNextThreeDays = (
    date: Date,
    referenceThreeDate: Date,
    nextThreeDays: Date
  ) => {
    return date >= referenceThreeDate && date <= nextThreeDays;
  };

  const DateColumns: GridColDef[] = [
    {
      field: "locationId",
      headerName: "Location ID",
      minWidth: 140,
      flex: 0.1,
      display: "flex",
      renderHeader: () => {
        return (
          <>
            <Typography variant="subtitle2" fontWeight={600}>
              LOCATION ID
            </Typography>
          </>
        );
      },
      renderCell: (params: any) => (
        <>
          <Box
            sx={{
              "& a": {
                color: "text.primary",
                textDecoration: "none",
                fontWeight: "500",
                "&:hover": {
                  textDecoration: "underline",
                },
              },
            }}
          >
            {params.value}
          </Box>
        </>
      ),
    },
    {
      field: "RAD_Start_F",
      headerName: "RAD START(F)",
      editable: true,
      minWidth: 150,
      flex: 0.1,
      display: "flex",
      type: "date",
      // cellClassName: 'editable-Date',
      renderHeader: () => {
        return (
          <>
            <Typography variant="subtitle2" fontWeight={600}>
              {"START(F)"}
            </Typography>
          </>
        );
      },
      renderCell: (params: any) => (
        <>
          <Box>{formatCustomCompleteDate(params.value, storedDateFormat)}</Box>
        </>
      ),
    },
    {
      field: "RAD_Complete_F",
      headerName: "RAD COMPLETE(F)",
      editable: true,
      minWidth: 150,
      flex: 0.1,
      display: "flex",
      type: "date",
      renderHeader: () => {
        return (
          <>
            <Typography variant="subtitle2" fontWeight={600}>
              {"COMPLETE(F)"}
            </Typography>
          </>
        );
      },
      renderCell: (params: any) => (
        <>
          <Box>{formatCustomCompleteDate(params.value, storedDateFormat)}</Box>
        </>
      ),
    },
    {
      field: "RAD_Start_A",
      headerName: "RAD START(A)",
      editable: true,
      minWidth: 150,
      flex: 0.1,
      display: "flex",
      type: "date",
      cellClassName: "editable-Date",
      renderHeader: () => {
        return (
          <>
            <Typography variant="subtitle2" fontWeight={600}>
              {"START(A)"}
            </Typography>
          </>
        );
      },
      renderCell: (params: any) => (
        <>
          <Box>{formatCustomCompleteDate(params.value, storedDateFormat)}</Box>
        </>
      ),
    },
    {
      field: "RAD_Complete_A",
      headerName: "RAD COMPLETE(A)",
      editable: true,
      minWidth: 150,
      flex: 0.1,
      display: "flex",
      type: "date",
      cellClassName: "editable-Date",
      renderHeader: () => {
        return (
          <>
            <Typography variant="subtitle2" fontWeight={600}>
              {"COMPLETE(A)"}
            </Typography>
          </>
        );
      },
      renderCell: (params: any) => (
        <>
          <Box>{formatCustomCompleteDate(params.value, storedDateFormat)}</Box>
        </>
      ),
    },
    {
      field: "RFDS_Start_F",
      headerName: "RFDS START(F)",
      editable: true,
      minWidth: 150,
      flex: 0.1,
      display: "flex",
      type: "date",
      renderHeader: () => {
        return (
          <>
            <Typography variant="subtitle2" fontWeight={600}>
              {"START(F)"}
            </Typography>
          </>
        );
      },
      renderCell: (params: any) => (
        <>
          <Box>{formatCustomCompleteDate(params.value, storedDateFormat)}</Box>
        </>
      ),
    },
    {
      field: "RFDS_Complete_F",
      headerName: "RFDS COMPLETE(F)",
      editable: true,
      minWidth: 150,
      flex: 0.1,
      display: "flex",
      type: "date",
      renderHeader: () => {
        return (
          <>
            <Typography variant="subtitle2" fontWeight={600}>
              {"COMPLETE(F)"}
            </Typography>
          </>
        );
      },
      renderCell: (params: any) => (
        <>
          <Box>{formatCustomCompleteDate(params.value, storedDateFormat)}</Box>
        </>
      ),
    },
    {
      field: "RD_Start_F",
      headerName: "RD START(F)",
      editable: true,
      minWidth: 150,
      flex: 0.1,
      display: "flex",
      type: "date",
      cellClassName: "editable-Date",
      renderHeader: () => {
        return (
          <>
            <Typography variant="subtitle2" fontWeight={600}>
              {"START(F)"}
            </Typography>
          </>
        );
      },
      renderCell: (params: any) => (
        <>
          <Box
            px="10px"
            sx={{
              backgroundColor: isWithinNextSevenDays(
                params.row.RD_Start_F,
                referenceDate,
                nextSevenDays
              )
                ? "#FFFA94"
                : "transparent",
              height: "100%",
              width: "100%",
            }}
          >
            <Stack
              justifyContent="center"
              sx={{
                height: "100%",
                width: "100%",
                color: isWithinNextThreeDays(
                  params.row.RD_Start_F,
                  referenceThreeDate,
                  nextThreeDays
                )
                  ? "error.main"
                  : "inherit",
                fontWeight: isWithinNextSevenDays(
                  params.row.RD_Start_F,
                  referenceDate,
                  nextSevenDays
                )
                  ? "600"
                  : "400",
              }}
            >
              {formatCustomCompleteDate(params.value, storedDateFormat)}
            </Stack>
          </Box>
        </>
      ),
    },
    {
      field: "RD_Complete_F",
      headerName: "RD COMPLETE(F)",
      editable: true,
      minWidth: 150,
      flex: 0.1,
      display: "flex",
      type: "date",
      cellClassName: "editable-Date",
      renderHeader: () => {
        return (
          <>
            <Typography variant="subtitle2" fontWeight={600}>
              {"COMPLETE(F)"}
            </Typography>
          </>
        );
      },
      renderCell: (params: any) => (
        <>
          <Box
            px="10px"
            sx={{
              backgroundColor: isWithinNextSevenDays(
                params.row.RD_Complete_F,
                referenceDate,
                nextSevenDays
              )
                ? "#FFFA94"
                : "transparent",
              height: "100%",
              width: "100%",
            }}
          >
            <Stack
              justifyContent="center"
              sx={{
                height: "100%",
                width: "100%",
                color: isWithinNextThreeDays(
                  params.row.RD_Complete_F,
                  referenceThreeDate,
                  nextThreeDays
                )
                  ? "error.main"
                  : "inherit",
                fontWeight: isWithinNextSevenDays(
                  params.row.RD_Complete_F,
                  referenceDate,
                  nextSevenDays
                )
                  ? "600"
                  : "400",
              }}
            >
              {formatCustomCompleteDate(params.value, storedDateFormat)}
            </Stack>
          </Box>
        </>
      ),
    },
  ];

  return (
    <Box
      sx={{
        height: 500,
        width: "100%",
        [`.${gridClasses.cell}.red`]: {
          backgroundColor: "#FFE7E5",
          color: "#FF2D1E",
          ["&.Mui-selected"]: {
            backgroundColor: "#ffd5d1",
            ["&:hover"]: {
              backgroundColor: "#ffc3bd",
            },
          },
        },
        [`.${gridClasses.cell}.green`]: {
          backgroundColor: "#CAFFE4",
          color: "#139B57",
          ["&.Mui-selected"]: {
            backgroundColor: "#b8ffd9",
            ["&:hover"]: {
              backgroundColor: "#a3ffce",
            },
          },
        },
      }}
    >
      <DataGridPremium
        rows={rowsDate}
        columns={DateColumns}
        checkboxSelection
        disableRowSelectionOnClick
        ignoreValueFormatterDuringExport
        cellSelection
        getCellClassName={(params: any) => {
          if (params.field === "RAD_Start_A") {
            return params.row.RAD_Start_F < params.row.RAD_Start_A
              ? "red"
              : "green";
          }

          if (params.field === "RAD_Complete_A") {
            return params.row.RAD_Complete_F < params.row.RAD_Complete_A
              ? "red"
              : "green";
          }

          return "";
        }}
        onCellEditStop={(params: GridCellEditStopParams, event: MuiEvent) => {
          if (params.reason === GridCellEditStopReasons.cellFocusOut) {
            event.defaultMuiPrevented = true;
          }
        }}
      />
    </Box>
  );
}
michelengelen commented 2 months ago

The problem is that you are adding a Box inside of the cell and that is not affected by the color change for selection. For this to take effect you would need to just apply a class to the cell and adjust the background color that way.

This is also way more efficient

{
  field: 'RFDS_Start_F',
  headerName: 'RFDS START(F)',
  editable: true,
  // this is in the column definition, so you can adjust this for each column
  cellClassName: (params: GridCellParams) => (params.row.id % 2 === 0 ? 'yellow' : ''),
  ...
}

...

// this should be done in the grid sx prop
...
[`& .${gridClasses.cell}.yellow`]: {
  backgroundColor: '#ffd04f',
  ['&.Mui-selected']: {
    backgroundColor: '#cea538',
    ['&:hover']: {
      backgroundColor: '#fdd56d',
    },
  },
},
...

With this it is possible to adjust the color and be efficient in doing it!

github-actions[bot] commented 2 months ago

:warning: This issue has been closed. If you have a similar problem but not exactly the same, please open a new issue. Now, if you have additional information related to this issue or things that could help future readers, feel free to leave a comment.

@mahammahmood: How did we do? Your experience with our support team matters to us. If you have a moment, please share your thoughts in this short Support Satisfaction survey.