import { useNavigate } from 'react-router-dom'; import { useQuery } from '@tanstack/react-query'; import { Box, Typography, Card, CardContent, Grid, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TablePagination, Chip, TextField, InputAdornment, MenuItem, Skeleton, } from '@mui/material'; import SearchIcon from '@mui/icons-material/Search'; import PendingActionsIcon from '@mui/icons-material/PendingActions'; import CheckCircleIcon from '@mui/icons-material/CheckCircle'; import TimerIcon from '@mui/icons-material/Timer'; import DescriptionIcon from '@mui/icons-material/Description'; import { usePaginatedList } from '../../../hooks/usePaginatedList'; import { proposalsApi, type ProposalListItem } from '../../../lib/api/proposals'; import { adminApi, type DashboardStats } from '../../../lib/api/admin'; import { QUERY_KEYS } from '../../../constants/queryKeys'; import { SERVICE_CATEGORIES, PRIORITIES } from '../../../constants'; const STATUS_COLORS: Record = { Draft: 'default', InReview: 'info', Approved: 'success', Sent: 'success', Revised: 'warning', }; const PRIORITY_COLORS: Record = { Standard: 'default', Urgent: 'warning', Emergency: 'error', }; function formatCurrency(amount: number): string { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount); } function formatDate(iso: string): string { return new Date(iso).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); } function StatCard({ icon, label, value, color }: { icon: React.ReactNode; label: string; value: string; color: string }) { return ( {icon} {label} {value} ); } export default function AdminDashboard() { const navigate = useNavigate(); const { data: stats, isLoading: statsLoading } = useQuery({ queryKey: [QUERY_KEYS.dashboard], queryFn: adminApi.getDashboard, }); const { rows, search, setSearch, page, setPage, pageSize, setPageSize, totalCount, loading, err, } = usePaginatedList(proposalsApi.getAll); return ( Admin Dashboard {statsLoading ? ( ) : ( } label="Pending Review" value={String(stats?.pendingCount ?? 0)} color="#1565c0" /> )} {statsLoading ? ( ) : ( } label="Approved This Week" value={String(stats?.approvedThisWeek ?? 0)} color="#2e7d32" /> )} {statsLoading ? ( ) : ( } label="Avg Turnaround" value={stats ? `${Math.round(stats.avgTurnaroundHours)}h` : '-'} color="#f57c00" /> )} {statsLoading ? ( ) : ( } label="Total Proposals" value={String(stats?.totalProposals ?? 0)} color="#5e35b1" /> )} setSearch(e.target.value)} sx={{ width: 240 }} slotProps={{ input: { startAdornment: ( ), }, }} /> {}} > All {SERVICE_CATEGORIES.map((c) => ( {c} ))} {}} > All {PRIORITIES.map((p) => ( {p} ))} {err && ( {err} )} Proposal # Customer WO # Category Priority Status Bid Amount Submitted Submitted By {loading ? Array.from({ length: 5 }).map((_, i) => ( {Array.from({ length: 9 }).map((_, j) => ( ))} )) : rows.map((row) => ( navigate(`/admin/proposals/${row.id}`)} > {row.proposalNumber} {row.customerName} {row.workOrderNumber} {row.serviceCategory} {formatCurrency(row.totalBidAmount)} {formatDate(row.submittedAt)} {row.submittedByName || '-'} ))} {!loading && rows.length === 0 && ( No proposals in queue )}
setPage(newPage + 1)} rowsPerPage={pageSize} onRowsPerPageChange={(e) => setPageSize(parseInt(e.target.value, 10))} rowsPerPageOptions={[12, 24, 48]} />
); }