diff --git a/flight-comparator/frontend/src/pages/Airports.tsx b/flight-comparator/frontend/src/pages/Airports.tsx index 099e742..4708e5c 100644 --- a/flight-comparator/frontend/src/pages/Airports.tsx +++ b/flight-comparator/frontend/src/pages/Airports.tsx @@ -1,129 +1,190 @@ -import { useState } from 'react'; +import { useRef, useState } from 'react'; +import { Search, MapPin, Copy, Check } from 'lucide-react'; import { airportApi } from '../api'; import type { Airport } from '../api'; +import EmptyState from '../components/EmptyState'; export default function Airports() { - const [query, setQuery] = useState(''); + const [query, setQuery] = useState(''); const [airports, setAirports] = useState([]); - const [loading, setLoading] = useState(false); - const [page, setPage] = useState(1); + const [loading, setLoading] = useState(false); + const [page, setPage] = useState(1); const [totalPages, setTotalPages] = useState(0); - const [total, setTotal] = useState(0); + const [total, setTotal] = useState(0); + const [searched, setSearched] = useState(false); + const [copied, setCopied] = useState(null); + const debounceTimer = useRef | undefined>(undefined); - const handleSearch = async (searchQuery: string, searchPage = 1) => { - if (searchQuery.length < 2) { + const doSearch = async (q: string, p = 1) => { + if (q.length < 2) { setAirports([]); + setSearched(false); return; } - try { setLoading(true); - const response = await airportApi.search(searchQuery, searchPage, 20); + const response = await airportApi.search(q, p, 20); setAirports(response.data.data); setTotalPages(response.data.pagination.pages); setTotal(response.data.pagination.total); - setPage(searchPage); - } catch (error) { - console.error('Failed to search airports:', error); + setPage(p); + setSearched(true); + } catch (err) { + console.error('Failed to search airports:', err); } finally { setLoading(false); } }; - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - handleSearch(query, 1); + const handleInputChange = (e: React.ChangeEvent) => { + const val = e.target.value; + setQuery(val); + if (debounceTimer.current) clearTimeout(debounceTimer.current); + debounceTimer.current = setTimeout(() => doSearch(val, 1), 300); + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter') { + if (debounceTimer.current) clearTimeout(debounceTimer.current); + doSearch(query, 1); + } + }; + + const copyCode = (code: string) => { + navigator.clipboard.writeText(code); + setCopied(code); + setTimeout(() => setCopied(null), 2000); }; return ( -
-

Airport Search

+
- {/* Search Form */} -
-
-
- setQuery(e.target.value)} - placeholder="Search by IATA code, city, or airport name..." - className="flex-1 px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" - /> - -
-

- Enter at least 2 characters to search -

-
+ {/* ── Search bar ────────────────────────────────────────────── */} +
+
- {/* Results */} - {airports.length > 0 && ( -
-
-

- Search Results -

- - {total} airport{total !== 1 ? 's' : ''} found + {/* ── Results ───────────────────────────────────────────────── */} + {loading ? ( +
Searching…
+ ) : airports.length > 0 ? ( +
+ {/* Table header */} +
+ Search Results + + {total} airport{total !== 1 ? 's' : ''}
-
- {airports.map((airport) => ( -
-
-
-
- + {/* Desktop table (hidden on mobile) */} +
+ + + + + + + + + + + {airports.map((airport) => ( + + + + + + + + ))} + +
IATAAirport NameCityCountry +
+ {airport.iata} - - {airport.name} - - -
- {airport.city}, {airport.country} -
+
{airport.name}{airport.city}{airport.country} + +
+
+ + {/* Mobile list (hidden on desktop) */} +
+ {airports.map((airport) => ( +
+
+
+ + {airport.iata} + + {airport.name}
- +

+ {airport.city}, {airport.country} +

+
))}
{/* Pagination */} {totalPages > 1 && ( -
-
+
+ Page {page} of {totalPages} -
-
+ +
@@ -131,14 +192,20 @@ export default function Airports() {
)}
+ ) : searched ? ( + + ) : ( + )} - {/* Empty State */} - {!loading && airports.length === 0 && query.length >= 2 && ( -
-

No airports found for "{query}"

-
- )}
); }