"use client"
import * as React from "react"
import {
ColumnDef,
ColumnFiltersState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
SortingState,
useReactTable,
VisibilityState,
} from "@tanstack/react-table"
import { ArrowUpDown, ChevronDown, MoreHorizontal } from "lucide-react"
import { Button } from "@/registry/new-york/ui/button"
import { Checkbox } from "@/registry/new-york/ui/checkbox"
import { Input } from "@/registry/new-york/ui/input"
import {
Menu,
MenuItem,
MenuSeparator,
MenuTrigger,
} from "@/registry/new-york/ui/menu"
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/registry/new-york/ui/table"
const data: Payment[] = [
{
id: "m5gr84i9",
amount: 316,
status: "success",
email: "ken99@example.com",
},
{
id: "3u1reuv4",
amount: 242,
status: "success",
email: "Abe45@example.com",
},
{
id: "derv1ws0",
amount: 837,
status: "processing",
email: "Monserrat44@example.com",
},
{
id: "5kma53ae",
amount: 874,
status: "success",
email: "Silas22@example.com",
},
{
id: "bhqecj4p",
amount: 721,
status: "failed",
email: "carmella@example.com",
},
]
export type Payment = {
id: string
amount: number
status: "pending" | "processing" | "success" | "failed"
email: string
}
export const columns: ColumnDef<Payment>[] = [
{
id: "select",
header: ({ table }) => (
<Checkbox
isSelected={
table.getIsAllPageRowsSelected() ||
(table.getIsSomePageRowsSelected() ? "indeterminate" : false)
}
onChange={(isSelected) => table.toggleAllPageRowsSelected(!!isSelected)}
aria-label="Select all"
/>
),
cell: ({ row }) => (
<Checkbox
isSelected={row.getIsSelected()}
onChange={(isSelected) => row.toggleSelected(!!isSelected)}
aria-label="Select row"
/>
),
enableSorting: false,
enableHiding: false,
},
{
accessorKey: "status",
header: "Status",
cell: ({ row }) => (
<div className="capitalize">{row.getValue("status")}</div>
),
},
{
accessorKey: "email",
header: ({ column }) => {
return (
<Button
variant="ghost"
onPress={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
Email
<ArrowUpDown />
</Button>
)
},
cell: ({ row }) => <div className="lowercase">{row.getValue("email")}</div>,
},
{
accessorKey: "amount",
header: () => <div className="text-right">Amount</div>,
cell: ({ row }) => {
const amount = parseFloat(row.getValue("amount"))
// Format the amount as a dollar amount
const formatted = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
}).format(amount)
return <div className="text-right font-medium">{formatted}</div>
},
},
{
id: "actions",
enableHiding: false,
cell: ({ row }) => {
const payment = row.original
return (
<MenuTrigger>
<Button variant="ghost" className="h-8 w-8 p-0">
<span className="sr-only">Open menu</span>
<MoreHorizontal />
</Button>
<Menu placement="bottom end">
<MenuItem
onAction={() => navigator.clipboard.writeText(payment.id)}
>
Copy payment ID
</MenuItem>
<MenuSeparator />
<MenuItem>View customer</MenuItem>
<MenuItem>View payment details</MenuItem>
</Menu>
</MenuTrigger>
)
},
},
]
export default function DataTableDemo() {
const [sorting, setSorting] = React.useState<SortingState>([])
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
)
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({})
const [rowSelection, setRowSelection] = React.useState({})
const table = useReactTable({
data,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
},
})
return (
<div className="w-full">
<div className="flex items-center py-4">
<Input
placeholder="Filter emails..."
value={(table.getColumn("email")?.getFilterValue() as string) ?? ""}
onChange={(event) =>
table.getColumn("email")?.setFilterValue(event.target.value)
}
className="max-w-sm"
/>
<MenuTrigger>
<Button variant="outline" className="ml-auto">
Columns <ChevronDown />
</Button>
<Menu
placement="bottom end"
selectionMode="multiple"
selectedKeys={Object.keys(columnVisibility).filter(
(key) => columnVisibility[key]
)}
onSelectionChange={(keys) => {
const newVisibility: VisibilityState = {}
table
.getAllColumns()
.filter((column) => column.getCanHide())
.forEach((column) => {
newVisibility[column.id] = Array.from(keys).includes(
column.id
)
})
setColumnVisibility(newVisibility)
}}
>
{table
.getAllColumns()
.filter((column) => column.getCanHide())
.map((column) => {
return (
<MenuItem
key={column.id}
id={column.id}
className="capitalize"
>
{column.id}
</MenuItem>
)
})}
</Menu>
</MenuTrigger>
</div>
<div className="overflow-hidden rounded-md border">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
)
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell
colSpan={columns.length}
className="h-24 text-center"
>
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
<div className="flex items-center justify-end space-x-2 py-4">
<div className="text-muted-foreground flex-1 text-sm">
{table.getFilteredSelectedRowModel().rows.length} of{" "}
{table.getFilteredRowModel().rows.length} row(s) selected.
</div>
<div className="space-x-2">
<Button
variant="outline"
size="sm"
onPress={() => table.previousPage()}
isDisabled={!table.getCanPreviousPage()}
>
Previous
</Button>
<Button
variant="outline"
size="sm"
onPress={() => table.nextPage()}
isDisabled={!table.getCanNextPage()}
>
Next
</Button>
</div>
</div>
</div>
)
}