import { useState, useEffect, useCallback } from "react"; import { Shield, CheckCircle, XCircle, Clock, Users, Zap, ZapOff, AlertTriangle, Loader2, Search, MoreHorizontal, UserPlus, Trash2, RefreshCw, Skull, Activity, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, } from "@/components/ui/sheet"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { useToast } from "@/hooks/use-toast"; import { api, ApiError, UserNetworkApproval, ActivationSession, KillSwitchEvent, PortalNetwork, OrganizationMember, ApprovalState, MembershipState, EnrichedMembership, DeviceStatus, } from "@/lib/api"; import { useCurrentOrganizationId } from "@/hooks/useCurrentOrganization"; function cn(...classes: (string | boolean | undefined | null)[]) { return classes.filter(Boolean).join(" "); } function formatDate(d: string | null | undefined) { if (!d) return "—"; return new Date(d).toLocaleDateString(undefined, { year: "numeric", month: "short", day: "numeric", }); } function formatExpiry(d: string | null | undefined) { if (!d) return "—"; const date = new Date(d); const now = new Date(); if (date < now) return "Expired"; const diff = Math.floor((date.getTime() - now.getTime()) / 1000 / 60); if (diff < 60) return `${diff}m left`; if (diff < 1440) return `${Math.floor(diff / 60)}h ${diff % 60}m left`; return `${Math.floor(diff / 1440)}d ${Math.floor((diff % 1440) / 60)}h left`; } function ApprovalStateBadge({ state }: { state: ApprovalState }) { const config: Record = { pending: { color: "bg-yellow-500/10 text-yellow-600 border-yellow-200", icon: , label: "Pending" }, approved: { color: "bg-green-500/10 text-green-600 border-green-200", icon: , label: "Approved" }, rejected: { color: "bg-red-500/10 text-red-600 border-red-200", icon: , label: "Rejected" }, revoked: { color: "bg-red-500/10 text-red-600 border-red-200", icon: , label: "Revoked" }, suspended: { color: "bg-orange-500/10 text-orange-600 border-orange-200", icon: , label: "Suspended" }, }; const { color, icon, label } = config[state] ?? { color: "bg-gray-500/10 text-gray-600 border-gray-200", icon: null, label: state }; return ( {icon}{label} ); } export default function AccessPage() { const { orgId } = useCurrentOrganizationId(); const { toast } = useToast(); const [approvals, setApprovals] = useState([]); const [pendingApprovals, setPendingApprovals] = useState([]); const [sessions, setSessions] = useState([]); const [killSwitchEvents, setKillSwitchEvents] = useState([]); const [networks, setNetworks] = useState([]); const [orgMembers, setOrgMembers] = useState([]); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const [search, setSearch] = useState(""); const [selectedNetworkFilter, setSelectedNetworkFilter] = useState("all"); const [approveId, setApproveId] = useState(null); const [rejectId, setRejectId] = useState(null); const [revokeId, setRevokeId] = useState(null); const [isApproving, setIsApproving] = useState(false); const [showAssign, setShowAssign] = useState(false); const [assignUserId, setAssignUserId] = useState(""); const [assignNetworkId, setAssignNetworkId] = useState(""); const [assignJustification, setAssignJustification] = useState(""); const [isAssigning, setIsAssigning] = useState(false); const [assignError, setAssignError] = useState(null); const [showKillSwitch, setShowKillSwitch] = useState(false); const [killTargetUserId, setKillTargetUserId] = useState(""); const [killScope, setKillScope] = useState<"organization" | "global">("organization"); const [killReason, setKillReason] = useState(""); const [isKilling, setIsKilling] = useState(false); const [killError, setKillError] = useState(null); const [endSessionId, setEndSessionId] = useState(null); const [isEndingSession, setIsEndingSession] = useState(false); const [selectedApproval, setSelectedApproval] = useState(null); const [allMemberships, setAllMemberships] = useState([]); const [isAllMembersLoading, setIsAllMembersLoading] = useState(false); const [allMembersSearch, setAllMembersSearch] = useState(""); const [allMembersNetworkFilter, setAllMembersNetworkFilter] = useState("all"); const [allMembersStateFilter, setAllMembersStateFilter] = useState("all"); const [selectedMembership, setSelectedMembership] = useState(null); const [adminActivatingId, setAdminActivatingId] = useState(null); const [adminDeactivatingId, setAdminDeactivatingId] = useState(null); const [adminDeletingId, setAdminDeletingId] = useState(null); const fetchData = useCallback(async () => { if (!orgId) { setIsLoading(false); return; } setIsLoading(true); setError(null); try { const [pendingRes, allApprovalsRes, sessionsRes, networksRes, membersRes, allMemsRes] = await Promise.allSettled([ api.zerotier.listPendingApprovals(orgId), api.zerotier.adminListAllApprovals(orgId), api.zerotier.listSessions(orgId), api.zerotier.listNetworks(orgId), api.organizations.getMembers(orgId), api.zerotier.adminListAllMemberships(orgId), ]); if (pendingRes.status === "fulfilled") setPendingApprovals(pendingRes.value.approvals || []); if (allApprovalsRes.status === "fulfilled") setApprovals(allApprovalsRes.value.approvals || []); if (sessionsRes.status === "fulfilled") setSessions(sessionsRes.value.sessions || []); if (networksRes.status === "fulfilled") setNetworks(networksRes.value.networks || []); if (membersRes.status === "fulfilled") setOrgMembers(membersRes.value.members || []); if (allMemsRes.status === "fulfilled") setAllMemberships(allMemsRes.value.memberships || []); } catch { setError("Failed to load access data. Please try again."); } finally { setIsLoading(false); } }, [orgId]); useEffect(() => { setApprovals([]); setPendingApprovals([]); fetchData(); }, [fetchData]); const handleApprove = async (approvalId: string) => { if (!orgId) return; setApproveId(approvalId); setIsApproving(true); try { await api.zerotier.approveRequest(orgId, approvalId); toast({ title: "Request approved" }); fetchData(); } catch (err) { toast({ variant: "destructive", title: "Failed to approve", description: err instanceof ApiError ? err.message : "Something went wrong." }); } finally { setApproveId(null); } }; const handleReject = async (approvalId: string) => { if (!orgId) return; setRejectId(approvalId); setIsApproving(true); try { await api.zerotier.rejectRequest(orgId, approvalId); toast({ title: "Request rejected" }); fetchData(); } catch (err) { toast({ variant: "destructive", title: "Failed to reject", description: err instanceof ApiError ? err.message : "Something went wrong." }); } finally { setRejectId(null); } }; const handleRevoke = async (approvalId: string) => { if (!orgId) return; setRevokeId(approvalId); setIsApproving(true); try { await api.zerotier.revokeApproval(orgId, approvalId); toast({ title: "Approval revoked" }); fetchData(); } catch (err) { toast({ variant: "destructive", title: "Failed to revoke", description: err instanceof ApiError ? err.message : "Something went wrong." }); } finally { setRevokeId(null); } }; const handleAssign = async () => { if (!orgId) return; setAssignError(null); if (!assignUserId) { setAssignError("Please select a user."); return; } if (!assignNetworkId) { setAssignError("Please select a network."); return; } setIsAssigning(true); try { await api.zerotier.assignAccess(orgId, { target_user_id: assignUserId, portal_network_id: assignNetworkId, justification: assignJustification.trim() || undefined, }); toast({ title: "Access assigned", description: "The user can now register devices for this network." }); setShowAssign(false); setAssignUserId(""); setAssignNetworkId(""); setAssignJustification(""); fetchData(); } catch (err) { setAssignError(err instanceof ApiError ? err.message : "Failed to assign access."); } finally { setIsAssigning(false); } }; const handleKillSwitch = async () => { if (!orgId) return; setKillError(null); if (!killTargetUserId) { setKillError("Please select a user."); return; } setIsKilling(true); try { await api.zerotier.triggerKillSwitch(orgId, { target_user_id: killTargetUserId, scope: killScope, reason: killReason.trim() || undefined, }); toast({ title: "Kill switch triggered", description: "All active sessions have been terminated." }); setShowKillSwitch(false); setKillTargetUserId(""); setKillScope("organization"); setKillReason(""); fetchData(); } catch (err) { setKillError(err instanceof ApiError ? err.message : "Failed to trigger kill switch."); } finally { setIsKilling(false); } }; const handleEndSession = async (sessionId: string) => { if (!orgId) return; setEndSessionId(sessionId); setIsEndingSession(true); try { await api.zerotier.endSession(orgId, sessionId); toast({ title: "Session ended" }); fetchData(); } catch (err) { toast({ variant: "destructive", title: "Failed to end session", description: err instanceof ApiError ? err.message : "Something went wrong." }); } finally { setEndSessionId(null); } }; const handleAdminActivate = async (membershipId: string) => { if (!orgId) return; setAdminActivatingId(membershipId); try { await api.zerotier.activateMembership(orgId, membershipId); toast({ title: "Membership activated" }); fetchData(); } catch (err) { toast({ variant: "destructive", title: "Failed to activate", description: err instanceof ApiError ? err.message : "Something went wrong." }); } finally { setAdminActivatingId(null); } }; const handleAdminDeactivate = async (membershipId: string) => { if (!orgId) return; setAdminDeactivatingId(membershipId); try { await api.zerotier.deactivateMembership(orgId, membershipId); toast({ title: "Membership deactivated" }); fetchData(); } catch (err) { toast({ variant: "destructive", title: "Failed to deactivate", description: err instanceof ApiError ? err.message : "Something went wrong." }); } finally { setAdminDeactivatingId(null); } }; const handleAdminDelete = async (membershipId: string) => { if (!orgId) return; setAdminDeletingId(membershipId); try { await api.zerotier.adminDeleteMembership(orgId, membershipId); toast({ title: "Membership permanently deleted" }); fetchData(); } catch (err) { toast({ variant: "destructive", title: "Failed to delete membership", description: err instanceof ApiError ? err.message : "Something went wrong." }); } finally { setAdminDeletingId(null); } }; const filteredPending = pendingApprovals.filter((a) => { if (selectedNetworkFilter !== "all" && a.portal_network_id !== selectedNetworkFilter) return false; if (search) { const q = search.toLowerCase(); if (!a.user_id.toLowerCase().includes(q)) return false; } return true; }); const filteredSessions = sessions.filter((s) => s.is_active); const activeSessions = filteredSessions; const getNetworkName = (networkId: string) => { return networks.find((n) => n.id === networkId)?.name ?? networkId; }; const getUserDisplay = (userId: string) => { const member = orgMembers.find((m) => m.user_id === userId); return member?.user?.email ?? member?.user?.full_name ?? userId; }; return (

Access Control

Manage network access requests, approvals, and active sessions

setSearch(e.target.value)} className="pl-10" />
Pending Requests {filteredPending.length > 0 && ( {filteredPending.length} )} Active Sessions {activeSessions.length > 0 && ( {activeSessions.length} )} All Approvals ({approvals.length}) All Members ({allMemberships.length}) {/* Pending Requests */} Pending Access Requests Review and approve or reject network access requests {isLoading ? (
Loading…
) : filteredPending.length === 0 ? (
{search || selectedNetworkFilter !== "all" ? "No pending requests match your filters." : "No pending requests at this time."}
) : (
{filteredPending.map((approval) => (

{getUserDisplay(approval.user_id)}

{getNetworkName(approval.portal_network_id)}

{approval.grant_type === "requested" ? "User request" : "Manager assignment"} {approval.justification && ` — "${approval.justification}"`}

{formatDate(approval.created_at)}

))}
)}
{/* Active Sessions */} Active Sessions Temporarily activated memberships currently in use {isLoading ? (
Loading…
) : activeSessions.length === 0 ? (
No active sessions.
) : (
{activeSessions.map((session) => (

{session.device_network_membership_id}

Activated: {formatDate(session.authenticated_at)} {formatExpiry(session.expires_at)}
))}
)}
{/* All Approvals */} All Approvals Complete history of network access grants {isLoading ? (
Loading…
) : approvals.length === 0 ? (
No approvals found.
) : (
{approvals.map((approval) => (

{getUserDisplay(approval.user_id)}

{getNetworkName(approval.portal_network_id)}

{approval.grant_type === "requested" ? "User request" : "Manager assignment"} {approval.justification && ` — "${approval.justification}"`}

{formatDate(approval.created_at)} {approval.granted_by_user_id && ` · Granted by: ${getUserDisplay(approval.granted_by_user_id)}`}

{(approval.state === "approved" || approval.state === "suspended") && ( )}
))}
)}
{/* All Members */} All Members Every device membership across all users and networks {isAllMembersLoading ? (
Loading…
) : allMemberships.length === 0 ? (
No memberships found.
) : (
{allMemberships.map((m) => ( ))}
User Device Network State Active Session Actions

{m.user_full_name || "—"}

{m.user_email || m.user_id}

{m.device_node_id || "—"}

{m.device_nickname || m.device_hostname || "—"}

{m.network_name || m.portal_network_id}

{m.network_environment && ( {m.network_environment} )}
{m.state ? ( {m.state} ) : "—"} {m.active_session ? ( {formatExpiry(m.active_session.expires_at)} ) : ( )}
{m.approved_for_activation && !m.currently_authorized && ( )} {m.currently_authorized && ( )}
)}
{/* Assign Access Dialog */} { if (!open) setShowAssign(false); }}> Assign Network Access Grant a user direct access to a network without a request.
setAssignJustification(e.target.value)} />
{assignError &&

{assignError}

}
{/* Kill Switch Dialog */} { if (!open) setShowKillSwitch(false); }}> Kill Switch Instantly deactivate all active sessions for a user across all managed networks. This cannot be undone.

This will immediately de-authorize all ZeroTier memberships for the selected user across all networks.

setKillReason(e.target.value)} />
{killError &&

{killError}

}
); }