Initial commit: Vuelato - buscador de vuelos
Some checks failed
ci / ci (22, ubuntu-latest) (push) Has been cancelled
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>
This commit is contained in:
67
app/composables/useLocations.ts
Normal file
67
app/composables/useLocations.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
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 }
|
||||
}
|
||||
Reference in New Issue
Block a user