Some checks failed
ci / ci (22, ubuntu-latest) (push) Has been cancelled
Nuxt 4 + Supabase + Flightics API. Incluye búsqueda de vuelos, inspiraciones, watchlist, tracking de precios y mapa interactivo. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
68 lines
1.8 KiB
TypeScript
68 lines
1.8 KiB
TypeScript
interface AirportResult {
|
|
iata: string
|
|
name: string
|
|
city_name: string
|
|
country_code: string
|
|
country_name: string
|
|
lat: number | null
|
|
lon: number | null
|
|
}
|
|
|
|
export function useLocations() {
|
|
const supabase = useSupabaseClient()
|
|
|
|
const airports = ref<AirportResult[]>([])
|
|
const loaded = ref(false)
|
|
|
|
async function loadAirports() {
|
|
if (loaded.value) return
|
|
const { data } = await supabase
|
|
.from('airports')
|
|
.select('iata, name, city_name, country_code, country_name, lat, lon')
|
|
.order('iata')
|
|
.limit(10000)
|
|
if (data && data.length > 0) {
|
|
airports.value = data as AirportResult[]
|
|
loaded.value = true
|
|
} else {
|
|
// Fallback: fetch from Flightics API and cache in Supabase
|
|
await syncLocations()
|
|
}
|
|
}
|
|
|
|
async function syncLocations() {
|
|
try {
|
|
const data = await $fetch('/api/sync/locations', { method: 'POST' })
|
|
if (data?.count) {
|
|
// Reload from Supabase after sync
|
|
const { data: fresh } = await supabase
|
|
.from('airports')
|
|
.select('iata, name, city_name, country_code, country_name, lat, lon')
|
|
.order('iata')
|
|
airports.value = (fresh as AirportResult[]) || []
|
|
loaded.value = true
|
|
}
|
|
} catch {
|
|
// Silently fail, user can retry
|
|
}
|
|
}
|
|
|
|
function normalize(s: string): string {
|
|
return s.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase()
|
|
}
|
|
|
|
function searchAirports(query: string): AirportResult[] {
|
|
if (!query || query.length < 2) return []
|
|
const q = normalize(query)
|
|
return airports.value
|
|
.filter(a =>
|
|
normalize(a.iata).includes(q) ||
|
|
normalize(a.name).includes(q) ||
|
|
normalize(a.city_name || '').includes(q)
|
|
)
|
|
.slice(0, 20)
|
|
}
|
|
|
|
return { airports, loaded, loadAirports, searchAirports, syncLocations }
|
|
}
|