"use client";
import { Button } from "@app/components/ui/button";
import {
ControlledDataTable,
type ExtendedColumnDef
} from "@app/components/ui/controlled-data-table";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger
} from "@app/components/ui/dropdown-menu";
import { useNavigationContext } from "@app/hooks/useNavigationContext";
import { toast } from "@app/hooks/useToast";
import { getNextSortOrder, getSortDirection } from "@app/lib/sortColumn";
import { type PaginationState } from "@tanstack/react-table";
import {
ArrowDown01Icon,
ArrowRight,
ArrowUp10Icon,
ChevronsUpDownIcon,
MoreHorizontal
} from "lucide-react";
import moment from "moment";
import { useTranslations } from "next-intl";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useMemo, useTransition } from "react";
import { useDebouncedCallback } from "use-debounce";
export type OrgRow = {
orgId: string;
name: string;
subnet: string | null;
createdAt: string | null;
userCount: number;
siteCount: number;
resourceCount: number;
};
type OrgTableProps = {
orgs: OrgRow[];
pagination: PaginationState;
rowCount: number;
};
export default function OrgsTable({
orgs,
pagination,
rowCount
}: OrgTableProps) {
const router = useRouter();
const t = useTranslations();
const {
navigate: filter,
isNavigating: isFiltering,
searchParams
} = useNavigationContext();
const [isRefreshing, startTransition] = useTransition();
function refreshData() {
startTransition(async () => {
try {
router.refresh();
} catch (error) {
toast({
title: t("error"),
description: t("refreshError"),
variant: "destructive"
});
}
});
}
function toggleSort(column: string) {
const newSearch = getNextSortOrder(column, searchParams);
filter({
searchParams: newSearch
});
}
function sortableHeader(column: string, label: string) {
const sortOrder = getSortDirection(column, searchParams);
const Icon =
sortOrder === "asc"
? ArrowDown01Icon
: sortOrder === "desc"
? ArrowUp10Icon
: ChevronsUpDownIcon;
return (
);
}
const columns = useMemo[]>(() => {
return [
{
accessorKey: "name",
friendlyName: t("name"),
enableHiding: false,
header: () => sortableHeader("name", t("name"))
},
{
accessorKey: "createdAt",
friendlyName: t("createdAt"),
header: () => sortableHeader("createdAt", t("createdAt")),
cell: ({ row }) => {
const createdAt = row.original.createdAt;
return (
{createdAt ? moment(createdAt).format("lll") : "-"}
);
}
},
{
accessorKey: "orgId",
friendlyName: t("orgId"),
header: () => {t("orgId")}
},
{
accessorKey: "subnet",
friendlyName: t("subnet"),
header: () => {t("subnet")},
cell: ({ row }) => {row.original.subnet || "-"}
},
{
accessorKey: "userCount",
friendlyName: t("users"),
header: () => {t("users")},
cell: ({ row }) => (
{row.original.userCount}
)
},
{
accessorKey: "siteCount",
friendlyName: t("sites"),
header: () => {t("sites")},
cell: ({ row }) => (
{row.original.siteCount}
)
},
{
accessorKey: "resourceCount",
friendlyName: t("resources"),
header: () => {t("resources")},
cell: ({ row }) => (
{row.original.resourceCount}
)
},
{
id: "actions",
enableHiding: false,
header: () => ,
cell: ({ row }) => {
const orgRow = row.original;
return (
);
}
}
];
}, [t, searchParams]);
const handlePaginationChange = (newPage: PaginationState) => {
searchParams.set("page", (newPage.pageIndex + 1).toString());
searchParams.set("pageSize", newPage.pageSize.toString());
filter({
searchParams
});
};
const handleSearchChange = useDebouncedCallback((query: string) => {
searchParams.set("query", query);
searchParams.delete("page");
filter({
searchParams
});
}, 300);
return (
);
}