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 && (
+
+ )}
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 ? (
+
+ ) : (
+
+ )}
+
+
Assign to Associations
@@ -232,7 +283,7 @@ export function BidQuoteDialog({ open, onOpenChange, onSuccess }) {
-