"use client";
import { Button, IconButton } from "@azmr/ui/button";
import { Badge, EmptyState } from "@azmr/ui/display";
import { Icon } from "@azmr/ui/icons";
import { Input } from "@azmr/ui/input";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@azmr/ui/menu";
import { Pagination } from "@azmr/ui/pagination";
import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@azmr/ui/table";
import { toast } from "@azmr/ui/toast";
import { ArrowDown, ArrowUp, ArrowUpDown, MoreHorizontal, Search, SearchX } from "lucide-react";
import { useId, useMemo, useState } from "react";
interface Customer {
name: string;
plan: "Starter" | "Business" | "Enterprise";
status: "Active" | "Trial" | "Overdue";
monthly: number;
}
const CUSTOMERS: Customer[] = [
{ name: "Aroha Ngata", plan: "Business", status: "Active", monthly: 240 },
{ name: "Mere Walker", plan: "Starter", status: "Trial", monthly: 0 },
{ name: "Hemi Te Rangi", plan: "Enterprise", status: "Active", monthly: 1800 },
{ name: "Tane Smith", plan: "Business", status: "Overdue", monthly: 240 },
{ name: "Rangi Bell", plan: "Starter", status: "Active", monthly: 49 },
{ name: "Kiri Parata", plan: "Business", status: "Active", monthly: 240 },
{ name: "Hana Cooper", plan: "Starter", status: "Overdue", monthly: 49 },
{ name: "Wiremu Tait", plan: "Enterprise", status: "Trial", monthly: 0 },
{ name: "Anika Rao", plan: "Business", status: "Active", monthly: 240 },
{ name: "Ngaio Reid", plan: "Starter", status: "Active", monthly: 49 },
{ name: "Tui Anderson", plan: "Business", status: "Trial", monthly: 0 },
{ name: "Manu Kerr", plan: "Enterprise", status: "Active", monthly: 1800 },
];
const STATUS_TONE = { Active: "success", Trial: "info", Overdue: "destructive" } as const;
const PAGE_SIZE = 5;
const nzd = new Intl.NumberFormat("en-NZ", { style: "currency", currency: "NZD" });
type SortKey = "name" | "plan" | "status" | "monthly";
export default function DataTablePage() {
const searchId = useId();
const [query, setQuery] = useState("");
const [sort, setSort] = useState<{ key: SortKey; direction: "ascending" | "descending" }>({
key: "name",
direction: "ascending",
});
const [page, setPage] = useState(1);
// Filter, then sort, then take the page. Each step works on the result of the one before.
const rows = useMemo(() => {
const needle = query.trim().toLowerCase();
const found = CUSTOMERS.filter(
(c) => !needle || `${c.name} ${c.plan} ${c.status}`.toLowerCase().includes(needle),
);
const factor = sort.direction === "ascending" ? 1 : -1;
return [...found].sort((a, b) => {
const x = a[sort.key];
const y = b[sort.key];
return (
(typeof x === "number" ? x - (y as number) : String(x).localeCompare(String(y))) * factor
);
});
}, [query, sort]);
const pageCount = Math.max(1, Math.ceil(rows.length / PAGE_SIZE));
const current = Math.min(page, pageCount);
const shown = rows.slice((current - 1) * PAGE_SIZE, current * PAGE_SIZE);
function sortBy(key: SortKey) {
setSort((s) => ({
key,
direction: s.key === key && s.direction === "ascending" ? "descending" : "ascending",
}));
setPage(1);
}
function header(key: SortKey, label: string, align?: "right") {
const active = sort.key === key;
const arrow = !active ? ArrowUpDown : sort.direction === "ascending" ? ArrowUp : ArrowDown;
return (
// aria-sort belongs on the column header, and only on the column that is sorted.
{rows.length === 0 ? "0 customers" : `Showing ${(current - 1) * PAGE_SIZE + 1}–${(current - 1) * PAGE_SIZE + shown.length} of ${rows.length} customers`}
{pageCount > 1 && (