From a27b1d6cfa8170a2d3bb1cc67297fe9778cc3be1 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 30 Nov 2025 23:27:22 +0100 Subject: [PATCH] fix search booking --- apps/frontend/app/dashboard/bookings/page.tsx | 183 +++++++++--------- 1 file changed, 96 insertions(+), 87 deletions(-) diff --git a/apps/frontend/app/dashboard/bookings/page.tsx b/apps/frontend/app/dashboard/bookings/page.tsx index 9fbcae7..e20bef6 100644 --- a/apps/frontend/app/dashboard/bookings/page.tsx +++ b/apps/frontend/app/dashboard/bookings/page.tsx @@ -11,90 +11,105 @@ import { useQuery } from '@tanstack/react-query'; import { listBookings, listCsvBookings } from '@/lib/api'; import Link from 'next/link'; -type BookingType = 'all' | 'standard' | 'csv'; +type SearchType = 'pallets' | 'weight' | 'route' | 'status' | 'date' | 'quote'; export default function BookingsListPage() { const [searchTerm, setSearchTerm] = useState(''); + const [searchType, setSearchType] = useState('route'); const [statusFilter, setStatusFilter] = useState(''); - const [bookingType, setBookingType] = useState('csv'); // Start with CSV bookings const [page, setPage] = useState(1); - // Fetch standard bookings - const { data: standardData, isLoading: standardLoading, error: standardError } = useQuery({ - queryKey: ['bookings', page, statusFilter, searchTerm], - queryFn: () => - listBookings({ - page, - limit: 10, - status: statusFilter || undefined, - }), - enabled: bookingType === 'all' || bookingType === 'standard', - retry: false, // Don't retry if it fails - }); - - // Fetch CSV bookings - const { data: csvData, isLoading: csvLoading, error: csvError } = useQuery({ - queryKey: ['csv-bookings', page, statusFilter], + // Fetch CSV bookings only (without status filter in API, we filter client-side) + const { data: csvData, isLoading, error: csvError } = useQuery({ + queryKey: ['csv-bookings', page], queryFn: () => listCsvBookings({ page, - limit: 10, - status: statusFilter as 'PENDING' | 'ACCEPTED' | 'REJECTED' | undefined, + limit: 100, // Fetch more to allow client-side filtering }), - enabled: bookingType === 'all' || bookingType === 'csv', }); // Log errors for debugging - if (standardError) console.error('Standard bookings error:', standardError); if (csvError) console.error('CSV bookings error:', csvError); - const isLoading = standardLoading || csvLoading; + // Filter bookings based on search term, search type, and status + const filterBookings = (bookings: any[]) => { + let filtered = bookings; - // Combine bookings based on filter - const getCombinedBookings = () => { - if (bookingType === 'standard') { - return (standardData?.bookings || []).map(b => ({ ...b, type: 'standard' as const })); + // Filter by status first (if status filter is active) + if (statusFilter) { + filtered = filtered.filter((booking: any) => booking.status === statusFilter); } - if (bookingType === 'csv') { - return (csvData?.bookings || []).map(b => ({ ...b, type: 'csv' as const })); + + // Then filter by search term if provided + if (searchTerm.trim()) { + const term = searchTerm.toLowerCase(); + + filtered = filtered.filter((booking: any) => { + switch (searchType) { + case 'pallets': + return booking.palletCount?.toString().includes(term); + case 'weight': + return booking.weightKG?.toString().includes(term); + case 'route': + const origin = booking.originCity?.toLowerCase() || ''; + const destination = booking.destinationCity?.toLowerCase() || ''; + return origin.includes(term) || destination.includes(term); + case 'status': + return booking.status?.toLowerCase().includes(term); + case 'date': + const date = new Date(booking.requestedPickupDate || booking.requestedAt).toLocaleDateString('fr-FR'); + return date.includes(term); + case 'quote': + return booking.id?.toLowerCase().includes(term) || booking.quoteNumber?.toLowerCase().includes(term); + default: + return true; + } + }); } - // For 'all', combine both - const standard = (standardData?.bookings || []).map(b => ({ ...b, type: 'standard' as const })); - const csv = (csvData?.bookings || []).map(b => ({ ...b, type: 'csv' as const })); - return [...standard, ...csv].sort((a, b) => { - const dateA = new Date((a as any).createdAt || (a as any).requestedAt || 0).getTime(); - const dateB = new Date((b as any).createdAt || (b as any).requestedAt || 0).getTime(); - return dateB - dateA; - }); + + return filtered; }; - const allBookings = getCombinedBookings(); + const allBookings = filterBookings((csvData?.bookings || []).map(b => ({ ...b, type: 'csv' as const }))); const statusOptions = [ { value: '', label: 'Tous les statuts' }, - // Standard booking statuses - { value: 'draft', label: 'Brouillon' }, - { value: 'pending', label: 'En attente' }, - { value: 'confirmed', label: 'Confirmé' }, - { value: 'in_transit', label: 'En transit' }, - { value: 'delivered', label: 'Livré' }, - { value: 'cancelled', label: 'Annulé' }, - // CSV booking statuses - { value: 'PENDING', label: 'En attente (CSV)' }, - { value: 'ACCEPTED', label: 'Accepté (CSV)' }, - { value: 'REJECTED', label: 'Refusé (CSV)' }, + { value: 'PENDING', label: 'En attente' }, + { value: 'ACCEPTED', label: 'Accepté' }, + { value: 'REJECTED', label: 'Refusé' }, ]; + const searchTypeOptions = [ + { value: 'route', label: 'Route (Origine/Destination)' }, + { value: 'pallets', label: 'Palettes/Colis' }, + { value: 'weight', label: 'Poids (kg)' }, + { value: 'status', label: 'Statut' }, + { value: 'date', label: 'Date' }, + { value: 'quote', label: 'N° Devis' }, + ]; + + const getPlaceholder = () => { + switch (searchType) { + case 'pallets': + return 'Rechercher par nombre de palettes...'; + case 'weight': + return 'Rechercher par poids en kg...'; + case 'route': + return 'Rechercher par ville (origine ou destination)...'; + case 'status': + return 'Rechercher par statut...'; + case 'date': + return 'Rechercher par date (JJ/MM/AAAA)...'; + case 'quote': + return 'Rechercher par numéro de devis...'; + default: + return 'Rechercher...'; + } + }; + const getStatusColor = (status: string) => { const colors: Record = { - // Standard statuses - draft: 'bg-gray-100 text-gray-800', - pending: 'bg-yellow-100 text-yellow-800', - confirmed: 'bg-green-100 text-green-800', - in_transit: 'bg-blue-100 text-blue-800', - delivered: 'bg-purple-100 text-purple-800', - cancelled: 'bg-red-100 text-red-800', - // CSV statuses PENDING: 'bg-yellow-100 text-yellow-800', ACCEPTED: 'bg-green-100 text-green-800', REJECTED: 'bg-red-100 text-red-800', @@ -104,14 +119,6 @@ export default function BookingsListPage() { const getStatusLabel = (status: string) => { const labels: Record = { - // Standard statuses - draft: 'Brouillon', - pending: 'En attente', - confirmed: 'Confirmé', - in_transit: 'En transit', - delivered: 'Livré', - cancelled: 'Annulé', - // CSV statuses PENDING: 'En attente', ACCEPTED: 'Accepté', REJECTED: 'Refusé', @@ -139,6 +146,23 @@ export default function BookingsListPage() { {/* Filters */}
+
+ + +
-
- - -
{/* Pagination */} - {((standardData?.total || 0) + (csvData?.total || 0)) > 10 && ( + {(csvData?.total || 0) > 20 && (