import React, { useState, useEffect } from 'react'; import { Link } from 'react-router-dom'; import { useAuth } from '../components/AuthContext'; import { CustomModal } from '../components/CustomModal'; import { Building2, Users, CreditCard, Shield, Trash2, Plus, Server, Activity, Database, HardDrive, RefreshCw, BarChart2, Edit, Download, Eye, Search, X } from 'lucide-react'; import toast from 'react-hot-toast'; const DEFAULT_BILLING_TIERS = [ { id: 'quick', name: 'Quick Scan', badge: 'QUICK', monthly_price: 499, yearly_price: 4990 }, { id: 'advanced', name: 'Advanced Scan', badge: 'ADVANCED', monthly_price: 4499, yearly_price: 44990 }, { id: 'deep', name: 'Deep Scan', badge: 'DEEP', monthly_price: 9999, yearly_price: 99990 }, { id: 'enterprise', name: 'Custom Solutions', badge: 'ENTERPRISE', monthly_price: 0, yearly_price: 0 } ]; const TablePagination = ({ currentPage, totalEntries, pageSize, onPageChange, onPageSizeChange }) => { const totalPages = Math.ceil(totalEntries / pageSize) || 1; const validCurrentPage = Math.min(Math.max(1, currentPage), totalPages); const startIndex = (validCurrentPage - 1) * pageSize; const endIndex = Math.min(startIndex + pageSize, totalEntries); return (
Rows per page: {totalEntries === 0 ? '0 of 0 records' : `${startIndex + 1} - ${endIndex} of ${totalEntries} records`}
{Array.from({ length: totalPages }, (_, i) => i + 1) .filter(p => p === 1 || p === totalPages || Math.abs(p - validCurrentPage) <= 1) .map((page, idx, arr) => { const prev = arr[idx - 1]; return ( {prev && page - prev > 1 && ...} ); })}
); }; const BillingTierCard = ({ tier, onSave }) => { const [monthly, setMonthly] = useState(((tier.monthly_price || 0) / 100).toFixed(2)); const [yearly, setYearly] = useState(((tier.yearly_price || 0) / 100).toFixed(2)); const [saving, setSaving] = useState(false); const [saved, setSaved] = useState(false); const handleSave = async () => { setSaving(true); if (onSave) { await onSave(tier.id, Math.round(parseFloat(monthly || 0) * 100), Math.round(parseFloat(yearly || 0) * 100)); } setSaving(false); setSaved(true); setTimeout(() => setSaved(false), 2000); }; const getAccentClass = (id) => { const key = (id || '').toLowerCase(); if (key.includes('quick')) return 'bg-[#4285f4]'; if (key.includes('advanced')) return 'bg-[#a855f7]'; if (key.includes('deep')) return 'bg-[#f97316]'; if (key.includes('enterprise') || key.includes('custom')) return 'bg-[#f97316]'; return 'bg-primary'; }; const getBadge = (tier) => { if (tier.badge) return tier.badge; const key = (tier.id || '').toLowerCase(); if (key.includes('quick')) return 'QUICK'; if (key.includes('advanced')) return 'ADVANCED'; if (key.includes('deep')) return 'DEEP'; if (key.includes('enterprise') || key.includes('custom')) return 'ENTERPRISE'; return (tier.id || '').toUpperCase(); }; const getDisplayName = (tier) => { if (tier.name && tier.name !== tier.id) return tier.name; const key = (tier.id || '').toLowerCase(); if (key.includes('quick')) return 'Quick Scan'; if (key.includes('advanced')) return 'Advanced Scan'; if (key.includes('deep')) return 'Deep Scan'; if (key.includes('enterprise') || key.includes('custom')) return 'Custom Solutions'; return tier.name || tier.id; }; return (
{/* Accent Top Border */}

{getDisplayName(tier)}

{getBadge(tier)}
$ setMonthly(e.target.value)} className="bg-transparent border-0 outline-none w-full font-mono font-bold text-on-surface text-sm" />
$ setYearly(e.target.value)} className="bg-transparent border-0 outline-none w-full font-mono font-bold text-on-surface text-sm" />
); }; // Helper functions for Reschedule Modal Date & Time const parseToISODate = (dateStr) => { if (!dateStr) return new Date().toISOString().split('T')[0]; if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) return dateStr; const parsed = new Date(dateStr); if (!isNaN(parsed.getTime())) { const yyyy = parsed.getFullYear(); const mm = String(parsed.getMonth() + 1).padStart(2, '0'); const dd = String(parsed.getDate()).padStart(2, '0'); return `${yyyy}-${mm}-${dd}`; } return new Date().toISOString().split('T')[0]; }; const formatToReadableDate = (isoStr) => { if (!isoStr) return ''; if (!/^\d{4}-\d{2}-\d{2}$/.test(isoStr)) return isoStr; const [yyyy, mm, dd] = isoStr.split('-'); const parsed = new Date(parseInt(yyyy, 10), parseInt(mm, 10) - 1, parseInt(dd, 10)); if (!isNaN(parsed.getTime())) { return parsed.toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' }); } return isoStr; }; const parseToISOTime = (timeStr) => { if (!timeStr) return '09:00'; if (/^\d{2}:\d{2}$/.test(timeStr)) return timeStr; const match = timeStr.match(/(\d{1,2}):(\d{2})\s*(AM|PM)?/i); if (match) { let hours = parseInt(match[1], 10); const minutes = match[2]; const ampm = match[3] ? match[3].toUpperCase() : null; if (ampm === 'PM' && hours < 12) hours += 12; if (ampm === 'AM' && hours === 12) hours = 0; return `${String(hours).padStart(2, '0')}:${minutes}`; } return '09:00'; }; const formatTo12HrTime = (isoTime) => { if (!isoTime) return ''; if (/AM|PM/i.test(isoTime)) return isoTime; const [hStr, mStr] = isoTime.split(':'); if (hStr !== undefined && mStr !== undefined) { let h = parseInt(hStr, 10); const ampm = h >= 12 ? 'PM' : 'AM'; h = h % 12 || 12; return `${String(h).padStart(2, '0')}:${mStr} ${ampm}`; } return isoTime; }; const SuperAdminPanel = () => { const { user, refreshAccessToken, loading: authLoading } = useAuth(); const authFetch = async (url, options = {}) => { let activeToken = localStorage.getItem('wss_token'); const headers = { 'Authorization': `Bearer ${activeToken}`, ...(options.headers || {}) }; let res = await fetch(url, { ...options, headers }); if (res.status === 401 && refreshAccessToken) { const newToken = await refreshAccessToken(); if (newToken) { headers['Authorization'] = `Bearer ${newToken}`; res = await fetch(url, { ...options, headers }); } } return res; }; const [organizations, setOrganizations] = useState([]); const [recentPayments, setRecentPayments] = useState([]); const [trends, setTrends] = useState([]); const [auditLogs, setAuditLogs] = useState([]); const [users, setUsers] = useState([]); const [demoBookings, setDemoBookings] = useState([]); const [emailLogs, setEmailLogs] = useState([]); const [loading, setLoading] = useState(true); const [activeTab, setActiveTab] = useState(() => { try { const params = new URLSearchParams(window.location.search); const tabFromUrl = params.get('tab'); const storedTab = localStorage.getItem('superAdminActiveTab'); return tabFromUrl || storedTab || 'overview'; } catch (e) { return 'overview'; } }); useEffect(() => { try { localStorage.setItem('superAdminActiveTab', activeTab); } catch (e) {} }, [activeTab]); const [sortOrgCol, setSortOrgCol] = useState('Tenant Name'); const [sortOrgDir, setSortOrgDir] = useState('asc'); const [sortUserCol, setSortUserCol] = useState('Email'); const [sortUserDir, setSortUserDir] = useState('asc'); // Filter states for Global Members const [userSearch, setUserSearch] = useState(''); const [userRoleFilter, setUserRoleFilter] = useState('all'); const [userOrgFilter, setUserOrgFilter] = useState('all'); const [sortBillCol, setSortBillCol] = useState('Date'); const [sortBillDir, setSortBillDir] = useState('desc'); // Pagination state for SuperAdmin tables const [orgPage, setOrgPage] = useState(1); const [orgPageSize, setOrgPageSize] = useState(25); const [userPage, setUserPage] = useState(1); const [userPageSize, setUserPageSize] = useState(25); const [auditPage, setAuditPage] = useState(1); const [auditPageSize, setAuditPageSize] = useState(25); const [bookingPage, setBookingPage] = useState(1); const [bookingPageSize, setBookingPageSize] = useState(25); const [emailPage, setEmailPage] = useState(1); const [emailPageSize, setEmailPageSize] = useState(25); const [bookingSearch, setBookingSearch] = useState(''); const [bookingStatusFilter, setBookingStatusFilter] = useState('all'); const getFilteredBookings = () => { return (demoBookings || []).filter(b => { if (!b) return false; const q = (bookingSearch || '').toLowerCase().trim(); const emailMatch = !bookingSearch || (b.email || '').toLowerCase().includes(q) || (b.company_size || '').toLowerCase().includes(q) || (b.meeting_date || '').toLowerCase().includes(q); const statusMatch = bookingStatusFilter === 'all' || (b.status || 'pending') === bookingStatusFilter; return emailMatch && statusMatch; }); }; // Payments Filtering const [paymentSearch, setPaymentSearch] = useState(''); const [paymentStatusFilter, setPaymentStatusFilter] = useState('all'); const getFilteredBills = () => { return (recentPayments || []).filter(p => { const q = paymentSearch.toLowerCase().trim(); const matchSearch = !paymentSearch || (p.org_name || '').toLowerCase().includes(q) || (p.stripe_payment_id || p.id || '').toLowerCase().includes(q) || (p.tier_id || '').toLowerCase().includes(q); const matchStatus = paymentStatusFilter === 'all' || (p.status || '').toLowerCase() === paymentStatusFilter.toLowerCase(); return matchSearch && matchStatus; }); }; const getSortedBills = () => { const filtered = getFilteredBills(); return [...filtered].sort((a, b) => { let aVal, bVal; switch (sortBillCol) { case 'Date': aVal = new Date(a.created_at || Date.now()).getTime(); bVal = new Date(b.created_at || Date.now()).getTime(); break; case 'Organization / User': aVal = a.org_name || ''; bVal = b.org_name || ''; break; case 'Tier': aVal = a.tier_id || ''; bVal = b.tier_id || ''; break; case 'Amount': aVal = a.amount || 0; bVal = b.amount || 0; break; case 'Status': aVal = a.status || ''; bVal = b.status || ''; break; default: return 0; } if (aVal < bVal) return sortBillDir === 'asc' ? -1 : 1; if (aVal > bVal) return sortBillDir === 'asc' ? 1 : -1; return 0; }); }; // Organizations Filtering const [orgSearch, setOrgSearch] = useState(''); const [orgTierFilter, setOrgTierFilter] = useState('all'); const [orgStatusFilter, setOrgStatusFilter] = useState('all'); const getFilteredOrgs = () => { return (organizations || []).filter(org => { const q = orgSearch.toLowerCase().trim(); const matchSearch = !orgSearch || (org.name || '').toLowerCase().includes(q) || (org.id || '').toLowerCase().includes(q); const rawTier = (org.tier || org.subscription_tier || '').toLowerCase(); const matchTier = orgTierFilter === 'all' || rawTier.includes(orgTierFilter.toLowerCase()); const orgStatus = (org.status || (org.is_active ? 'active' : 'inactive')).toLowerCase(); const matchStatus = orgStatusFilter === 'all' || orgStatus === orgStatusFilter.toLowerCase(); return matchSearch && matchTier && matchStatus; }); }; const getSortedOrgs = () => { const filtered = getFilteredOrgs(); return [...filtered].sort((a, b) => { let aVal, bVal; switch (sortOrgCol) { case 'Tenant Name': aVal = a.name || ''; bVal = b.name || ''; break; case 'Tier': aVal = a.tier || a.subscription_tier || ''; bVal = b.tier || b.subscription_tier || ''; break; case 'Status': aVal = a.status || (a.is_active ? 'active' : 'inactive'); bVal = b.status || (b.is_active ? 'active' : 'inactive'); break; default: return 0; } if (aVal < bVal) return sortOrgDir === 'asc' ? -1 : 1; if (aVal > bVal) return sortOrgDir === 'asc' ? 1 : -1; return 0; }); }; // Audit Logs Filtering const [auditSearch, setAuditSearch] = useState(''); const getFilteredAuditLogs = () => { return (auditLogs || []).filter(log => { if (!auditSearch) return true; const q = auditSearch.toLowerCase().trim(); return (log.action || '').toLowerCase().includes(q) || (log.user_email || log.admin_id || '').toLowerCase().includes(q) || (log.target_name || log.target_id || '').toLowerCase().includes(q); }); }; // Outbound Email Logs Filtering const [emailSearch, setEmailSearch] = useState(''); const [emailStatusFilter, setEmailStatusFilter] = useState('all'); const getFilteredEmails = () => { return (emailLogs || []).filter(e => { const q = emailSearch.toLowerCase().trim(); const matchSearch = !emailSearch || (e.recipient || '').toLowerCase().includes(q) || (e.subject || '').toLowerCase().includes(q); const matchStatus = emailStatusFilter === 'all' || (e.status || '').toLowerCase() === emailStatusFilter.toLowerCase(); return matchSearch && matchStatus; }); }; const handleUserSort = (column) => { if (column === 'Actions') return; if (sortUserCol === column) { setSortUserDir(sortUserDir === 'asc' ? 'desc' : 'asc'); } else { setSortUserCol(column); setSortUserDir('asc'); } }; const getFilteredUsers = () => { return (users || []).filter(u => { if (userSearch) { const q = userSearch.toLowerCase().trim(); const emailMatch = (u.email || '').toLowerCase().includes(q); const roleMatch = (u.role || '').toLowerCase().includes(q); const orgMatch = (u.org_name || '').toLowerCase().includes(q); if (!emailMatch && !roleMatch && !orgMatch) return false; } if (userRoleFilter !== 'all') { if ((u.role || '').toLowerCase() !== userRoleFilter.toLowerCase()) return false; } if (userOrgFilter !== 'all') { if (userOrgFilter === 'no_org') { if (u.org_id || (u.org_name && !u.org_name.startsWith('No Org'))) return false; } else { if (String(u.org_id) !== String(userOrgFilter) && u.org_name !== userOrgFilter) return false; } } return true; }); }; const getSortedUsers = () => { const filtered = getFilteredUsers(); return [...filtered].sort((a, b) => { let aVal, bVal; switch (sortUserCol) { case 'Email': aVal = a.email || ''; bVal = b.email || ''; break; case 'Role': aVal = a.role || ''; bVal = b.role || ''; break; case 'Organization': aVal = a.org_name || ''; bVal = b.org_name || ''; break; default: return 0; } if (aVal < bVal) return sortUserDir === 'asc' ? -1 : 1; if (aVal > bVal) return sortUserDir === 'asc' ? 1 : -1; return 0; }); }; const clearUserFilters = () => { setUserSearch(''); setUserRoleFilter('all'); setUserOrgFilter('all'); setUserPage(1); }; const handleBillSort = (column) => { if (column === 'Invoice') return; if (sortBillCol === column) { setSortBillDir(sortBillDir === 'asc' ? 'desc' : 'asc'); } else { setSortBillCol(column); setSortBillDir('asc'); } }; const [metrics, setMetrics] = useState({ total_tenants: 0, active_licenses: 0, global_users: 0, active_scanners: 0, total_scanners: 15, arr: 0, db_connections: 0, db_query_time: 0, queue_size: 0, active_threads: 0 }); const fetchStats = async () => { setLoading(true); try { const activeToken = localStorage.getItem('wss_token'); if (!activeToken) { setLoading(false); return; } const [globalRes, bookingsRes, emailLogsRes] = await Promise.all([ authFetch('/api/auth/global-stats'), authFetch('/api/demo/bookings'), authFetch('/api/auth/email-logs') ]); if (globalRes && globalRes.ok) { const data = await globalRes.json(); setOrganizations(Array.isArray(data.organizations) ? data.organizations : []); setMetrics(data.metrics || {}); setRecentPayments(Array.isArray(data.recent_payments) ? data.recent_payments : []); setTrends(Array.isArray(data.trends) ? data.trends : []); setAuditLogs(Array.isArray(data.audit_logs) ? data.audit_logs : []); setUsers(Array.isArray(data.users) ? data.users : []); } if (bookingsRes && bookingsRes.ok) { const data = await bookingsRes.json(); setDemoBookings(Array.isArray(data.bookings) ? data.bookings : []); } if (emailLogsRes && emailLogsRes.ok) { const data = await emailLogsRes.json(); setEmailLogs(Array.isArray(data.logs) ? data.logs : []); } } catch (err) { console.error('Failed to fetch global stats', err); } finally { setLoading(false); } }; useEffect(() => { fetchStats(); }, []); // Modal States const [pricingModalOpen, setPricingModalOpen] = useState(false); const [activeScansModalOpen, setActiveScansModalOpen] = useState(false); // Custom Prompts & Confirms const [confirmModal, setConfirmModal] = useState({ isOpen: false, title: '', desc: '', onConfirm: null, type: 'primary' }); const [promptModal, setPromptModal] = useState({ isOpen: false, title: '', desc: '', inputs: [], onConfirm: null }); const [promptValues, setPromptValues] = useState({}); const [showPasswordPrompt, setShowPasswordPrompt] = useState({}); const [viewInvoice, setViewInvoice] = useState(null); const [rescheduleModal, setRescheduleModal] = useState({ isOpen: false, bookingId: null, email: '', meetingDate: '', isoDate: '', meetingTime: '', isoTime: '', status: 'rescheduled' }); const closeConfirm = () => setConfirmModal({ isOpen: false, title: '', desc: '', onConfirm: null, type: 'primary' }); const closePrompt = () => { setPromptModal({ isOpen: false, title: '', desc: '', inputs: [], onConfirm: null }); setPromptValues({}); setShowPasswordPrompt({}); }; const handlePromptChange = (key, value) => setPromptValues(prev => ({ ...prev, [key]: value })); const handleSuspend = (orgId, currentStatus) => { const action = currentStatus === 'suspended' ? 'activate' : 'suspend'; setConfirmModal({ isOpen: true, title: `${action === 'activate' ? 'Activate' : 'Suspend'} Tenant`, desc: `Are you sure you want to ${action} this tenant?`, type: action === 'suspend' ? 'error' : 'primary', onConfirm: async () => { try { const res = await fetch(`/api/auth/organizations/${orgId}/suspend`, { method: 'POST', headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}` } }); if (res.ok) fetchStats(); } catch (err) { } closeConfirm(); } }); }; const handleDeleteTenant = (orgId, orgName) => { setConfirmModal({ isOpen: true, title: 'Delete Tenant', desc: `Are you sure you want to completely delete ${orgName}? This action cannot be undone.`, type: 'error', onConfirm: async () => { try { const res = await fetch(`/api/auth/organizations/${orgId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}` } }); if (res.ok) { toast.success('Tenant deleted successfully'); fetchStats(); } else { toast.error('Failed to delete tenant'); } } catch (err) { toast.error('Network error'); } closeConfirm(); } }); }; const handleImpersonate = (orgId, orgName) => { setConfirmModal({ isOpen: true, title: 'Impersonate Tenant', desc: `Log in as administrator for ${orgName}?`, type: 'primary', onConfirm: async () => { try { const res = await fetch(`/api/auth/impersonate/${orgId}`, { method: 'POST', headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}` } }); if (res.ok) { const data = await res.json(); localStorage.setItem('original_admin_token', localStorage.getItem('wss_token')); localStorage.setItem('wss_token', data.access_token); window.location.href = '/dashboard'; } } catch (err) { } closeConfirm(); } }); }; const [tiers, setTiers] = useState([]); const [fetchingTiers, setFetchingTiers] = useState(false); const openPricingModal = async () => { setPricingModalOpen(true); setFetchingTiers(true); try { const res = await fetch('/api/billing/tiers', { headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}` } }); if (res.ok) { const data = await res.json(); if (Array.isArray(data) && data.length > 0) { setTiers(data); } else { setTiers(DEFAULT_BILLING_TIERS); } } else { setTiers(DEFAULT_BILLING_TIERS); } } catch (err) { setTiers(DEFAULT_BILLING_TIERS); } setFetchingTiers(false); }; const handleUpdateTier = async (tierId, monthly, yearly) => { try { await fetch(`/api/billing/tiers/${tierId}`, { method: 'PUT', headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ monthly_price: parseInt(monthly), yearly_price: parseInt(yearly) }) }); fetchStats(); } catch (err) { } }; const [activeScans, setActiveScans] = useState([]); const [fetchingActiveScans, setFetchingActiveScans] = useState(false); const openActiveScansModal = async () => { setActiveScansModalOpen(true); setFetchingActiveScans(true); try { const res = await fetch('/api/scans/active', { headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}` } }); if (res.ok) { const data = await res.json(); setActiveScans(data.scans || []); } } catch (err) { } setFetchingActiveScans(false); }; const handleKillScan = (scanId) => { setConfirmModal({ isOpen: true, title: 'Terminate Scan', desc: 'Are you sure you want to forcibly terminate this scan?', type: 'error', onConfirm: async () => { try { await fetch(`/api/scans/${scanId}/terminate`, { method: 'POST', headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}` } }); openActiveScansModal(); } catch (err) { } closeConfirm(); } }); }; const handleProvisionTenant = () => { setPromptValues({ tier: 'none', name: '', admin_email: '' }); setPromptModal({ isOpen: true, title: 'Add New Organization', desc: 'Create a new tenant organization.', inputs: [ { key: 'name', label: 'Organization Name', placeholder: 'Enter organization name...' }, { key: 'tier', label: 'Subscription Tier', type: 'select', options: [ { label: 'None', value: 'none' }, { label: 'Quick', value: 'quick' }, { label: 'Advanced', value: 'advanced' }, { label: 'Deep', value: 'deep' }, { label: 'Enterprise(Custom)', value: 'Enterprise(Custom)' } ] }, { key: 'admin_email', label: 'Admin Email (Optional)', placeholder: 'admin@company.com' } ], onConfirm: async (values) => { try { const res = await fetch('/api/auth/organizations', { method: 'POST', headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ name: values.name, tier: values.tier, admin_email: values.admin_email }) }); if (res.ok) { toast.success('Organization created successfully'); fetchStats(); } else { toast.error('Failed to create organization'); } } catch (err) { toast.error('Network error creating organization'); } closePrompt(); } }); }; const handleAssignScans = (org) => { setPromptValues({ scan_type: 'Deep', count: '1' }); setPromptModal({ isOpen: true, title: 'Assign Custom Scans', desc: `Grant specific scan limits for ${org.name}`, inputs: [ { key: 'scan_type', label: 'Scan Type', type: 'select', options: ['Quick', 'Advanced', 'Deep'] }, { key: 'count', label: 'Number of Scans', placeholder: 'e.g., 5' } ], onConfirm: async (values) => { const addedCount = parseInt(values.count); if (isNaN(addedCount) || addedCount <= 0) { toast.error('Please enter a valid scan count'); return; } try { const res = await fetch(`/api/auth/organizations/${org.id}/quotas`, { method: 'POST', headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ scan_type: values.scan_type, count: addedCount }) }); if (res.ok) { toast.success(`${addedCount} ${values.scan_type} scan(s) assigned successfully!`); // Optimistic instant state update setOrganizations(prevOrgs => prevOrgs.map(o => { if (o.id === org.id) { const existingQuotas = o.quotas || []; let found = false; const updatedQuotas = existingQuotas.map(q => { if (q.scan_type?.toLowerCase() === values.scan_type?.toLowerCase()) { found = true; return { ...q, allocated_count: q.allocated_count === -1 ? -1 : (q.allocated_count || 0) + addedCount }; } return q; }); if (!found) { updatedQuotas.push({ scan_type: values.scan_type, allocated_count: addedCount, used_count: 0 }); } return { ...o, quotas: updatedQuotas }; } return o; })); fetchStats(); } else { const data = await res.json(); toast.error(data.message || 'Failed to assign scans.'); } } catch (err) { toast.error('Network error assigning scans.'); } closePrompt(); } }); }; const handleEditTenant = (org) => { const rawTier = (org.tier || org.subscription_tier || 'none'); const isCustom = rawTier.toLowerCase().includes('custom') || rawTier.toLowerCase().includes('enterprise'); const initialTier = isCustom ? 'Enterprise(Custom)' : ['none', 'quick', 'advanced', 'deep'].includes(rawTier.toLowerCase()) ? rawTier.toLowerCase() : 'none'; setPromptValues({ name: org.name, tier: initialTier }); setPromptModal({ isOpen: true, title: 'Edit Organization', desc: `Modify settings for ${org.name}`, inputs: [ { key: 'name', label: 'Organization Name', placeholder: 'Enter organization name...' }, { key: 'tier', label: 'Subscription Tier', type: 'select', options: [ { label: 'None', value: 'none' }, { label: 'Quick', value: 'quick' }, { label: 'Advanced', value: 'advanced' }, { label: 'Deep', value: 'deep' }, { label: 'Enterprise(Custom)', value: 'Enterprise(Custom)' } ] } ], onConfirm: async (values) => { try { const res = await fetch(`/api/auth/organizations/${org.id}`, { method: 'PUT', headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ name: values.name, tier: values.tier }) }); if (res.ok) { toast.success('Organization updated successfully'); fetchStats(); } else { toast.error('Failed to update organization'); } } catch (err) { toast.error('Network error updating organization'); } closePrompt(); } }); }; // Member CRUD const MEMBER_ROLE_OPTIONS = (user?.role === 'admin' ? [ { label: 'Admin', value: 'admin' }, { label: 'SOC Analyst', value: 'soc_analyst' }, { label: 'Organization Admin', value: 'org_admin' }, { label: 'Executive User', value: 'executive_user' }, { label: 'Support Engineer', value: 'support_engineer' }, { label: 'Read Only', value: 'read_only' } ] : [ { label: 'Admin', value: 'admin' }, { label: 'SOC Analyst', value: 'soc_analyst' }, { label: 'Organization Admin', value: 'org_admin' }, { label: 'Executive User', value: 'executive_user' }, { label: 'Super Admin', value: 'super_admin' }, { label: 'Support Engineer', value: 'support_engineer' }, { label: 'Read Only', value: 'read_only' } ] ); const handleAddMember = () => { const orgOptions = [ { label: 'None (Global)', value: '' }, ...(organizations || []).map(o => ({ label: o.name, value: String(o.id) })) ]; setPromptValues({ email: '', password: '', role: 'admin', org_id: '' }); setPromptModal({ isOpen: true, title: 'Add Member', desc: 'Invite or add a new global platform member.', inputs: [ { key: 'email', label: 'User Email', placeholder: 'user@example.com' }, { key: 'password', label: 'Password (Optional - Auto-generated if left blank)', placeholder: 'Set initial password...', type: 'password', showRules: true }, { key: 'role', label: 'Role', type: 'select', options: MEMBER_ROLE_OPTIONS }, { key: 'org_id', label: 'Organization', type: 'select', options: orgOptions } ], onConfirm: async (values) => { if (!values.email || !values.email.trim()) { toast.error('Please enter a valid user email'); return; } const pwd = values.password ? values.password.trim() : ''; if (pwd && (pwd.length < 8 || !/[A-Z]/.test(pwd) || !/[a-z]/.test(pwd) || !/[^A-Za-z0-9]/.test(pwd))) { toast.error('Password must meet all 4 security requirements (8+ chars, 1 uppercase, 1 lowercase, 1 special character).'); return; } try { const res = await authFetch('/api/auth/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: values.email.trim(), role: values.role, org_id: values.org_id || null, password: pwd || null }) }); const data = await res.json().catch(() => ({})); if (res.ok) { toast.success('Member added successfully'); fetchStats(); } else { toast.error(data.message || 'Failed to add member'); } } catch (err) { toast.error('Network error adding member'); } closePrompt(); } }); }; const handleEditMember = (u) => { const orgOptions = [ { label: 'None (Global)', value: '' }, ...(organizations || []).map(o => ({ label: o.name, value: String(o.id) })) ]; let initialOrgId = (u.org_id !== undefined && u.org_id !== null) ? String(u.org_id) : ''; if (!initialOrgId && u.org_name && u.org_name !== 'No Org (Super Admin)' && organizations) { const match = organizations.find(o => o.name === u.org_name); if (match) initialOrgId = String(match.id); } const isSupport = user?.role === 'support_engineer'; setPromptValues({ email: u.email, role: u.role || 'admin', org_id: initialOrgId, password: '' }); const modalInputs = [ { key: 'email', label: 'User Email', disabled: true } ]; if (!isSupport) { modalInputs.push({ key: 'password', label: 'New Password (Leave blank to keep current password)', placeholder: 'Type new password to update...', type: 'password', showRules: true }); } modalInputs.push( { key: 'role', label: 'Role', type: 'select', options: MEMBER_ROLE_OPTIONS }, { key: 'org_id', label: 'Organization', type: 'select', options: orgOptions } ); setPromptModal({ isOpen: true, title: isSupport ? 'Edit Member Role & Organization' : 'Edit Member & Password', desc: isSupport ? `Update role & organization mapping for ${u.email}` : `Update details & credentials for ${u.email}`, inputs: modalInputs, onConfirm: async (vals) => { const pwd = vals.password ? vals.password.trim() : ''; if (pwd && !isSupport && (pwd.length < 8 || !/[A-Z]/.test(pwd) || !/[a-z]/.test(pwd) || !/[^A-Za-z0-9]/.test(pwd))) { toast.error('Password must meet all 4 security requirements (8+ chars, 1 uppercase, 1 lowercase, 1 special character).'); return; } try { const res = await authFetch(`/api/auth/users/${u.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ role: vals.role, org_id: vals.org_id || null, password: (!isSupport && pwd) ? pwd : null }) }); const data = await res.json().catch(() => ({})); if (res.ok) { toast.success('Member details updated successfully'); fetchStats(); } else { toast.error(data.message || 'Failed to update member'); } } catch (err) { toast.error('Network error updating member'); } closePrompt(); } }); }; const handleDownloadInvoice = (payment) => { const invoiceHtml = ` Invoice - ${payment.id}

LarShield

Payment Receipt & Invoice

Date: ${new Date(payment.created_at).toLocaleString()}
Organization: ${payment.org_name}
Email: ${payment.user_email}
Subscription Tier: ${payment.tier_id} Plan
Status: ${payment.status.toUpperCase()}
Total Amount: ${payment.currency === 'INR' ? '₹' : '$'}${payment.amount.toLocaleString(undefined, { minimumFractionDigits: 2 })}
`; const blob = new Blob([invoiceHtml], { type: 'text/html' }); const url = URL.createObjectURL(blob); window.open(url, '_blank'); }; const isSupportEngineer = user?.role === 'support_engineer'; const isSuperAdmin = user?.role === 'super_admin' || user?.role === 'admin' || sessionStorage.getItem('superAdminAuth') === 'true'; if (authLoading || loading) { return (
sync Verifying Management Session...
); } if (!isSuperAdmin && !isSupportEngineer) { return (
lock

Access Restricted

You do not have administrative permissions to access LarShield Global Management.

Go to Dashboard Super Admin Login
); } const handleUpdateBookingStatus = async (bookingId, status) => { try { const res = await fetch(`/api/demo/bookings/${bookingId}`, { method: 'PUT', headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ status }) }); if (res.ok) { toast.success(`Booking status updated to ${status}`); fetchStats(); } else { toast.error("Failed to update booking status"); } } catch (err) { toast.error("Network error updating booking"); } }; const handleCancelBooking = (booking) => { setConfirmModal({ isOpen: true, title: 'Cancel Demo Booking', desc: `Are you sure you want to cancel the demo call booking for ${booking.email || 'this lead'}?`, type: 'error', onConfirm: async () => { await handleUpdateBookingStatus(booking.id, 'cancelled'); closeConfirm(); } }); }; const handleOpenReschedule = (booking) => { const rawDate = booking.meeting_date || ''; const rawTime = booking.meeting_time || ''; const isoDate = parseToISODate(rawDate); const isoTime = parseToISOTime(rawTime); const formattedDate = formatToReadableDate(isoDate); const formattedTime = formatTo12HrTime(isoTime); setRescheduleModal({ isOpen: true, bookingId: booking.id, email: booking.email, meetingDate: formattedDate, isoDate: isoDate, meetingTime: formattedTime, isoTime: isoTime, status: booking.status === 'pending' || !booking.status ? 'rescheduled' : booking.status }); }; const handleSaveReschedule = async (e) => { e.preventDefault(); try { const res = await fetch(`/api/demo/bookings/${rescheduleModal.bookingId}`, { method: 'PUT', headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ meeting_date: rescheduleModal.meetingDate || formatToReadableDate(rescheduleModal.isoDate), meeting_time: rescheduleModal.meetingTime || formatTo12HrTime(rescheduleModal.isoTime), status: rescheduleModal.status }) }); if (res.ok) { toast.success("Demo booking rescheduled successfully!"); setRescheduleModal({ isOpen: false, bookingId: null, email: '', meetingDate: '', isoDate: '', meetingTime: '', isoTime: '', status: 'rescheduled' }); fetchStats(); } else { toast.error("Failed to reschedule demo booking"); } } catch (err) { toast.error("Error rescheduling booking"); } }; const handleDeleteBooking = (booking) => { const bookingId = typeof booking === 'object' ? booking.id : booking; const email = typeof booking === 'object' && booking.email ? booking.email : ''; setConfirmModal({ isOpen: true, title: 'Delete Demo Lead', desc: email ? `Are you sure you want to permanently delete the demo lead for ${email}?` : 'Are you sure you want to permanently delete this demo booking lead?', type: 'error', onConfirm: async () => { try { const res = await fetch(`/api/demo/bookings/${bookingId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}` } }); if (res.ok) { toast.success("Demo lead deleted successfully"); fetchStats(); } else { toast.error("Failed to delete demo lead"); } } catch (err) { toast.error("Error deleting lead"); } closeConfirm(); } }); }; return (
{/* Support Engineer Information Banner */} {isSupportEngineer && (
support_agent
Support Engineer Portal (Client Support)
Permissions: Can view customer environments, assist troubleshooting (impersonation), and inspect logs & active scans. (Cannot delete organizations or change subscription pricing).
Support Role
)} {/* Header Section */}

{isSupportEngineer ? 'Support Engineer Operations' : 'LarShield Global Management'}

{isSupportEngineer ? 'Client environment inspection, troubleshooting assistance, and system logs.' : 'Centralized oversight for all client organizations and scanning nodes.'}

{!isSupportEngineer && ( )} Org Dashboard Logs & Threats {!isSupportEngineer && ( )}
{/* Tab Navigation */}
{['overview', 'organizations', 'members', 'audit', 'bookings', 'emails'].map(tab => ( ))}
{activeTab === 'overview' && ( <>

Total Tenants

{metrics.total_tenants}

Active Licenses

{metrics.active_licenses}

Global Users

{metrics.global_users}

Active Scanners

{metrics.active_scanners}/{metrics.total_scanners}

Node Infrastructure

PostgreSQL Cluster
HEALTHY
Connections{metrics.db_connections || 0} / 500
Celery Workers
5 ? 'bg-yellow-500/10 text-yellow-600 border-yellow-500/20' : 'bg-green-500/10 text-green-600 border-green-500/20'}`}>{metrics.queue_size > 5 ? 'HEAVY LOAD' : 'NORMAL'}
Queue Size{metrics.queue_size || 0} scans

receipt_long Global Transaction History

setPaymentSearch(e.target.value)} className="bg-surface-container border border-outline-variant/60 rounded-lg pl-8 pr-7 py-1 text-[12.5px] outline-none text-on-surface w-48" /> {paymentSearch && ( )}
{loading ?
Fetching logs...
: (
{['Date', 'Organization / User', 'Tier', 'Amount', 'Status', 'Invoice'].map((h, i) => ( ))} {recentPayments.length === 0 ? : getSortedBills().map(p => ( ))}
handleBillSort(h)} className={`px-md py-sm font-bold text-[12px] uppercase tracking-wider ${i === 5 ? 'text-right' : ''} ${h !== 'Invoice' ? 'cursor-pointer hover:bg-surface-container-highest transition-colors group' : ''}`} >
{h} {h !== 'Invoice' && ( {sortBillCol === h && sortBillDir === 'desc' ? 'arrow_downward' : 'arrow_upward'} )}
No recent transactions.
{new Date(p.created_at).toLocaleDateString()}
{p.org_name}
{p.tier_id} {p.currency === 'INR' ? '₹' : '$'}{p.amount.toLocaleString(undefined, { minimumFractionDigits: 2 })}
{p.status === 'successful' ? 'Success' : 'Failed'}
)}

history System Audit Logs

{loading ?
Fetching logs...
: (
{auditLogs.length === 0 ? : auditLogs.slice(0, 5).map(log => ( ))}
Date & Time Admin User Action / Event Organization / Target
No audit logs found.
{new Date(log.created_at || log.timestamp).toLocaleString()}
{log.user_email}
{log.action.includes('Terminated') ? {log.action} : log.action} {log.target_name || log.target_id || '-'}
)}
)} {activeTab === 'organizations' && (

Client Organizations Directory

{ setOrgSearch(e.target.value); setOrgPage(1); }} className="bg-surface border border-outline-variant/60 text-on-surface text-[13px] font-medium rounded-lg pl-9 pr-8 py-1.5 outline-none focus:border-primary w-48" /> {orgSearch && ( )}
{(orgSearch || orgTierFilter !== 'all' || orgStatusFilter !== 'all') && ( )}
{loading ?
Fetching directory...
: ( {['Tenant Name', 'Tier', 'Status', 'Quotas', 'Actions'].map((h, i) => ( ))} {getSortedOrgs().slice((orgPage - 1) * orgPageSize, orgPage * orgPageSize).map((org) => ( ))}
handleOrgSort(h)} className={`px-md py-sm font-bold text-[12px] uppercase tracking-wider ${i === 4 ? 'text-right' : ''} ${(h !== 'Actions' && h !== 'Quotas') ? 'cursor-pointer hover:bg-surface-container-highest transition-colors group' : ''}`} >
{h} {(h !== 'Actions' && h !== 'Quotas') && ( {sortOrgCol === h && sortOrgDir === 'desc' ? 'arrow_downward' : 'arrow_upward'} )}
{org.name}
{org.tier || org.subscription_tier}
{org.status ? org.status.charAt(0).toUpperCase() + org.status.slice(1) : (org.is_active ? 'Active' : 'Inactive')}
{org.quotas?.filter(q => ['Quick', 'Advanced', 'Deep'].includes(q.scan_type)).map((q, idx) => { const remaining = q.allocated_count === -1 ? '∞' : Math.max(0, q.allocated_count - (q.used_count || 0)); const style = q.scan_type === 'Deep' ? 'bg-orange-500/10 text-orange-600 border-orange-500/30' : q.scan_type === 'Advanced' ? 'bg-purple-500/10 text-purple-600 border-purple-500/30' : q.scan_type === 'Quick' ? 'bg-blue-500/10 text-blue-600 border-blue-500/30' : 'bg-emerald-500/10 text-emerald-600 border-emerald-500/30'; return (
{q.scan_type}: {remaining}
); })}
{!isSupportEngineer && ( <> )}
)}
)} {activeTab === 'members' && (

Global Members

Centralized user management, role assignments, and client org mapping.

{!isSupportEngineer && ( )}
{/* Filter & Search Bar */}
{/* Search Input */}
{ setUserSearch(e.target.value); setUserPage(1); }} className="w-full pl-9 pr-8 py-2 bg-surface border border-outline-variant/60 rounded-lg text-[13px] text-on-surface focus:outline-none focus:border-primary" /> {userSearch && ( )}
{/* Filter by Role */}
Role:
{/* Filter by Organization */}
Organization:
{/* Reset Button */} {(userSearch || userRoleFilter !== 'all' || userOrgFilter !== 'all') && ( )}
{loading ?
Fetching users...
: getSortedUsers().length === 0 ? (

No members match your filter criteria.

Try clearing your search terms or filter criteria.

{(userSearch || userRoleFilter !== 'all' || userOrgFilter !== 'all') && ( )}
) : ( {['Email', 'Role', 'Organization', 'Actions'].map((h, i) => ( ))} {getSortedUsers().slice((userPage - 1) * userPageSize, userPage * userPageSize).map((u) => ( ))}
handleUserSort(h)} className={`px-md py-sm font-bold text-[12px] uppercase tracking-wider ${i === 3 ? 'text-right' : ''} ${h !== 'Actions' ? 'cursor-pointer hover:bg-surface-container-highest transition-colors group' : ''}`} >
{h} {h !== 'Actions' && ( {sortUserCol === h && sortUserDir === 'desc' ? 'arrow_downward' : 'arrow_upward'} )}
{u.email} {u.role ? u.role.replace(/_/g, ' ') : 'User'} {u.org_name} {!isSupportEngineer && ( )}
)}
)} {activeTab === 'audit' && (

history Full System Audit Logs

{ setAuditSearch(e.target.value); setAuditPage(1); }} className="w-full bg-surface border border-outline-variant/60 text-on-surface text-[13px] font-medium rounded-lg pl-9 pr-8 py-1.5 outline-none focus:border-primary" /> {auditSearch && ( )}
{loading ?
Fetching logs...
: ( <>
{getFilteredAuditLogs().length === 0 ? ( ) : ( getFilteredAuditLogs().slice((auditPage - 1) * auditPageSize, auditPage * auditPageSize).map((log) => ( )) )}
Date & Time Admin User Action / Event Organization / Target
No audit logs match your search.
{new Date(log.created_at || log.timestamp).toLocaleString()}
{log.user_email}
{log.action.includes('Terminated') ? {log.action} : log.action} {log.target_name || log.target_id || '-'}
)}
)} {activeTab === 'bookings' && (

event Demo Bookings & Leads

Total Leads: {getFilteredBookings().length}
{/* Filter Controls Bar */}
{ setBookingSearch(e.target.value); setBookingPage(1); }} className="w-full bg-surface border border-outline-variant/60 rounded-lg pl-9 pr-8 py-1.5 text-[13px] outline-none focus:border-primary text-on-surface font-medium" /> {bookingSearch && ( )}
Status:
{(bookingSearch || bookingStatusFilter !== 'all') && ( )}
{getFilteredBookings().length === 0 ? (
No demo bookings match your filter criteria.
) : ( <>
{getFilteredBookings().slice((bookingPage - 1) * bookingPageSize, bookingPage * bookingPageSize).map(b => { const statusStyle = b.status === 'completed' ? 'bg-green-500/10 text-green-600 border-green-500/30' : b.status === 'cancelled' ? 'bg-red-500/10 text-red-600 border-red-500/30' : b.status === 'rescheduled' ? 'bg-blue-500/10 text-blue-600 border-blue-500/30' : 'bg-orange-500/10 text-orange-600 border-orange-500/30'; const statusLabel = b.status === 'completed' ? 'Completed / Conducted' : b.status === 'cancelled' ? 'Cancelled / Not Conducted' : b.status === 'rescheduled' ? 'Rescheduled' : 'Pending'; return ( ); })}
Email Size Date & Time Status Actions
{b.email} {b.company_size?.replace('Company Size: ', '')} {b.meeting_date}
{b.meeting_time}
{statusLabel}
{b.status !== 'completed' && ( )} {b.status !== 'cancelled' && ( )}
)}
)} {activeTab === 'emails' && (

mail Outbound Email Logs

{ setEmailSearch(e.target.value); setEmailPage(1); }} className="bg-surface border border-outline-variant/60 text-on-surface text-[13px] font-medium rounded-lg pl-9 pr-8 py-1.5 outline-none focus:border-primary w-56" /> {emailSearch && ( )}
{(emailSearch || emailStatusFilter !== 'all') && ( )}
{getFilteredEmails().length === 0 ? (
No emails match your filter criteria.
) : ( <>
{getFilteredEmails().slice((emailPage - 1) * emailPageSize, emailPage * emailPageSize).map(log => ( ))}
Timestamp Recipient Subject Status
{new Date(log.sent_at).toLocaleString()} {log.recipient} {log.subject} {log.status}
)}
)} {/* Pricing Modal using CustomModal */} setPricingModalOpen(false)} title="Dynamic Billing Control" description="Manage subscription tiers and pricing across the platform." maxWidth="max-w-4xl" > {fetchingTiers ? (
sync Loading Billing Data...
) : (
{tiers.map(tier => ( ))}
)}
{/* Active Scans Modal */} setActiveScansModalOpen(false)} title="Active Scans"> {fetchingActiveScans ?
Loading...
: activeScans.length === 0 ?
No active scans.
: (
{activeScans.map(scan => (
{scan.target_url}
Org ID: {scan.org_id}
))}
)}
{/* Prompt Modal */} } >
{promptModal.inputs.map(input => (
{input.type === 'select' ? ( ) : input.type === 'password' ? (
handlePromptChange(input.key, e.target.value)} placeholder={input.placeholder} disabled={input.disabled} className="w-full bg-surface-container border border-outline-variant rounded-lg pl-3 pr-10 py-2 focus:border-primary outline-none text-on-surface text-sm" />
{input.showRules && (promptValues[input.key] || '').length > 0 && (
= 8 ? 'text-green-600 dark:text-green-500 font-bold' : 'text-on-surface-variant'}`}> {(promptValues[input.key] || '').length >= 8 ? 'check_circle' : 'radio_button_unchecked'} At least 8 characters
{/[A-Z]/.test(promptValues[input.key] || '') ? 'check_circle' : 'radio_button_unchecked'} One uppercase letter
{/[a-z]/.test(promptValues[input.key] || '') ? 'check_circle' : 'radio_button_unchecked'} One lowercase letter
{/[^A-Za-z0-9]/.test(promptValues[input.key] || '') ? 'check_circle' : 'radio_button_unchecked'} One special character
)}
) : ( handlePromptChange(input.key, e.target.value)} placeholder={input.placeholder} disabled={input.disabled} className={`bg-surface-container border border-outline-variant rounded-lg px-3 py-2 focus:border-primary outline-none text-on-surface ${input.disabled ? 'bg-surface-container-high text-on-surface-variant opacity-80 cursor-not-allowed' : ''}`} /> )}
))}
{/* Confirm Modal */} } /> {/* Invoice View Modal */} setViewInvoice(null)} title="Invoice Details" footer={ <> } > {viewInvoice && (

LarShield

Payment Receipt & Invoice

Date
{new Date(viewInvoice.created_at).toLocaleString()}
Billed To
{viewInvoice.org_name}
{viewInvoice.user_email}
Status
{viewInvoice.status}
Description Amount
{viewInvoice.tier_id} Subscription Plan {viewInvoice.currency === 'INR' ? '₹' : '$'}{viewInvoice.amount.toLocaleString(undefined, { minimumFractionDigits: 2 })}
Total Amount
{viewInvoice.currency === 'INR' ? '₹' : '$'}{viewInvoice.amount.toLocaleString(undefined, { minimumFractionDigits: 2 })}
)}
{/* Reschedule Demo Call Modal using CustomModal */} setRescheduleModal({ ...rescheduleModal, isOpen: false })} title="Reschedule Demo Call" description="Select a new meeting date, time slot, and update booking status." maxWidth="max-w-lg" >
{rescheduleModal.meetingDate && ( calendar_today {rescheduleModal.meetingDate} )}
{ const newIso = e.target.value; setRescheduleModal(prev => ({ ...prev, isoDate: newIso, meetingDate: formatToReadableDate(newIso) })); }} className="w-full border border-outline-variant rounded-lg p-2.5 text-xs text-on-surface bg-surface-container-lowest focus:border-primary outline-none cursor-pointer" />
{rescheduleModal.meetingTime && ( schedule {rescheduleModal.meetingTime} )}
{/* Time Picker */} { const newIso = e.target.value; setRescheduleModal(prev => ({ ...prev, isoTime: newIso, meetingTime: formatTo12HrTime(newIso) })); }} className="w-full border border-outline-variant rounded-lg p-2.5 text-xs text-on-surface bg-surface-container-lowest focus:border-primary outline-none cursor-pointer mb-2" /> {/* Quick Time Slots */}
Quick Select Time Slot:
{['09:00 AM', '10:00 AM', '11:00 AM', '02:00 PM', '04:00 PM', '05:00 PM', '06:00 PM', '09:30 PM'].map((slot) => { const isSelected = rescheduleModal.meetingTime === slot; return ( ); })}
); }; export default SuperAdminPanel;