"use client"; import { DataTable, ExtendedColumnDef } from "@app/components/ui/data-table"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@app/components/ui/dropdown-menu"; import { Button } from "@app/components/ui/button"; import { ArrowUpDown, MoreHorizontal } from "lucide-react"; import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import CreateSiteProvisioningKeyCredenza from "@app/components/CreateSiteProvisioningKeyCredenza"; import EditSiteProvisioningKeyCredenza from "@app/components/EditSiteProvisioningKeyCredenza"; import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog"; import { toast } from "@app/hooks/useToast"; import { formatAxiosError } from "@app/lib/api"; import { createApiClient } from "@app/lib/api"; import { useEnvContext } from "@app/hooks/useEnvContext"; import { usePaidStatus } from "@app/hooks/usePaidStatus"; import moment from "moment"; import { useTranslations } from "next-intl"; import { build } from "@server/build"; import { TierFeature, tierMatrix } from "@server/lib/billing/tierMatrix"; export type SiteProvisioningKeyRow = { id: string; key: string; name: string; createdAt: string; lastUsed: string | null; maxBatchSize: number | null; numUsed: number; validUntil: string | null; }; type SiteProvisioningKeysTableProps = { keys: SiteProvisioningKeyRow[]; orgId: string; }; export default function SiteProvisioningKeysTable({ keys, orgId }: SiteProvisioningKeysTableProps) { const router = useRouter(); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [selected, setSelected] = useState( null ); const [rows, setRows] = useState(keys); const api = createApiClient(useEnvContext()); const t = useTranslations(); const { isPaidUser } = usePaidStatus(); const canUseSiteProvisioning = isPaidUser(tierMatrix[TierFeature.SiteProvisioningKeys]) && build !== "oss"; const [isRefreshing, setIsRefreshing] = useState(false); const [createOpen, setCreateOpen] = useState(false); const [editOpen, setEditOpen] = useState(false); const [editingKey, setEditingKey] = useState(null); useEffect(() => { setRows(keys); }, [keys]); const refreshData = async () => { setIsRefreshing(true); try { await new Promise((resolve) => setTimeout(resolve, 200)); router.refresh(); } catch (error) { toast({ title: t("error"), description: t("refreshError"), variant: "destructive" }); } finally { setIsRefreshing(false); } }; const deleteKey = async (siteProvisioningKeyId: string) => { try { await api.delete( `/org/${orgId}/site-provisioning-key/${siteProvisioningKeyId}` ); router.refresh(); setIsDeleteModalOpen(false); setSelected(null); setRows((prev) => prev.filter((row) => row.id !== siteProvisioningKeyId)); } catch (e) { console.error(t("provisioningKeysErrorDelete"), e); toast({ variant: "destructive", title: t("provisioningKeysErrorDelete"), description: formatAxiosError( e, t("provisioningKeysErrorDeleteMessage") ) }); throw e; } }; const columns: ExtendedColumnDef[] = [ { accessorKey: "name", enableHiding: false, friendlyName: t("name"), header: ({ column }) => { return ( ); } }, { accessorKey: "key", friendlyName: t("key"), header: () => {t("key")}, cell: ({ row }) => { const r = row.original; return {r.key}; } }, { accessorKey: "maxBatchSize", friendlyName: t("provisioningKeysMaxBatchSize"), header: () => ( {t("provisioningKeysMaxBatchSize")} ), cell: ({ row }) => { const r = row.original; return ( {r.maxBatchSize == null ? t("provisioningKeysMaxBatchUnlimited") : r.maxBatchSize} ); } }, { accessorKey: "numUsed", friendlyName: t("provisioningKeysNumUsed"), header: () => ( {t("provisioningKeysNumUsed")} ), cell: ({ row }) => { const r = row.original; return {r.numUsed}; } }, { accessorKey: "validUntil", friendlyName: t("provisioningKeysValidUntil"), header: () => ( {t("provisioningKeysValidUntil")} ), cell: ({ row }) => { const r = row.original; return ( {r.validUntil ? moment(r.validUntil).format("lll") : t("provisioningKeysNoExpiry")} ); } }, { accessorKey: "lastUsed", friendlyName: t("provisioningKeysLastUsed"), header: () => ( {t("provisioningKeysLastUsed")} ), cell: ({ row }) => { const r = row.original; return ( {r.lastUsed ? moment(r.lastUsed).format("lll") : t("provisioningKeysNeverUsed")} ); } }, { accessorKey: "createdAt", friendlyName: t("createdAt"), header: () => {t("createdAt")}, cell: ({ row }) => { const r = row.original; return {moment(r.createdAt).format("lll")}; } }, { id: "actions", enableHiding: false, header: () => , cell: ({ row }) => { const r = row.original; return (
{ setEditingKey(r); setEditOpen(true); }} > {t("edit")} { setSelected(r); setIsDeleteModalOpen(true); }} > {t("delete")}
); } } ]; return ( <> { setEditOpen(v); if (!v) { setEditingKey(null); } }} orgId={orgId} provisioningKey={editingKey} /> {selected && ( { setIsDeleteModalOpen(val); if (!val) { setSelected(null); } }} dialog={

{t("provisioningKeysQuestionRemove")}

{t("provisioningKeysMessageRemove")}

} buttonText={t("provisioningKeysDeleteConfirm")} onConfirm={async () => deleteKey(selected.id)} string={selected.name} title={t("provisioningKeysDelete")} /> )} { if (canUseSiteProvisioning) { setCreateOpen(true); } }} addButtonDisabled={!canUseSiteProvisioning} onRefresh={refreshData} isRefreshing={isRefreshing} addButtonText={t("provisioningKeysAdd")} enableColumnVisibility={true} stickyLeftColumn="name" stickyRightColumn="actions" /> ); }