setup husky prettier eslint

This commit is contained in:
2026-03-18 19:39:52 +05:30
parent 42624cae94
commit b675dd857b
93 changed files with 11269 additions and 6011 deletions

View File

@@ -1,189 +1,194 @@
"use client";
import React from "react";
'use client';
import React from 'react';
import {
ColumnDef,
SortingState,
flexRender,
getCoreRowModel,
useReactTable,
getSortedRowModel,
getPaginationRowModel,
} from "@tanstack/react-table";
ColumnDef,
SortingState,
flexRender,
getCoreRowModel,
useReactTable,
getSortedRowModel,
getPaginationRowModel,
} from '@tanstack/react-table';
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 { 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 TopHeader from "./Header";
import TableHeader from "./TableHeader";
import { TableFooter } from "./Footer";
import { cn } from "@/lib/utils";
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>[];
data: TData[];
title?: string;
onAddNew?: () => void;
addButtonText?: string;
isLoading?: boolean;
onEdit?: (item: TData) => void;
onDelete?: (item: TData) => void;
pagination?: {
skip: number;
limit: number;
totalItems?: number;
onPageChange: (newSkip: number) => void;
onLimitChange: (newLimit: number) => void;
};
columns: ColumnDef<TData, TValue>[];
data: TData[];
title?: string;
onAddNew?: () => void;
addButtonText?: string;
isLoading?: boolean;
onEdit?: (item: TData) => void;
onDelete?: (item: TData) => void;
pagination?: {
skip: number;
limit: number;
totalItems?: number;
onPageChange: (newSkip: number) => void;
onLimitChange: (newLimit: number) => void;
};
}
export function DataTable<TData, TValue>({
columns: initialColumns,
data,
title,
onAddNew,
addButtonText,
isLoading = false,
onEdit,
onDelete,
pagination,
columns: initialColumns,
data,
title,
onAddNew,
addButtonText,
isLoading = false,
onEdit,
onDelete,
pagination,
}: DataTableProps<TData, TValue>) {
const [rowSelection, setRowSelection] = React.useState({});
const [sorting, setSorting] = React.useState<SortingState>([]);
const [rowSelection, setRowSelection] = React.useState({});
const [sorting, setSorting] = React.useState<SortingState>([]);
const columns = React.useMemo(() => {
const cols: ColumnDef<TData, TValue>[] = [
...initialColumns,
];
const columns = React.useMemo(() => {
const cols: ColumnDef<TData, TValue>[] = [...initialColumns];
if (onEdit || onDelete) {
cols.push({
id: "actions",
header: () => <div className="text-right px-4">Action</div>,
cell: ({ row }) => {
const item = row.original;
return (
<div className="flex justify-end gap-3 px-4">
{onEdit && (
<button
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>
)}
{onDelete && (
<button
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>
)}
</div>
);
},
});
}
return cols;
}, [initialColumns, onEdit, onDelete]);
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
onRowSelectionChange: setRowSelection,
onSortingChange: setSorting,
getSortedRowModel: getSortedRowModel(),
getPaginationRowModel: getPaginationRowModel(),
manualPagination: !!pagination,
pageCount: pagination?.totalItems ? Math.ceil(pagination.totalItems / pagination.limit) : -1,
state: {
rowSelection,
sorting,
pagination: pagination ? {
pageIndex: Math.floor(pagination.skip / pagination.limit),
pageSize: pagination.limit,
} : undefined,
},
onPaginationChange: (updater) => {
if (typeof updater === 'function' && pagination) {
const newState = updater({
pageIndex: Math.floor(pagination.skip / pagination.limit),
pageSize: pagination.limit,
});
pagination.onLimitChange(newState.pageSize);
pagination.onPageChange(newState.pageIndex * newState.pageSize);
}
},
});
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">
<TopHeader
title={title}
itemCount={data.length}
onAddNew={onAddNew}
addButtonText={addButtonText}
/>
<div className="px-6 py-2">
<Table containerClassName="max-h-[calc(100vh-300px)] overflow-y-auto scrollbar-thin" 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">
{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>
))}
</TableRow>
))
) : table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<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">
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell
colSpan={columns.length}
className="h-48 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>
</div>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
<TableFooter table={table} />
if (onEdit || onDelete) {
cols.push({
id: 'actions',
header: () => <div className="text-right px-4">Action</div>,
cell: ({ row }) => {
const item = row.original;
return (
<div className="flex justify-end gap-3 px-4">
{onEdit && (
<button
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>
)}
{onDelete && (
<button
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>
)}
</div>
);
},
});
}
return cols;
}, [initialColumns, onEdit, onDelete]);
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
onRowSelectionChange: setRowSelection,
onSortingChange: setSorting,
getSortedRowModel: getSortedRowModel(),
getPaginationRowModel: getPaginationRowModel(),
manualPagination: !!pagination,
pageCount: pagination?.totalItems ? Math.ceil(pagination.totalItems / pagination.limit) : -1,
state: {
rowSelection,
sorting,
pagination: pagination
? {
pageIndex: Math.floor(pagination.skip / pagination.limit),
pageSize: pagination.limit,
}
: undefined,
},
onPaginationChange: (updater) => {
if (typeof updater === 'function' && pagination) {
const newState = updater({
pageIndex: Math.floor(pagination.skip / pagination.limit),
pageSize: pagination.limit,
});
pagination.onLimitChange(newState.pageSize);
pagination.onPageChange(newState.pageIndex * newState.pageSize);
}
},
});
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">
<TopHeader
title={title}
itemCount={data.length}
onAddNew={onAddNew}
addButtonText={addButtonText}
/>
<div className="px-6 py-2">
<Table
containerClassName="max-h-[calc(100vh-300px)] overflow-y-auto scrollbar-thin"
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"
>
{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>
))}
</TableRow>
))
) : table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<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"
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-48 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>
</div>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
);
<TableFooter table={table} />
</div>
</div>
);
}