diff --git a/src/components/BidQuoteDetailsDialog.jsx b/src/components/BidQuoteDetailsDialog.jsx index 6fb9e66..9a0121c 100644 --- a/src/components/BidQuoteDetailsDialog.jsx +++ b/src/components/BidQuoteDetailsDialog.jsx @@ -94,6 +94,14 @@ export function BidQuoteDetailsDialog({ open, onOpenChange, bid, onRefresh }) {
Status: {bid.status}
{bid.received_date &&
Received: {format(new Date(bid.received_date), 'MMM d, yyyy')}
} + {bid.document_url && ( +
+ + đź“„ {bid.document_name || 'View attached PDF'} + +
+ )} diff --git a/src/components/BidQuoteDialog.jsx b/src/components/BidQuoteDialog.jsx index c9e10ce..1069988 100644 --- a/src/components/BidQuoteDialog.jsx +++ b/src/components/BidQuoteDialog.jsx @@ -38,6 +38,9 @@ export function BidQuoteDialog({ open, onOpenChange, onSuccess }) { const [associations, setAssociations] = useState([]); const [selectedAssociations, setSelectedAssociations] = useState([]); const [uploading, setUploading] = useState(false); + const [fileUploading, setFileUploading] = useState(false); + const [documentUrl, setDocumentUrl] = useState(''); + const [documentName, setDocumentName] = useState(''); const { user } = useAuth(); const { toast } = useToast(); @@ -55,9 +58,34 @@ export function BidQuoteDialog({ open, onOpenChange, onSuccess }) { fetchAssociations(); form.reset(); setSelectedAssociations([]); + setDocumentUrl(''); + setDocumentName(''); } }, [open, form]); + const handleFileUpload = async (e) => { + const f = e.target.files?.[0]; + if (!f) return; + if (f.type !== 'application/pdf') { + toast({ variant: 'destructive', title: 'PDF only', description: 'Please upload a PDF file.' }); + return; + } + setFileUploading(true); + try { + const path = `${user?.id || 'anon'}/${Date.now()}-${f.name.replace(/[^a-zA-Z0-9._-]/g, '_')}`; + const { error } = await supabase.storage.from('bid-attachments').upload(path, f, { upsert: true }); + if (error) throw error; + const { data } = supabase.storage.from('bid-attachments').getPublicUrl(path); + setDocumentUrl(data.publicUrl); + setDocumentName(f.name); + toast({ title: 'PDF attached', description: f.name }); + } catch (err) { + toast({ variant: 'destructive', title: 'Upload failed', description: err.message }); + } finally { + setFileUploading(false); + } + }; + const fetchAssociations = async () => { try { const { data, error } = await supabase @@ -91,7 +119,9 @@ export function BidQuoteDialog({ open, onOpenChange, onSuccess }) { amount: values.amount || 0, association_id: assocId, created_by: user?.id, - status: 'pending' + status: 'pending', + document_url: documentUrl || null, + document_name: documentName || null, })); const { error } = await supabase.from('bids_quotes').insert(inserts); @@ -191,6 +221,27 @@ export function BidQuoteDialog({ open, onOpenChange, onSuccess }) { )} /> +
+ Attachment (PDF) + {documentName ? ( +
+ + {documentName} + + +
+ ) : ( + + )} +
+
Assign to Associations @@ -232,7 +283,7 @@ export function BidQuoteDialog({ open, onOpenChange, onSuccess }) { -