Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Update frontend/src/pages/SuperAdminPanel.jsx
Browse files
frontend/src/pages/SuperAdminPanel.jsx
CHANGED
|
@@ -331,6 +331,21 @@ const SuperAdminPanel = () => {
|
|
| 331 |
const [emailPage, setEmailPage] = useState(1);
|
| 332 |
const [emailPageSize, setEmailPageSize] = useState(25);
|
| 333 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 334 |
const handleOrgSort = (column) => {
|
| 335 |
if (column === 'Quotas' || column === 'Actions') return;
|
| 336 |
if (sortOrgCol === column) {
|
|
@@ -1716,10 +1731,65 @@ const SuperAdminPanel = () => {
|
|
| 1716 |
|
| 1717 |
{activeTab === 'bookings' && (
|
| 1718 |
<div className="flex flex-col gap-md mb-xl animate-fade-in">
|
| 1719 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1720 |
<div className="bg-surface border border-outline-variant rounded-2xl overflow-hidden shadow-sm">
|
| 1721 |
-
{
|
| 1722 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1723 |
) : (
|
| 1724 |
<>
|
| 1725 |
<div className="overflow-x-auto">
|
|
@@ -1734,7 +1804,7 @@ const SuperAdminPanel = () => {
|
|
| 1734 |
</tr>
|
| 1735 |
</thead>
|
| 1736 |
<tbody className="divide-y divide-outline-variant">
|
| 1737 |
-
{
|
| 1738 |
const statusStyle =
|
| 1739 |
b.status === 'completed'
|
| 1740 |
? 'bg-green-500/10 text-green-600 border-green-500/30'
|
|
@@ -1809,7 +1879,7 @@ const SuperAdminPanel = () => {
|
|
| 1809 |
</div>
|
| 1810 |
<TablePagination
|
| 1811 |
currentPage={bookingPage}
|
| 1812 |
-
totalEntries={
|
| 1813 |
pageSize={bookingPageSize}
|
| 1814 |
onPageChange={setBookingPage}
|
| 1815 |
onPageSizeChange={setBookingPageSize}
|
|
|
|
| 331 |
const [emailPage, setEmailPage] = useState(1);
|
| 332 |
const [emailPageSize, setEmailPageSize] = useState(25);
|
| 333 |
|
| 334 |
+
const [bookingSearch, setBookingSearch] = useState('');
|
| 335 |
+
const [bookingStatusFilter, setBookingStatusFilter] = useState('all');
|
| 336 |
+
|
| 337 |
+
const getFilteredBookings = () => {
|
| 338 |
+
return (demoBookings || []).filter(b => {
|
| 339 |
+
const emailMatch = !bookingSearch ||
|
| 340 |
+
(b.email || '').toLowerCase().includes(bookingSearch.toLowerCase()) ||
|
| 341 |
+
(b.company_size || '').toLowerCase().includes(bookingSearch.toLowerCase()) ||
|
| 342 |
+
(b.meeting_date || '').toLowerCase().includes(bookingSearch.toLowerCase());
|
| 343 |
+
|
| 344 |
+
const statusMatch = bookingStatusFilter === 'all' || (b.status || 'pending') === bookingStatusFilter;
|
| 345 |
+
return emailMatch && statusMatch;
|
| 346 |
+
});
|
| 347 |
+
};
|
| 348 |
+
|
| 349 |
const handleOrgSort = (column) => {
|
| 350 |
if (column === 'Quotas' || column === 'Actions') return;
|
| 351 |
if (sortOrgCol === column) {
|
|
|
|
| 1731 |
|
| 1732 |
{activeTab === 'bookings' && (
|
| 1733 |
<div className="flex flex-col gap-md mb-xl animate-fade-in">
|
| 1734 |
+
<div className="flex flex-col md:flex-row md:items-center justify-between gap-md mb-xs">
|
| 1735 |
+
<h2 className="font-headline-sm font-bold text-on-surface flex items-center text-[18px]"><span className="material-symbols-outlined text-primary mr-2">event</span> Demo Bookings & Leads</h2>
|
| 1736 |
+
<div className="text-[12.5px] font-bold text-on-surface-variant">
|
| 1737 |
+
Total Leads: <span className="text-primary font-extrabold">{getFilteredBookings().length}</span>
|
| 1738 |
+
</div>
|
| 1739 |
+
</div>
|
| 1740 |
+
|
| 1741 |
<div className="bg-surface border border-outline-variant rounded-2xl overflow-hidden shadow-sm">
|
| 1742 |
+
{/* Filter Controls Bar */}
|
| 1743 |
+
<div className="p-md bg-surface-container-high/40 border-b border-outline-variant/60 flex flex-col md:flex-row justify-between items-start md:items-center gap-md">
|
| 1744 |
+
<div className="flex items-center gap-sm flex-wrap w-full md:w-auto">
|
| 1745 |
+
<div className="relative flex-1 md:w-64">
|
| 1746 |
+
<Search className="w-4 h-4 absolute left-3 top-2.5 text-on-surface-variant" />
|
| 1747 |
+
<input
|
| 1748 |
+
type="text"
|
| 1749 |
+
placeholder="Search email, company size, date..."
|
| 1750 |
+
value={bookingSearch}
|
| 1751 |
+
onChange={(e) => { setBookingSearch(e.target.value); setBookingPage(1); }}
|
| 1752 |
+
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"
|
| 1753 |
+
/>
|
| 1754 |
+
{bookingSearch && (
|
| 1755 |
+
<button
|
| 1756 |
+
onClick={() => { setBookingSearch(''); setBookingPage(1); }}
|
| 1757 |
+
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"
|
| 1758 |
+
>
|
| 1759 |
+
<X className="w-3.5 h-3.5" />
|
| 1760 |
+
</button>
|
| 1761 |
+
)}
|
| 1762 |
+
</div>
|
| 1763 |
+
|
| 1764 |
+
<div className="flex items-center gap-1.5">
|
| 1765 |
+
<span className="text-[11px] font-bold text-on-surface-variant uppercase tracking-wider shrink-0">Status:</span>
|
| 1766 |
+
<select
|
| 1767 |
+
value={bookingStatusFilter}
|
| 1768 |
+
onChange={(e) => { setBookingStatusFilter(e.target.value); setBookingPage(1); }}
|
| 1769 |
+
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"
|
| 1770 |
+
>
|
| 1771 |
+
<option value="all">All Statuses</option>
|
| 1772 |
+
<option value="pending">Pending</option>
|
| 1773 |
+
<option value="completed">Completed</option>
|
| 1774 |
+
<option value="rescheduled">Rescheduled</option>
|
| 1775 |
+
<option value="cancelled">Cancelled</option>
|
| 1776 |
+
</select>
|
| 1777 |
+
</div>
|
| 1778 |
+
|
| 1779 |
+
{(bookingSearch || bookingStatusFilter !== 'all') && (
|
| 1780 |
+
<button
|
| 1781 |
+
onClick={() => { setBookingSearch(''); setBookingStatusFilter('all'); setBookingPage(1); }}
|
| 1782 |
+
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"
|
| 1783 |
+
>
|
| 1784 |
+
<X className="w-4 h-4" />
|
| 1785 |
+
Reset Filters
|
| 1786 |
+
</button>
|
| 1787 |
+
)}
|
| 1788 |
+
</div>
|
| 1789 |
+
</div>
|
| 1790 |
+
|
| 1791 |
+
{getFilteredBookings().length === 0 ? (
|
| 1792 |
+
<div className="p-xl text-center text-on-surface-variant font-bold">No demo bookings match your filter criteria.</div>
|
| 1793 |
) : (
|
| 1794 |
<>
|
| 1795 |
<div className="overflow-x-auto">
|
|
|
|
| 1804 |
</tr>
|
| 1805 |
</thead>
|
| 1806 |
<tbody className="divide-y divide-outline-variant">
|
| 1807 |
+
{getFilteredBookings().slice((bookingPage - 1) * bookingPageSize, bookingPage * bookingPageSize).map(b => {
|
| 1808 |
const statusStyle =
|
| 1809 |
b.status === 'completed'
|
| 1810 |
? 'bg-green-500/10 text-green-600 border-green-500/30'
|
|
|
|
| 1879 |
</div>
|
| 1880 |
<TablePagination
|
| 1881 |
currentPage={bookingPage}
|
| 1882 |
+
totalEntries={getFilteredBookings().length}
|
| 1883 |
pageSize={bookingPageSize}
|
| 1884 |
onPageChange={setBookingPage}
|
| 1885 |
onPageSizeChange={setBookingPageSize}
|