/** * Custom hook for managing bookings */ import { useState, useEffect, useCallback } from 'react'; import { Booking, BookingFilters, BookingListResponse, ExportOptions } from '@/types/booking'; export function useBookings(initialFilters?: BookingFilters) { const [bookings, setBookings] = useState([]); const [total, setTotal] = useState(0); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [filters, setFilters] = useState(initialFilters || {}); const [selectedBookings, setSelectedBookings] = useState>(new Set()); const fetchBookings = useCallback(async () => { setLoading(true); setError(null); try { // Build query parameters const queryParams = new URLSearchParams(); if (filters.status && filters.status.length > 0) { queryParams.append('status', filters.status.join(',')); } if (filters.search) queryParams.append('search', filters.search); if (filters.carrier) queryParams.append('carrier', filters.carrier); if (filters.originPort) queryParams.append('originPort', filters.originPort); if (filters.destinationPort) queryParams.append('destinationPort', filters.destinationPort); if (filters.shipper) queryParams.append('shipper', filters.shipper); if (filters.consignee) queryParams.append('consignee', filters.consignee); if (filters.createdFrom) queryParams.append('createdFrom', filters.createdFrom); if (filters.createdTo) queryParams.append('createdTo', filters.createdTo); if (filters.etdFrom) queryParams.append('etdFrom', filters.etdFrom); if (filters.etdTo) queryParams.append('etdTo', filters.etdTo); if (filters.sortBy) queryParams.append('sortBy', filters.sortBy); if (filters.sortOrder) queryParams.append('sortOrder', filters.sortOrder); queryParams.append('page', String(filters.page || 1)); queryParams.append('pageSize', String(filters.pageSize || 20)); const response = await fetch(`/api/v1/bookings/advanced/search?${queryParams.toString()}`, { headers: { Authorization: `Bearer ${localStorage.getItem('accessToken')}`, }, }); if (!response.ok) { throw new Error('Failed to fetch bookings'); } const data: BookingListResponse = await response.json(); setBookings(data.bookings); setTotal(data.total); } catch (err: any) { setError(err.message || 'An error occurred'); } finally { setLoading(false); } }, [filters]); useEffect(() => { fetchBookings(); }, [fetchBookings]); const updateFilters = useCallback((newFilters: Partial) => { setFilters(prev => ({ ...prev, ...newFilters })); }, []); const resetFilters = useCallback(() => { setFilters({}); setSelectedBookings(new Set()); }, []); const toggleBookingSelection = useCallback((bookingId: string) => { setSelectedBookings((prev: Set) => { const newSet = new Set(prev); if (newSet.has(bookingId)) { newSet.delete(bookingId); } else { newSet.add(bookingId); } return newSet; }); }, []); const toggleAllBookings = useCallback(() => { if (selectedBookings.size === bookings.length) { setSelectedBookings(new Set()); } else { setSelectedBookings(new Set(bookings.map(b => b.id))); } }, [bookings, selectedBookings]); const clearSelection = useCallback(() => { setSelectedBookings(new Set()); }, []); const exportBookings = useCallback( async (options: ExportOptions) => { try { const response = await fetch('/api/v1/bookings/export', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('accessToken')}`, }, body: JSON.stringify({ format: options.format, fields: options.fields, bookingIds: options.bookingIds || Array.from(selectedBookings), }), }); if (!response.ok) { throw new Error('Export failed'); } // Download file const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `bookings-export.${options.format}`; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); } catch (err: any) { throw new Error(err.message || 'Export failed'); } }, [selectedBookings] ); return { bookings, total, loading, error, filters, selectedBookings, updateFilters, resetFilters, toggleBookingSelection, toggleAllBookings, clearSelection, exportBookings, refetch: fetchBookings, }; }