feat: add role user modules and shared table updates

This commit is contained in:
2026-06-15 20:07:06 +05:30
parent 8d4ff49633
commit bea47d29d5
21 changed files with 1245 additions and 133 deletions

View File

@@ -13,12 +13,11 @@ import {
import { Table, TableBody, TableCell, TableRow } from '@/components/ui/table';
import { Skeleton } from '@/components/ui/skeleton';
import { Button } from '@/components/ui/button';
import { Edit3, MoreHorizontal, Trash2 } from 'lucide-react';
import { Edit3, Trash2 } from 'lucide-react';
import TopHeader from './Header';
import TableHeader from './TableHeader';
import { TableFooter } from './Footer';
import { cn } from '@/lib/utils';
export interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[];
@@ -29,6 +28,9 @@ export interface DataTableProps<TData, TValue> {
isLoading?: boolean;
onEdit?: (item: TData) => void;
onDelete?: (item: TData) => void;
toolbar?: React.ReactNode;
emptyTitle?: string;
emptyDescription?: string;
pagination?: {
skip: number;
limit: number;
@@ -47,6 +49,9 @@ export function DataTable<TData, TValue>({
isLoading = false,
onEdit,
onDelete,
toolbar,
emptyTitle = 'No results found.',
emptyDescription = 'Try adjusting your filters or search terms.',
pagination,
}: DataTableProps<TData, TValue>) {
const [rowSelection, setRowSelection] = React.useState({});
@@ -58,32 +63,34 @@ export function DataTable<TData, TValue>({
if (onEdit || onDelete) {
cols.push({
id: 'actions',
header: () => <div className="text-right px-4">Action</div>,
header: () => <div className="text-right">Actions</div>,
cell: ({ row }) => {
const item = row.original;
return (
<div className="flex justify-end gap-3 px-4">
<div className="flex justify-end gap-2">
{onEdit && (
<button
<Button
variant="outline"
size="sm"
onClick={(e) => {
e.stopPropagation();
onEdit(item);
}}
className="flex items-center justify-center h-8 w-8 rounded-md text-primary hover:bg-foreground/10 transition-all duration-200"
>
<Edit3 className="h-4.5 w-4.5" />
</button>
<Edit3 className="size-4" />
</Button>
)}
{onDelete && (
<button
<Button
variant="outline"
size="sm"
onClick={(e) => {
e.stopPropagation();
onDelete(item);
}}
className="flex items-center justify-center h-8 w-8 rounded-md text-red-500 hover:bg-foreground/10 transition-all duration-200"
>
<Trash2 className="h-4.5 w-4.5" />
</button>
<Trash2 className="size-4 text-destructive" />
</Button>
)}
</div>
);
@@ -126,31 +133,28 @@ export function DataTable<TData, TValue>({
});
return (
<div className="rounded-xl border border-border/50 bg-muted/10 p-1 space-y-6">
<div className="bg-background/40 dark:bg-background/60 backdrop-blur-xl rounded-xl border border-border/50 overflow-hidden transition-all duration-300">
<section className="space-y-4 rounded-lg border bg-card p-4">
<TopHeader
title={title}
itemCount={data.length}
itemCount={pagination?.totalItems ?? data.length}
onAddNew={onAddNew}
addButtonText={addButtonText}
toolbar={toolbar}
/>
<div className="px-6 py-2">
<div>
<Table
containerClassName="max-h-[calc(100vh-300px)] overflow-y-auto scrollbar-thin"
containerClassName="max-h-[calc(100vh-300px)] overflow-y-auto"
className="border-separate border-spacing-0"
>
<TableHeader table={table} />
<TableBody>
{isLoading ? (
Array.from({ length: 5 }).map((_, idx) => (
<TableRow
key={idx}
className="border-b border-border/30 last:border-0 hover:bg-muted/5"
>
<TableRow key={idx}>
{columns.map((_, colIdx) => (
<TableCell key={colIdx} className="px-6 py-6 border-b border-border/30">
<Skeleton className="h-4 w-full max-w-[140px] opacity-20" />
<TableCell key={colIdx}>
<Skeleton className="h-4 w-full max-w-[140px]" />
</TableCell>
))}
</TableRow>
@@ -160,13 +164,9 @@ export function DataTable<TData, TValue>({
<TableRow
key={row.id}
data-state={row.getIsSelected() && 'selected'}
className="group hover:bg-muted/10 transition-colors"
>
{row.getVisibleCells().map((cell) => (
<TableCell
key={cell.id}
className="px-4 py-3 border-b border-border/50 align-middle text-muted-foreground text-sm font-medium group-hover:text-foreground"
>
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
@@ -174,12 +174,10 @@ export function DataTable<TData, TValue>({
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-48 text-center">
<TableCell colSpan={columns.length} className="h-28 text-center">
<div className="flex flex-col items-center justify-center text-muted-foreground gap-1">
<p className="font-bold text-sm tracking-tight">No results found.</p>
<p className="text-xs opacity-60 font-medium">
Try adjusting your filters or search terms.
</p>
<p className="text-sm font-medium">{emptyTitle}</p>
<p className="text-xs">{emptyDescription}</p>
</div>
</TableCell>
</TableRow>
@@ -187,8 +185,7 @@ export function DataTable<TData, TValue>({
</TableBody>
</Table>
</div>
<TableFooter table={table} />
</div>
</div>
<TableFooter table={table} totalItems={pagination?.totalItems ?? data.length} />
</section>
);
}