diff --git a/flight-comparator/api_server.py b/flight-comparator/api_server.py index d6ec9f1..3828a36 100644 --- a/flight-comparator/api_server.py +++ b/flight-comparator/api_server.py @@ -1827,7 +1827,7 @@ async def get_scan_flights( departure_time, arrival_time, price, stops FROM flights WHERE scan_id = ? AND destination = ? - ORDER BY price ASC, date ASC + ORDER BY date ASC, price ASC LIMIT ? OFFSET ? """, (scan_id, destination.upper(), limit, offset)) else: @@ -1836,7 +1836,7 @@ async def get_scan_flights( departure_time, arrival_time, price, stops FROM flights WHERE scan_id = ? - ORDER BY price ASC, date ASC + ORDER BY date ASC, price ASC LIMIT ? OFFSET ? """, (scan_id, limit, offset)) diff --git a/flight-comparator/frontend/src/pages/ScanDetails.tsx b/flight-comparator/frontend/src/pages/ScanDetails.tsx index e2927f9..9eeb66c 100644 --- a/flight-comparator/frontend/src/pages/ScanDetails.tsx +++ b/flight-comparator/frontend/src/pages/ScanDetails.tsx @@ -52,8 +52,10 @@ export default function ScanDetails() { const [totalPages, setTotalPages] = useState(1); const [sortField, setSortField] = useState<'min_price' | 'destination' | 'flight_count'>('min_price'); const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc'); - const [expandedRoute, setExpandedRoute] = useState(null); - const [flightsByDest, setFlightsByDest] = useState>({}); + const [expandedRoute, setExpandedRoute] = useState(null); + const [flightsByDest, setFlightsByDest] = useState>({}); + const [flightSortField, setFlightSortField] = useState<'date' | 'price'>('date'); + const [flightSortDir, setFlightSortDir] = useState<'asc' | 'desc'>('asc'); const [loadingFlights, setLoadingFlights] = useState(null); const [rerunning, setRerunning] = useState(false); const [confirmDelete, setConfirmDelete] = useState(false); @@ -115,6 +117,24 @@ export default function ScanDetails() { } }; + const handleFlightSort = (field: 'date' | 'price') => { + if (flightSortField === field) { + setFlightSortDir(d => d === 'asc' ? 'desc' : 'asc'); + } else { + setFlightSortField(field); + setFlightSortDir('asc'); + } + }; + + const sortedFlights = (flights: Flight[]) => + [...flights].sort((a, b) => { + const aVal = flightSortField === 'date' ? a.date : (a.price ?? Infinity); + const bVal = flightSortField === 'date' ? b.date : (b.price ?? Infinity); + if (aVal < bVal) return flightSortDir === 'asc' ? -1 : 1; + if (aVal > bVal) return flightSortDir === 'asc' ? 1 : -1; + return 0; + }); + const toggleFlights = async (destination: string) => { if (expandedRoute === destination) { setExpandedRoute(null); return; } setExpandedRoute(destination); @@ -217,6 +237,13 @@ export default function ScanDetails() { : ; }; + const FlightSortIcon = ({ field }: { field: 'date' | 'price' }) => { + if (flightSortField !== field) return ; + return flightSortDir === 'asc' + ? + : ; + }; + const thCls = (field?: typeof sortField) => cn( 'px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider select-none', field @@ -670,15 +697,29 @@ export default function ScanDetails() { - + - + - {(flightsByDest[route.destination] || []).map((f) => ( + {sortedFlights(flightsByDest[route.destination] || []).map((f) => (
Date handleFlightSort('date')} + > + + Date + + Airline Departure ArrivalPrice handleFlightSort('price')} + > + + Price + +
{weekday(f.date)}