import { useState } from 'react'; import { useParams, useNavigate } from 'react-router'; import { AlertDialog, Badge, Button, Card, KpiStrip, Spinner, useToast, } from '@cameleer/design-system'; import { ArrowLeft, RefreshCw, Trash2 } from 'lucide-react'; import { useVendorTenant, useSuspendTenant, useActivateTenant, useDeleteTenant, useRenewLicense, } from '../../api/vendor-hooks'; import { ServerStatusBadge } from '../../components/ServerStatusBadge'; import { tierColor } from '../../utils/tier'; import styles from '../../styles/platform.module.css'; function licenseDaysRemaining(expiresAt: string | null | undefined): number { if (!expiresAt) return 0; return Math.ceil((new Date(expiresAt).getTime() - Date.now()) / 86_400_000); } function statusColor(status: string): 'success' | 'error' | 'warning' | 'auto' { switch (status?.toUpperCase()) { case 'ACTIVE': return 'success'; case 'SUSPENDED': return 'warning'; case 'PROVISIONING': return 'auto'; case 'ERROR': return 'error'; default: return 'auto'; } } export function TenantDetailPage() { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const { toast } = useToast(); const { data, isLoading } = useVendorTenant(id ?? null); const suspendTenant = useSuspendTenant(); const activateTenant = useActivateTenant(); const deleteTenant = useDeleteTenant(); const renewLicense = useRenewLicense(); const [deleteOpen, setDeleteOpen] = useState(false); if (isLoading) { return (
); } if (!data) { return (

Tenant not found.

); } const { tenant, serverState, license } = data; const daysRemaining = licenseDaysRemaining(license?.expiresAt); const isSuspended = tenant.status?.toUpperCase() === 'SUSPENDED'; async function handleSuspendToggle() { if (!id) return; try { if (isSuspended) { await activateTenant.mutateAsync(id); toast({ title: 'Tenant activated', variant: 'success' }); } else { await suspendTenant.mutateAsync(id); toast({ title: 'Tenant suspended', variant: 'warning' }); } } catch (err) { toast({ title: 'Action failed', description: String(err), variant: 'error' }); } } async function handleDelete() { if (!id) return; try { await deleteTenant.mutateAsync(id); toast({ title: 'Tenant deleted', variant: 'success' }); navigate('/vendor/tenants'); } catch (err) { toast({ title: 'Delete failed', description: String(err), variant: 'error' }); } } async function handleRenewLicense() { if (!id) return; try { await renewLicense.mutateAsync(id); toast({ title: 'License renewed', variant: 'success' }); } catch (err) { toast({ title: 'Renewal failed', description: String(err), variant: 'error' }); } } return (
{/* Header */}

{tenant.name}

{/* KPI Strip */} {/* Cards grid */}
{/* Server Info */}
State
Endpoint {tenant.serverEndpoint ?? '—'}
{tenant.provisionError && (
Error {tenant.provisionError}
)}
{/* License Info */} {license ? (
Tier
Expires {new Date(license.expiresAt).toLocaleDateString()}
Days remaining {daysRemaining}d
) : (

No license issued.

)}
{/* Tenant Info */}
ID {tenant.id}
Slug {tenant.slug}
Created {new Date(tenant.createdAt).toLocaleDateString()}
Updated {new Date(tenant.updatedAt).toLocaleDateString()}
{/* Actions */}
{/* Delete confirmation dialog */} setDeleteOpen(false)} onConfirm={handleDelete} title="Delete Tenant" description={`Are you sure you want to delete "${tenant.name}"? This action cannot be undone.`} confirmLabel="Delete" cancelLabel="Cancel" variant="danger" loading={deleteTenant.isPending} />
); }