xpeditis2.0/apps/frontend/src/hooks/useBookings.ts
David-Henri ARNAUD c5c15eb1f9 feature phase 3
2025-10-13 17:54:32 +02:00

153 lines
4.8 KiB
TypeScript

/**
* 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<Booking[]>([]);
const [total, setTotal] = useState(0);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [filters, setFilters] = useState<BookingFilters>(initialFilters || {});
const [selectedBookings, setSelectedBookings] = useState<Set<string>>(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<BookingFilters>) => {
setFilters((prev) => ({ ...prev, ...newFilters }));
}, []);
const resetFilters = useCallback(() => {
setFilters({});
setSelectedBookings(new Set());
}, []);
const toggleBookingSelection = useCallback((bookingId: string) => {
setSelectedBookings((prev) => {
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,
};
}