252 lines
7.3 KiB
TypeScript
252 lines
7.3 KiB
TypeScript
import { createSelector } from "@reduxjs/toolkit";
|
|
import { Box, IconButton, MenuItem, Select } from "@mui/material";
|
|
import OpenInNewIcon from "@mui/icons-material/OpenInNew";
|
|
import { GridColDef, GridRenderCellParams } from "@mui/x-data-grid";
|
|
import { RootState } from "@/app/redux/store";
|
|
import { TABLE_COLUMNS } from "../constants";
|
|
import { selectTransactionStatuses } from "@/app/redux/metadata/selectors";
|
|
import { DataRowBase } from "../types";
|
|
|
|
const TRANSACTION_STATUS_FALLBACK: string[] = [
|
|
"pending",
|
|
"completed",
|
|
"failed",
|
|
"inprogress",
|
|
"error",
|
|
];
|
|
|
|
type SelectorProps = {
|
|
enableStatusActions: boolean;
|
|
extraColumns?: string[] | null;
|
|
showExtraColumns?: boolean;
|
|
localRows: DataRowBase[];
|
|
handleStatusChange: (rowId: number, newStatus: string) => void;
|
|
};
|
|
|
|
// -------------------------
|
|
// Basic Selectors (props-driven)
|
|
// -------------------------
|
|
|
|
const propsEnableStatusActions = (_: RootState, props: SelectorProps) =>
|
|
props.enableStatusActions;
|
|
|
|
const propsExtraColumns = (_: RootState, props: SelectorProps) =>
|
|
props.extraColumns ?? null;
|
|
|
|
const propsShowExtraColumns = (_: RootState, props: SelectorProps) =>
|
|
props.showExtraColumns ?? false;
|
|
|
|
const propsLocalRows = (_: RootState, props: SelectorProps) =>
|
|
props.localRows ?? [];
|
|
|
|
const propsStatusChangeHandler = (_: RootState, props: SelectorProps) =>
|
|
props.handleStatusChange;
|
|
|
|
// -------------------------
|
|
// Base Columns
|
|
// -------------------------
|
|
|
|
const makeSelectBaseColumns = () =>
|
|
createSelector([propsEnableStatusActions], enableStatusActions => {
|
|
if (!enableStatusActions) return TABLE_COLUMNS;
|
|
|
|
return [
|
|
...TABLE_COLUMNS,
|
|
{
|
|
field: "actions",
|
|
headerName: "Actions",
|
|
width: 160,
|
|
sortable: false,
|
|
filterable: false,
|
|
} as GridColDef,
|
|
];
|
|
});
|
|
|
|
// -------------------------
|
|
// Visible Columns
|
|
// -------------------------
|
|
|
|
const makeSelectVisibleColumns = () =>
|
|
createSelector(
|
|
[makeSelectBaseColumns(), propsExtraColumns, propsShowExtraColumns],
|
|
(baseColumns, extraColumns, showExtraColumns) => {
|
|
if (!extraColumns || extraColumns.length === 0) return baseColumns;
|
|
|
|
return showExtraColumns
|
|
? baseColumns
|
|
: baseColumns.filter(col => !extraColumns.includes(col.field));
|
|
}
|
|
);
|
|
|
|
// -------------------------
|
|
// Resolved Statuses (STATE-based)
|
|
// -------------------------
|
|
|
|
const makeSelectResolvedStatuses = () =>
|
|
createSelector([selectTransactionStatuses], statuses =>
|
|
statuses.length > 0 ? statuses : TRANSACTION_STATUS_FALLBACK
|
|
);
|
|
|
|
// -------------------------
|
|
// Enhanced Columns
|
|
// -------------------------
|
|
|
|
export const makeSelectEnhancedColumns = () =>
|
|
createSelector(
|
|
[
|
|
makeSelectVisibleColumns(),
|
|
propsLocalRows,
|
|
propsStatusChangeHandler,
|
|
makeSelectResolvedStatuses(),
|
|
],
|
|
(
|
|
visibleColumns,
|
|
localRows,
|
|
handleStatusChange,
|
|
resolvedStatusOptions
|
|
): GridColDef[] => {
|
|
return visibleColumns.map(col => {
|
|
// --------------------------------
|
|
// 1. STATUS COLUMN RENDERER
|
|
// --------------------------------
|
|
if (col.field === "status") {
|
|
return {
|
|
...col,
|
|
renderCell: (params: GridRenderCellParams) => {
|
|
const value = params.value?.toLowerCase();
|
|
let bgColor = "#e0e0e0";
|
|
let textColor = "#000";
|
|
|
|
switch (value) {
|
|
case "completed":
|
|
bgColor = "#d0f0c0";
|
|
textColor = "#1b5e20";
|
|
break;
|
|
case "pending":
|
|
bgColor = "#fff4cc";
|
|
textColor = "#9e7700";
|
|
break;
|
|
case "inprogress":
|
|
bgColor = "#cce5ff";
|
|
textColor = "#004085";
|
|
break;
|
|
case "error":
|
|
bgColor = "#ffcdd2";
|
|
textColor = "#c62828";
|
|
break;
|
|
}
|
|
|
|
return (
|
|
<Box
|
|
sx={{
|
|
backgroundColor: bgColor,
|
|
color: textColor,
|
|
px: 1.5,
|
|
py: 0.5,
|
|
borderRadius: 1,
|
|
fontWeight: 500,
|
|
textTransform: "capitalize",
|
|
display: "inline-block",
|
|
width: "100%",
|
|
textAlign: "center",
|
|
}}
|
|
>
|
|
{params.value}
|
|
</Box>
|
|
);
|
|
},
|
|
};
|
|
}
|
|
|
|
// --------------------------------
|
|
// 2. USER ID COLUMN
|
|
// --------------------------------
|
|
if (col.field === "userId") {
|
|
return {
|
|
...col,
|
|
headerAlign: "center",
|
|
align: "center",
|
|
renderCell: (params: GridRenderCellParams) => (
|
|
<Box
|
|
sx={{
|
|
display: "grid",
|
|
gridTemplateColumns: "1fr auto",
|
|
alignItems: "center",
|
|
width: "100%",
|
|
px: 1,
|
|
}}
|
|
onClick={e => e.stopPropagation()}
|
|
>
|
|
<Box
|
|
sx={{
|
|
fontWeight: 500,
|
|
fontSize: "0.875rem",
|
|
color: "text.primary",
|
|
}}
|
|
>
|
|
{params.value}
|
|
</Box>
|
|
<IconButton
|
|
href={`/users/${params.value}`}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
size="small"
|
|
sx={{ p: 0.5, ml: 1 }}
|
|
onClick={e => e.stopPropagation()}
|
|
>
|
|
<OpenInNewIcon fontSize="small" />
|
|
</IconButton>
|
|
</Box>
|
|
),
|
|
};
|
|
}
|
|
|
|
// --------------------------------
|
|
// 3. ACTIONS COLUMN
|
|
// --------------------------------
|
|
if (col.field === "actions") {
|
|
return {
|
|
...col,
|
|
renderCell: (params: GridRenderCellParams) => {
|
|
const currentRow = localRows.find(row => row.id === params.id);
|
|
|
|
const options =
|
|
currentRow?.options?.map(option => option.value) ??
|
|
resolvedStatusOptions;
|
|
|
|
const uniqueOptions = Array.from(new Set(options));
|
|
|
|
return (
|
|
<Select<string>
|
|
value={currentRow?.status ?? ""}
|
|
onChange={e =>
|
|
handleStatusChange(
|
|
params.id as number,
|
|
e.target.value as string
|
|
)
|
|
}
|
|
size="small"
|
|
fullWidth
|
|
displayEmpty
|
|
sx={{
|
|
"& .MuiOutlinedInput-notchedOutline": { border: "none" },
|
|
"& .MuiSelect-select": { py: 0.5 },
|
|
}}
|
|
onClick={e => e.stopPropagation()}
|
|
>
|
|
{uniqueOptions.map(option => (
|
|
<MenuItem key={option} value={option}>
|
|
{option}
|
|
</MenuItem>
|
|
))}
|
|
</Select>
|
|
);
|
|
},
|
|
};
|
|
}
|
|
|
|
return col;
|
|
});
|
|
}
|
|
);
|