/** * Rate Search Page * * Search and compare shipping rates from multiple carriers */ 'use client'; import { useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { searchRates } from '@/lib/api'; import { searchPorts, Port } from '@/lib/api/ports'; type ContainerType = '20GP' | '40GP' | '40HC' | '45HC' | '20RF' | '40RF'; type Mode = 'SEA' | 'AIR' | 'ROAD' | 'RAIL'; interface SearchForm { originPort: string; destinationPort: string; containerType: ContainerType; departureDate: string; mode: Mode; isHazmat: boolean; quantity: number; } export default function RateSearchPage() { const [searchForm, setSearchForm] = useState({ originPort: '', destinationPort: '', containerType: '40HC', departureDate: '', mode: 'SEA', isHazmat: false, quantity: 1, }); const [hasSearched, setHasSearched] = useState(false); const [originSearch, setOriginSearch] = useState(''); const [destinationSearch, setDestinationSearch] = useState(''); const [priceRange, setPriceRange] = useState<[number, number]>([0, 10000]); const [transitTimeMax, setTransitTimeMax] = useState(50); const [selectedCarriers, setSelectedCarriers] = useState([]); const [sortBy, setSortBy] = useState<'price' | 'transitTime' | 'co2'>('price'); // Port autocomplete const { data: originPortsData } = useQuery({ queryKey: ['ports', originSearch], queryFn: () => searchPorts({ query: originSearch, limit: 10 }), enabled: originSearch.length >= 2, // Only search after 2 characters }); const { data: destinationPortsData } = useQuery({ queryKey: ['ports', destinationSearch], queryFn: () => searchPorts({ query: destinationSearch, limit: 10 }), enabled: destinationSearch.length >= 2, // Only search after 2 characters }); const originPorts = originPortsData?.ports || []; const destinationPorts = destinationPortsData?.ports || []; // Rate search const { data: rateQuotes, isLoading: isSearching, error: searchError, } = useQuery({ queryKey: ['rates', searchForm], queryFn: () => searchRates({ origin: searchForm.originPort, destination: searchForm.destinationPort, containerType: searchForm.containerType, departureDate: searchForm.departureDate, mode: searchForm.mode, isHazmat: searchForm.isHazmat, quantity: searchForm.quantity, }), enabled: hasSearched && !!searchForm.originPort && !!searchForm.destinationPort, }); const handleSearch = (e: React.FormEvent) => { e.preventDefault(); setHasSearched(true); }; // Filter and sort results const filteredAndSortedQuotes = rateQuotes?.rates ? rateQuotes.rates .filter((quote: any) => { const price = quote.pricing.totalAmount; const inPriceRange = price >= priceRange[0] && price <= priceRange[1]; const inTransitTime = quote.route.transitDays <= transitTimeMax; const matchesCarrier = selectedCarriers.length === 0 || selectedCarriers.includes(quote.carrier.name); return inPriceRange && inTransitTime && matchesCarrier; }) .sort((a: any, b: any) => { if (sortBy === 'price') { return a.pricing.totalAmount - b.pricing.totalAmount; } else if (sortBy === 'transitTime') { return a.route.transitDays - b.route.transitDays; } else { return (a.co2Emissions?.value || 0) - (b.co2Emissions?.value || 0); } }) : []; // Get unique carriers for filter const availableCarriers = rateQuotes?.rates ? Array.from(new Set(rateQuotes.rates.map((q: any) => q.carrier.name))) : []; const toggleCarrier = (carrier: string) => { setSelectedCarriers(prev => prev.includes(carrier) ? prev.filter(c => c !== carrier) : [...prev, carrier] ); }; return (
{/* Header */}

Search Shipping Rates

Compare rates from multiple carriers in real-time

{/* Search Form */}
{/* Ports */}
{/* Origin Port */}
{ setOriginSearch(e.target.value); if (e.target.value.length < 2) { setSearchForm({ ...searchForm, originPort: '' }); } }} placeholder="e.g., Rotterdam, Shanghai" className="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500" /> {originPorts && originPorts.length > 0 && (
{originPorts.map((port: Port) => ( ))}
)}
{/* Destination Port */}
{ setDestinationSearch(e.target.value); if (e.target.value.length < 2) { setSearchForm({ ...searchForm, destinationPort: '' }); } }} placeholder="e.g., Los Angeles, Hamburg" className="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500" /> {destinationPorts && destinationPorts.length > 0 && (
{destinationPorts.map((port: Port) => ( ))}
)}
{/* Container & Mode */}
setSearchForm({ ...searchForm, quantity: parseInt(e.target.value) || 1 }) } className="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500" />
setSearchForm({ ...searchForm, departureDate: e.target.value })} min={new Date().toISOString().split('T')[0]} className="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500" />
{/* Hazmat */}
setSearchForm({ ...searchForm, isHazmat: e.target.checked })} className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" />
{/* Submit */}
{/* Error */} {searchError && (
Failed to search rates. Please try again.
)} {/* Results */} {hasSearched && !isSearching && rateQuotes && (
{/* Filters Sidebar */}

Sort By

Price Range (USD)

setPriceRange([0, parseInt(e.target.value)])} className="w-full" />
Up to ${priceRange[1].toLocaleString()}

Max Transit Time (days)

setTransitTimeMax(parseInt(e.target.value))} className="w-full" />
{transitTimeMax} days
{availableCarriers.length > 0 && (

Carriers

{availableCarriers.map(carrier => ( ))}
)}
{/* Results List */}

{filteredAndSortedQuotes.length} Rate {filteredAndSortedQuotes.length !== 1 ? 's' : ''} Found

{filteredAndSortedQuotes.length === 0 ? (

No rates found

Try adjusting your filters or search criteria

) : ( filteredAndSortedQuotes.map((quote: any) => (
{/* Carrier Info */}
{quote.carrier.logoUrl ? ( {quote.carrier.name} ) : (
{quote.carrier.name.substring(0, 2).toUpperCase()}
)}

{quote.carrier.name}

{quote.carrier.scac}

{/* Price */}
${quote.pricing.totalAmount.toLocaleString()}
{quote.pricing.currency}
{/* Route Info */}
Departure
{new Date(quote.route.etd).toLocaleDateString()}
Transit Time
{quote.route.transitDays} days
Arrival
{new Date(quote.route.eta).toLocaleDateString()}
{/* Route Path */}
{quote.route.originPort} {quote.route.transshipmentPorts && quote.route.transshipmentPorts.length > 0 && ( <> via {quote.route.transshipmentPorts.join(', ')} )} {quote.route.destinationPort}
{/* Additional Info */}
{quote.co2Emissions && (
🌱 {quote.co2Emissions.value} kg CO2
)} {quote.availability && (
📦 {quote.availability} containers available
)}
{/* Surcharges */} {quote.pricing.surcharges && quote.pricing.surcharges.length > 0 && (
Includes surcharges:
{quote.pricing.surcharges.map((surcharge: any, idx: number) => ( {surcharge.name}: ${surcharge.amount} ))}
)} {/* Actions */}
)) )}
)} {/* Empty State */} {!hasSearched && (

Search for Shipping Rates

Enter your origin, destination, and container details to compare rates from multiple carriers

)}
); }