|
import React from 'react'; |
|
import { |
|
Table, |
|
TableBody, |
|
TableCell, |
|
TableHead, |
|
TableHeaderCell, |
|
TableRow, |
|
Text, |
|
Badge, |
|
Icon, |
|
Button, |
|
Card, |
|
} from "@tremor/react"; |
|
import { Tooltip } from "antd"; |
|
|
|
interface Column { |
|
header: string; |
|
accessor: string; |
|
cellRenderer?: (value: any, row: any) => React.ReactNode; |
|
width?: string; |
|
style?: React.CSSProperties; |
|
} |
|
|
|
interface Action<T = any> { |
|
icon?: React.ComponentType<any>; |
|
onClick: (item: T) => void; |
|
condition?: () => boolean; |
|
tooltip?: string; |
|
} |
|
|
|
interface DeleteModalProps { |
|
isOpen: boolean; |
|
onConfirm: () => void; |
|
onCancel: () => void; |
|
title: string; |
|
message: string; |
|
} |
|
|
|
interface DataTableProps { |
|
data: any[]; |
|
columns: Column[]; |
|
actions?: Action[]; |
|
emptyMessage?: string; |
|
deleteModal?: DeleteModalProps; |
|
} |
|
|
|
const DataTable: React.FC<DataTableProps> = ({ |
|
data, |
|
columns, |
|
actions, |
|
emptyMessage = "No data available", |
|
deleteModal |
|
}) => { |
|
const renderCell = (column: Column, row: any) => { |
|
const value = row[column.accessor]; |
|
|
|
if (column.cellRenderer) { |
|
return column.cellRenderer(value, row); |
|
} |
|
|
|
|
|
if (Array.isArray(value)) { |
|
return ( |
|
<div style={{ display: "flex", flexDirection: "column" }}> |
|
{value.length === 0 ? ( |
|
<Badge size="xs" className="mb-1" color="red"> |
|
<Text>None</Text> |
|
</Badge> |
|
) : ( |
|
value.map((item: any, index: number) => ( |
|
<Badge |
|
key={index} |
|
size="xs" |
|
className="mb-1" |
|
color="blue" |
|
> |
|
<Text> |
|
{String(item).length > 30 |
|
? `${String(item).slice(0, 30)}...` |
|
: item} |
|
</Text> |
|
</Badge> |
|
)) |
|
)} |
|
</div> |
|
); |
|
} |
|
|
|
return value?.toString() || ''; |
|
}; |
|
|
|
return ( |
|
<Card className="w-full mx-auto flex-auto overflow-y-auto max-h-[40vh]"> |
|
<Table> |
|
<TableHead> |
|
<TableRow> |
|
{columns.map((column, index) => ( |
|
<TableHeaderCell key={index}>{column.header}</TableHeaderCell> |
|
))} |
|
{actions && actions.length > 0 && ( |
|
<TableHeaderCell>Actions</TableHeaderCell> |
|
)} |
|
</TableRow> |
|
</TableHead> |
|
|
|
<TableBody> |
|
{data && data.length > 0 ? ( |
|
data.map((row, rowIndex) => ( |
|
<TableRow key={rowIndex}> |
|
{columns.map((column, colIndex) => ( |
|
<TableCell |
|
key={colIndex} |
|
style={{ |
|
maxWidth: column.width || "4px", |
|
whiteSpace: "pre-wrap", |
|
overflow: "hidden", |
|
...column.style |
|
}} |
|
> |
|
{column.accessor === 'id' ? ( |
|
<Tooltip title={row[column.accessor]}> |
|
{renderCell(column, row)} |
|
</Tooltip> |
|
) : ( |
|
renderCell(column, row) |
|
)} |
|
</TableCell> |
|
))} |
|
{actions && actions.length > 0 && ( |
|
<TableCell> |
|
{actions.map((action, actionIndex) => ( |
|
// @ts-ignore |
|
action.condition?.(row) !== false && ( |
|
<Tooltip key={actionIndex} title={action.tooltip}> |
|
<Icon |
|
// @ts-ignore |
|
icon={action.icon} |
|
size="sm" |
|
onClick={() => action.onClick(row)} |
|
className="cursor-pointer mx-1" |
|
/> |
|
</Tooltip> |
|
) |
|
))} |
|
</TableCell> |
|
)} |
|
</TableRow> |
|
)) |
|
) : ( |
|
<TableRow> |
|
<TableCell colSpan={columns.length + (actions ? 1 : 0)}> |
|
<Text className="text-center">{emptyMessage}</Text> |
|
</TableCell> |
|
</TableRow> |
|
)} |
|
</TableBody> |
|
</Table> |
|
|
|
</Card> |
|
); |
|
}; |
|
|
|
export default DataTable; |
|
export type { Action, Column, DataTableProps, DeleteModalProps }; |