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>
170 lines
4.6 KiB
Vue
170 lines
4.6 KiB
Vue
<script setup lang="ts">
|
|
const emit = defineEmits<{
|
|
search: [data: {
|
|
mode: string
|
|
departures: string[]
|
|
destination: string[]
|
|
dateFrom: string
|
|
dateTo: string
|
|
stayMinDays: number
|
|
stayMaxDays: number
|
|
passengers: { adult: number; child: number; infant: number }
|
|
maxStops: number | null
|
|
budget: number | null
|
|
}]
|
|
}>()
|
|
|
|
defineProps<{
|
|
compact?: boolean
|
|
}>()
|
|
|
|
const { homeAirports, defaultPassengers } = useUserPreferences()
|
|
|
|
const mode = ref('roundtrip')
|
|
const departures = ref('')
|
|
const destination = ref('')
|
|
const dateFrom = ref('')
|
|
const dateTo = ref('')
|
|
const stayMinDays = ref(2)
|
|
const stayMaxDays = ref(6)
|
|
const passengers = ref({ adult: 2, child: 0, infant: 0 })
|
|
const maxStops = ref<number | null>(null)
|
|
const budget = ref(500)
|
|
const showBudget = ref(false)
|
|
|
|
// Apply user preferences when available
|
|
watch(homeAirports, (airports) => {
|
|
if (airports.length && !departures.value) {
|
|
departures.value = airports.join(',')
|
|
}
|
|
}, { immediate: true })
|
|
|
|
watch(defaultPassengers, (p) => {
|
|
if (p.adult > 0) passengers.value = { ...p }
|
|
}, { immediate: true })
|
|
|
|
const showDestination = computed(() => mode.value !== 'explore')
|
|
const showDateTo = computed(() => mode.value !== 'oneway')
|
|
const showStayDuration = computed(() => ['roundtrip', 'multicity'].includes(mode.value))
|
|
const isWeekend = computed(() => mode.value === 'weekend')
|
|
const isExplore = computed(() => mode.value === 'explore')
|
|
|
|
function submit() {
|
|
emit('search', {
|
|
mode: mode.value,
|
|
departures: departures.value.split(',').map(s => s.trim().toUpperCase()).filter(Boolean),
|
|
destination: destination.value.split(',').map(s => s.trim().toUpperCase()).filter(Boolean),
|
|
dateFrom: dateFrom.value,
|
|
dateTo: dateTo.value || dateFrom.value,
|
|
stayMinDays: stayMinDays.value,
|
|
stayMaxDays: stayMaxDays.value,
|
|
passengers: passengers.value,
|
|
maxStops: maxStops.value,
|
|
budget: showBudget.value ? budget.value : null
|
|
})
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<form class="space-y-4" @submit.prevent="submit">
|
|
<SearchModeTabs v-model="mode" />
|
|
|
|
<div :class="compact ? 'space-y-3' : 'space-y-4'">
|
|
<!-- Origen -->
|
|
<UFormField label="Origen">
|
|
<SearchAirportInput
|
|
v-model="departures"
|
|
placeholder="Buscar aeropuerto..."
|
|
icon="i-lucide-plane-takeoff"
|
|
multiple
|
|
/>
|
|
</UFormField>
|
|
|
|
<!-- Destino (no en modo explorar) -->
|
|
<UFormField v-if="showDestination" label="Destino">
|
|
<SearchAirportInput
|
|
v-model="destination"
|
|
placeholder="NTE"
|
|
icon="i-lucide-plane-landing"
|
|
multiple
|
|
/>
|
|
</UFormField>
|
|
|
|
<!-- Fechas -->
|
|
<SearchDateRangePicker
|
|
v-model:date-from="dateFrom"
|
|
v-model:date-to="dateTo"
|
|
:single-date="!showDateTo"
|
|
/>
|
|
|
|
<!-- Estancia (roundtrip, multicity) -->
|
|
<SearchStayDurationPicker
|
|
v-if="showStayDuration"
|
|
v-model:min-days="stayMinDays"
|
|
v-model:max-days="stayMaxDays"
|
|
/>
|
|
|
|
<!-- Weekend hint -->
|
|
<UAlert
|
|
v-if="isWeekend"
|
|
color="info"
|
|
icon="i-lucide-info"
|
|
title="Busca vuelos de viernes a domingo automaticamente"
|
|
/>
|
|
|
|
<!-- Explore hint -->
|
|
<UAlert
|
|
v-if="isExplore"
|
|
color="info"
|
|
icon="i-lucide-compass"
|
|
title="Descubre destinos baratos desde tu aeropuerto"
|
|
/>
|
|
|
|
<!-- Pasajeros en popover -->
|
|
<UFormField label="Pasajeros">
|
|
<UPopover>
|
|
<UButton
|
|
:label="`${passengers.adult + passengers.child + passengers.infant} pasajero(s)`"
|
|
icon="i-lucide-users"
|
|
color="neutral"
|
|
variant="outline"
|
|
block
|
|
class="justify-start"
|
|
/>
|
|
<template #content>
|
|
<div class="p-4 w-64">
|
|
<PassengerPicker v-model="passengers" />
|
|
</div>
|
|
</template>
|
|
</UPopover>
|
|
</UFormField>
|
|
|
|
<!-- Opciones avanzadas -->
|
|
<div class="flex flex-wrap gap-4 items-end">
|
|
<div>
|
|
<p class="text-xs text-muted mb-1">Escalas</p>
|
|
<SearchMaxStopsFilter v-model="maxStops" />
|
|
</div>
|
|
<UButton
|
|
:label="showBudget ? 'Ocultar presupuesto' : 'Presupuesto max'"
|
|
icon="i-lucide-wallet"
|
|
color="neutral"
|
|
variant="ghost"
|
|
size="xs"
|
|
@click="showBudget = !showBudget"
|
|
/>
|
|
</div>
|
|
|
|
<SearchBudgetSlider v-if="showBudget" v-model="budget" />
|
|
</div>
|
|
|
|
<UButton
|
|
type="submit"
|
|
:label="isExplore ? 'Explorar destinos' : 'Buscar vuelos'"
|
|
icon="i-lucide-search"
|
|
size="lg"
|
|
block
|
|
/>
|
|
</form>
|
|
</template>
|