Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Update frontend/src/pages/SuperAdminPanel.jsx
Browse files
frontend/src/pages/SuperAdminPanel.jsx
CHANGED
|
@@ -97,7 +97,7 @@ const BillingTierCard = ({ tier, onSave }) => {
|
|
| 97 |
};
|
| 98 |
|
| 99 |
const SuperAdminPanel = () => {
|
| 100 |
-
const { user, refreshAccessToken } = useAuth();
|
| 101 |
|
| 102 |
const authFetch = async (url, options = {}) => {
|
| 103 |
let activeToken = localStorage.getItem('wss_token');
|
|
@@ -148,7 +148,7 @@ const SuperAdminPanel = () => {
|
|
| 148 |
};
|
| 149 |
|
| 150 |
const getSortedOrgs = () => {
|
| 151 |
-
return [...organizations].sort((a, b) => {
|
| 152 |
let aVal, bVal;
|
| 153 |
switch (sortOrgCol) {
|
| 154 |
case 'Tenant Name': aVal = a.name || ''; bVal = b.name || ''; break;
|
|
@@ -173,7 +173,7 @@ const SuperAdminPanel = () => {
|
|
| 173 |
};
|
| 174 |
|
| 175 |
const getSortedUsers = () => {
|
| 176 |
-
return [...users].sort((a, b) => {
|
| 177 |
let aVal, bVal;
|
| 178 |
switch (sortUserCol) {
|
| 179 |
case 'Email': aVal = a.email || ''; bVal = b.email || ''; break;
|
|
@@ -198,10 +198,10 @@ const SuperAdminPanel = () => {
|
|
| 198 |
};
|
| 199 |
|
| 200 |
const getSortedBills = () => {
|
| 201 |
-
return [...recentPayments].sort((a, b) => {
|
| 202 |
let aVal, bVal;
|
| 203 |
switch (sortBillCol) {
|
| 204 |
-
case 'Date': aVal = new Date(a.created_at).getTime(); bVal = new Date(b.created_at).getTime(); break;
|
| 205 |
case 'Organization / User': aVal = a.org_name || ''; bVal = b.org_name || ''; break;
|
| 206 |
case 'Tier': aVal = a.tier_id || ''; bVal = b.tier_id || ''; break;
|
| 207 |
case 'Amount': aVal = a.amount || 0; bVal = b.amount || 0; break;
|
|
@@ -230,27 +230,32 @@ const SuperAdminPanel = () => {
|
|
| 230 |
const fetchStats = async () => {
|
| 231 |
setLoading(true);
|
| 232 |
try {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 233 |
const [globalRes, bookingsRes, emailLogsRes] = await Promise.all([
|
| 234 |
authFetch('/api/auth/global-stats'),
|
| 235 |
authFetch('/api/demo/bookings'),
|
| 236 |
authFetch('/api/auth/email-logs')
|
| 237 |
]);
|
| 238 |
-
if (globalRes.ok) {
|
| 239 |
const data = await globalRes.json();
|
| 240 |
-
setOrganizations(data.organizations
|
| 241 |
setMetrics(data.metrics || {});
|
| 242 |
-
setRecentPayments(data.recent_payments
|
| 243 |
-
setTrends(data.trends
|
| 244 |
-
setAuditLogs(data.audit_logs
|
| 245 |
-
setUsers(data.users
|
| 246 |
}
|
| 247 |
-
if (bookingsRes.ok) {
|
| 248 |
const data = await bookingsRes.json();
|
| 249 |
-
setDemoBookings(data.bookings
|
| 250 |
}
|
| 251 |
-
if (emailLogsRes.ok) {
|
| 252 |
const data = await emailLogsRes.json();
|
| 253 |
-
setEmailLogs(data.logs
|
| 254 |
}
|
| 255 |
} catch (err) {
|
| 256 |
console.error('Failed to fetch global stats', err);
|
|
@@ -583,10 +588,39 @@ const SuperAdminPanel = () => {
|
|
| 583 |
const [viewInvoice, setViewInvoice] = useState(null);
|
| 584 |
|
| 585 |
const isSupportEngineer = user?.role === 'support_engineer';
|
| 586 |
-
const isSuperAdmin = user?.role === 'super_admin' || user?.role === 'admin';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 587 |
|
| 588 |
if (!isSuperAdmin && !isSupportEngineer) {
|
| 589 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 590 |
}
|
| 591 |
|
| 592 |
const [rescheduleModal, setRescheduleModal] = useState({
|
|
|
|
| 97 |
};
|
| 98 |
|
| 99 |
const SuperAdminPanel = () => {
|
| 100 |
+
const { user, refreshAccessToken, loading: authLoading } = useAuth();
|
| 101 |
|
| 102 |
const authFetch = async (url, options = {}) => {
|
| 103 |
let activeToken = localStorage.getItem('wss_token');
|
|
|
|
| 148 |
};
|
| 149 |
|
| 150 |
const getSortedOrgs = () => {
|
| 151 |
+
return [...(organizations || [])].sort((a, b) => {
|
| 152 |
let aVal, bVal;
|
| 153 |
switch (sortOrgCol) {
|
| 154 |
case 'Tenant Name': aVal = a.name || ''; bVal = b.name || ''; break;
|
|
|
|
| 173 |
};
|
| 174 |
|
| 175 |
const getSortedUsers = () => {
|
| 176 |
+
return [...(users || [])].sort((a, b) => {
|
| 177 |
let aVal, bVal;
|
| 178 |
switch (sortUserCol) {
|
| 179 |
case 'Email': aVal = a.email || ''; bVal = b.email || ''; break;
|
|
|
|
| 198 |
};
|
| 199 |
|
| 200 |
const getSortedBills = () => {
|
| 201 |
+
return [...(recentPayments || [])].sort((a, b) => {
|
| 202 |
let aVal, bVal;
|
| 203 |
switch (sortBillCol) {
|
| 204 |
+
case 'Date': aVal = new Date(a.created_at || Date.now()).getTime(); bVal = new Date(b.created_at || Date.now()).getTime(); break;
|
| 205 |
case 'Organization / User': aVal = a.org_name || ''; bVal = b.org_name || ''; break;
|
| 206 |
case 'Tier': aVal = a.tier_id || ''; bVal = b.tier_id || ''; break;
|
| 207 |
case 'Amount': aVal = a.amount || 0; bVal = b.amount || 0; break;
|
|
|
|
| 230 |
const fetchStats = async () => {
|
| 231 |
setLoading(true);
|
| 232 |
try {
|
| 233 |
+
const activeToken = localStorage.getItem('wss_token');
|
| 234 |
+
if (!activeToken) {
|
| 235 |
+
setLoading(false);
|
| 236 |
+
return;
|
| 237 |
+
}
|
| 238 |
const [globalRes, bookingsRes, emailLogsRes] = await Promise.all([
|
| 239 |
authFetch('/api/auth/global-stats'),
|
| 240 |
authFetch('/api/demo/bookings'),
|
| 241 |
authFetch('/api/auth/email-logs')
|
| 242 |
]);
|
| 243 |
+
if (globalRes && globalRes.ok) {
|
| 244 |
const data = await globalRes.json();
|
| 245 |
+
setOrganizations(Array.isArray(data.organizations) ? data.organizations : []);
|
| 246 |
setMetrics(data.metrics || {});
|
| 247 |
+
setRecentPayments(Array.isArray(data.recent_payments) ? data.recent_payments : []);
|
| 248 |
+
setTrends(Array.isArray(data.trends) ? data.trends : []);
|
| 249 |
+
setAuditLogs(Array.isArray(data.audit_logs) ? data.audit_logs : []);
|
| 250 |
+
setUsers(Array.isArray(data.users) ? data.users : []);
|
| 251 |
}
|
| 252 |
+
if (bookingsRes && bookingsRes.ok) {
|
| 253 |
const data = await bookingsRes.json();
|
| 254 |
+
setDemoBookings(Array.isArray(data.bookings) ? data.bookings : []);
|
| 255 |
}
|
| 256 |
+
if (emailLogsRes && emailLogsRes.ok) {
|
| 257 |
const data = await emailLogsRes.json();
|
| 258 |
+
setEmailLogs(Array.isArray(data.logs) ? data.logs : []);
|
| 259 |
}
|
| 260 |
} catch (err) {
|
| 261 |
console.error('Failed to fetch global stats', err);
|
|
|
|
| 588 |
const [viewInvoice, setViewInvoice] = useState(null);
|
| 589 |
|
| 590 |
const isSupportEngineer = user?.role === 'support_engineer';
|
| 591 |
+
const isSuperAdmin = user?.role === 'super_admin' || user?.role === 'admin' || sessionStorage.getItem('superAdminAuth') === 'true';
|
| 592 |
+
|
| 593 |
+
if (authLoading) {
|
| 594 |
+
return (
|
| 595 |
+
<div className="flex h-[70vh] items-center justify-center">
|
| 596 |
+
<div className="flex flex-col items-center gap-3">
|
| 597 |
+
<span className="material-symbols-outlined animate-spin text-3xl text-primary">sync</span>
|
| 598 |
+
<span className="font-bold text-on-surface-variant text-sm">Verifying Management Session...</span>
|
| 599 |
+
</div>
|
| 600 |
+
</div>
|
| 601 |
+
);
|
| 602 |
+
}
|
| 603 |
|
| 604 |
if (!isSuperAdmin && !isSupportEngineer) {
|
| 605 |
+
return (
|
| 606 |
+
<div className="min-h-[60vh] flex flex-col items-center justify-center text-center p-6">
|
| 607 |
+
<div className="w-16 h-16 rounded-full bg-red-500/10 text-error flex items-center justify-center mb-4">
|
| 608 |
+
<span className="material-symbols-outlined text-3xl">lock</span>
|
| 609 |
+
</div>
|
| 610 |
+
<h2 className="text-xl font-bold text-on-surface mb-2">Access Restricted</h2>
|
| 611 |
+
<p className="text-on-surface-variant text-sm max-w-md mb-6 leading-relaxed">
|
| 612 |
+
You do not have administrative permissions to access LarShield Global Management.
|
| 613 |
+
</p>
|
| 614 |
+
<div className="flex gap-3">
|
| 615 |
+
<Link to="/dashboard" className="px-4 py-2 bg-primary text-white rounded-lg font-bold text-sm no-underline shadow-md">
|
| 616 |
+
Go to Dashboard
|
| 617 |
+
</Link>
|
| 618 |
+
<Link to="/larshield-superadmin" className="px-4 py-2 bg-surface-container border border-outline-variant text-on-surface rounded-lg font-bold text-sm no-underline">
|
| 619 |
+
Super Admin Login
|
| 620 |
+
</Link>
|
| 621 |
+
</div>
|
| 622 |
+
</div>
|
| 623 |
+
);
|
| 624 |
}
|
| 625 |
|
| 626 |
const [rescheduleModal, setRescheduleModal] = useState({
|