import React, { useState, useEffect } from 'react';
import { useAuth } from '../components/AuthContext';
import { Link, useNavigate } from 'react-router-dom';
import toast from 'react-hot-toast';
import {
Users,
Shield,
Search,
Filter,
X,
Edit,
Key,
Activity,
Layers,
Mail,
Calendar,
RefreshCw,
CheckCircle2,
AlertTriangle,
Info,
Building2,
CreditCard,
Server,
Database,
HardDrive,
Eye,
Download,
Receipt,
Trash2,
CheckCircle,
XCircle,
BarChart3
} from 'lucide-react';
import { CustomModal } from '../components/CustomModal';
const parseToISODate = (str) => {
if (!str) return '';
const d = new Date(str);
if (!isNaN(d.getTime())) return d.toISOString().split('T')[0];
return '';
};
const parseToISOTime = (str) => {
if (!str) return '';
const match = str.match(/(\d+):(\d+)\s*(AM|PM)?/i);
if (match) {
let hours = parseInt(match[1], 10);
const minutes = match[2];
const ampm = match[3];
if (ampm) {
if (ampm.toUpperCase() === 'PM' && hours < 12) hours += 12;
if (ampm.toUpperCase() === 'AM' && hours === 12) hours = 0;
}
return `${String(hours).padStart(2, '0')}:${minutes}`;
}
return '';
};
const formatToReadableDate = (isoDate) => {
if (!isoDate) return '';
const [y, m, d] = isoDate.split('-');
const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
return `${months[parseInt(m, 10) - 1]} ${parseInt(d, 10)}, ${y}`;
};
const formatTo12HrTime = (isoTime) => {
if (!isoTime) return '';
const [h, m] = isoTime.split(':');
let hours = parseInt(h, 10);
const ampm = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12 || 12;
return `${String(hours).padStart(2, '0')}:${m} ${ampm}`;
};
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 MEMBER_ROLE_OPTIONS = [
{ 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' }
];
export const SupportEngineerPanel = () => {
const { user, refreshAccessToken } = useAuth();
const navigate = useNavigate();
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 [metrics, setMetrics] = useState({});
const [auditLogs, setAuditLogs] = useState([]);
const [users, setUsers] = useState([]);
const [recentPayments, setRecentPayments] = 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('supportEngineerActiveTab');
return tabFromUrl || storedTab || 'overview';
} catch (e) {
return 'overview';
}
});
useEffect(() => {
try {
localStorage.setItem('supportEngineerActiveTab', activeTab);
} catch (e) {}
}, [activeTab]);
// Billing Sorting State
const [sortBillCol, setSortBillCol] = useState('Date');
const [sortBillDir, setSortBillDir] = useState('desc');
// Table sorting states
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');
// Filter states for Bookings
const [bookingSearch, setBookingSearch] = useState('');
const [bookingStatusFilter, setBookingStatusFilter] = useState('all');
const getFilteredBookings = () => {
return (demoBookings || []).filter(b => {
const displayEmail = b.email || b.user_email || '';
const emailMatch = !bookingSearch ||
displayEmail.toLowerCase().includes(bookingSearch.toLowerCase()) ||
(b.company_size || '').toLowerCase().includes(bookingSearch.toLowerCase()) ||
(b.meeting_date || '').toLowerCase().includes(bookingSearch.toLowerCase());
const statusMatch = bookingStatusFilter === 'all' || (b.status || 'pending') === bookingStatusFilter;
return emailMatch && statusMatch;
});
};
// Pagination states
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);
// Active Scans & Invoice Modals
const [activeScansModalOpen, setActiveScansModalOpen] = useState(false);
const [activeScans, setActiveScans] = useState([]);
const [fetchingActiveScans, setFetchingActiveScans] = useState(false);
const [viewInvoice, setViewInvoice] = useState(null);
// Custom Prompt Modal state for editing member roles/orgs (without password)
const [promptModal, setPromptModal] = useState({ isOpen: false, title: '', desc: '', inputs: [], onConfirm: null });
const [promptValues, setPromptValues] = useState({});
const [confirmModal, setConfirmModal] = useState({ isOpen: false, title: '', desc: '', onConfirm: null, type: 'primary' });
const closePrompt = () => { setPromptModal({ isOpen: false, title: '', desc: '', inputs: [], onConfirm: null }); setPromptValues({}); };
const closeConfirm = () => setConfirmModal({ isOpen: false, title: '', desc: '', onConfirm: null, type: 'primary' });
const [rescheduleModal, setRescheduleModal] = useState({ isOpen: false, bookingId: null, email: '', meetingDate: '', isoDate: '', meetingTime: '', isoTime: '', status: 'rescheduled' });
const handleUpdateBookingStatus = async (bookingId, status) => {
try {
const res = await authFetch(`/api/demo/bookings/${bookingId}`, {
method: 'PUT',
headers: { '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 || booking.user_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 || booking.user_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 authFetch(`/api/demo/bookings/${rescheduleModal.bookingId}`, {
method: 'PUT',
headers: { '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.user_email) ? (booking.email || booking.user_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 authFetch(`/api/demo/bookings/${bookingId}`, {
method: 'DELETE'
});
if (res.ok) {
toast.success("Demo booking lead deleted successfully!");
fetchStats();
} else {
toast.error("Failed to delete demo lead");
}
} catch (err) {
toast.error("Error deleting lead");
}
closeConfirm();
}
});
};
const handlePromptChange = (key, value) => setPromptValues(prev => ({ ...prev, [key]: value }));
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 : []);
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("SupportEngineerPanel fetch error:", err);
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchStats();
}, []);
const openActiveScansModal = async () => {
setActiveScansModalOpen(true);
setFetchingActiveScans(true);
try {
const res = await authFetch('/api/scans/active');
if (res.ok) {
const data = await res.json();
setActiveScans(data.scans || []);
}
} catch (err) {
console.error("Error fetching active scans:", 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 authFetch(`/api/scans/${scanId}/terminate`, { method: 'POST' });
toast.success('Scan terminated successfully');
openActiveScansModal();
} catch (err) {
toast.error('Failed to terminate scan');
}
closeConfirm();
}
});
};
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: aVal = new Date(a.created_at).getTime(); bVal = new Date(b.created_at).getTime();
}
if (aVal < bVal) return sortBillDir === 'asc' ? -1 : 1;
if (aVal > bVal) return sortBillDir === 'asc' ? 1 : -1;
return 0;
});
};
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 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: aVal = a.name || ''; bVal = b.name || '';
}
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 getFilteredUsers = () => {
return (users || []).filter(u => {
const emailMatch = !userSearch || u.email?.toLowerCase().includes(userSearch.toLowerCase());
const roleMatch = userRoleFilter === 'all' || u.role === userRoleFilter;
const orgMatch = userOrgFilter === 'all' || (
userOrgFilter === 'no_org' ? !u.org_id : String(u.org_id) === String(userOrgFilter)
);
return emailMatch && roleMatch && orgMatch;
});
};
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: aVal = a.email || ''; bVal = b.email || '';
}
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 handleImpersonate = (orgId, orgName) => {
setConfirmModal({
isOpen: true,
title: 'Inspect Tenant Environment',
desc: `Log in as administrator for ${orgName} to troubleshoot customer issue?`,
type: 'primary',
onConfirm: async () => {
try {
const res = await authFetch(`/api/auth/impersonate/${orgId}`, {
method: 'POST'
});
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';
} else {
toast.error('Failed to inspect tenant environment');
}
} catch (err) {
toast.error('Network error during environment inspection');
}
closeConfirm();
}
});
};
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);
}
setPromptValues({
email: u.email,
role: u.role || 'admin',
org_id: initialOrgId
});
setPromptModal({
isOpen: true,
title: 'Edit Member Role & Organization',
desc: `Update role or organization assignment for ${u.email}`,
inputs: [
{ key: 'email', label: 'User Email', disabled: true },
{ key: 'role', label: 'Role', type: 'select', options: MEMBER_ROLE_OPTIONS },
{ key: 'org_id', label: 'Organization', type: 'select', options: orgOptions }
],
onConfirm: async (vals) => {
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
})
});
const data = await res.json().catch(() => ({}));
if (res.ok) {
toast.success('Member role & organization updated successfully');
fetchStats();
} else {
toast.error(data.message || 'Failed to update member');
}
} catch (err) {
toast.error('Network error updating member');
}
closePrompt();
}
});
};
return (
{/* Header Banner */}
Support Engineer Operations
Client environment inspection, troubleshooting assistance, and system logs.
Sync Metrics
navigate('/organization')}
className="flex items-center gap-1.5 px-3.5 py-1.5 bg-surface-container border border-outline-variant hover:bg-surface-container-high text-on-surface rounded-lg font-bold text-[12.5px] cursor-pointer transition-all shadow-2xs"
>
Org Dashboard
navigate('/super-admin/logs')}
className="flex items-center gap-1.5 px-3.5 py-1.5 bg-surface-container border border-outline-variant hover:bg-surface-container-high text-on-surface rounded-lg font-bold text-[12.5px] cursor-pointer transition-all shadow-2xs"
>
Logs & Threats
{/* Tabs Navigation (Pill Design matching screenshot) */}
{[
{ id: 'overview', label: 'Overview' },
{ id: 'organizations', label: 'Organizations' },
{ id: 'members', label: 'Members' },
{ id: 'audit', label: 'Audit Logs' },
{ id: 'bookings', label: 'Bookings' },
{ id: 'emails', label: 'Emails' }
].map(tab => (
setActiveTab(tab.id)}
className={`px-4 py-2 font-bold text-[13.5px] rounded-lg transition-all cursor-pointer border-0 ${
activeTab === tab.id
? 'bg-primary text-white shadow-sm'
: 'text-on-surface-variant hover:text-on-surface bg-transparent hover:bg-surface-container/50'
}`}
>
{tab.label}
))}
{/* OVERVIEW TAB */}
{activeTab === 'overview' && (
{/* Quick Metrics Grid */}
Total Tenants
{metrics.total_tenants || organizations.length || 0}
Active Licenses
{metrics.active_licenses || 0}
Global Users
{metrics.global_users || users.length || 0}
Active Scanners
{metrics.active_scanners || 0}/{metrics.total_scanners || 50}
{/* Infrastructure Node & System Health Cards */}
Node Infrastructure & Health
Database Cluster Connection Load
HEALTHY
Active Connections
{metrics.db_connections || 14} / 500
Celery Workers & Queue Status
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 pending
Inspect Active Scans
{/* Support Guidance Box */}
Support Engineer Operating Scope
As a Support Engineer, you have full diagnostic visibility across platform performance metrics, customer environment states, active scans, and transaction logs.
• Use the Inspect Tenant tool in Organizations tab to troubleshoot tenant issues in real-time.
• Modify client role assignments or org mappings to resolve onboarding configurations.
• Member passwords and organization creation/deletion are restricted for administrative security.
System Status: Fully Operational
Online
{/* Global Transaction & Billing History */}
Global Transactions & Invoices
{loading ? (
Fetching transaction 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}
))}
{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">
))}
)}
{/* System Audit Trail Preview */}
Recent System Audit Events
setActiveTab('audit')} className="text-primary font-bold text-[13px] hover:underline bg-transparent border-0 cursor-pointer">
View All Logs →
{loading ? (
Fetching audit logs...
) : (
Date & Time
User
Action / Event
Target
{auditLogs.length === 0 ? (
No audit logs found.
) : auditLogs.slice(0, 5).map(log => (
{new Date(log.timestamp).toLocaleString()}
{log.user_email}
{log.action}
{log.target_name || log.target_id || '-'}
))}
)}
)}
{/* ORGANIZATIONS TAB */}
{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}
))}
{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="Inspect Customer Environment / Assist Troubleshooting">
vpn_key
))}
)}
)}
{/* MEMBERS TAB */}
{activeTab === 'members' && (
Global Members (Read-Only)
Inspect user accounts, assigned roles, and organization mappings across all platform tenants.
{/* Filter & Search Bar */}
{
setUserSearch(e.target.value);
setUserPage(1);
}}
className="w-full bg-surface border border-outline-variant/60 text-on-surface text-[13px] font-medium rounded-lg pl-9 pr-8 py-2 focus:outline-none focus:border-primary placeholder:text-on-surface-variant/50"
/>
{userSearch && (
setUserSearch('')} 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">
)}
{
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
{MEMBER_ROLE_OPTIONS.map(r => (
{r.label}
))}
{
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}
))}
{(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'].map((h) => (
handleUserSort(h)}
className="px-md py-sm font-bold text-[12px] uppercase tracking-wider cursor-pointer hover:bg-surface-container-highest transition-colors group"
>
{h}
))}
{getSortedUsers().slice((userPage - 1) * userPageSize, userPage * userPageSize).map((u) => (
{u.email}
{u.role ? u.role.replace(/_/g, ' ') : 'User'}
{u.org_name}
))}
)}
)}
{/* AUDIT LOGS TAB */}
{activeTab === 'audit' && (
Global Audit Logs
{auditLogs.length === 0 ? (
No audit logs available.
) : (
<>
Timestamp
Action
User Email
Target
{auditLogs.slice((auditPage - 1) * auditPageSize, auditPage * auditPageSize).map((log) => (
{new Date(log.timestamp).toLocaleString()}
{log.action}
{log.user_email}
{log.target_name || log.target_id || '-'}
))}
>
)}
)}
{/* BOOKINGS TAB */}
{activeTab === 'bookings' && (
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' :
b.status === 'cancelled' ? 'Cancelled' :
b.status === 'rescheduled' ? 'Rescheduled' : 'Pending';
const displayEmail = b.email || b.user_email;
return (
{displayEmail}
{b.company_size ? b.company_size.replace('Company Size: ', '') : 'N/A'}
{b.meeting_date}
{b.meeting_time}
{statusLabel}
{b.status !== 'completed' && (
handleUpdateBookingStatus(b.id, 'completed')}
className="bg-primary text-white border-0 py-1.5 px-3 rounded font-bold cursor-pointer text-[11px] hover:brightness-110 transition-all flex items-center gap-1 shadow-xs"
title="Mark Demo as Completed"
>
Mark 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"
>
Cancel
)}
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"
>
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"
>
);
})}
>
)}
)}
{/* EMAILS TAB */}
{activeTab === 'emails' && (
Outbound Email Logs
{emailLogs.length === 0 ? (
No email logs available.
) : (
<>
Timestamp
Recipient
Subject
Status
{emailLogs.slice((emailPage - 1) * emailPageSize, emailPage * emailPageSize).map((log) => (
{new Date(log.sent_at).toLocaleString()}
{log.recipient}
{log.subject}
{log.status}
))}
>
)}
)}
{/* Active Scans Modal */}
setActiveScansModalOpen(false)} title="Active Scans Diagnostic">
{fetchingActiveScans ? Loading active scans...
: activeScans.length === 0 ? No active scans running right now.
: (
{activeScans.map(scan => (
{scan.target_url}
Scan ID: {scan.id} | 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 hover:bg-error/20 transition-all text-xs">
Terminate Scan
))}
)}
{/* 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}
Subscription Plan
Amount
{viewInvoice.tier_id} Plan Subscription
{viewInvoice.currency === 'INR' ? '₹' : '$'}{viewInvoice.amount.toLocaleString(undefined, { minimumFractionDigits: 2 })}
Total Amount Paid
{viewInvoice.currency === 'INR' ? '₹' : '$'}{viewInvoice.amount.toLocaleString(undefined, { minimumFractionDigits: 2 })}
)}
{/* Prompt Modal for Editing Role/Org */}
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} ;
})}
) : (
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
>
}
/>
{/* 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 SupportEngineerPanel;