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:
{
onPageSizeChange(Number(e.target.value));
onPageChange(1);
}}
className="bg-surface border border-outline-variant/60 text-on-surface rounded px-2 py-1 text-[12px] font-bold focus:outline-none cursor-pointer"
>
10
25
50
100
{totalEntries === 0 ? '0 of 0 records' : `${startIndex + 1} - ${endIndex} of ${totalEntries} records`}
onPageChange(Math.max(1, validCurrentPage - 1))}
disabled={validCurrentPage === 1}
className="px-3 py-1.5 rounded-lg border border-outline-variant/60 bg-surface hover:bg-surface-container-high text-on-surface font-bold text-[12px] disabled:opacity-40 disabled:cursor-not-allowed cursor-pointer transition-colors"
>
Previous
{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 && ... }
onPageChange(page)}
className={`w-7 h-7 rounded-lg text-[12px] font-bold transition-colors cursor-pointer ${
validCurrentPage === page
? 'bg-primary text-on-primary shadow-2xs'
: 'bg-surface hover:bg-surface-container-high border border-outline-variant/60 text-on-surface'
}`}
>
{page}
);
})}
onPageChange(Math.min(totalPages, validCurrentPage + 1))}
disabled={validCurrentPage >= totalPages}
className="px-3 py-1.5 rounded-lg border border-outline-variant/60 bg-surface hover:bg-surface-container-high text-on-surface font-bold text-[12px] disabled:opacity-40 disabled:cursor-not-allowed cursor-pointer transition-colors"
>
Next
);
};
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)}
{saving ? (
sync
) : saved ? (
check_circle
) : (
save
)}
{saving ? 'Saving...' : saved ? 'Saved!' : 'Save Changes'}
);
};
// 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}
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.'}
Sync Metrics
{!isSupportEngineer && (
Manage Pricing
)}
Org Dashboard
Logs & Threats
{!isSupportEngineer && (
Add Organization
)}
{/* Tab Navigation */}
{['overview', 'organizations', 'members', 'audit', 'bookings', 'emails'].map(tab => (
setActiveTab(tab)}
className={`px-4 py-2 font-bold text-[14px] rounded-lg transition-colors capitalize ${activeTab === tab ? 'bg-primary text-white shadow-md' : 'bg-transparent text-on-surface-variant hover:text-on-surface hover:bg-surface-container'
} border-0 cursor-pointer`}
>
{tab === 'audit' ? 'Audit Logs' : tab.replace('_', ' ')}
))}
{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
Inspect Active Scans
receipt_long Global Transaction History
{loading ?
Fetching logs...
: (
{['Date', 'Organization / User', 'Tier', 'Amount', 'Status', 'Invoice'].map((h, i) => (
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'}
)}
))}
{recentPayments.length === 0 ? No recent transactions. : getSortedBills().map(p => (
{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'}
setViewInvoice(p)} className="text-on-surface-variant hover:text-primary transition-colors bg-transparent border-0 cursor-pointer p-1" title="View Invoice">
handleDownloadInvoice(p)} className="text-on-surface-variant hover:text-primary transition-colors bg-transparent border-0 cursor-pointer p-1" title="Download Invoice">
))}
)}
history System Audit Logs
setActiveTab('audit')} className="text-primary font-bold text-[13px] hover:underline bg-transparent border-0 cursor-pointer">
View All
{loading ?
Fetching logs...
: (
Date & Time
Admin User
Action / Event
Organization / Target
{auditLogs.length === 0 ? No audit logs found. : auditLogs.slice(0, 5).map(log => (
{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 && (
{ setOrgSearch(''); setOrgPage(1); }} className="absolute right-2.5 top-2 text-on-surface-variant hover:text-on-surface border-0 bg-transparent cursor-pointer">
)}
{ setOrgTierFilter(e.target.value); setOrgPage(1); }}
className="bg-surface border border-outline-variant/60 text-on-surface text-[13px] font-medium rounded-lg px-3 py-1.5 outline-none focus:border-primary cursor-pointer"
>
All Tiers
Quick
Advanced
Deep
Enterprise
Free
{ setOrgStatusFilter(e.target.value); setOrgPage(1); }}
className="bg-surface border border-outline-variant/60 text-on-surface text-[13px] font-medium rounded-lg px-3 py-1.5 outline-none focus:border-primary cursor-pointer"
>
All Statuses
Active
Inactive
{(orgSearch || orgTierFilter !== 'all' || orgStatusFilter !== 'all') && (
{ setOrgSearch(''); setOrgTierFilter('all'); setOrgStatusFilter('all'); setOrgPage(1); }}
className="text-error hover:underline text-[12.5px] font-bold flex items-center gap-1 cursor-pointer bg-transparent border-0 px-1"
>
Reset
)}
{loading ?
Fetching directory...
: (
{['Tenant Name', 'Tier', 'Status', 'Quotas', 'Actions'].map((h, i) => (
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'}
)}
))}
{getSortedOrgs().slice((orgPage - 1) * orgPageSize, orgPage * orgPageSize).map((org) => (
{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}
);
})}
handleImpersonate(org.id, org.name)} className="text-on-surface-variant hover:text-primary transition-colors bg-transparent border-0 cursor-pointer p-1" title="View Customer Environment / Assist Troubleshooting">
vpn_key
{!isSupportEngineer && (
<>
handleAssignScans(org)} className="text-on-surface-variant hover:text-primary transition-colors bg-transparent border-0 cursor-pointer p-1" title="Assign Custom Scans">
add_box
handleEditTenant(org)} className="text-on-surface-variant hover:text-primary transition-colors bg-transparent border-0 cursor-pointer p-1" title="Edit Tenant">
edit
handleSuspend(org.id, org.status)} className="text-on-surface-variant hover:text-error transition-colors bg-transparent border-0 cursor-pointer p-1" title="Suspend Tenant">
{org.status === 'suspended' ? 'play_arrow' : 'pause_circle'}
handleDeleteTenant(org.id, org.name)} className="text-on-surface-variant hover:text-error transition-colors bg-transparent border-0 cursor-pointer p-1" title="Delete Tenant">
delete
>
)}
))}
)}
)}
{activeTab === 'members' && (
Global Members
Centralized user management, role assignments, and client org mapping.
{!isSupportEngineer && (
Add Member
)}
{/* 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 && (
{ setUserSearch(''); setUserPage(1); }}
className="absolute right-2.5 top-1/2 -translate-y-1/2 text-on-surface-variant hover:text-on-surface bg-transparent border-0 cursor-pointer p-0.5"
>
)}
{/* Filter by Role */}
Role:
{
setUserRoleFilter(e.target.value);
setUserPage(1);
}}
className="bg-surface border border-outline-variant/60 text-on-surface text-[13px] font-medium rounded-lg px-3 py-2 focus:outline-none focus:border-primary cursor-pointer w-full sm:w-auto"
>
All Roles
Admin
SOC Analyst
Organization Admin
Executive User
{user?.role !== 'admin' && Super Admin }
Support Engineer
Read Only
{/* Filter by Organization */}
Organization:
{
setUserOrgFilter(e.target.value);
setUserPage(1);
}}
className="bg-surface border border-outline-variant/60 text-on-surface text-[13px] font-medium rounded-lg px-3 py-2 focus:outline-none focus:border-primary cursor-pointer w-full sm:w-auto max-w-[200px] truncate"
>
All Organizations
No Org (Super Admin / Global)
{(organizations || []).map(org => (
{org.name}
))}
{/* Reset Button */}
{(userSearch || userRoleFilter !== 'all' || userOrgFilter !== 'all') && (
Reset Filters
)}
{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') && (
Clear All Filters
)}
) : (
{['Email', 'Role', 'Organization', 'Actions'].map((h, i) => (
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'}
)}
))}
{getSortedUsers().slice((userPage - 1) * userPageSize, userPage * userPageSize).map((u) => (
{u.email}
{u.role ? u.role.replace(/_/g, ' ') : 'User'}
{u.org_name}
handleEditMember(u)}
className="text-on-surface-variant hover:text-primary transition-colors bg-transparent border-0 cursor-pointer p-1"
title={isSupportEngineer ? "Edit Member Role & Organization" : "Edit Member Details & Password"}
>
{!isSupportEngineer && (
{
setConfirmModal({
isOpen: true,
title: 'Delete Member',
desc: `Are you sure you want to delete ${u.email}?`,
type: 'error',
onConfirm: async () => {
try {
const res = await authFetch(`/api/auth/users/${u.id}`, {
method: 'DELETE'
});
if (res.ok) {
toast.success('Member deleted successfully');
fetchStats();
} else {
toast.error('Failed to delete member');
}
} catch (err) {
toast.error('Network error deleting member');
}
closeConfirm();
}
});
}} className="text-on-surface-variant hover:text-error transition-colors bg-transparent border-0 cursor-pointer p-1" title="Delete Member">
)}
))}
)}
)}
{activeTab === 'audit' && (
{loading ?
Fetching logs...
: (
<>
Date & Time
Admin User
Action / Event
Organization / Target
{getFilteredAuditLogs().length === 0 ? (
No audit logs match your search.
) : (
getFilteredAuditLogs().slice((auditPage - 1) * auditPageSize, auditPage * auditPageSize).map((log) => (
{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 && (
{ setBookingSearch(''); setBookingPage(1); }}
className="absolute right-2.5 top-1/2 -translate-y-1/2 text-on-surface-variant hover:text-on-surface bg-transparent border-0 cursor-pointer p-0.5"
>
)}
Status:
{ setBookingStatusFilter(e.target.value); setBookingPage(1); }}
className="bg-surface border border-outline-variant/60 text-on-surface text-[13px] font-medium rounded-lg px-3 py-1.5 focus:outline-none focus:border-primary cursor-pointer"
>
All Statuses
Pending
Completed
Rescheduled
Cancelled
{(bookingSearch || bookingStatusFilter !== 'all') && (
{ setBookingSearch(''); setBookingStatusFilter('all'); setBookingPage(1); }}
className="text-error hover:underline text-[12.5px] font-bold flex items-center gap-1 cursor-pointer bg-transparent border-0 px-1 ml-auto md:ml-0"
>
Reset Filters
)}
{getFilteredBookings().length === 0 ? (
No demo bookings match your filter criteria.
) : (
<>
Email
Size
Date & Time
Status
Actions
{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 (
{b.email}
{b.company_size?.replace('Company Size: ', '')}
{b.meeting_date}
{b.meeting_time}
{statusLabel}
{b.status !== 'completed' && (
handleUpdateBookingStatus(b.id, 'completed')}
className="bg-green-600 text-white border-0 py-1 px-2.5 rounded font-bold cursor-pointer text-[11px] hover:bg-green-700 transition-all flex items-center gap-1 shadow-xs"
title="Mark Demo as Completed"
>
check_circle
Complete
)}
{b.status !== 'cancelled' && (
handleCancelBooking(b)}
className="bg-red-500/10 text-red-600 hover:bg-red-600 hover:text-white border border-red-500/30 py-1 px-2.5 rounded font-bold cursor-pointer text-[11px] transition-all flex items-center gap-1"
title="Mark as Cancelled or Couldn't Show Demo"
>
cancel
Cancelled
)}
handleOpenReschedule(b)}
className="bg-blue-500/10 text-blue-600 hover:bg-blue-600 hover:text-white border border-blue-500/30 py-1 px-2.5 rounded font-bold cursor-pointer text-[11px] transition-all flex items-center gap-1"
title="Reschedule Date & Time"
>
edit_calendar
Reschedule
handleDeleteBooking(b)}
className="text-on-surface-variant hover:text-red-600 border-0 bg-transparent p-1 cursor-pointer transition-colors"
title="Delete Lead"
>
delete
);
})}
>
)}
)}
{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 && (
{ setEmailSearch(''); setEmailPage(1); }} className="absolute right-2.5 top-1/2 -translate-y-1/2 text-on-surface-variant hover:text-on-surface border-0 bg-transparent cursor-pointer p-0.5">
)}
{ setEmailStatusFilter(e.target.value); setEmailPage(1); }}
className="bg-surface border border-outline-variant/60 text-on-surface text-[13px] font-medium rounded-lg px-3 py-1.5 outline-none focus:border-primary cursor-pointer"
>
All Statuses
Sent
Failed
{(emailSearch || emailStatusFilter !== 'all') && (
{ setEmailSearch(''); setEmailStatusFilter('all'); setEmailPage(1); }}
className="text-error hover:underline text-[12.5px] font-bold flex items-center gap-1 cursor-pointer bg-transparent border-0 px-1"
>
Reset
)}
{getFilteredEmails().length === 0 ? (
No emails match your filter criteria.
) : (
<>
Timestamp
Recipient
Subject
Status
{getFilteredEmails().slice((emailPage - 1) * emailPageSize, emailPage * emailPageSize).map(log => (
{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}
handleKillScan(scan.id)} className="bg-error/10 text-error border border-error/20 py-1.5 px-3 rounded font-bold cursor-pointer border-0">Terminate
))}
)}
{/* Prompt Modal */}
Cancel
promptModal.onConfirm(promptValues)} className="px-4 py-2 bg-primary text-on-primary rounded-lg font-bold border-0 cursor-pointer">Confirm
>
}
>
{promptModal.inputs.map(input => (
{input.label}
{input.type === 'select' ? (
handlePromptChange(input.key, e.target.value)}
className="bg-surface-container border border-outline-variant rounded-lg px-3 py-2 focus:border-primary outline-none text-on-surface"
>
{input.options.map(opt => {
const val = typeof opt === 'object' ? opt.value : opt;
const lbl = typeof opt === 'object' ? opt.label : opt;
return {lbl} ;
})}
) : 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"
/>
setShowPasswordPrompt(prev => ({ ...prev, [input.key]: !prev[input.key] }))}
className="absolute right-2 top-1/2 -translate-y-1/2 text-on-surface-variant hover:text-primary bg-transparent border-0 cursor-pointer p-1 flex items-center justify-center"
title={showPasswordPrompt[input.key] ? "Hide password" : "Show password"}
>
{showPasswordPrompt[input.key] ? 'visibility_off' : 'visibility'}
{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 */}
Cancel
Confirm
>
}
/>
{/* Invoice View Modal */}
setViewInvoice(null)}
title="Invoice Details"
footer={
<>
setViewInvoice(null)} className="px-4 py-2 text-on-surface-variant hover:bg-surface-container rounded-lg font-bold border-0 bg-transparent cursor-pointer">Close
{ handleDownloadInvoice(viewInvoice); setViewInvoice(null); }} className="px-4 py-2 bg-primary text-white flex items-center gap-2 rounded-lg font-bold border-0 cursor-pointer">
Download PDF
>
}
>
{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"
>
);
};
export default SuperAdminPanel;