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>
81 lines
3.4 KiB
Vue
81 lines
3.4 KiB
Vue
<script setup lang="ts">
|
|
import type { Leg } from '~/server/utils/flightics'
|
|
|
|
const props = defineProps<{
|
|
leg: Leg
|
|
index: number
|
|
originTzOffset?: number
|
|
showOriginTime?: boolean
|
|
}>()
|
|
|
|
const { resolve } = useAirlineNames()
|
|
|
|
function formatTime(dateStr: string) {
|
|
return new Date(dateStr).toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit' })
|
|
}
|
|
|
|
function formatDate(dateStr: string) {
|
|
return new Date(dateStr).toLocaleDateString('es-ES', { day: 'numeric', month: 'short' })
|
|
}
|
|
|
|
function segDuration(dep: number, arr: number) {
|
|
const mins = Math.round((arr - dep) / 60)
|
|
const h = Math.floor(mins / 60)
|
|
const m = mins % 60
|
|
return h > 0 ? `${h}h ${m}m` : `${m}m`
|
|
}
|
|
|
|
// Convert a UTC timestamp to a time string in the origin airport's timezone
|
|
function toOriginTime(utcTimestamp: number): string {
|
|
const localSeconds = utcTimestamp + (props.originTzOffset ?? 0)
|
|
const d = new Date(localSeconds * 1000)
|
|
return d.toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit', timeZone: 'UTC' })
|
|
}
|
|
|
|
// Check if a segment's local timezone differs from the origin
|
|
function isDifferentTz(localTimestamp: number, utcTimestamp: number): boolean {
|
|
return (localTimestamp - utcTimestamp) !== (props.originTzOffset ?? 0)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex items-center gap-4 py-2">
|
|
<UBadge :label="index === 0 ? 'Ida' : 'Vuelta'" :color="index === 0 ? 'primary' : 'info'" variant="subtle" size="sm" />
|
|
|
|
<div v-for="(seg, i) in leg.segments" :key="i" class="flex items-center gap-3 flex-1">
|
|
<div class="text-center">
|
|
<p class="text-lg font-semibold">{{ formatTime(seg.departureDate) }}</p>
|
|
<p v-if="showOriginTime && isDifferentTz(seg.departureTimestamp, seg.departureUtcTimestamp)" class="text-[10px] text-primary-500">({{ toOriginTime(seg.departureUtcTimestamp) }})</p>
|
|
<p class="text-xs text-neutral-500">{{ seg.departureCode }}</p>
|
|
<p class="text-xs text-neutral-400">{{ formatDate(seg.departureDate) }}</p>
|
|
</div>
|
|
|
|
<div class="flex-1 flex flex-col items-center">
|
|
<p class="text-xs text-neutral-500">
|
|
<span v-if="resolve(seg.company.code, seg.company.name)" class="font-medium">
|
|
{{ resolve(seg.company.code, seg.company.name) }} ·
|
|
</span>
|
|
<span>{{ seg.company.code }} {{ seg.number }}</span>
|
|
</p>
|
|
<div class="w-full relative flex items-center">
|
|
<div class="flex-1 border-t border-dashed border-neutral-300 dark:border-neutral-600" />
|
|
<div class="flex items-center gap-1 px-1.5">
|
|
<UIcon name="i-lucide-plane" class="text-neutral-400 text-xs" />
|
|
<span class="text-[10px] text-neutral-400 whitespace-nowrap">{{ segDuration(seg.departureUtcTimestamp, seg.arrivalUtcTimestamp) }}</span>
|
|
</div>
|
|
<div class="flex-1 border-t border-dashed border-neutral-300 dark:border-neutral-600" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="text-center">
|
|
<p class="text-lg font-semibold">{{ formatTime(seg.arrivalDate) }}</p>
|
|
<p v-if="showOriginTime && isDifferentTz(seg.arrivalTimestamp, seg.arrivalUtcTimestamp)" class="text-[10px] text-primary-500">({{ toOriginTime(seg.arrivalUtcTimestamp) }})</p>
|
|
<p class="text-xs text-neutral-500">{{ seg.arrivalCode }}</p>
|
|
<p class="text-xs text-neutral-400">{{ formatDate(seg.arrivalDate) }}</p>
|
|
</div>
|
|
|
|
<UIcon v-if="i < leg.segments.length - 1" name="i-lucide-arrow-right" class="text-neutral-300" />
|
|
</div>
|
|
</div>
|
|
</template>
|