larxius commited on
Commit
e27309a
·
verified ·
1 Parent(s): b0bcbf0

Update frontend/src/pages/SuperAdminPanel.jsx

Browse files
Files changed (1) hide show
  1. frontend/src/pages/SuperAdminPanel.jsx +258 -136
frontend/src/pages/SuperAdminPanel.jsx CHANGED
@@ -12,6 +12,78 @@ const DEFAULT_BILLING_TIERS = [
12
  { id: 'enterprise', name: 'Custom Solutions', badge: 'ENTERPRISE', monthly_price: 0, yearly_price: 0 }
13
  ];
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  const BillingTierCard = ({ tier, onSave }) => {
16
  const [monthly, setMonthly] = useState(((tier.monthly_price || 0) / 100).toFixed(2));
17
  const [yearly, setYearly] = useState(((tier.yearly_price || 0) / 100).toFixed(2));
@@ -238,6 +310,22 @@ const SuperAdminPanel = () => {
238
  const [sortBillCol, setSortBillCol] = useState('Date');
239
  const [sortBillDir, setSortBillDir] = useState('desc');
240
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  const handleOrgSort = (column) => {
242
  if (column === 'Quotas' || column === 'Actions') return;
243
  if (sortOrgCol === column) {
@@ -1234,7 +1322,7 @@ const SuperAdminPanel = () => {
1234
  </tr>
1235
  </thead>
1236
  <tbody className="divide-y divide-outline-variant">
1237
- {getSortedOrgs().map((org) => (
1238
  <tr key={org.id} className="hover:bg-surface-container transition-colors group">
1239
  <td className="px-md py-sm"><div className="font-bold text-on-surface text-[14px]">{org.name}</div></td>
1240
  <td className="px-md py-sm"><span className="px-2 py-0.5 rounded border text-[11px] font-bold tracking-wide bg-surface-container-high border-outline-variant text-on-surface-variant">{org.tier || org.subscription_tier}</span></td>
@@ -1281,6 +1369,13 @@ const SuperAdminPanel = () => {
1281
  </tbody>
1282
  </table>
1283
  )}
 
 
 
 
 
 
 
1284
  </div>
1285
  </div>
1286
  )}
@@ -1317,7 +1412,7 @@ const SuperAdminPanel = () => {
1317
  </tr>
1318
  </thead>
1319
  <tbody className="divide-y divide-outline-variant">
1320
- {getSortedUsers().map((u) => (
1321
  <tr key={u.id} className="hover:bg-surface-container transition-colors group">
1322
  <td className="px-md py-sm font-bold text-on-surface text-[14px]">{u.email}</td>
1323
  <td className="px-md py-sm"><span className="px-2 py-0.5 rounded border text-[11px] font-bold tracking-wide bg-surface-container-high border-outline-variant text-on-surface-variant">{u.role}</span></td>
@@ -1354,6 +1449,13 @@ const SuperAdminPanel = () => {
1354
  </tbody>
1355
  </table>
1356
  )}
 
 
 
 
 
 
 
1357
  </div>
1358
  </div>
1359
  )}
@@ -1363,30 +1465,39 @@ const SuperAdminPanel = () => {
1363
  <h2 className="font-headline-sm font-bold text-on-surface flex items-center text-[18px] mb-md"><span className="material-symbols-outlined text-primary mr-2">history</span> Full System Audit Logs</h2>
1364
  <div className="bg-surface-container-lowest border border-outline-variant rounded-2xl overflow-hidden shadow-sm">
1365
  {loading ? <div className="p-10 text-center text-on-surface-variant">Fetching logs...</div> : (
1366
- <div className="overflow-x-auto">
1367
- <table className="w-full text-left text-sm border-collapse">
1368
- <thead className="bg-surface-container text-on-surface-variant border-b border-outline-variant">
1369
- <tr>
1370
- <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Date & Time</th>
1371
- <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Admin User</th>
1372
- <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Action / Event</th>
1373
- <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Organization / Target</th>
1374
- </tr>
1375
- </thead>
1376
- <tbody className="divide-y divide-outline-variant">
1377
- {auditLogs.length === 0 ? <tr><td colSpan="4" className="p-10 text-center text-on-surface-variant">No audit logs found.</td></tr> : auditLogs.map((log) => (
1378
- <tr key={log.id} className="hover:bg-surface-container transition-colors">
1379
- <td className="px-md py-sm text-[13px] text-on-surface-variant">{new Date(log.created_at || log.timestamp).toLocaleString()}</td>
1380
- <td className="px-md py-sm"><div className="font-bold text-on-surface text-[13px]">{log.user_email}</div></td>
1381
- <td className="px-md py-sm text-[13px] text-on-surface-variant font-medium">
1382
- {log.action.includes('Terminated') ? <span className="text-error font-bold">{log.action}</span> : log.action}
1383
- </td>
1384
- <td className="px-md py-sm font-bold text-[13px] text-on-surface">{log.target_name || log.target_id || '-'}</td>
1385
  </tr>
1386
- ))}
1387
- </tbody>
1388
- </table>
1389
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1390
  )}
1391
  </div>
1392
  </div>
@@ -1399,98 +1510,100 @@ const SuperAdminPanel = () => {
1399
  {demoBookings.length === 0 ? (
1400
  <div className="p-xl text-center text-on-surface-variant font-bold">No demo bookings found.</div>
1401
  ) : (
1402
- <div className="overflow-x-auto">
1403
- <table className="w-full text-left border-collapse">
1404
- <thead className="bg-surface-container-lowest border-b border-outline-variant">
1405
- <tr>
1406
- <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Email</th>
1407
- <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Size</th>
1408
- <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Date & Time</th>
1409
- <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Status</th>
1410
- <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Actions</th>
1411
- </tr>
1412
- </thead>
1413
- <tbody className="divide-y divide-outline-variant">
1414
- {demoBookings.map(b => {
1415
- const statusStyle =
1416
- b.status === 'completed'
1417
- ? 'bg-green-500/10 text-green-600 border-green-500/30'
1418
- : b.status === 'cancelled'
1419
- ? 'bg-red-500/10 text-red-600 border-red-500/30'
1420
- : b.status === 'rescheduled'
1421
- ? 'bg-blue-500/10 text-blue-600 border-blue-500/30'
1422
- : 'bg-orange-500/10 text-orange-600 border-orange-500/30';
1423
-
1424
- const statusLabel =
1425
- b.status === 'completed' ? 'Completed / Conducted' :
1426
- b.status === 'cancelled' ? 'Cancelled / Not Conducted' :
1427
- b.status === 'rescheduled' ? 'Rescheduled' : 'Pending';
1428
-
1429
- return (
1430
- <tr key={b.id} className="hover:bg-surface-container-lowest transition-colors">
1431
- <td className="px-md py-sm font-bold text-on-surface text-[13px]">{b.email}</td>
1432
- <td className="px-md py-sm text-on-surface-variant text-[13px]">{b.company_size?.replace('Company Size: ', '')}</td>
1433
- <td className="px-md py-sm text-on-surface-variant text-[13px]">
1434
- {b.meeting_date} <br/>
1435
- <span className="text-[11px] font-bold text-primary">{b.meeting_time}</span>
1436
- </td>
1437
- <td className="px-md py-sm">
1438
- <span className={`px-2.5 py-1 rounded-full text-[11px] font-bold uppercase tracking-wider border ${statusStyle}`}>
1439
- {statusLabel}
1440
- </span>
1441
- </td>
1442
- <td className="px-md py-sm">
1443
- <div className="flex items-center gap-1.5 flex-wrap">
1444
- {/* Complete Button */}
1445
- {b.status !== 'completed' && (
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1446
  <button
1447
- onClick={() => handleUpdateBookingStatus(b.id, 'completed')}
1448
- className="bg-green-600 text-white border-0 py-1 px-2.5 rounded font-bold cursor-pointer text-[11px] hover:bg-green-700 transition-all flex items-center gap-1 shadow-xs"
1449
- title="Mark Demo as Completed"
1450
  >
1451
- <span className="material-symbols-outlined text-[14px]">check_circle</span>
1452
- Complete
1453
  </button>
1454
- )}
1455
-
1456
- {/* Cancel / Couldn't Conduct Button */}
1457
- {b.status !== 'cancelled' && (
1458
  <button
1459
- onClick={() => handleCancelBooking(b)}
1460
- 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"
1461
- title="Mark as Cancelled or Couldn't Show Demo"
1462
  >
1463
- <span className="material-symbols-outlined text-[14px]">cancel</span>
1464
- Cancelled
1465
  </button>
1466
- )}
1467
-
1468
- {/* Reschedule Button */}
1469
- <button
1470
- onClick={() => handleOpenReschedule(b)}
1471
- 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"
1472
- title="Reschedule Date & Time"
1473
- >
1474
- <span className="material-symbols-outlined text-[14px]">edit_calendar</span>
1475
- Reschedule
1476
- </button>
1477
-
1478
- {/* Delete Lead Button */}
1479
- <button
1480
- onClick={() => handleDeleteBooking(b)}
1481
- className="text-on-surface-variant hover:text-red-600 border-0 bg-transparent p-1 cursor-pointer transition-colors"
1482
- title="Delete Lead"
1483
- >
1484
- <span className="material-symbols-outlined text-[16px]">delete</span>
1485
- </button>
1486
- </div>
1487
- </td>
1488
- </tr>
1489
- );
1490
- })}
1491
- </tbody>
1492
- </table>
1493
- </div>
1494
  )}
1495
  </div>
1496
  </div>
@@ -1503,32 +1616,41 @@ const SuperAdminPanel = () => {
1503
  {emailLogs.length === 0 ? (
1504
  <div className="p-xl text-center text-on-surface-variant font-bold">No emails sent yet.</div>
1505
  ) : (
1506
- <div className="overflow-x-auto">
1507
- <table className="w-full text-left border-collapse">
1508
- <thead className="bg-surface-container-lowest border-b border-outline-variant">
1509
- <tr>
1510
- <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Timestamp</th>
1511
- <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Recipient</th>
1512
- <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Subject</th>
1513
- <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Status</th>
1514
- </tr>
1515
- </thead>
1516
- <tbody className="divide-y divide-outline-variant">
1517
- {emailLogs.map(log => (
1518
- <tr key={log.id} className="hover:bg-surface-container-lowest transition-colors">
1519
- <td className="px-md py-sm text-on-surface-variant text-[13px]">{new Date(log.sent_at).toLocaleString()}</td>
1520
- <td className="px-md py-sm font-bold text-on-surface text-[13px]">{log.recipient}</td>
1521
- <td className="px-md py-sm text-on-surface-variant text-[13px]">{log.subject}</td>
1522
- <td className="px-md py-sm">
1523
- <span className={`px-2 py-0.5 rounded text-[11px] font-bold uppercase tracking-wider ${log.status === 'sent' ? 'bg-green-500/10 text-green-600' : 'bg-red-500/10 text-red-600'}`}>
1524
- {log.status}
1525
- </span>
1526
- </td>
1527
  </tr>
1528
- ))}
1529
- </tbody>
1530
- </table>
1531
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1532
  )}
1533
  </div>
1534
  </div>
 
12
  { id: 'enterprise', name: 'Custom Solutions', badge: 'ENTERPRISE', monthly_price: 0, yearly_price: 0 }
13
  ];
14
 
15
+ const TablePagination = ({ currentPage, totalEntries, pageSize, onPageChange, onPageSizeChange }) => {
16
+ const totalPages = Math.ceil(totalEntries / pageSize) || 1;
17
+ const validCurrentPage = Math.min(Math.max(1, currentPage), totalPages);
18
+ const startIndex = (validCurrentPage - 1) * pageSize;
19
+ const endIndex = Math.min(startIndex + pageSize, totalEntries);
20
+
21
+ return (
22
+ <div className="p-4 border-t border-outline-variant/60 bg-surface-container-lowest flex flex-col sm:flex-row items-center justify-between gap-3 text-[13px] text-on-surface-variant">
23
+ <div className="flex items-center gap-2">
24
+ <span className="font-medium">Rows per page:</span>
25
+ <select
26
+ value={pageSize}
27
+ onChange={(e) => {
28
+ onPageSizeChange(Number(e.target.value));
29
+ onPageChange(1);
30
+ }}
31
+ 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"
32
+ >
33
+ <option value={10}>10</option>
34
+ <option value={25}>25</option>
35
+ <option value={50}>50</option>
36
+ <option value={100}>100</option>
37
+ </select>
38
+ <span className="ml-2 font-medium">
39
+ {totalEntries === 0 ? '0 of 0 records' : `${startIndex + 1} - ${endIndex} of ${totalEntries} records`}
40
+ </span>
41
+ </div>
42
+
43
+ <div className="flex items-center gap-1.5">
44
+ <button
45
+ onClick={() => onPageChange(Math.max(1, validCurrentPage - 1))}
46
+ disabled={validCurrentPage === 1}
47
+ 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"
48
+ >
49
+ Previous
50
+ </button>
51
+
52
+ <div className="flex items-center gap-1 px-1">
53
+ {Array.from({ length: totalPages }, (_, i) => i + 1)
54
+ .filter(p => p === 1 || p === totalPages || Math.abs(p - validCurrentPage) <= 1)
55
+ .map((page, idx, arr) => {
56
+ const prev = arr[idx - 1];
57
+ return (
58
+ <React.Fragment key={page}>
59
+ {prev && page - prev > 1 && <span className="px-1 text-on-surface-variant text-[12px]">...</span>}
60
+ <button
61
+ onClick={() => onPageChange(page)}
62
+ className={`w-7 h-7 rounded-lg text-[12px] font-bold transition-colors cursor-pointer ${
63
+ validCurrentPage === page
64
+ ? 'bg-primary text-on-primary shadow-2xs'
65
+ : 'bg-surface hover:bg-surface-container-high border border-outline-variant/60 text-on-surface'
66
+ }`}
67
+ >
68
+ {page}
69
+ </button>
70
+ </React.Fragment>
71
+ );
72
+ })}
73
+ </div>
74
+
75
+ <button
76
+ onClick={() => onPageChange(Math.min(totalPages, validCurrentPage + 1))}
77
+ disabled={validCurrentPage >= totalPages}
78
+ 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"
79
+ >
80
+ Next
81
+ </button>
82
+ </div>
83
+ </div>
84
+ );
85
+ };
86
+
87
  const BillingTierCard = ({ tier, onSave }) => {
88
  const [monthly, setMonthly] = useState(((tier.monthly_price || 0) / 100).toFixed(2));
89
  const [yearly, setYearly] = useState(((tier.yearly_price || 0) / 100).toFixed(2));
 
310
  const [sortBillCol, setSortBillCol] = useState('Date');
311
  const [sortBillDir, setSortBillDir] = useState('desc');
312
 
313
+ // Pagination state for SuperAdmin tables
314
+ const [orgPage, setOrgPage] = useState(1);
315
+ const [orgPageSize, setOrgPageSize] = useState(25);
316
+
317
+ const [userPage, setUserPage] = useState(1);
318
+ const [userPageSize, setUserPageSize] = useState(25);
319
+
320
+ const [auditPage, setAuditPage] = useState(1);
321
+ const [auditPageSize, setAuditPageSize] = useState(25);
322
+
323
+ const [bookingPage, setBookingPage] = useState(1);
324
+ const [bookingPageSize, setBookingPageSize] = useState(25);
325
+
326
+ const [emailPage, setEmailPage] = useState(1);
327
+ const [emailPageSize, setEmailPageSize] = useState(25);
328
+
329
  const handleOrgSort = (column) => {
330
  if (column === 'Quotas' || column === 'Actions') return;
331
  if (sortOrgCol === column) {
 
1322
  </tr>
1323
  </thead>
1324
  <tbody className="divide-y divide-outline-variant">
1325
+ {getSortedOrgs().slice((orgPage - 1) * orgPageSize, orgPage * orgPageSize).map((org) => (
1326
  <tr key={org.id} className="hover:bg-surface-container transition-colors group">
1327
  <td className="px-md py-sm"><div className="font-bold text-on-surface text-[14px]">{org.name}</div></td>
1328
  <td className="px-md py-sm"><span className="px-2 py-0.5 rounded border text-[11px] font-bold tracking-wide bg-surface-container-high border-outline-variant text-on-surface-variant">{org.tier || org.subscription_tier}</span></td>
 
1369
  </tbody>
1370
  </table>
1371
  )}
1372
+ <TablePagination
1373
+ currentPage={orgPage}
1374
+ totalEntries={getSortedOrgs().length}
1375
+ pageSize={orgPageSize}
1376
+ onPageChange={setOrgPage}
1377
+ onPageSizeChange={setOrgPageSize}
1378
+ />
1379
  </div>
1380
  </div>
1381
  )}
 
1412
  </tr>
1413
  </thead>
1414
  <tbody className="divide-y divide-outline-variant">
1415
+ {getSortedUsers().slice((userPage - 1) * userPageSize, userPage * userPageSize).map((u) => (
1416
  <tr key={u.id} className="hover:bg-surface-container transition-colors group">
1417
  <td className="px-md py-sm font-bold text-on-surface text-[14px]">{u.email}</td>
1418
  <td className="px-md py-sm"><span className="px-2 py-0.5 rounded border text-[11px] font-bold tracking-wide bg-surface-container-high border-outline-variant text-on-surface-variant">{u.role}</span></td>
 
1449
  </tbody>
1450
  </table>
1451
  )}
1452
+ <TablePagination
1453
+ currentPage={userPage}
1454
+ totalEntries={getSortedUsers().length}
1455
+ pageSize={userPageSize}
1456
+ onPageChange={setUserPage}
1457
+ onPageSizeChange={setUserPageSize}
1458
+ />
1459
  </div>
1460
  </div>
1461
  )}
 
1465
  <h2 className="font-headline-sm font-bold text-on-surface flex items-center text-[18px] mb-md"><span className="material-symbols-outlined text-primary mr-2">history</span> Full System Audit Logs</h2>
1466
  <div className="bg-surface-container-lowest border border-outline-variant rounded-2xl overflow-hidden shadow-sm">
1467
  {loading ? <div className="p-10 text-center text-on-surface-variant">Fetching logs...</div> : (
1468
+ <>
1469
+ <div className="overflow-x-auto">
1470
+ <table className="w-full text-left text-sm border-collapse">
1471
+ <thead className="bg-surface-container text-on-surface-variant border-b border-outline-variant">
1472
+ <tr>
1473
+ <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Date & Time</th>
1474
+ <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Admin User</th>
1475
+ <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Action / Event</th>
1476
+ <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Organization / Target</th>
 
 
 
 
 
 
 
 
 
 
1477
  </tr>
1478
+ </thead>
1479
+ <tbody className="divide-y divide-outline-variant">
1480
+ {auditLogs.length === 0 ? <tr><td colSpan="4" className="p-10 text-center text-on-surface-variant">No audit logs found.</td></tr> : auditLogs.slice((auditPage - 1) * auditPageSize, auditPage * auditPageSize).map((log) => (
1481
+ <tr key={log.id} className="hover:bg-surface-container transition-colors">
1482
+ <td className="px-md py-sm text-[13px] text-on-surface-variant">{new Date(log.created_at || log.timestamp).toLocaleString()}</td>
1483
+ <td className="px-md py-sm"><div className="font-bold text-on-surface text-[13px]">{log.user_email}</div></td>
1484
+ <td className="px-md py-sm text-[13px] text-on-surface-variant font-medium">
1485
+ {log.action.includes('Terminated') ? <span className="text-error font-bold">{log.action}</span> : log.action}
1486
+ </td>
1487
+ <td className="px-md py-sm font-bold text-[13px] text-on-surface">{log.target_name || log.target_id || '-'}</td>
1488
+ </tr>
1489
+ ))}
1490
+ </tbody>
1491
+ </table>
1492
+ </div>
1493
+ <TablePagination
1494
+ currentPage={auditPage}
1495
+ totalEntries={auditLogs.length}
1496
+ pageSize={auditPageSize}
1497
+ onPageChange={setAuditPage}
1498
+ onPageSizeChange={setAuditPageSize}
1499
+ />
1500
+ </>
1501
  )}
1502
  </div>
1503
  </div>
 
1510
  {demoBookings.length === 0 ? (
1511
  <div className="p-xl text-center text-on-surface-variant font-bold">No demo bookings found.</div>
1512
  ) : (
1513
+ <>
1514
+ <div className="overflow-x-auto">
1515
+ <table className="w-full text-left border-collapse">
1516
+ <thead className="bg-surface-container-lowest border-b border-outline-variant">
1517
+ <tr>
1518
+ <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Email</th>
1519
+ <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Size</th>
1520
+ <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Date & Time</th>
1521
+ <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Status</th>
1522
+ <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Actions</th>
1523
+ </tr>
1524
+ </thead>
1525
+ <tbody className="divide-y divide-outline-variant">
1526
+ {demoBookings.slice((bookingPage - 1) * bookingPageSize, bookingPage * bookingPageSize).map(b => {
1527
+ const statusStyle =
1528
+ b.status === 'completed'
1529
+ ? 'bg-green-500/10 text-green-600 border-green-500/30'
1530
+ : b.status === 'cancelled'
1531
+ ? 'bg-red-500/10 text-red-600 border-red-500/30'
1532
+ : b.status === 'rescheduled'
1533
+ ? 'bg-blue-500/10 text-blue-600 border-blue-500/30'
1534
+ : 'bg-orange-500/10 text-orange-600 border-orange-500/30';
1535
+
1536
+ const statusLabel =
1537
+ b.status === 'completed' ? 'Completed / Conducted' :
1538
+ b.status === 'cancelled' ? 'Cancelled / Not Conducted' :
1539
+ b.status === 'rescheduled' ? 'Rescheduled' : 'Pending';
1540
+
1541
+ return (
1542
+ <tr key={b.id} className="hover:bg-surface-container-lowest transition-colors">
1543
+ <td className="px-md py-sm font-bold text-on-surface text-[13px]">{b.email}</td>
1544
+ <td className="px-md py-sm text-on-surface-variant text-[13px]">{b.company_size?.replace('Company Size: ', '')}</td>
1545
+ <td className="px-md py-sm text-on-surface-variant text-[13px]">
1546
+ {b.meeting_date} <br/>
1547
+ <span className="text-[11px] font-bold text-primary">{b.meeting_time}</span>
1548
+ </td>
1549
+ <td className="px-md py-sm">
1550
+ <span className={`px-2.5 py-1 rounded-full text-[11px] font-bold uppercase tracking-wider border ${statusStyle}`}>
1551
+ {statusLabel}
1552
+ </span>
1553
+ </td>
1554
+ <td className="px-md py-sm">
1555
+ <div className="flex items-center gap-1.5 flex-wrap">
1556
+ {b.status !== 'completed' && (
1557
+ <button
1558
+ onClick={() => handleUpdateBookingStatus(b.id, 'completed')}
1559
+ className="bg-green-600 text-white border-0 py-1 px-2.5 rounded font-bold cursor-pointer text-[11px] hover:bg-green-700 transition-all flex items-center gap-1 shadow-xs"
1560
+ title="Mark Demo as Completed"
1561
+ >
1562
+ <span className="material-symbols-outlined text-[14px]">check_circle</span>
1563
+ Complete
1564
+ </button>
1565
+ )}
1566
+ {b.status !== 'cancelled' && (
1567
+ <button
1568
+ onClick={() => handleCancelBooking(b)}
1569
+ 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"
1570
+ title="Mark as Cancelled or Couldn't Show Demo"
1571
+ >
1572
+ <span className="material-symbols-outlined text-[14px]">cancel</span>
1573
+ Cancelled
1574
+ </button>
1575
+ )}
1576
  <button
1577
+ onClick={() => handleOpenReschedule(b)}
1578
+ 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"
1579
+ title="Reschedule Date & Time"
1580
  >
1581
+ <span className="material-symbols-outlined text-[14px]">edit_calendar</span>
1582
+ Reschedule
1583
  </button>
 
 
 
 
1584
  <button
1585
+ onClick={() => handleDeleteBooking(b)}
1586
+ className="text-on-surface-variant hover:text-red-600 border-0 bg-transparent p-1 cursor-pointer transition-colors"
1587
+ title="Delete Lead"
1588
  >
1589
+ <span className="material-symbols-outlined text-[16px]">delete</span>
 
1590
  </button>
1591
+ </div>
1592
+ </td>
1593
+ </tr>
1594
+ );
1595
+ })}
1596
+ </tbody>
1597
+ </table>
1598
+ </div>
1599
+ <TablePagination
1600
+ currentPage={bookingPage}
1601
+ totalEntries={demoBookings.length}
1602
+ pageSize={bookingPageSize}
1603
+ onPageChange={setBookingPage}
1604
+ onPageSizeChange={setBookingPageSize}
1605
+ />
1606
+ </>
 
 
 
 
 
 
 
 
 
 
 
 
1607
  )}
1608
  </div>
1609
  </div>
 
1616
  {emailLogs.length === 0 ? (
1617
  <div className="p-xl text-center text-on-surface-variant font-bold">No emails sent yet.</div>
1618
  ) : (
1619
+ <>
1620
+ <div className="overflow-x-auto">
1621
+ <table className="w-full text-left border-collapse">
1622
+ <thead className="bg-surface-container-lowest border-b border-outline-variant">
1623
+ <tr>
1624
+ <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Timestamp</th>
1625
+ <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Recipient</th>
1626
+ <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Subject</th>
1627
+ <th className="px-md py-sm font-bold text-[12px] uppercase tracking-wider">Status</th>
 
 
 
 
 
 
 
 
 
 
 
 
1628
  </tr>
1629
+ </thead>
1630
+ <tbody className="divide-y divide-outline-variant">
1631
+ {emailLogs.slice((emailPage - 1) * emailPageSize, emailPage * emailPageSize).map(log => (
1632
+ <tr key={log.id} className="hover:bg-surface-container-lowest transition-colors">
1633
+ <td className="px-md py-sm text-on-surface-variant text-[13px]">{new Date(log.sent_at).toLocaleString()}</td>
1634
+ <td className="px-md py-sm font-bold text-on-surface text-[13px]">{log.recipient}</td>
1635
+ <td className="px-md py-sm text-on-surface-variant text-[13px]">{log.subject}</td>
1636
+ <td className="px-md py-sm">
1637
+ <span className={`px-2 py-0.5 rounded text-[11px] font-bold uppercase tracking-wider ${log.status === 'sent' ? 'bg-green-500/10 text-green-600' : 'bg-red-500/10 text-red-600'}`}>
1638
+ {log.status}
1639
+ </span>
1640
+ </td>
1641
+ </tr>
1642
+ ))}
1643
+ </tbody>
1644
+ </table>
1645
+ </div>
1646
+ <TablePagination
1647
+ currentPage={emailPage}
1648
+ totalEntries={emailLogs.length}
1649
+ pageSize={emailPageSize}
1650
+ onPageChange={setEmailPage}
1651
+ onPageSizeChange={setEmailPageSize}
1652
+ />
1653
+ </>
1654
  )}
1655
  </div>
1656
  </div>