import { useNavigate } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query';
import {
Box,
Typography,
Card,
CardContent,
Grid,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Chip,
Button,
Skeleton,
} from '@mui/material';
import AddCircleIcon from '@mui/icons-material/AddCircle';
import DescriptionIcon from '@mui/icons-material/Description';
import HourglassTopIcon from '@mui/icons-material/HourglassTop';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import SendIcon from '@mui/icons-material/Send';
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
import WarningAmberIcon from '@mui/icons-material/WarningAmber';
import ReportIcon from '@mui/icons-material/Report';
import { proposalsApi, type ProposalListItem, type ProposalStats } from '../../lib/api/proposals';
import { QUERY_KEYS } from '../../constants/queryKeys';
import { STATUS_COLORS, STATUS_LABELS, PRIORITY_LABELS, PRIORITY_COLORS, PRIORITY_ROW_SX } from '../../constants';
import { formatBidAmount, formatDate } from '../../lib/format';
import { useDocumentTitle } from '../../hooks/useDocumentTitle';
import { useAuth } from '../../hooks/useAuth';
function KpiCard({ icon, label, value, onClick }: { icon: React.ReactNode; label: string; value: string; onClick: () => void }) {
return (
{icon}
{label}
{value}
);
}
export default function Dashboard() {
useDocumentTitle('Dashboard');
const navigate = useNavigate();
const { user } = useAuth();
const isAdmin = user?.role === 'Admin' || user?.role === 'SysAdmin';
const { data: recentData, isLoading: recentLoading, error: recentError } = useQuery<{ items: ProposalListItem[]; totalCount: number }>({
queryKey: [QUERY_KEYS.proposals, 'dashboard-recent', isAdmin],
queryFn: () => proposalsApi.getAll({ page: 1, pageSize: 5, mine: !isAdmin }),
});
const { data: stats, isLoading: statsLoading } = useQuery({
queryKey: [QUERY_KEYS.proposals, 'stats'],
queryFn: () => proposalsApi.getStats(),
});
const isLoading = recentLoading || statsLoading;
const proposals = recentData?.items ?? [];
const total = stats?.totalCount ?? 0;
const counts = {
inReview: stats?.inReviewCount ?? 0,
approved: stats?.approvedCount ?? 0,
sent: stats?.sentCount ?? 0,
};
const kpiCards = isAdmin
? [
{ icon: , label: 'All Proposals', value: String(total), onClick: () => navigate('/admin/proposals') },
{ icon: , label: 'Pending Review', value: String(counts.inReview), onClick: () => navigate('/admin') },
{ icon: , label: 'Approved', value: String(counts.approved), onClick: () => navigate('/admin/proposals?status=Approved') },
{ icon: , label: 'Sent', value: String(counts.sent), onClick: () => navigate('/admin/proposals?status=Sent') },
]
: [
{ icon: , label: 'Total Submitted', value: String(total), onClick: () => navigate('/proposals') },
{ icon: , label: 'In Review', value: String(counts.inReview), onClick: () => navigate('/proposals?status=InReview') },
{ icon: , label: 'Approved', value: String(counts.approved), onClick: () => navigate('/proposals?status=Approved') },
{ icon: , label: 'Sent', value: String(counts.sent), onClick: () => navigate('/proposals?status=Sent') },
];
return (
Dashboard
}
onClick={() => navigate('/proposals/new')}
>
New Proposal
{kpiCards.map((card) => (
{isLoading ? (
) : (
)}
))}
Recent Proposals
}
onClick={() => navigate(isAdmin ? '/admin/proposals' : '/proposals')}
>
View All Proposals
Proposal #
Customer
WO #
Category
Priority
Status
Bid Amount
Submitted
{isLoading
? Array.from({ length: 5 }).map((_, i) => (
{Array.from({ length: 8 }).map((_, j) => (
))}
))
: proposals.map((row) => (
navigate(`/proposals/${row.id}`)}
>
{row.proposalNumber}
{row.customerName}
{row.workOrderNumber}
{row.serviceCategory}
: row.priority === 'Urgent' ? : undefined}
/>
{formatBidAmount(row.totalBidAmount)}
{formatDate(row.submittedAt)}
))}
{!isLoading && recentError && (
Failed to load proposals. Please try again.
)}
{!isLoading && !recentError && proposals.length === 0 && (
No proposals yet. Submit your first one!
)}
);
}