2025-11-25 10:50:27 +01:00

195 lines
5.8 KiB
TypeScript

"use client";
import React, { useState, useEffect, useCallback, useMemo } from "react";
import { DataGrid, GridPaginationModel } from "@mui/x-data-grid";
import { Box, Paper, Alert } from "@mui/material";
import DataTableHeader from "./DataTableHeader";
import StatusChangeDialog from "./StatusChangeDialog";
import Spinner from "@/app/components/Spinner/Spinner";
import {
selectStatus,
selectError,
selectPagination,
selectPaginationModel,
} from "@/app/redux/advanedSearch/selectors";
import { makeSelectEnhancedColumns } from "./re-selectors";
import { useDispatch, useSelector } from "react-redux";
import { DataRowBase } from "./types";
import { setPagination } from "@/app/redux/advanedSearch/advancedSearchSlice";
import { AppDispatch } from "@/app/redux/store";
interface DataTableProps<TRow extends DataRowBase> {
rows: TRow[];
extraColumns?: string[];
enableStatusActions?: boolean;
totalRows?: number;
}
const DataTable = <TRow extends DataRowBase>({
rows: localRows,
extraColumns,
enableStatusActions = false,
totalRows: totalRows,
}: DataTableProps<TRow>) => {
const dispatch = useDispatch<AppDispatch>();
const [showExtraColumns, setShowExtraColumns] = useState(false);
const [modalOpen, setModalOpen] = useState(false);
const [selectedRowId, setSelectedRowId] = useState<number | null>(null);
const [pendingStatus, setPendingStatus] = useState<string>("");
const [reason, setReason] = useState<string>("");
const [statusUpdateError, setStatusUpdateError] = useState<string | null>(
null
);
const [isUpdatingStatus, setIsUpdatingStatus] = useState(false);
const status = useSelector(selectStatus);
const errorMessage = useSelector(selectError);
const pagination = useSelector(selectPagination);
const paginationModel = useSelector(selectPaginationModel);
const handlePaginationModelChange = useCallback(
(model: GridPaginationModel) => {
console.log("model", model);
const nextPage = model.page + 1;
const nextLimit = model.pageSize;
if (nextPage !== pagination.page || nextLimit !== pagination.limit) {
dispatch(setPagination({ page: nextPage, limit: nextLimit }));
}
},
[dispatch, pagination.page, pagination.limit]
);
const handleStatusChange = useCallback((rowId: number, newStatus: string) => {
setSelectedRowId(rowId);
setPendingStatus(newStatus);
setModalOpen(true);
}, []);
const handleStatusSave = async () => {
if (!selectedRowId || !pendingStatus) return;
setStatusUpdateError(null);
setIsUpdatingStatus(true);
try {
const payload = {
data: {
status: pendingStatus,
notes: reason.trim(),
},
fields: ["Status", "Notes"],
};
const response = await fetch(
`/api/dashboard/transactions/${selectedRowId}`,
{
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
}
);
const result = await response.json();
if (!response.ok) {
throw new Error(
result?.message || result?.error || "Failed to update transaction"
);
}
setModalOpen(false);
setReason("");
setPendingStatus("");
setStatusUpdateError(null);
setSelectedRowId(null);
} catch (err) {
setStatusUpdateError(
err instanceof Error ? err.message : "Failed to update transaction"
);
} finally {
setIsUpdatingStatus(false);
}
};
const selectEnhancedColumns = useMemo(makeSelectEnhancedColumns, []);
const enhancedColumns = useSelector(state =>
selectEnhancedColumns(state, {
enableStatusActions,
extraColumns,
showExtraColumns,
localRows,
handleStatusChange,
})
);
return (
<>
{status === "loading" && <Spinner size="small" color="#fff" />}
{status === "failed" && (
<Alert severity="error">
{errorMessage || "Failed to load transactions."}
</Alert>
)}
<Paper sx={{ width: "100%", overflowX: "hidden" }}>
<DataTableHeader
extraColumns={extraColumns}
showExtraColumns={showExtraColumns}
onToggleExtraColumns={() => setShowExtraColumns(prev => !prev)}
onOpenExport={() => {}}
/>
<Box sx={{ width: "85vw" }}>
<Box sx={{ minWidth: 1200 }}>
<DataGrid
rows={localRows}
columns={enhancedColumns}
paginationModel={paginationModel}
onPaginationModelChange={handlePaginationModelChange}
paginationMode={totalRows ? "server" : "client"}
rowCount={totalRows}
pageSizeOptions={[10, 25, 50, 100]}
sx={{
border: 0,
cursor: "pointer",
"& .MuiDataGrid-cell": {
py: 1,
textAlign: "center",
justifyContent: "center",
display: "flex",
alignItems: "center",
},
"& .MuiDataGrid-columnHeader": {
textAlign: "center",
justifyContent: "center",
},
}}
/>
</Box>
</Box>
<StatusChangeDialog
open={modalOpen}
newStatus={pendingStatus}
reason={reason}
setReason={setReason}
handleClose={() => {
setModalOpen(false);
setReason("");
setPendingStatus("");
setStatusUpdateError(null);
setSelectedRowId(null);
}}
handleSave={handleStatusSave}
isSubmitting={isUpdatingStatus}
errorMessage={statusUpdateError}
/>
</Paper>
</>
);
};
// Memoize to avoid unnecessary re-renders
export default React.memo(DataTable);