larxius commited on
Commit
a3f860a
·
verified ·
1 Parent(s): df821e6

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 <div className="text-on-surface text-center mt-20 font-bold">Access Denied. You do not have LarShield Management permissions.</div>;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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({