"use client"; import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog"; import { DataTable } from "@app/components/ui/data-table"; import { ExtendedColumnDef } from "@app/components/ui/data-table"; import { Button } from "@app/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@app/components/ui/dropdown-menu"; import { useEnvContext } from "@app/hooks/useEnvContext"; import { toast } from "@app/hooks/useToast"; import { createApiClient, formatAxiosError } from "@app/lib/api"; import { ArrowRight, ArrowUpDown, ArrowUpRight, MoreHorizontal, CircleSlash } from "lucide-react"; import { useTranslations } from "next-intl"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useMemo, useState, useTransition } from "react"; import { Badge } from "./ui/badge"; import { InfoPopup } from "./ui/info-popup"; import ClientDownloadBanner from "./ClientDownloadBanner"; export type ClientRow = { id: number; name: string; subnet: string; // siteIds: string; mbIn: string; mbOut: string; orgId: string; online: boolean; olmVersion?: string; olmUpdateAvailable: boolean; userId: string | null; username: string | null; userEmail: string | null; niceId: string; agent: string | null; archived?: boolean; blocked?: boolean; }; type ClientTableProps = { userClients: ClientRow[]; orgId: string; }; export default function UserDevicesTable({ userClients }: ClientTableProps) { const router = useRouter(); const t = useTranslations(); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [isBlockModalOpen, setIsBlockModalOpen] = useState(false); const [selectedClient, setSelectedClient] = useState( null ); const api = createApiClient(useEnvContext()); const [isRefreshing, startTransition] = useTransition(); const defaultUserColumnVisibility = { subnet: false, niceId: false }; const refreshData = () => { startTransition(() => { try { router.refresh(); } catch (error) { toast({ title: t("error"), description: t("refreshError"), variant: "destructive" }); } }); }; const deleteClient = (clientId: number) => { api.delete(`/client/${clientId}`) .catch((e) => { console.error("Error deleting client", e); toast({ variant: "destructive", title: "Error deleting client", description: formatAxiosError(e, "Error deleting client") }); }) .then(() => { startTransition(() => { router.refresh(); setIsDeleteModalOpen(false); }); }); }; const archiveClient = (clientId: number) => { api.post(`/client/${clientId}/archive`) .catch((e) => { console.error("Error archiving client", e); toast({ variant: "destructive", title: "Error archiving client", description: formatAxiosError(e, "Error archiving client") }); }) .then(() => { startTransition(() => { router.refresh(); }); }); }; const unarchiveClient = (clientId: number) => { api.post(`/client/${clientId}/unarchive`) .catch((e) => { console.error("Error unarchiving client", e); toast({ variant: "destructive", title: "Error unarchiving client", description: formatAxiosError(e, "Error unarchiving client") }); }) .then(() => { startTransition(() => { router.refresh(); }); }); }; const blockClient = (clientId: number) => { api.post(`/client/${clientId}/block`) .catch((e) => { console.error("Error blocking client", e); toast({ variant: "destructive", title: "Error blocking client", description: formatAxiosError(e, "Error blocking client") }); }) .then(() => { startTransition(() => { router.refresh(); setIsBlockModalOpen(false); setSelectedClient(null); }); }); }; const unblockClient = (clientId: number) => { api.post(`/client/${clientId}/unblock`) .catch((e) => { console.error("Error unblocking client", e); toast({ variant: "destructive", title: "Error unblocking client", description: formatAxiosError(e, "Error unblocking client") }); }) .then(() => { startTransition(() => { router.refresh(); }); }); }; // Check if there are any rows without userIds in the current view's data const hasRowsWithoutUserId = useMemo(() => { return userClients.some((client) => !client.userId); }, [userClients]); const columns: ExtendedColumnDef[] = useMemo(() => { const baseColumns: ExtendedColumnDef[] = [ { accessorKey: "name", enableHiding: false, friendlyName: "Name", header: ({ column }) => { return ( ); }, cell: ({ row }) => { const r = row.original; return (
{r.name} {r.archived && ( {t("archived")} )} {r.blocked && ( {t("blocked")} )}
); } }, { accessorKey: "niceId", friendlyName: t("identifier"), header: ({ column }) => { return ( ); } }, { accessorKey: "userEmail", friendlyName: "User", header: ({ column }) => { return ( ); }, cell: ({ row }) => { const r = row.original; return r.userId ? ( ) : ( "-" ); } }, // { // accessorKey: "siteName", // header: ({ column }) => { // return ( // // ); // }, // cell: ({ row }) => { // const r = row.original; // return ( // // // // ); // } // }, { accessorKey: "online", friendlyName: "Connectivity", header: ({ column }) => { return ( ); }, cell: ({ row }) => { const originalRow = row.original; if (originalRow.online) { return (
Connected
); } else { return (
Disconnected
); } } }, { accessorKey: "mbIn", friendlyName: "Data In", header: ({ column }) => { return ( ); } }, { accessorKey: "mbOut", friendlyName: "Data Out", header: ({ column }) => { return ( ); } }, { accessorKey: "client", friendlyName: t("agent"), header: ({ column }) => { return ( ); }, cell: ({ row }) => { const originalRow = row.original; return (
{originalRow.agent && originalRow.olmVersion ? ( {originalRow.agent + " v" + originalRow.olmVersion} ) : ( "-" )} {/*originalRow.olmUpdateAvailable && ( )*/}
); } }, { accessorKey: "subnet", friendlyName: "Address", header: ({ column }) => { return ( ); } } ]; baseColumns.push({ id: "actions", enableHiding: false, header: () => , cell: ({ row }) => { const clientRow = row.original; return (
{ if (clientRow.archived) { unarchiveClient(clientRow.id); } else { archiveClient(clientRow.id); } }} > {clientRow.archived ? "Unarchive" : "Archive"} { if (clientRow.blocked) { unblockClient(clientRow.id); } else { setSelectedClient(clientRow); setIsBlockModalOpen(true); } }} > {clientRow.blocked ? "Unblock" : "Block"} {!clientRow.userId && ( // Machine client - also show delete option { setSelectedClient(clientRow); setIsDeleteModalOpen(true); }} > Delete )}
); } }); return baseColumns; }, [hasRowsWithoutUserId, t]); return ( <> {selectedClient && !selectedClient.userId && ( { setIsDeleteModalOpen(val); setSelectedClient(null); }} dialog={

{t("deleteClientQuestion")}

{t("clientMessageRemove")}

} buttonText="Confirm Delete Client" onConfirm={async () => deleteClient(selectedClient!.id)} string={selectedClient.name} title="Delete Client" /> )} {selectedClient && ( { setIsBlockModalOpen(val); if (!val) { setSelectedClient(null); } }} dialog={

{t("blockClientQuestion")}

{t("blockClientMessage")}

} buttonText={t("blockClientConfirm")} onConfirm={async () => blockClient(selectedClient!.id)} string={selectedClient.name} title={t("blockClient")} /> )} { if (selectedValues.length === 0) return true; const rowArchived = row.archived || false; const rowBlocked = row.blocked || false; const isActive = !rowArchived && !rowBlocked; if (selectedValues.includes("active") && isActive) return true; if (selectedValues.includes("archived") && rowArchived) return true; if (selectedValues.includes("blocked") && rowBlocked) return true; return false; }, defaultValues: ["active"] // Default to showing active clients } ]} /> ); }