import { useState } from 'react'; import { Link, useNavigate, useParams } from 'react-router-dom'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { ArrowLeft, Edit, Trash2 } from 'lucide-react'; import { toast } from 'sonner'; import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Separator, Skeleton, } from '@vector/ui'; import { deleteHost, getHost, listHostDeployedParts } from '../lib/api/hosts.js'; import { ApiRequestError } from '../lib/api/client.js'; import { queryKeys } from '../lib/queryKeys.js'; import { useAuth } from '../contexts/AuthContext.js'; import { HostStateBadge, HostStackBadge } from '../components/hosts/HostStateBadge.js'; import { HostTimeline } from '../components/hosts/HostTimeline.js'; import { HostFormDialog } from '../components/hosts/HostFormDialog.js'; import { PartStateBadge } from '../components/parts/PartStateBadge.js'; import { ConfirmDialog } from '../components/ConfirmDialog.js'; function DetailRow({ label, value }: { label: string; value: React.ReactNode }) { return (
{label}
{value}
); } export default function HostDetail() { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const queryClient = useQueryClient(); const { user } = useAuth(); const isAdmin = user?.role === 'ADMIN'; const [editOpen, setEditOpen] = useState(false); const [confirmDelete, setConfirmDelete] = useState(false); const { data: host, isPending, isError, error } = useQuery({ queryKey: queryKeys.hosts.detail(id!), queryFn: () => getHost(id!), enabled: Boolean(id), }); const deployedPartsQuery = useQuery({ queryKey: queryKeys.hosts.deployedParts(id!), queryFn: () => listHostDeployedParts(id!), enabled: Boolean(id), }); const deleteMutation = useMutation({ mutationFn: () => deleteHost(id!), onSuccess: () => { toast.success('Host deleted'); queryClient.invalidateQueries({ queryKey: queryKeys.hosts.all }); navigate('/hosts', { replace: true }); }, onError: (err) => { toast.error(err instanceof ApiRequestError ? err.body.message : 'Delete failed'); }, }); if (isPending) { return (
); } if (isError || !host) { const msg = error instanceof ApiRequestError ? error.body.message : 'Host not found.'; return ( Host unavailable {msg} ); } const deployedParts = deployedPartsQuery.data ?? []; return (

{host.name}

{host.assetId} {host.location ? ` · ${host.location}` : ''}

{isAdmin && ( )}
Summary
{host.assetId}} /> — } />
{host.notes && ( <>

Notes

{host.notes}

)}
History FMs, repairs, part swaps, and host field changes.
Deployed parts Parts currently installed on this host. {deployedPartsQuery.isPending ? ( ) : deployedParts.length === 0 ? (

No parts deployed here.

) : (
{deployedParts.map((p) => ( ))}
Serial MPN Manufacturer State
{p.serialNumber} {p.partModel.mpn} {p.manufacturer.name}
)}
deleteMutation.mutate()} />
); }