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>
136 lines
3.9 KiB
TypeScript
136 lines
3.9 KiB
TypeScript
interface WatchlistItem {
|
|
id: string
|
|
booking_token: string
|
|
route_summary: string
|
|
departure_code: string
|
|
arrival_code: string
|
|
departure_date: string
|
|
original_price: number
|
|
current_price: number | null
|
|
price_status: string
|
|
passengers_adult: number
|
|
passengers_child: number
|
|
passengers_infant: number
|
|
last_checked_at: string | null
|
|
created_at: string
|
|
}
|
|
|
|
export function useWatchlist() {
|
|
const supabase = useSupabaseClient()
|
|
const user = useSupabaseUser()
|
|
|
|
const items = ref<WatchlistItem[]>([])
|
|
const loading = ref(false)
|
|
|
|
async function fetchAll() {
|
|
if (!user.value) return
|
|
loading.value = true
|
|
const { data } = await supabase
|
|
.from('watchlist')
|
|
.select('*')
|
|
.order('created_at', { ascending: false })
|
|
items.value = (data as WatchlistItem[]) || []
|
|
loading.value = false
|
|
}
|
|
|
|
async function add(params: {
|
|
bookingToken: string
|
|
routeSummary: string
|
|
departureCode: string
|
|
arrivalCode: string
|
|
departureDate: string
|
|
price: number
|
|
passengers: { adult: number; child: number; infant: number }
|
|
}) {
|
|
if (!user.value) return false
|
|
const { error } = await supabase.from('watchlist').insert({
|
|
user_id: user.value.id,
|
|
booking_token: params.bookingToken,
|
|
route_summary: params.routeSummary,
|
|
departure_code: params.departureCode,
|
|
arrival_code: params.arrivalCode,
|
|
departure_date: params.departureDate,
|
|
original_price: params.price,
|
|
current_price: params.price,
|
|
passengers_adult: params.passengers.adult,
|
|
passengers_child: params.passengers.child,
|
|
passengers_infant: params.passengers.infant
|
|
})
|
|
if (!error) await fetchAll()
|
|
return !error
|
|
}
|
|
|
|
async function remove(id: string) {
|
|
const { error } = await supabase.from('watchlist').delete().eq('id', id)
|
|
if (!error) items.value = items.value.filter(i => i.id !== id)
|
|
return !error
|
|
}
|
|
|
|
async function checkPrice(item: WatchlistItem) {
|
|
try {
|
|
const data = await $fetch<any>('/api/check', {
|
|
method: 'POST',
|
|
body: {
|
|
bookingToken: item.booking_token,
|
|
local: 'en',
|
|
passengersCount: {
|
|
adult: item.passengers_adult,
|
|
child: item.passengers_child,
|
|
infant: item.passengers_infant
|
|
}
|
|
}
|
|
})
|
|
|
|
const newPrice = data.trip.totalCost
|
|
let status = 'available'
|
|
if (newPrice < item.original_price) status = 'price_down'
|
|
else if (newPrice > item.original_price) status = 'price_up'
|
|
|
|
await supabase.from('watchlist').update({
|
|
current_price: newPrice,
|
|
price_status: status,
|
|
last_checked_at: new Date().toISOString()
|
|
}).eq('id', item.id)
|
|
|
|
// Update local state
|
|
const idx = items.value.findIndex(i => i.id === item.id)
|
|
if (idx >= 0) {
|
|
items.value[idx] = { ...items.value[idx], current_price: newPrice, price_status: status, last_checked_at: new Date().toISOString() }
|
|
}
|
|
return { price: newPrice, status }
|
|
} catch {
|
|
await supabase.from('watchlist').update({
|
|
price_status: 'unavailable',
|
|
last_checked_at: new Date().toISOString()
|
|
}).eq('id', item.id)
|
|
|
|
const idx = items.value.findIndex(i => i.id === item.id)
|
|
if (idx >= 0) {
|
|
items.value[idx] = { ...items.value[idx], price_status: 'unavailable', last_checked_at: new Date().toISOString() }
|
|
}
|
|
return { price: null, status: 'unavailable' }
|
|
}
|
|
}
|
|
|
|
async function checkAll() {
|
|
for (const item of items.value) {
|
|
await checkPrice(item)
|
|
}
|
|
}
|
|
|
|
function isWatched(bookingToken: string) {
|
|
return items.value.some(i => i.booking_token === bookingToken)
|
|
}
|
|
|
|
function getWatchedItem(bookingToken: string) {
|
|
return items.value.find(i => i.booking_token === bookingToken)
|
|
}
|
|
|
|
watch(user, (u) => {
|
|
if (u) fetchAll()
|
|
else items.value = []
|
|
}, { immediate: true })
|
|
|
|
return { items, loading, fetchAll, add, remove, checkPrice, checkAll, isWatched, getWatchedItem }
|
|
}
|