diff --git "a/frontend/src/pages/SuperAdminPanel.jsx" "b/frontend/src/pages/SuperAdminPanel.jsx"
--- "a/frontend/src/pages/SuperAdminPanel.jsx"
+++ "b/frontend/src/pages/SuperAdminPanel.jsx"
@@ -1,1241 +1,1275 @@
-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 } from 'lucide-react';
-import toast from 'react-hot-toast';
-
-const BillingTierCard = ({ tier, onSave }) => {
- // Convert from cents (stored in DB) to dollars for UI display
- const [monthly, setMonthly] = useState((tier.monthly_price / 100).toFixed(2));
- const [yearly, setYearly] = useState((tier.yearly_price / 100).toFixed(2));
- const [saving, setSaving] = useState(false);
- const [saved, setSaved] = useState(false);
-
- const handleSave = async () => {
- setSaving(true);
- // Convert dollars back to cents before sending to API
- await onSave(tier.id, Math.round(parseFloat(monthly) * 100), Math.round(parseFloat(yearly) * 100));
- setSaving(false);
- setSaved(true);
- setTimeout(() => setSaved(false), 2000);
- };
-
- return (
-
- {/* Accent Top Border based on tier name */}
-
-
-
-
-
- {tier.name}
-
-
- {tier.id}
-
-
-
-
-
-
-
Monthly Price
-
- $
- setMonthly(e.target.value)}
- className="w-full bg-surface-container-high border border-outline-variant rounded-lg pl-8 pr-3 py-2 focus:border-primary focus:ring-1 focus:ring-primary outline-none text-on-surface font-mono font-bold transition-all"
- />
-
-
-
-
-
Yearly Price
-
- $
- setYearly(e.target.value)}
- className="w-full bg-surface-container-high border border-outline-variant rounded-lg pl-8 pr-3 py-2 focus:border-primary focus:ring-1 focus:ring-primary outline-none text-on-surface font-mono font-bold transition-all"
- />
-
-
-
-
-
-
- {saving ? (
- sync
- ) : saved ? (
- check_circle
- ) : (
- save
- )}
- {saving ? 'Saving...' : saved ? 'Saved!' : 'Save Changes'}
-
-
-
- );
-};
-
-const SuperAdminPanel = () => {
- const { user } = useAuth();
- 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('overview');
-
- const [sortOrgCol, setSortOrgCol] = useState('Tenant Name');
- const [sortOrgDir, setSortOrgDir] = useState('asc');
-
- const [sortUserCol, setSortUserCol] = useState('Email');
- const [sortUserDir, setSortUserDir] = useState('asc');
-
- const [sortBillCol, setSortBillCol] = useState('Date');
- const [sortBillDir, setSortBillDir] = useState('desc');
-
- const handleOrgSort = (column) => {
- if (column === 'Quotas' || column === 'Actions') return;
- if (sortOrgCol === column) {
- setSortOrgDir(sortOrgDir === 'asc' ? 'desc' : 'asc');
- } else {
- setSortOrgCol(column);
- setSortOrgDir('asc');
- }
- };
-
- const getSortedOrgs = () => {
- return [...organizations].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;
- });
- };
-
- const handleUserSort = (column) => {
- if (column === 'Actions') return;
- if (sortUserCol === column) {
- setSortUserDir(sortUserDir === 'asc' ? 'desc' : 'asc');
- } else {
- setSortUserCol(column);
- setSortUserDir('asc');
- }
- };
-
- const getSortedUsers = () => {
- return [...users].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 handleBillSort = (column) => {
- if (column === 'Invoice') return;
- if (sortBillCol === column) {
- setSortBillDir(sortBillDir === 'asc' ? 'desc' : 'asc');
- } else {
- setSortBillCol(column);
- setSortBillDir('asc');
- }
- };
-
- const getSortedBills = () => {
- return [...recentPayments].sort((a, b) => {
- let aVal, bVal;
- switch (sortBillCol) {
- case 'Date': aVal = new Date(a.created_at).getTime(); bVal = new Date(b.created_at).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;
- });
- };
-
- 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 token = localStorage.getItem('wss_token');
- const [globalRes, bookingsRes, emailLogsRes] = await Promise.all([
- fetch('/api/auth/global-stats', { headers: { 'Authorization': `Bearer ${token}` } }),
- fetch('/api/demo/bookings', { headers: { 'Authorization': `Bearer ${token}` } }),
- fetch('/api/auth/email-logs', { headers: { 'Authorization': `Bearer ${token}` } })
- ]);
- if (globalRes.ok) {
- const data = await globalRes.json();
- setOrganizations(data.organizations || []);
- setMetrics(data.metrics || {});
- setRecentPayments(data.recent_payments || []);
- setTrends(data.trends || []);
- setAuditLogs(data.audit_logs || []);
- setUsers(data.users || []);
- }
- if (bookingsRes.ok) {
- const data = await bookingsRes.json();
- setDemoBookings(data.bookings || []);
- }
- if (emailLogsRes.ok) {
- const data = await emailLogsRes.json();
- setEmailLogs(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 closeConfirm = () => setConfirmModal({ isOpen: false, title: '', desc: '', onConfirm: null, type: 'primary' });
- const closePrompt = () => { setPromptModal({ isOpen: false, title: '', desc: '', inputs: [], onConfirm: null }); setPromptValues({}); };
-
- 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) setTiers(await res.json());
- } catch (err) { }
- 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: 'free' });
- setPromptModal({
- isOpen: true,
- title: 'Add New Organization',
- desc: 'Create a new tenant organization.',
- inputs: [
- { key: 'name', label: 'Organization Name', placeholder: 'Enter name...' },
- { key: 'tier', label: 'Subscription Tier', placeholder: 'free, quick, standard, advanced, enterprise' }
- ],
- 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 })
- });
- if (res.ok) fetchStats();
- } catch (err) { }
- 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) => {
- 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: parseInt(values.count) })
- });
- if (res.ok) toast.success('Custom scans assigned successfully!');
- else toast.error('Failed to assign scans.');
- } catch (err) { }
- closePrompt();
- }
- });
- };
-
- const handleEditTenant = (org) => {
- setPromptValues({ name: org.name, tier: org.tier.toLowerCase() });
- setPromptModal({
- isOpen: true,
- title: 'Edit Organization',
- desc: `Modify settings for ${org.name}`,
- inputs: [
- { key: 'name', label: 'Organization Name' },
- { key: 'tier', label: 'Subscription Tier' }
- ],
- 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) fetchStats();
- } catch (err) { }
- closePrompt();
- }
- });
- };
-
- // Member CRUD
- const handleAddMember = () => {
- setPromptValues({ role: 'soc_analyst', email: '', org_id: '' });
- setPromptModal({
- isOpen: true,
- title: 'Add Global Member',
- desc: 'Invite a user to an organization.',
- inputs: [
- { key: 'email', label: 'User Email', placeholder: 'user@example.com' },
- { key: 'role', label: 'Role', placeholder: 'soc_analyst, executive, org_admin, etc' },
- { key: 'org_id', label: 'Organization ID', placeholder: 'Optional' }
- ],
- onConfirm: async (values) => {
- try {
- const res = await fetch('/api/auth/users', {
- method: 'POST',
- headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}`, 'Content-Type': 'application/json' },
- body: JSON.stringify({ email: values.email, role: values.role, org_id: values.org_id })
- });
- if (res.ok) fetchStats();
- } catch (err) { }
- 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 [viewInvoice, setViewInvoice] = useState(null);
-
- const isSupportEngineer = user?.role === 'support_engineer';
- const isSuperAdmin = user?.role === 'super_admin' || user?.role === 'admin';
-
- if (!isSuperAdmin && !isSupportEngineer) {
- return Access Denied. You do not have LarShield Management permissions.
;
- }
-
- const handleCompleteBooking = async (bookingId) => {
- 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: 'completed' })
- });
- if (res.ok) {
- toast.success("Booking marked as completed");
- fetchStats();
- } else {
- toast.error("Failed to update booking status");
- }
- } catch (err) {
- toast.error("Network error updating booking");
- }
- };
-
- 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
-
-
- stop_circle Inspect Active Scans {!isSupportEngineer && '(Kill Switch)'}
-
-
-
-
-
- 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
-
- {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().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?.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' :
- 'bg-blue-500/10 text-blue-600 border-blue-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 ml-xs" 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 ml-xs" 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 ml-xs" 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 ml-xs" title="Delete Tenant">
- delete
-
- >
- )}
-
-
- ))}
-
-
- )}
-
-
- )}
-
- {activeTab === 'members' && (
-
-
-
Global Members
- {!isSupportEngineer && (
-
Add Member
- )}
-
-
- {loading ?
Fetching users...
: (
-
-
-
- {['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().map((u) => (
-
- {u.email}
- {u.role}
- {u.org_name}
-
- {!isSupportEngineer ? (
- <>
- {
- setPromptValues({ role: u.role });
- setPromptModal({
- isOpen: true,
- title: 'Edit Member Role',
- desc: `Update role for ${u.email}`,
- inputs: [{ key: 'role', label: 'Role' }],
- onConfirm: async (vals) => {
- try {
- await fetch(`/api/auth/users/${u.id}/role`, {
- method: 'PUT',
- headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}`, 'Content-Type': 'application/json' },
- body: JSON.stringify({ role: vals.role })
- });
- fetchStats();
- } catch (err) { }
- closePrompt();
- }
- });
- }} className="text-on-surface-variant hover:text-primary transition-colors bg-transparent border-0 cursor-pointer p-1">
- {
- setConfirmModal({
- isOpen: true,
- title: 'Delete Member',
- desc: `Are you sure you want to delete ${u.email}?`,
- type: 'error',
- onConfirm: async () => {
- try {
- await fetch(`/api/auth/users/${u.id}`, {
- method: 'DELETE',
- headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}` }
- });
- fetchStats();
- } catch (err) { }
- closeConfirm();
- }
- });
- }} className="text-on-surface-variant hover:text-error transition-colors bg-transparent border-0 cursor-pointer p-1">
- >
- ) : (
- Read Only
- )}
-
-
- ))}
-
-
- )}
-
-
- )}
-
- {activeTab === 'audit' && (
-
-
history Full System Audit Logs
-
- {loading ?
Fetching logs...
: (
-
-
-
-
- Date & Time
- Admin User
- Action / Event
- Organization / Target
-
-
-
- {auditLogs.length === 0 ? No audit logs found. : auditLogs.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
-
- {demoBookings.length === 0 ? (
-
No demo bookings found.
- ) : (
-
-
-
-
- Email
- Size
- Date & Time
- Status
- Actions
-
-
-
- {demoBookings.map(b => (
-
- {b.email}
- {b.company_size.replace('Company Size: ', '')}
-
- {b.meeting_date}
- {b.meeting_time}
-
-
-
- {b.status}
-
-
-
- {b.status !== 'completed' && (
- handleCompleteBooking(b.id)} className="bg-primary text-white border-0 py-1 px-3 rounded font-bold cursor-pointer text-[12px] hover:brightness-110 active:scale-95 transition-all">
- Mark Complete
-
- )}
-
-
- ))}
-
-
-
- )}
-
-
- )}
-
- {activeTab === 'emails' && (
-
-
mail Outbound Email Logs
-
- {emailLogs.length === 0 ? (
-
No emails sent yet.
- ) : (
-
-
-
-
- Timestamp
- Recipient
- Subject
- Status
-
-
-
- {emailLogs.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 => {opt} )}
-
- ) : (
- handlePromptChange(input.key, e.target.value)}
- placeholder={input.placeholder}
- className="bg-surface-container border border-outline-variant rounded-lg px-3 py-2 focus:border-primary outline-none text-on-surface"
- />
- )}
-
- ))}
-
-
-
- {/* 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 })}
-
-
-
- )}
-
-
- );
-};
-
-export default SuperAdminPanel;
+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 } from 'lucide-react';
+import toast from 'react-hot-toast';
+
+const BillingTierCard = ({ tier, onSave }) => {
+ // Convert from cents (stored in DB) to dollars for UI display
+ const [monthly, setMonthly] = useState((tier.monthly_price / 100).toFixed(2));
+ const [yearly, setYearly] = useState((tier.yearly_price / 100).toFixed(2));
+ const [saving, setSaving] = useState(false);
+ const [saved, setSaved] = useState(false);
+
+ const handleSave = async () => {
+ setSaving(true);
+ // Convert dollars back to cents before sending to API
+ await onSave(tier.id, Math.round(parseFloat(monthly) * 100), Math.round(parseFloat(yearly) * 100));
+ setSaving(false);
+ setSaved(true);
+ setTimeout(() => setSaved(false), 2000);
+ };
+
+ return (
+
+ {/* Accent Top Border based on tier name */}
+
+
+
+
+
+ {tier.name}
+
+
+ {tier.id}
+
+
+
+
+
+
+
Monthly Price
+
+ $
+ setMonthly(e.target.value)}
+ className="w-full bg-surface-container-high border border-outline-variant rounded-lg pl-8 pr-3 py-2 focus:border-primary focus:ring-1 focus:ring-primary outline-none text-on-surface font-mono font-bold transition-all"
+ />
+
+
+
+
+
Yearly Price
+
+ $
+ setYearly(e.target.value)}
+ className="w-full bg-surface-container-high border border-outline-variant rounded-lg pl-8 pr-3 py-2 focus:border-primary focus:ring-1 focus:ring-primary outline-none text-on-surface font-mono font-bold transition-all"
+ />
+
+
+
+
+
+
+ {saving ? (
+ sync
+ ) : saved ? (
+ check_circle
+ ) : (
+ save
+ )}
+ {saving ? 'Saving...' : saved ? 'Saved!' : 'Save Changes'}
+
+
+
+ );
+};
+
+const SuperAdminPanel = () => {
+ const { user } = useAuth();
+ 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('overview');
+
+ const [sortOrgCol, setSortOrgCol] = useState('Tenant Name');
+ const [sortOrgDir, setSortOrgDir] = useState('asc');
+
+ const [sortUserCol, setSortUserCol] = useState('Email');
+ const [sortUserDir, setSortUserDir] = useState('asc');
+
+ const [sortBillCol, setSortBillCol] = useState('Date');
+ const [sortBillDir, setSortBillDir] = useState('desc');
+
+ const handleOrgSort = (column) => {
+ if (column === 'Quotas' || column === 'Actions') return;
+ if (sortOrgCol === column) {
+ setSortOrgDir(sortOrgDir === 'asc' ? 'desc' : 'asc');
+ } else {
+ setSortOrgCol(column);
+ setSortOrgDir('asc');
+ }
+ };
+
+ const getSortedOrgs = () => {
+ return [...organizations].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;
+ });
+ };
+
+ const handleUserSort = (column) => {
+ if (column === 'Actions') return;
+ if (sortUserCol === column) {
+ setSortUserDir(sortUserDir === 'asc' ? 'desc' : 'asc');
+ } else {
+ setSortUserCol(column);
+ setSortUserDir('asc');
+ }
+ };
+
+ const getSortedUsers = () => {
+ return [...users].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 handleBillSort = (column) => {
+ if (column === 'Invoice') return;
+ if (sortBillCol === column) {
+ setSortBillDir(sortBillDir === 'asc' ? 'desc' : 'asc');
+ } else {
+ setSortBillCol(column);
+ setSortBillDir('asc');
+ }
+ };
+
+ const getSortedBills = () => {
+ return [...recentPayments].sort((a, b) => {
+ let aVal, bVal;
+ switch (sortBillCol) {
+ case 'Date': aVal = new Date(a.created_at).getTime(); bVal = new Date(b.created_at).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;
+ });
+ };
+
+ 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 token = localStorage.getItem('wss_token');
+ const [globalRes, bookingsRes, emailLogsRes] = await Promise.all([
+ fetch('/api/auth/global-stats', { headers: { 'Authorization': `Bearer ${token}` } }),
+ fetch('/api/demo/bookings', { headers: { 'Authorization': `Bearer ${token}` } }),
+ fetch('/api/auth/email-logs', { headers: { 'Authorization': `Bearer ${token}` } })
+ ]);
+ if (globalRes.ok) {
+ const data = await globalRes.json();
+ setOrganizations(data.organizations || []);
+ setMetrics(data.metrics || {});
+ setRecentPayments(data.recent_payments || []);
+ setTrends(data.trends || []);
+ setAuditLogs(data.audit_logs || []);
+ setUsers(data.users || []);
+ }
+ if (bookingsRes.ok) {
+ const data = await bookingsRes.json();
+ setDemoBookings(data.bookings || []);
+ }
+ if (emailLogsRes.ok) {
+ const data = await emailLogsRes.json();
+ setEmailLogs(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 closeConfirm = () => setConfirmModal({ isOpen: false, title: '', desc: '', onConfirm: null, type: 'primary' });
+ const closePrompt = () => { setPromptModal({ isOpen: false, title: '', desc: '', inputs: [], onConfirm: null }); setPromptValues({}); };
+
+ 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) setTiers(await res.json());
+ } catch (err) { }
+ 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: 'free' });
+ setPromptModal({
+ isOpen: true,
+ title: 'Add New Organization',
+ desc: 'Create a new tenant organization.',
+ inputs: [
+ { key: 'name', label: 'Organization Name', placeholder: 'Enter name...' },
+ { key: 'tier', label: 'Subscription Tier', placeholder: 'free, quick, standard, advanced, enterprise' }
+ ],
+ 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 })
+ });
+ if (res.ok) fetchStats();
+ } catch (err) { }
+ 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) => {
+ setPromptValues({ name: org.name, tier: org.tier.toLowerCase() });
+ setPromptModal({
+ isOpen: true,
+ title: 'Edit Organization',
+ desc: `Modify settings for ${org.name}`,
+ inputs: [
+ { key: 'name', label: 'Organization Name' },
+ { key: 'tier', label: 'Subscription Tier' }
+ ],
+ 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) fetchStats();
+ } catch (err) { }
+ closePrompt();
+ }
+ });
+ };
+
+ // Member CRUD
+ const handleAddMember = () => {
+ setPromptValues({ role: 'soc_analyst', email: '', org_id: '' });
+ setPromptModal({
+ isOpen: true,
+ title: 'Add Global Member',
+ desc: 'Invite a user to an organization.',
+ inputs: [
+ { key: 'email', label: 'User Email', placeholder: 'user@example.com' },
+ { key: 'role', label: 'Role', placeholder: 'soc_analyst, executive, org_admin, etc' },
+ { key: 'org_id', label: 'Organization ID', placeholder: 'Optional' }
+ ],
+ onConfirm: async (values) => {
+ try {
+ const res = await fetch('/api/auth/users', {
+ method: 'POST',
+ headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}`, 'Content-Type': 'application/json' },
+ body: JSON.stringify({ email: values.email, role: values.role, org_id: values.org_id })
+ });
+ if (res.ok) fetchStats();
+ } catch (err) { }
+ 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 [viewInvoice, setViewInvoice] = useState(null);
+
+ const isSupportEngineer = user?.role === 'support_engineer';
+ const isSuperAdmin = user?.role === 'super_admin' || user?.role === 'admin';
+
+ if (!isSuperAdmin && !isSupportEngineer) {
+ return Access Denied. You do not have LarShield Management permissions.
;
+ }
+
+ const handleCompleteBooking = async (bookingId) => {
+ 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: 'completed' })
+ });
+ if (res.ok) {
+ toast.success("Booking marked as completed");
+ fetchStats();
+ } else {
+ toast.error("Failed to update booking status");
+ }
+ } catch (err) {
+ toast.error("Network error updating booking");
+ }
+ };
+
+ 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
+
+
+ stop_circle Inspect Active Scans {!isSupportEngineer && '(Kill Switch)'}
+
+
+
+
+
+ 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
+
+ {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().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?.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' :
+ 'bg-blue-500/10 text-blue-600 border-blue-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 ml-xs" 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 ml-xs" 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 ml-xs" 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 ml-xs" title="Delete Tenant">
+ delete
+
+ >
+ )}
+
+
+ ))}
+
+
+ )}
+
+
+ )}
+
+ {activeTab === 'members' && (
+
+
+
Global Members
+ {!isSupportEngineer && (
+
Add Member
+ )}
+
+
+ {loading ?
Fetching users...
: (
+
+
+
+ {['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().map((u) => (
+
+ {u.email}
+ {u.role}
+ {u.org_name}
+
+ {!isSupportEngineer ? (
+ <>
+ {
+ setPromptValues({ role: u.role });
+ setPromptModal({
+ isOpen: true,
+ title: 'Edit Member Role',
+ desc: `Update role for ${u.email}`,
+ inputs: [{ key: 'role', label: 'Role' }],
+ onConfirm: async (vals) => {
+ try {
+ await fetch(`/api/auth/users/${u.id}/role`, {
+ method: 'PUT',
+ headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}`, 'Content-Type': 'application/json' },
+ body: JSON.stringify({ role: vals.role })
+ });
+ fetchStats();
+ } catch (err) { }
+ closePrompt();
+ }
+ });
+ }} className="text-on-surface-variant hover:text-primary transition-colors bg-transparent border-0 cursor-pointer p-1">
+ {
+ setConfirmModal({
+ isOpen: true,
+ title: 'Delete Member',
+ desc: `Are you sure you want to delete ${u.email}?`,
+ type: 'error',
+ onConfirm: async () => {
+ try {
+ await fetch(`/api/auth/users/${u.id}`, {
+ method: 'DELETE',
+ headers: { 'Authorization': `Bearer ${localStorage.getItem('wss_token')}` }
+ });
+ fetchStats();
+ } catch (err) { }
+ closeConfirm();
+ }
+ });
+ }} className="text-on-surface-variant hover:text-error transition-colors bg-transparent border-0 cursor-pointer p-1">
+ >
+ ) : (
+ Read Only
+ )}
+
+
+ ))}
+
+
+ )}
+
+
+ )}
+
+ {activeTab === 'audit' && (
+
+
history Full System Audit Logs
+
+ {loading ?
Fetching logs...
: (
+
+
+
+
+ Date & Time
+ Admin User
+ Action / Event
+ Organization / Target
+
+
+
+ {auditLogs.length === 0 ? No audit logs found. : auditLogs.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
+
+ {demoBookings.length === 0 ? (
+
No demo bookings found.
+ ) : (
+
+
+
+
+ Email
+ Size
+ Date & Time
+ Status
+ Actions
+
+
+
+ {demoBookings.map(b => (
+
+ {b.email}
+ {b.company_size.replace('Company Size: ', '')}
+
+ {b.meeting_date}
+ {b.meeting_time}
+
+
+
+ {b.status}
+
+
+
+ {b.status !== 'completed' && (
+ handleCompleteBooking(b.id)} className="bg-primary text-white border-0 py-1 px-3 rounded font-bold cursor-pointer text-[12px] hover:brightness-110 active:scale-95 transition-all">
+ Mark Complete
+
+ )}
+
+
+ ))}
+
+
+
+ )}
+
+
+ )}
+
+ {activeTab === 'emails' && (
+
+
mail Outbound Email Logs
+
+ {emailLogs.length === 0 ? (
+
No emails sent yet.
+ ) : (
+
+
+
+
+ Timestamp
+ Recipient
+ Subject
+ Status
+
+
+
+ {emailLogs.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 => {opt} )}
+
+ ) : (
+ handlePromptChange(input.key, e.target.value)}
+ placeholder={input.placeholder}
+ className="bg-surface-container border border-outline-variant rounded-lg px-3 py-2 focus:border-primary outline-none text-on-surface"
+ />
+ )}
+
+ ))}
+
+
+
+ {/* 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 })}
+
+
+
+ )}
+
+
+ );
+};
+
+export default SuperAdminPanel;