feat: improve data-table responsiveness and add bulk action support

This commit is contained in:
Yoga Pangestu 2026-04-14 23:05:37 +07:00
parent 54ccda7d80
commit 68e007e305

View File

@ -160,14 +160,39 @@ export function DataTable<TData, TValue>({
return (
<div className="space-y-4">
<div className="flex items-center justify-between gap-2">
<div className="flex flex-1 items-center gap-2">
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div className="flex flex-1 flex-col sm:flex-row items-stretch sm:items-center gap-2">
<Input
placeholder="Cari..."
value={globalFilter ?? ""}
onChange={(event) => setGlobalFilter(event.target.value)}
className="max-w-sm"
/>
</div>
<div className="flex items-center gap-2 ml-auto">
{selectedRows.length > 0 && bulkActions && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="secondary" className="gap-2 animate-in fade-in slide-in-from-left-2 transition-all">
Aksi Massal ({selectedRows.length})
<ChevronDown className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{bulkActions.map((action, i) => (
<DropdownMenuItem
key={i}
onClick={() => action.onClick(selectedRows.map((r) => r.original))}
className={action.variant === "destructive" ? "text-red-600 focus:text-red-600" : ""}
>
{action.icon && <action.icon className="mr-2 h-4 w-4" />}
{action.label}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
)}
{filters && filters.length > 0 && (
<DropdownMenu>
@ -177,7 +202,7 @@ export function DataTable<TData, TValue>({
Filter
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="w-48">
<DropdownMenuContent align="end" className="w-48">
<DropdownMenuLabel>Filter Berdasarkan</DropdownMenuLabel>
<DropdownMenuSeparator />
{filters.map((filter) => {
@ -216,64 +241,41 @@ export function DataTable<TData, TValue>({
</DropdownMenu>
)}
{selectedRows.length > 0 && bulkActions && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="secondary" className="gap-2 animate-in fade-in slide-in-from-left-2 transition-all">
Aksi Massal ({selectedRows.length})
<ChevronDown className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
{bulkActions.map((action, i) => (
<DropdownMenuItem
key={i}
onClick={() => action.onClick(selectedRows.map((r) => r.original))}
className={action.variant === "destructive" ? "text-red-600 focus:text-red-600" : ""}
>
{action.icon && <action.icon className="mr-2 h-4 w-4" />}
{action.label}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
)}
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" className="gap-2">
<Settings2 className="h-4 w-4" />
Kolom
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-48">
<DropdownMenuLabel>Tampilan Kolom</DropdownMenuLabel>
<DropdownMenuSeparator />
{table
.getAllColumns()
.filter((column) => column.getCanHide())
.map((column) => {
return (
<DropdownMenuCheckboxItem
key={column.id}
className="capitalize"
checked={column.getIsVisible()}
onCheckedChange={(value) => column.toggleVisibility(!!value)}
onSelect={(e) => e.preventDefault()}
>
{(column.columnDef.meta as any)?.title ||
(typeof column.columnDef.header === "string"
? column.columnDef.header
: String(column.id).replace(/_/g, " "))}
</DropdownMenuCheckboxItem>
);
})}
</DropdownMenuContent>
</DropdownMenu>
</div>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" className="ml-auto gap-2">
<Settings2 className="h-4 w-4" />
Kolom
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-48">
<DropdownMenuLabel>Tampilan Kolom</DropdownMenuLabel>
<DropdownMenuSeparator />
{table
.getAllColumns()
.filter((column) => column.getCanHide())
.map((column) => {
return (
<DropdownMenuCheckboxItem
key={column.id}
className="capitalize"
checked={column.getIsVisible()}
onCheckedChange={(value) => column.toggleVisibility(!!value)}
onSelect={(e) => e.preventDefault()}
>
{(column.columnDef.meta as any)?.title ||
(typeof column.columnDef.header === "string"
? column.columnDef.header
: String(column.id).replace(/_/g, " "))}
</DropdownMenuCheckboxItem>
);
})}
</DropdownMenuContent>
</DropdownMenu>
</div>
<div className="overflow-hidden rounded-md border bg-background">
<div className="overflow-x-auto rounded-md border bg-background">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
@ -333,13 +335,13 @@ export function DataTable<TData, TValue>({
</Table>
</div>
<div className="flex items-center justify-between py-4">
<div className="flex-1 text-sm text-muted-foreground">
<div className="flex flex-col sm:flex-row items-center justify-between gap-4 py-4">
<div className="text-sm text-muted-foreground">
{table.getFilteredSelectedRowModel().rows.length} dari{" "}
{table.getFilteredRowModel().rows.length} baris dipilih.
</div>
<div className="flex items-center space-x-6 lg:space-x-8">
<div className="flex items-center space-x-2">
<div className="flex flex-col sm:flex-row items-center gap-4 sm:gap-6 lg:gap-8">
<div className="flex items-center gap-2">
<p className="text-sm font-medium">Baris per halaman</p>
<Select
value={`${table.getState().pagination.pageSize}`}