import { useState, useEffect } from "react"; import { createColumnHelper } from "@tanstack/react-table"; import { format } from "date-fns"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Search } from "lucide-react"; export const pageSizes = [10, 25, 50, 75, 100, 250, 500, 750, 1000] // ── Badge style map for enum values ─────────────────────────────────────────── export const BADGE_STYLES = { "Active": "bg-emerald-100 text-emerald-800 border-emerald-200", "Not Active": "bg-rose-100 text-rose-700 border-rose-200", "Verified": "bg-blue-100 text-blue-800 border-blue-200", "Not Verified": "bg-amber-100 text-amber-700 border-amber-200", "system": "bg-violet-50 text-violet-700 border-violet-200", "google": "bg-orange-50 text-orange-700 border-orange-200", "admin": "bg-red-100 text-red-700 border-red-200", "user": "bg-blue-100 text-blue-700 border-blue-200", "staff": "bg-green-100 text-green-700 border-green-200", }; function EnumBadge({ value }) { return ( {value} ); } export function formatDate(value) { if (!value) return null; try { return format(new Date(value), "MMM d, yyyy"); } catch { return value; } } function renderCell(attr, value) { if (value === null || value === undefined || value === "") { return -; } switch (attr.type) { case "enum": if (attr.field === "is_active") return ; else if (attr.field === "is_verified") return ; else return ; case "date": return {formatDate(value)}; case "number": return {value}; default: return {value}; } } export function ColumnFilter({ column, attr }) { const columnValue = column.getFilterValue() ?? ""; const [inputValue, setInputValue] = useState(columnValue); // keep in sync when external reset happens useEffect(() => { setInputValue(columnValue); }, [columnValue]); // ───────────────────────────────────────────── // ENUM (AUTO APPLY) // ───────────────────────────────────────────── if (attr.type === "enum") { return ( ); } // ───────────────────────────────────────────── // DATE (SINGLE) // ───────────────────────────────────────────── if (attr.type === "date") { const value = inputValue && typeof inputValue === "object" && ("from" in inputValue || "to" in inputValue) ? inputValue : null; const isRange = !!value; return (
{/* MODE TOGGLE */}
{/* SINGLE DATE */} {!isRange && ( { const val = e.target.value; setInputValue(val); column.setFilterValue(val); }} className="h-7 text-xs" /> )} {/* RANGE */} {isRange && (
{ const next = { from: e.target.value, to: value.to || "", }; setInputValue(next); column.setFilterValue(next); }} className="h-7 text-xs" /> { const next = { from: value.from || "", to: e.target.value, }; setInputValue(next); column.setFilterValue(next); }} className="h-7 text-xs" />
)}
); } // ───────────────────────────────────────────── // TEXT FILTER (manual apply) // ───────────────────────────────────────────── return (
setInputValue(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") { column.setFilterValue(inputValue); } }} placeholder="Filter..." className="h-7 text-xs w-full" />
); } // ── Sort icon ────────────────────────────────────────────────────────────────── export function SortIcon({ column }) { const s = column.getIsSorted(); if (s === "asc") return ; if (s === "desc") return ; return ; } // ── Build columns dynamically from attributes ────────────────────────────────── const columnHelper = createColumnHelper(); export function buildColumns(attributes, { cellOverrides = {} } = {}) { return attributes.map((attr) => columnHelper.accessor(attr.field, { id: attr.field, header: attr.name, enableSorting: true, enableColumnFilter: true, filterFn: (row, colId, filterValue) => { if (!filterValue) return true; const val = String(row.getValue(colId) ?? "").toLowerCase(); return val.includes(String(filterValue).toLowerCase()); }, cell: (info) => cellOverrides[attr.field] // ← check override first ? cellOverrides[attr.field](info) : renderCell(attr, info.getValue()), meta: { attr }, }) ); }