192 lines
5.2 KiB
TypeScript
192 lines
5.2 KiB
TypeScript
"use client";
|
|
import { useState, useEffect, useMemo } from "react";
|
|
import {
|
|
Box,
|
|
TextField,
|
|
IconButton,
|
|
InputAdornment,
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableContainer,
|
|
TableHead,
|
|
TableRow,
|
|
Checkbox,
|
|
Paper,
|
|
MenuItem,
|
|
InputLabel,
|
|
Select,
|
|
FormControl,
|
|
SelectChangeEvent,
|
|
debounce,
|
|
} from "@mui/material";
|
|
import SearchIcon from "@mui/icons-material/Search";
|
|
import { useRouter, useSearchParams } from "next/navigation";
|
|
|
|
export interface TableColumn<T> {
|
|
field: keyof T | string;
|
|
headerName: string;
|
|
render?: (value: unknown, row: T) => React.ReactNode;
|
|
}
|
|
|
|
interface MenuItemOption {
|
|
value: string;
|
|
label?: string;
|
|
}
|
|
|
|
interface DynamicTableProps<T extends { id: string | number }> {
|
|
data: {
|
|
rows: T[];
|
|
columns: TableColumn<T>[];
|
|
actions: MenuItemOption[];
|
|
};
|
|
searchParamKey?: string;
|
|
}
|
|
|
|
export function ApproveTable<T extends { id: string | number }>({
|
|
data,
|
|
searchParamKey = "merchantId",
|
|
}: DynamicTableProps<T>) {
|
|
const { rows, columns, actions } = data;
|
|
|
|
const router = useRouter();
|
|
const searchParams = useSearchParams();
|
|
|
|
const [selected, setSelected] = useState<(string | number)[]>([]);
|
|
const [search, setSearch] = useState("");
|
|
|
|
useEffect(() => {
|
|
const urlValue = searchParams.get(searchParamKey) ?? "";
|
|
setSearch(urlValue);
|
|
}, [searchParams, searchParamKey]);
|
|
|
|
const updateURL = useMemo(
|
|
() =>
|
|
debounce((value: string) => {
|
|
const params = new URLSearchParams(searchParams.toString());
|
|
if (value) params.set(searchParamKey, value);
|
|
else params.delete(searchParamKey);
|
|
|
|
router.replace(`?${params.toString()}`, { scroll: false });
|
|
}, 400),
|
|
[router, searchParams, searchParamKey],
|
|
);
|
|
|
|
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const value = e.target.value;
|
|
setSearch(value);
|
|
updateURL(value);
|
|
};
|
|
|
|
const handleCheckboxChange = (id: string | number, checked: boolean) => {
|
|
setSelected((prev) =>
|
|
checked ? [...prev, id] : prev.filter((x) => x !== id),
|
|
);
|
|
};
|
|
|
|
const handleToggleAll = (checked: boolean) => {
|
|
setSelected(checked ? rows.map((r) => r.id) : []);
|
|
};
|
|
|
|
const [action, setAction] = useState("");
|
|
const handleActionChange = (e: SelectChangeEvent<string>) => {
|
|
const selectedAction = e.target.value;
|
|
setAction(selectedAction);
|
|
|
|
if (selected.length > 0) {
|
|
console.log("Selected Ids", selected);
|
|
console.log("Selected Action:", selectedAction);
|
|
} else {
|
|
console.warn("No rows selected for action:", selectedAction);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Box p={2}>
|
|
<Box
|
|
mb={2}
|
|
display="flex"
|
|
justifyContent="space-between"
|
|
alignItems="center"
|
|
>
|
|
<TextField
|
|
variant="outlined"
|
|
placeholder="Search..."
|
|
size="small"
|
|
value={search}
|
|
onChange={handleSearchChange}
|
|
InputProps={{
|
|
endAdornment: (
|
|
<InputAdornment position="end">
|
|
<IconButton>
|
|
<SearchIcon />
|
|
</IconButton>
|
|
</InputAdornment>
|
|
),
|
|
}}
|
|
/>
|
|
|
|
<Box sx={{ width: 180, display: "flex", justifyContent: "center" }}>
|
|
<FormControl fullWidth>
|
|
<InputLabel>Action</InputLabel>
|
|
<Select
|
|
value={action}
|
|
label="Action"
|
|
onChange={handleActionChange}
|
|
size="small"
|
|
>
|
|
{actions.map((item) => (
|
|
<MenuItem key={item.value} value={item.value}>
|
|
{item.label ?? item.value}
|
|
</MenuItem>
|
|
))}
|
|
</Select>
|
|
</FormControl>
|
|
</Box>
|
|
</Box>
|
|
|
|
<TableContainer component={Paper}>
|
|
<Table size="small">
|
|
<TableHead>
|
|
<TableRow>
|
|
<TableCell padding="checkbox">
|
|
<Checkbox
|
|
checked={selected.length === rows.length && rows.length > 0}
|
|
indeterminate={
|
|
selected.length > 0 && selected.length < rows.length
|
|
}
|
|
onChange={(e) => handleToggleAll(e.target.checked)}
|
|
/>
|
|
</TableCell>
|
|
{columns.map((col, i) => (
|
|
<TableCell key={i}>{col.headerName}</TableCell>
|
|
))}
|
|
</TableRow>
|
|
</TableHead>
|
|
<TableBody>
|
|
{rows.map((row, idx) => (
|
|
<TableRow key={idx}>
|
|
<TableCell padding="checkbox">
|
|
<Checkbox
|
|
checked={selected.includes(row.id)}
|
|
onChange={(e) =>
|
|
handleCheckboxChange(row.id, e.target.checked)
|
|
}
|
|
/>
|
|
</TableCell>
|
|
{columns.map((col, colIdx) => (
|
|
<TableCell key={colIdx}>
|
|
{col.render
|
|
? col.render(row[col.field as keyof T], row)
|
|
: (row[col.field as keyof T] as React.ReactNode)}
|
|
</TableCell>
|
|
))}
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
</TableContainer>
|
|
</Box>
|
|
);
|
|
}
|