import { useParams, useNavigate } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query';
import {
Box,
Typography,
Card,
CardContent,
Grid,
Chip,
Divider,
Button,
Skeleton,
Stepper,
Step,
StepLabel,
} from '@mui/material';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import { proposalsApi, type ProposalDetail } from '../../../lib/api/proposals';
import { STATUS_COLORS } from '../../../constants';
import { formatCurrency, formatDateTime } from '../../../lib/format';
import { useDocumentTitle } from '../../../hooks/useDocumentTitle';
const STATUS_ORDER = ['Draft', 'InReview', 'Approved', 'Sent'];
function InfoRow({ label, value }: { label: string; value: React.ReactNode }) {
return (
{label}
{value || '-'}
);
}
export default function ProposalDetailPage() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const { data: proposal, isLoading, error } = useQuery({
queryKey: ['proposals', id],
queryFn: () => proposalsApi.getById(id!),
enabled: !!id,
});
useDocumentTitle(proposal?.proposalNumber ?? 'Proposal');
if (isLoading) {
return (
);
}
if (error || !proposal) {
return (
{error instanceof Error ? error.message : 'Proposal not found'}
} onClick={() => navigate('/proposals')} sx={{ mt: 2 }}>
Back to Proposals
);
}
const activeStep = STATUS_ORDER.indexOf(proposal.status);
return (
} onClick={() => navigate('/proposals')}>
Back
{proposal.proposalNumber}
Status Timeline
{proposal.status === 'Revised' ? (
) : (
= 0 ? activeStep : 0} alternativeLabel>
{STATUS_ORDER.map((label) => (
{label}
))}
)}
Proposal Details
Scope of Work
{proposal.refinedScope || proposal.scopeOfWork}
{proposal.notes && (
<>
Notes
{proposal.notes}
>
)}
{(proposal.approvedAt || proposal.sentAt) && (
Approval & Delivery
{proposal.vendorTotalCost !== null && (
)}
)}
);
}