diff --git a/frontend/src/components/ShipperDashboard.jsx b/frontend/src/components/ShipperDashboard.jsx new file mode 100644 index 0000000..f0d7741 --- /dev/null +++ b/frontend/src/components/ShipperDashboard.jsx @@ -0,0 +1,164 @@ +import React, { useState, useEffect } from 'react'; +import { useQuery } from '@tanstack/react-query'; +import { supabase } from '../supabaseClient'; +import { formatINR } from '../lib/india'; +import { getStatusColor } from '../lib/india'; + +function ShipperDashboard() { + const [selectedLoadId, setSelectedLoadId] = useState(null); + const [bidModalOpen, setBidModalOpen] = useState(false); + + const { data: loads, isLoading, isError } = useQuery({ + queryKey: ['loads'], + queryFn: async () => { + const { data, error } = await supabase + .from('loads') + .select('*, shipper:shippers(name), vehicle:vehicles(number)') + .order('date', { ascending: false }) + .limit(100); + if (error) throw error; + return data; + }, + }); + + const { data: bids } = useQuery({ + queryKey: ['bids', selectedLoadId], + queryFn: async () => { + const { data, error } = await supabase + .from('bids') + .select('*, driver:portal_users(username)') + .eq('load_id', selectedLoadId) + .order('created_at', { ascending: false }); + if (error) throw error; + return data; + }, + }); + + const handleAccept = async (bidId) => { + await fetch('/api/update-bid-status', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ bidId, newStatus: 'accepted' }), + }); + // Refresh data after update + await refetch(); + }; + + const { refetch } = useQuery({ + queryKey: ['loads'], + queryFn: async () => { + const { data, error } = await supabase + .from('loads') + .select('*, shipper:shippers(name), vehicle:vehicles(number)') + .order('date', { ascending: false }) + .limit(100); + if (error) throw error; + return data; + }, + ); + + return ( +
| Date | +Route | +Shipper | +Freight | +Status | +Bids | +Actions | +
|---|---|---|---|---|---|---|
| {new Date(load.date).toLocaleDateString('en-IN')} | +{load.from_city} → {load.to_city} | +{load.shipper?.name || ' — '} | +{formatINR(load.freight_charged)} | ++ + {load.status} + + | +
+ {bids ? (
+
+ {bids.map((b) => (
+
+ ) : ' — '}
+ {selectedLoadId === load.id && (
+
+ {bid.driver?.username || ' — '}: {formatINR(bid.bid_amount)}
+
+ ))}
+
+ {bids.length > 0 && (
+ <>
+
+
+ }
+
+ }
+ |
+