import { useState } from 'react'; import { Title, Text, Card, Table, SimpleGrid, Group, Stack, Badge, Loader, Center, ThemeIcon, Tabs, Switch, TextInput, Avatar, Modal, Button, PasswordInput, Select, NumberInput, Menu, Divider, Progress, Tooltip, Drawer, RingProgress, Paper, } from '@mantine/core'; import { useDisclosure } from '@mantine/hooks'; import { IconUsers, IconBuilding, IconShieldLock, IconSearch, IconCrown, IconPlus, IconArchive, IconChevronDown, IconCircleCheck, IconBan, IconArchiveOff, IconDashboard, IconHeartRateMonitor, IconSparkles, IconCalendar, IconActivity, IconCurrencyDollar, IconClipboardCheck, IconLogin, } from '@tabler/icons-react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import api from '../../services/api'; interface AdminUser { id: string; email: string; firstName: string; lastName: string; isSuperadmin: boolean; isPlatformOwner?: boolean; lastLoginAt: string; createdAt: string; organizations: { id: string; name: string; role: string }[]; } interface AdminOrg { id: string; name: string; schema_name: string; status: string; email: string; phone: string; member_count: string; created_at: string; contract_number: string; plan_level: string; payment_date: string; confirmation_number: string; renewal_date: string; last_activity: string; } interface PlatformMetrics { totalUsers: number; superadminCount: number; platformOwnerCount: number; activeUsers30d: number; totalOrganizations: number; activeOrganizations: number; archivedOrganizations: number; suspendedOrganizations: number; trialOrganizations: number; planBreakdown: { plan: string; count: number }[]; statusBreakdown: { status: string; count: number }[]; newTenantsPerMonth: { month: string; count: number }[]; newUsersPerMonth: { month: string; count: number }[]; aiRequestsLast30d: number; aiSuccessfulLast30d: number; aiAvgResponseMs: number; } interface TenantHealth { id: string; name: string; schemaName: string; status: string; planLevel: string; createdAt: string; paymentDate: string; renewalDate: string; memberCount: number; lastLogin: string; activeUsers30d: number; aiUsage30d: number; cashOnHand: number; hasBudget: boolean; journalEntries30d: number; healthScore: number; } interface TenantDetail { organization: any; lastLogin: string; loginsThisWeek: number; loginsThisMonth: number; activeUsers30d: number; weeklyLogins: { week: string; count: number }[]; monthlyLogins: { month: string; count: number }[]; aiRecommendations30d: number; memberCount: number; cashOnHand: number; hasBudget: boolean; recentTransactions: number; } interface CreateTenantForm { orgName: string; email: string; phone: string; addressLine1: string; city: string; state: string; zipCode: string; contractNumber: string; planLevel: string; fiscalYearStartMonth: number | ''; adminEmail: string; adminPassword: string; adminFirstName: string; adminLastName: string; } const initialFormState: CreateTenantForm = { orgName: '', email: '', phone: '', addressLine1: '', city: '', state: '', zipCode: '', contractNumber: '', planLevel: 'standard', fiscalYearStartMonth: 1, adminEmail: '', adminPassword: '', adminFirstName: '', adminLastName: '', }; const planBadgeColor: Record = { standard: 'blue', premium: 'violet', enterprise: 'orange' }; const statusColor: Record = { active: 'green', trial: 'yellow', suspended: 'red', archived: 'gray' }; function healthScoreColor(score: number): string { if (score >= 75) return 'green'; if (score >= 50) return 'yellow'; if (score >= 25) return 'orange'; return 'red'; } function formatCurrency(amount: number): string { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }).format(amount); } function formatDate(dateStr: string | null | undefined): string { if (!dateStr) return '\u2014'; return new Date(dateStr).toLocaleDateString(); } function formatDateTime(dateStr: string | null | undefined): string { if (!dateStr) return 'Never'; return new Date(dateStr).toLocaleString(); } export function AdminPage() { const [search, setSearch] = useState(''); const [activeTab, setActiveTab] = useState('dashboard'); const [createModalOpened, { open: openCreateModal, close: closeCreateModal }] = useDisclosure(false); const [form, setForm] = useState(initialFormState); const [statusConfirm, setStatusConfirm] = useState<{ orgId: string; orgName: string; newStatus: string } | null>(null); const [selectedOrgId, setSelectedOrgId] = useState(null); const [drawerOpened, { open: openDrawer, close: closeDrawer }] = useDisclosure(false); const [subForm, setSubForm] = useState({ paymentDate: '', confirmationNumber: '', renewalDate: '' }); const queryClient = useQueryClient(); // ── Queries ── const { data: metrics, isLoading: metricsLoading } = useQuery({ queryKey: ['admin-metrics'], queryFn: async () => { const { data } = await api.get('/admin/metrics'); return data; }, }); const { data: users, isLoading: usersLoading } = useQuery({ queryKey: ['admin-users'], queryFn: async () => { const { data } = await api.get('/admin/users'); return data; }, }); const { data: orgs, isLoading: orgsLoading } = useQuery({ queryKey: ['admin-orgs'], queryFn: async () => { const { data } = await api.get('/admin/organizations'); return data; }, }); const { data: tenantsHealth, isLoading: healthLoading } = useQuery({ queryKey: ['admin-tenants-health'], queryFn: async () => { const { data } = await api.get('/admin/tenants-health'); return data; }, enabled: activeTab === 'health', }); const { data: tenantDetail, isLoading: detailLoading } = useQuery({ queryKey: ['admin-tenant-detail', selectedOrgId], queryFn: async () => { const { data } = await api.get(`/admin/organizations/${selectedOrgId}/detail`); return data; }, enabled: !!selectedOrgId && drawerOpened, }); // ── Mutations ── const toggleSuperadmin = useMutation({ mutationFn: async ({ userId, isSuperadmin }: { userId: string; isSuperadmin: boolean }) => { await api.post(`/admin/users/${userId}/superadmin`, { isSuperadmin }); }, onSuccess: () => queryClient.invalidateQueries({ queryKey: ['admin-users'] }), }); const createTenant = useMutation({ mutationFn: async (payload: CreateTenantForm) => { const { data } = await api.post('/admin/tenants', payload); return data; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['admin-orgs'] }); queryClient.invalidateQueries({ queryKey: ['admin-users'] }); queryClient.invalidateQueries({ queryKey: ['admin-metrics'] }); setForm(initialFormState); closeCreateModal(); }, }); const changeOrgStatus = useMutation({ mutationFn: async ({ orgId, status }: { orgId: string; status: string }) => { await api.put(`/admin/organizations/${orgId}/status`, { status }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['admin-orgs'] }); queryClient.invalidateQueries({ queryKey: ['admin-metrics'] }); setStatusConfirm(null); }, }); const updateSubscription = useMutation({ mutationFn: async ({ orgId, data: subData }: { orgId: string; data: any }) => { await api.put(`/admin/organizations/${orgId}/subscription`, subData); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['admin-orgs'] }); queryClient.invalidateQueries({ queryKey: ['admin-tenant-detail', selectedOrgId] }); }, }); // ── Helpers ── const updateField = (key: K, value: CreateTenantForm[K]) => { setForm((prev) => ({ ...prev, [key]: value })); }; const canSubmitCreate = form.orgName.trim() !== '' && form.adminEmail.trim() !== '' && form.adminPassword.trim() !== ''; const filteredUsers = (users || []).filter(u => !search || u.email.toLowerCase().includes(search.toLowerCase()) || `${u.firstName} ${u.lastName}`.toLowerCase().includes(search.toLowerCase()) ); const filteredOrgs = (orgs || []).filter(o => !search || o.name.toLowerCase().includes(search.toLowerCase()) || o.schema_name.toLowerCase().includes(search.toLowerCase()) ); const openOrgDetail = (orgId: string) => { setSelectedOrgId(orgId); const org = (orgs || []).find(o => o.id === orgId); if (org) { setSubForm({ paymentDate: org.payment_date ? org.payment_date.split('T')[0] : '', confirmationNumber: org.confirmation_number || '', renewalDate: org.renewal_date ? org.renewal_date.split('T')[0] : '', }); } openDrawer(); }; return (
Platform Administration HOA LedgerIQ SaaS Management Console
}> SuperAdmin
} value={search} onChange={(e) => setSearch(e.currentTarget.value)} /> }> Dashboard }> Organizations ({filteredOrgs.length}) }> Users ({filteredUsers.length}) }> Tenant Health {/* ── TAB 1: Dashboard ── */} {metricsLoading ? (
) : metrics ? (
Total Users {metrics.totalUsers} {metrics.activeUsers30d} active (30d)
Organizations {metrics.totalOrganizations} {metrics.activeOrganizations} active
AI Requests (30d) {metrics.aiRequestsLast30d} {metrics.aiAvgResponseMs ? `Avg ${(metrics.aiAvgResponseMs / 1000).toFixed(1)}s` : 'No data'}
SuperAdmins {metrics.superadminCount} {metrics.suspendedOrganizations} suspended, {metrics.archivedOrganizations} archived
Plan Distribution {metrics.planBreakdown.map((p) => ( {p.plan} {p.count} tenant{p.count !== 1 ? 's' : ''} 0 ? (p.count / metrics.totalOrganizations) * 100 : 0} size="lg" radius="xl" color={planBadgeColor[p.plan] || 'gray'} style={{ width: '50%' }} /> ))} Status Breakdown {metrics.statusBreakdown.map((s) => ( {s.status} {s.count} org{s.count !== 1 ? 's' : ''} 0 ? (s.count / metrics.totalOrganizations) * 100 : 0} size="lg" radius="xl" color={statusColor[s.status] || 'gray'} style={{ width: '50%' }} /> ))}
) : null}
{/* ── TAB 2: Organizations ── */} {orgsLoading ? (
) : ( Organization Status Plan Members Last Activity Subscription Created {filteredOrgs.map((o) => ( openOrgDetail(o.id)}>
{o.name} {o.schema_name}
} onClick={(e) => e.stopPropagation()} > {o.status} Change status {o.status !== 'active' && ( } color="green" onClick={(e) => { e.stopPropagation(); setStatusConfirm({ orgId: o.id, orgName: o.name, newStatus: 'active' }); }}> Set Active )} {o.status !== 'suspended' && ( } color="red" onClick={(e) => { e.stopPropagation(); setStatusConfirm({ orgId: o.id, orgName: o.name, newStatus: 'suspended' }); }}> Suspend )} {o.status !== 'archived' && ( } color="gray" onClick={(e) => { e.stopPropagation(); setStatusConfirm({ orgId: o.id, orgName: o.name, newStatus: 'archived' }); }}> Archive )} {o.plan_level} {o.member_count} {formatDateTime(o.last_activity)} {o.renewal_date ? ( Renews {formatDate(o.renewal_date)} ) : ( Not set )} {formatDate(o.created_at)}
))}
)}
{/* ── TAB 3: Users ── */} {usersLoading ? (
) : ( User Email Organizations Last Login SuperAdmin {filteredUsers.map((u) => ( {u.firstName?.[0]}{u.lastName?.[0]}
{u.firstName} {u.lastName} {u.isPlatformOwner && ( Platform Owner )}
{u.email} {u.organizations.map((o) => ( {o.name} ({o.role}) ))} {u.organizations.length === 0 && ( No organizations )} {u.lastLoginAt ? new Date(u.lastLoginAt).toLocaleDateString() : 'Never'} {u.isPlatformOwner ? ( ) : ( toggleSuperadmin.mutate({ userId: u.id, isSuperadmin: !u.isSuperadmin, })} size="sm" color="red" /> )}
))}
)}
{/* ── TAB 4: Tenant Health ── */} {healthLoading ? (
) : ( Tenant Health Score Active Users Last Login Budget Transactions (30d) Cash on Hand AI Usage (30d) Renewal {(tenantsHealth || []) .filter(t => !search || t.name.toLowerCase().includes(search.toLowerCase())) .map((t) => ( openOrgDetail(t.id)}>
{t.name} {t.status} {t.planLevel}
{t.healthScore} } /> {t.healthScore >= 75 ? 'Healthy' : t.healthScore >= 50 ? 'Fair' : t.healthScore >= 25 ? 'At Risk' : 'Critical'} {t.activeUsers30d} / {t.memberCount} {formatDateTime(t.lastLogin)} {t.hasBudget ? ( ) : ( )} {t.journalEntries30d} 0 ? undefined : 'red'}> {formatCurrency(t.cashOnHand)} 0 ? 'violet' : 'gray'}> {t.aiUsage30d} {formatDate(t.renewalDate)}
))}
)}
{/* ── Tenant Detail Drawer ── */} Tenant Details} position="right" size="lg" > {detailLoading ? (
) : tenantDetail ? ( {tenantDetail.organization.name} Schema {tenantDetail.organization.schema_name} Status {tenantDetail.organization.status} Plan {tenantDetail.organization.plan_level} Contract # {tenantDetail.organization.contract_number || '\u2014'} Members {tenantDetail.memberCount} Activity Last Login {formatDateTime(tenantDetail.lastLogin)} Logins This Week {tenantDetail.loginsThisWeek} Logins This Month {tenantDetail.loginsThisMonth} Active Users (30d) {tenantDetail.activeUsers30d} AI Recommendations (30d) {tenantDetail.aiRecommendations30d} Setup Health Cash on Hand {formatCurrency(tenantDetail.cashOnHand)} Has Budget {tenantDetail.hasBudget ? 'Yes' : 'No'} Recent Transactions (30d) {tenantDetail.recentTransactions} Subscription setSubForm(p => ({ ...p, paymentDate: e.currentTarget.value }))} /> setSubForm(p => ({ ...p, confirmationNumber: e.currentTarget.value }))} /> setSubForm(p => ({ ...p, renewalDate: e.currentTarget.value }))} /> ) : ( No data available )}
{/* ── Create Tenant Modal ── */} { closeCreateModal(); setForm(initialFormState); }} title="Create New Tenant" size="lg" > Organization Details updateField('orgName', e.currentTarget.value)} /> updateField('email', e.currentTarget.value)} /> updateField('phone', e.currentTarget.value)} /> updateField('addressLine1', e.currentTarget.value)} /> updateField('city', e.currentTarget.value)} /> updateField('state', e.currentTarget.value)} /> updateField('zipCode', e.currentTarget.value)} /> updateField('contractNumber', e.currentTarget.value)} />