'use client'; import { useEffect, useMemo, useRef, useState } from 'react'; import { Shield, Monitor, Smartphone, Tablet, Loader2, AlertTriangle, Radio, Flame, ShieldAlert, KeyRound, RefreshCw, Search, Globe, Clock, X, Copy, Check, ShieldOff, } from 'lucide-react'; import { adminService, SessionInfo, AuditLogEntry } from '@/services/api/adminService'; import { parseJwt, getAccessToken } from '@/services/api/client'; import { format } from 'date-fns'; import { toast } from 'sonner'; import { TablePagination, useClientPagination } from '@/components/ui/TablePagination'; import { StatsSparklineCard, datesToSparkline, weekOverWeekChange } from '@/components/ui/StatsSparklineCard'; type DeviceFilter = 'all' | 'desktop' | 'mobile' | 'tablet'; type InsightTab = 'sessions' | 'history' | 'failed'; function normalizeDeviceType(type: string): DeviceFilter { const value = (type || '').toLowerCase(); if (value.includes('mobile') || value.includes('phone')) return 'mobile'; if (value.includes('tablet')) return 'tablet'; return 'desktop'; } function deviceTone(type: DeviceFilter) { if (type === 'mobile') { return { box: 'bg-success/10 text-success', bar: 'bg-success', badge: 'bg-success text-white', }; } if (type === 'tablet') { return { box: 'bg-warning/10 text-warning', bar: 'bg-warning', badge: 'bg-warning text-white', }; } return { box: 'bg-muted text-foreground', bar: 'bg-muted-foreground', badge: 'bg-muted text-foreground', }; } function remainingLabel(expiresAt: string) { const ms = new Date(expiresAt).getTime() - Date.now(); if (Number.isNaN(ms) || ms <= 0) return { text: 'Expired', urgent: true }; const mins = Math.floor(ms / 60000); if (mins < 60) return { text: `${mins}m left`, urgent: true }; const hours = Math.floor(mins / 60); if (hours < 24) return { text: `${hours}h ${mins % 60}m left`, urgent: hours < 2 }; const days = Math.floor(hours / 24); if (days < 7) return { text: `${days}d left`, urgent: false }; return { text: 'Active', urgent: false }; } export default function SecurityPage() { const [sessions, setSessions] = useState([]); const [failedLogins, setFailedLogins] = useState([]); const [loading, setLoading] = useState(true); const [revoking, setRevoking] = useState(null); const [mfaCode, setMfaCode] = useState(''); const [actionLoading, setActionLoading] = useState(false); const [currentUserId, setCurrentUserId] = useState(null); const [deviceFilter, setDeviceFilter] = useState('all'); const [deviceSearch, setDeviceSearch] = useState(''); const [insightTab, setInsightTab] = useState('sessions'); const [showResetDialog, setShowResetDialog] = useState(false); const [resetPassword, setResetPassword] = useState(''); const [resetPhrase, setResetPhrase] = useState(''); const [copiedIp, setCopiedIp] = useState(null); const devicesRef = useRef(null); const failedRef = useRef(null); const pager = useClientPagination(failedLogins); const fetchData = async () => { setLoading(true); try { const [sessionsData, failedData] = await Promise.allSettled([ adminService.listSessions(0, 100), adminService.getFailedLogins(20), ]); if (sessionsData.status === 'fulfilled') setSessions(sessionsData.value.sessions); if (failedData.status === 'fulfilled') setFailedLogins(failedData.value); } catch { toast.error('Failed to load security data'); } finally { setLoading(false); } }; useEffect(() => { fetchData(); const token = getAccessToken(); if (token) { const payload = parseJwt(token); if (payload && payload.sub) { setCurrentUserId(payload.sub as string); } } }, []); const handleRevoke = async (sessionId: string) => { setRevoking(sessionId); try { await adminService.revokeSession(sessionId); toast.success('Session ended on this device'); fetchData(); } catch (err: unknown) { const message = err instanceof Error ? err.message : 'Failed to revoke session'; toast.error(message); } finally { setRevoking(null); } }; const handleKillSwitch = async (e: React.FormEvent) => { e.preventDefault(); if (!currentUserId) { toast.error('Could not determine current admin ID. Please re-authenticate.'); return; } if (!mfaCode.trim()) { toast.error('Please enter your MFA verification code'); return; } setActionLoading(true); try { const res = await adminService.requestKillSwitch(currentUserId, mfaCode); toast.success(res.detail || 'Kill switch executed successfully. All users logged out.'); setMfaCode(''); fetchData(); } catch (err: unknown) { const message = err instanceof Error ? err.message : 'Failed to execute kill switch'; toast.error(message); } finally { setActionLoading(false); } }; const handleCancelKillSwitch = async () => { if (!currentUserId) { toast.error('Could not determine current admin ID. Please re-authenticate.'); return; } setActionLoading(true); try { const res = await adminService.cancelKillSwitch(currentUserId); toast.success(res.detail || 'Kill switch cancelled. Access restored.'); fetchData(); } catch (err: unknown) { const message = err instanceof Error ? err.message : 'Failed to cancel kill switch'; toast.error(message); } finally { setActionLoading(false); } }; const handleSelfDestruct = async (e: React.FormEvent) => { e.preventDefault(); if (!currentUserId) { toast.error('Could not determine current admin ID. Please re-authenticate.'); return; } if (!mfaCode.trim()) { toast.error('Please enter your MFA verification code'); return; } setActionLoading(true); try { const res = await adminService.selfDestruct(currentUserId, mfaCode); toast.success(res.detail || 'Self destruct completed. All sessions destroyed.'); setMfaCode(''); fetchData(); } catch (err: unknown) { const message = err instanceof Error ? err.message : 'Failed to execute self-destruct'; toast.error(message); } finally { setActionLoading(false); } }; const handleFactoryReset = async () => { if (!resetPassword.trim()) { toast.error('Enter your admin password'); return; } if (resetPhrase !== 'CONFIRM_FACTORY_RESET_WIPE_2026') { toast.error('Invalid confirmation phrase'); return; } setActionLoading(true); try { const token = getAccessToken(); const res = await fetch( `${process.env.NEXT_PUBLIC_API_URL || ''}/api/v1/admin/security/factory-reset`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, body: JSON.stringify({ password: resetPassword, confirmation_phrase: resetPhrase }), } ); if (!res.ok) { const err = await res.json().catch(() => ({ detail: 'Reset failed' })); throw new Error(err.detail || 'Reset failed'); } toast.success('Platform factory reset completed. Redirecting to login...'); setShowResetDialog(false); localStorage.clear(); setTimeout(() => { window.location.href = '/login'; }, 2000); } catch (err: unknown) { const message = err instanceof Error ? err.message : 'Factory reset failed'; toast.error(message); } finally { setActionLoading(false); } }; const getDeviceIcon = (type: DeviceFilter, className = 'w-5 h-5') => { if (type === 'mobile') return ; if (type === 'tablet') return ; return ; }; const activeSessions = sessions.filter((s) => s.is_active); const boardSessions = insightTab === 'history' ? sessions : activeSessions; const deviceCounts = useMemo(() => { const counts: Record = { desktop: 0, mobile: 0, tablet: 0 }; for (const session of boardSessions) { const devType = normalizeDeviceType(session.device_type); counts[devType] = (counts[devType] || 0) + 1; } return counts; }, [boardSessions]); const filteredDevices = useMemo(() => { const q = deviceSearch.trim().toLowerCase(); return boardSessions.filter((session) => { const kind = normalizeDeviceType(session.device_type); const matchesType = deviceFilter === 'all' || kind === deviceFilter; const haystack = [session.browser, session.operating_system, session.device_name, session.ip_address] .join(' ') .toLowerCase(); return matchesType && (!q || haystack.includes(q)); }); }, [boardSessions, deviceFilter, deviceSearch]); const devicePager = useClientPagination(filteredDevices, 6); const mixTotal = boardSessions.length || 1; const copyIp = async (ip: string) => { try { await navigator.clipboard.writeText(ip); setCopiedIp(ip); toast.success('IP address copied'); setTimeout(() => setCopiedIp(null), 1500); } catch { toast.error('Could not copy IP address'); } }; const openInsight = (tab: InsightTab) => { setInsightTab(tab); const node = tab === 'failed' ? failedRef.current : devicesRef.current; node?.scrollIntoView({ behavior: 'smooth', block: 'start' }); }; const dataCardShell = 'crm-radius-section border border-border bg-card shadow-[0_1px_3px_rgba(16,24,40,0.06)] overflow-visible min-w-0'; const labelClass = 'block text-[11px] font-semibold text-muted-foreground uppercase mb-1.5'; const primaryButton = 'inline-flex items-center justify-center gap-2 h-9 min-h-9 px-4 crm-radius-control bg-primary hover:bg-primary/90 text-white text-[13px] font-semibold cursor-pointer disabled:opacity-50 whitespace-nowrap'; const secondaryButton = 'inline-flex items-center justify-center gap-2 h-9 min-h-9 px-4 crm-radius-control border border-border bg-card text-foreground text-[13px] font-medium hover:bg-muted cursor-pointer disabled:opacity-50 whitespace-nowrap'; const inputClass = 'w-full h-9 pl-8 pr-3 crm-radius-control border border-border bg-card text-[13px] text-foreground placeholder:text-muted-foreground focus:outline-none focus:border-primary transition-colors'; return (

Security & Sessions

{activeSessions.length}
s.expires_at))} deltaPercent={weekOverWeekChange(activeSessions.map((s) => s.expires_at))} active={insightTab === 'sessions'} onClick={() => openInsight('sessions')} /> s.expires_at))} deltaPercent={weekOverWeekChange(sessions.map((s) => s.expires_at))} active={insightTab === 'history'} onClick={() => openInsight('history')} /> l.created_at))} deltaPercent={weekOverWeekChange(failedLogins.map((l) => l.created_at))} active={insightTab === 'failed'} onClick={() => openInsight('failed')} />

{insightTab === 'history' ? 'Session history' : 'Active connected devices'}

{insightTab !== 'history' && ( Live {activeSessions.length} )}

{insightTab === 'history' ? 'Every recorded admin session, including devices that have already signed out.' : 'Devices currently holding an open admin session.'}

setDeviceSearch(e.target.value)} className={inputClass} />
{([ { id: 'all' as DeviceFilter, label: 'All devices', count: boardSessions.length, icon: Radio, tone: 'bg-primary/10 text-primary', bar: 'bg-primary' }, { id: 'desktop' as DeviceFilter, label: 'Desktop', count: deviceCounts.desktop, icon: Monitor, tone: deviceTone('desktop').box, bar: deviceTone('desktop').bar }, { id: 'mobile' as DeviceFilter, label: 'Mobile', count: deviceCounts.mobile, icon: Smartphone, tone: deviceTone('mobile').box, bar: deviceTone('mobile').bar }, { id: 'tablet' as DeviceFilter, label: 'Tablet', count: deviceCounts.tablet, icon: Tablet, tone: deviceTone('tablet').box, bar: deviceTone('tablet').bar }, ]).map((tile) => { const selected = deviceFilter === tile.id; const Icon = tile.icon; const share = mixTotal ? (tile.count / mixTotal) * 100 : 0; return ( ); })}
{loading ? (
) : filteredDevices.length === 0 ? (
{deviceSearch || deviceFilter !== 'all' ? 'No connected devices match your search.' : 'No sessions found.'}
) : (
{devicePager.items.map((session) => { const kind = normalizeDeviceType(session.device_type); const tone = deviceTone(kind); const yours = Boolean(currentUserId && session.user_id === currentUserId); const remaining = remainingLabel(session.expires_at); const live = session.is_active; return (
{getDeviceIcon(kind, 'w-5 h-5')} {live && ( )}
{kind}

{session.browser || 'Unknown browser'}

{session.operating_system || 'Unknown OS'} {session.device_name ? ` · ${session.device_name}` : ''}

{yours && ( You )} {live ? remaining.text : 'Ended'}
IP {session.ip_address || '—'}
Expires {format(new Date(session.expires_at), 'dd MMM, hh:mm a')}
{live ? ( ) : (
Ended
)}
); })}
)}

Failed login audit

Authentication attempts that did not succeed.

{loading ? ( ) : failedLogins.length === 0 ? ( ) : ( pager.items.map((log) => ( )) )}
Action Entity IP address User agent Time
No security failures recorded
{log.action} {log.entity_type} {log.ip_address} {log.user_agent || '—'} {format(new Date(log.created_at), 'dd MMM yyyy, hh:mm a')}

Global kill switch

Disables public client access and ends every active user session.

setMfaCode(e.target.value)} className={inputClass} />

Force session termination

Ends all sessions in the database without changing the lockout setting.

setMfaCode(e.target.value)} className={inputClass} />

Platform factory reset

Wipes core, CRM and commerce tables plus uploads, then reseeds master roles.

Infrastructure

Admin authority {currentUserId ? 'Super Admin' : 'Unknown'}
Audit log engine Operational
MFA router SHA256 Standard
{showResetDialog && (
!actionLoading && setShowResetDialog(false)} >
e.stopPropagation()} >

Factory reset

This permanently wipes platform data. Type the confirmation phrase to continue.

setResetPassword(e.target.value)} className="w-full h-9 px-3 crm-radius-control border border-border bg-card text-[13px] text-foreground focus:outline-none focus:border-primary" />
setResetPhrase(e.target.value)} placeholder="CONFIRM_FACTORY_RESET_WIPE_2026" className="w-full h-9 px-3 crm-radius-control border border-border bg-card text-[13px] text-foreground focus:outline-none focus:border-primary font-mono" />
)}
); }