79 lines
2.0 KiB
TypeScript
79 lines
2.0 KiB
TypeScript
|
|
import { type ReactNode } from 'react'
|
||
|
|
|
||
|
|
export interface Column<T> {
|
||
|
|
header: string
|
||
|
|
accessor: (row: T) => ReactNode
|
||
|
|
className?: string
|
||
|
|
}
|
||
|
|
|
||
|
|
interface AdminTableProps<T> {
|
||
|
|
columns: Column<T>[]
|
||
|
|
data: T[]
|
||
|
|
isLoading?: boolean
|
||
|
|
emptyMessage?: string
|
||
|
|
onRowClick?: (row: T) => void
|
||
|
|
keyFn: (row: T) => string | number
|
||
|
|
}
|
||
|
|
|
||
|
|
export function AdminTable<T>({
|
||
|
|
columns,
|
||
|
|
data,
|
||
|
|
isLoading,
|
||
|
|
emptyMessage = 'No data found.',
|
||
|
|
onRowClick,
|
||
|
|
keyFn,
|
||
|
|
}: AdminTableProps<T>) {
|
||
|
|
if (isLoading) {
|
||
|
|
return (
|
||
|
|
<div className="text-center py-8 text-gray-500 dark:text-gray-400">
|
||
|
|
Loading...
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
if (data.length === 0) {
|
||
|
|
return (
|
||
|
|
<div className="text-center py-8 text-gray-500 dark:text-gray-400">
|
||
|
|
{emptyMessage}
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="overflow-x-auto">
|
||
|
|
<table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
||
|
|
<thead className="bg-gray-50 dark:bg-gray-800">
|
||
|
|
<tr>
|
||
|
|
{columns.map((col) => (
|
||
|
|
<th
|
||
|
|
key={col.header}
|
||
|
|
className={`px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider ${col.className ?? ''}`}
|
||
|
|
>
|
||
|
|
{col.header}
|
||
|
|
</th>
|
||
|
|
))}
|
||
|
|
</tr>
|
||
|
|
</thead>
|
||
|
|
<tbody className="bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-700">
|
||
|
|
{data.map((row) => (
|
||
|
|
<tr
|
||
|
|
key={keyFn(row)}
|
||
|
|
onClick={onRowClick ? () => onRowClick(row) : undefined}
|
||
|
|
className={onRowClick ? 'cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800' : ''}
|
||
|
|
>
|
||
|
|
{columns.map((col) => (
|
||
|
|
<td
|
||
|
|
key={col.header}
|
||
|
|
className={`px-4 py-3 text-sm whitespace-nowrap ${col.className ?? ''}`}
|
||
|
|
>
|
||
|
|
{col.accessor(row)}
|
||
|
|
</td>
|
||
|
|
))}
|
||
|
|
</tr>
|
||
|
|
))}
|
||
|
|
</tbody>
|
||
|
|
</table>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|