| Status | Amount | |||
|---|---|---|---|---|
success | ken99@example.com | $316.00 | ||
success | Abe45@example.com | $242.00 | ||
processing | Monserrat44@example.com | $837.00 | ||
success | Silas22@example.com | $874.00 | ||
failed | carmella@example.com | $721.00 |
"use client";
import * as React from "react";
import {
type ColumnDef,
type ColumnFiltersState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
type SortingState,
useReactTable,
type VisibilityState,
} from "@tanstack/react-table";
import { Button } from "@smartacteam/ambient-web/button";
import { Checkbox } from "@smartacteam/ambient-web/checkbox";
import { Menu } from "@smartacteam/ambient-web/dropdown-menu";
import { CentralIcon } from "@smartacteam/ambient-web/icon";
import { Input } from "@smartacteam/ambient-web/input";
import { Table } from "@smartacteam/ambient-web/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
checked={table.getIsAllPageRowsSelected()}
indeterminate={table.getIsSomePageRowsSelected()}
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
aria-label="Select all"
/>
),
cell: ({ row }) => (
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
aria-label="Select row"
/>
),
enableSorting: false,
enableHiding: false,
},
{
id: "status",
accessorKey: "status",
header: "Status",
cell: ({ row }) => (
<div className="capitalize">{row.getValue("status")}</div>
),
},
{
accessorKey: "email",
header: ({ column }) => {
return (
<Button
size="sm"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
Email
<CentralIcon
name="IconChevronGrabberVertical"
radius="2"
stroke="1.5"
fill="outlined"
/>
</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 (
<Menu.Root>
<Menu.Trigger
render={
<Button className="size-8 p-0">
<span className="sr-only">Open menu</span>
<CentralIcon
name="IconDotGrid1x3Horizontal"
radius="2"
stroke="1.5"
fill="outlined"
/>
</Button>
}
/>
<Menu.Content align="end">
<Menu.Item
onClick={() => navigator.clipboard.writeText(payment.id)}
>
Copy payment ID
</Menu.Item>
<Menu.Separator />
<Menu.Item>View customer</Menu.Item>
<Menu.Item>View payment details</Menu.Item>
</Menu.Content>
</Menu.Root>
);
},
},
];
export 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.Text
placeholder="Filter emails..."
value={(table.getColumn("email")?.getFilterValue() as string) ?? ""}
onChange={(event) =>
table.getColumn("email")?.setFilterValue(event.target.value)
}
className="h-8 max-w-sm text-sm"
/>
<Menu.Root>
<Menu.Trigger
render={
<Button size="sm" className="ml-auto h-8">
Columns{" "}
<CentralIcon
name="IconChevronDownSmall"
radius="2"
stroke="1.5"
fill="outlined"
className="size-3.5"
/>
</Button>
}
/>
<Menu.Content align="end">
{table
.getAllColumns()
.filter((column) => column.getCanHide())
.map((column) => {
return (
<Menu.CheckboxItem
key={column.id}
className="capitalize"
checked={column.getIsVisible()}
onCheckedChange={(value) =>
column.toggleVisibility(!!value)
}
>
{column.id}
</Menu.CheckboxItem>
);
})}
</Menu.Content>
</Menu.Root>
</div>
<Table.Root>
<Table.Header>
{table.getHeaderGroups().map((headerGroup) => (
<Table.Row key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<Table.Head key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</Table.Head>
);
})}
</Table.Row>
))}
</Table.Header>
<Table.Body>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<Table.Row
key={row.id}
interactive
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => {
return (
<Table.Cell
key={cell.id}
variant={
cell.column.id === "status" ? "header" : "default"
}
>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</Table.Cell>
);
})}
</Table.Row>
))
) : (
<Table.Row>
<Table.Cell colSpan={columns.length} className="h-24 text-center">
No results.
</Table.Cell>
</Table.Row>
)}
</Table.Body>
</Table.Root>
<div className="flex items-center justify-end space-x-2 py-4">
<div className="flex-1 text-sm text-foreground-secondary">
{table.getFilteredSelectedRowModel().rows.length} of{" "}
{table.getFilteredRowModel().rows.length} row(s) selected.
</div>
<div className="flex gap-2">
<Button
size="sm"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
Previous
</Button>
<Button
size="sm"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
Next
</Button>
</div>
</div>
</div>
);
}