import { useState, useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; import { useMutation } from '@tanstack/react-query'; import { Box, Typography, Card, CardContent, TextField, Button, Grid, MenuItem, Autocomplete, CircularProgress, } from '@mui/material'; import SendIcon from '@mui/icons-material/Send'; import { toast } from 'react-toastify'; import { proposalsApi, type CreateProposalRequest } from '../../../lib/api/proposals'; import { customersApi, type Customer } from '../../../lib/api/customers'; import { SERVICE_CATEGORIES, PRIORITIES } from '../../../constants'; import { queryClient } from '../../../lib/queryClient'; export default function ProposalFormPage() { const navigate = useNavigate(); const [form, setForm] = useState({ workOrderNumber: '', customerName: '', customerAddress: '', scopeOfWork: '', serviceCategory: '', priority: 'Standard', notes: '', }); const [customers, setCustomers] = useState([]); const [customerLoading, setCustomerLoading] = useState(false); const [addresses, setAddresses] = useState([]); const [vendorFile, setVendorFile] = useState(null); const handleChange = (field: keyof CreateProposalRequest, value: string) => { setForm((prev) => ({ ...prev, [field]: value })); }; const searchCustomers = useCallback(async (query: string) => { if (query.length < 2) return; setCustomerLoading(true); try { const results = await customersApi.search(query); setCustomers(results); } catch { setCustomers([]); } finally { setCustomerLoading(false); } }, []); const handleCustomerSelect = (_: unknown, value: Customer | string | null) => { if (!value) { setForm((prev) => ({ ...prev, customerName: '', customerAddress: '' })); setAddresses([]); return; } if (typeof value === 'string') { setForm((prev) => ({ ...prev, customerName: value, customerAddress: '' })); setAddresses([]); } else { setForm((prev) => ({ ...prev, customerName: value.name, customerAddress: value.addresses[0] || '' })); setAddresses(value.addresses); } }; const createMutation = useMutation({ mutationFn: async () => { const proposal = await proposalsApi.create(form); if (vendorFile) { const { uploadUrl } = await proposalsApi.uploadAttachment(proposal.id, vendorFile.name); await fetch(uploadUrl, { method: 'PUT', body: vendorFile, headers: { 'Content-Type': vendorFile.type || 'application/pdf' }, }); } return proposal; }, onSuccess: (proposal) => { queryClient.invalidateQueries({ queryKey: ['proposals'] }); toast.success(`Proposal ${proposal.proposalNumber} submitted`); navigate(`/proposals/${proposal.id}`); }, }); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); createMutation.mutate(); }; const isValid = form.workOrderNumber.trim() && form.customerName.trim() && form.customerAddress.trim() && form.scopeOfWork.trim() && form.serviceCategory; return ( New Proposal Request handleChange('workOrderNumber', e.target.value)} /> (typeof opt === 'string' ? opt : opt.name)} loading={customerLoading} onInputChange={(_, value) => searchCustomers(value)} onChange={handleCustomerSelect} renderInput={(params) => ( {customerLoading && } {params.InputProps.endAdornment} ), }, }} /> )} /> {addresses.length > 1 ? ( handleChange('customerAddress', e.target.value)} > {addresses.map((addr) => ( {addr} ))} ) : ( handleChange('customerAddress', e.target.value)} /> )} handleChange('serviceCategory', e.target.value)} > {SERVICE_CATEGORIES.map((cat) => ( {cat} ))} handleChange('priority', e.target.value)} > {PRIORITIES.map((p) => ( {p} ))} handleChange('scopeOfWork', e.target.value)} placeholder="Describe the work needed..." /> handleChange('notes', e.target.value)} /> ); }