"use client" import * as React from "react" import { type SortingState, type Table } from "@tanstack/react-table" import { ArrowDownUp, ChevronsUpDown, GripVertical, Trash2, } from "lucide-react" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "@/components/ui/command" import { Sortable, SortableItem, SortableDragHandle, } from "@/components/ui/sortable" import { cn, toSentenceCase } from "@/lib/utils" /** * A simpler, local-state version of the column "sort list". * - No `useQueryState` or URL sync * - We store a local `sorting: SortingState` and whenever it changes, we do `table.setSorting(sorting)`. */ interface DataTableSortListLocalProps { /** TanStack Table instance */ table: Table } export function ClientDataTableSortList({ table }: DataTableSortListLocalProps) { // 2) local SortingState const [sorting, setSorting] = React.useState([]) // 3) Keep the table in sync React.useEffect(() => { table.setSorting(sorting) }, [sorting, table]) // 4) columns that can be sorted const sortableColumns = React.useMemo(() => { return table .getAllColumns() .flatMap((column) => { if (column.columns && column.columns.length > 0) { return column.columns.filter(c => c.getCanSort()); } return column.getCanSort() ? [column] : []; }) .filter((col) => col.getCanSort()) .map((col) => ({ id: col.id, // excelHeader 를 사용 중이면 label이 없을 수 있으니 fallback label: (col.columnDef.meta?.excelHeader as string) || toSentenceCase(col.id), })) }, [table]) // 5) "Add sort" → pick first unsorted column function addSort() { const used = new Set(sorting.map((s) => s.id)) const firstUnused = sortableColumns.find((col) => !used.has(col.id)) if (!firstUnused) return setSorting((prev) => [...prev, { id: firstUnused.id, desc: false }]) } // 6) update sort item by column id function updateSort( columnId: string, patch: Partial<{ id: string; desc: boolean }> ) { setSorting((prev) => prev.map((s) => (s.id === columnId ? { ...s, ...patch } : s)) ) } // 7) remove a sort item function removeSort(columnId: string) { setSorting((prev) => prev.filter((s) => s.id !== columnId)) } // 8) reorder sorting items via drag function moveSort(activeIndex: number, overIndex: number) { setSorting((prev) => { const arr = [...prev] const [removed] = arr.splice(activeIndex, 1) if (!removed) return prev arr.splice(overIndex, 0, removed) return arr }) } const isSortingEmpty = sorting.length === 0 return ( moveSort(activeIndex, overIndex)} overlay={
} > 0 ? "gap-3.5" : "gap-2" )} > {isSortingEmpty ? (

{ "No sorting applied"}

{ "Add sorting to organize your results."}

) : (

{ "Sort by"}

)} {/* Sorting items */} {sorting.length > 0 && (
{sorting.map((sortItem) => { const col = sortableColumns.find((c) => c.id === sortItem.id) const columnLabel = col ? col.label : toSentenceCase(sortItem.id) return (
{/* Column name selector */} { "No columns found."} {sortableColumns.map((col) => ( { // change the ID of the sort item updateSort(sortItem.id, { id: val, desc: false }) }} > {col.label} ))} {/* Sort direction */} {/* remove sort */} {/* drag handle */}
) })}
)} {/* Footer: "Add sort" & "Reset" */}
{sorting.length > 0 && ( )}
) }