import { LoadingSpinner } from '@/assets/components/LoadingSpinner'; import { DashedDivider } from '@/assets/components/reserva/DashedDivider'; import { DocumentoRow } from '@/assets/components/reserva/DocumentoRow'; import { formatCurrency, formatDateLong, formatDateShort, getImageUrl, } from '@/assets/components/reserva/formatters'; import { HotelCard } from '@/assets/components/reserva/HotelCard'; import { PassageiroCard } from '@/assets/components/reserva/PassageiroCard'; import { Section } from '@/assets/components/reserva/Section'; import { StatusBadge } from '@/assets/components/reserva/StatusBadge'; import { ValorReservaCard } from '@/assets/components/reserva/ValorReservaCard'; import { VooCard } from '@/assets/components/reserva/VooCard'; import { API_ENDPOINTS, buildApiUrl } from '@/assets/config/api'; import { useAuth } from '@/assets/contexts/useAuth'; import { cacheReservaFull, getCachedReservaFull } from '@/assets/services/offlineStorage'; import { Documento, Escala, JsonData, Pagamento, ReservaData, ReservaResponse, VooDirection, VooSegment, } from '@/assets/types'; import styles from '@/styles/screens/reserva/detail.styles'; import { FontAwesome } from '@expo/vector-icons'; import { Stack, useLocalSearchParams } from 'expo-router'; import React, { useEffect, useMemo, useState } from 'react'; import { Image, RefreshControl, ScrollView, Text, View, } from 'react-native'; export default function ReservaDetalheScreen() { const { referencia } = useLocalSearchParams<{ referencia: string }>(); const { token } = useAuth(); const [isLoading, setIsLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const [error, setError] = useState(null); const [reservaData, setReservaData] = useState(null); const [pagamentos, setPagamentos] = useState([]); const [documentos, setDocumentos] = useState([]); const [expandedPassageiros, setExpandedPassageiros] = useState>(new Set()); const [cachedAt, setCachedAt] = useState(null); const [isFromCache, setIsFromCache] = useState(false); const togglePassageiro = (idx: number) => { setExpandedPassageiros((prev) => { const next = new Set(prev); if (next.has(idx)) { next.delete(idx); } else { next.add(idx); } return next; }); }; const fetchReserva = async () => { try { setError(null); if (!token || !referencia) { throw new Error('Dados de autenticacao em falta'); } const formData = new FormData(); formData.append('token', token); formData.append('referenciaViagem', referencia); const response = await fetch(buildApiUrl(API_ENDPOINTS.GET_RESERVA), { method: 'POST', headers: { Accept: 'application/json' }, body: formData, }); const data: ReservaResponse = await response.json(); if (!response.ok || data.status !== 200 || !data.reserva) { throw new Error(data.message || 'Nao foi possivel carregar a reserva'); } const pagamentosData = data.pagamentos || []; const documentosData = data.documentos || []; const now = new Date().toISOString(); setReservaData(data.reserva); setPagamentos(pagamentosData); setDocumentos(documentosData); setCachedAt(now); setIsFromCache(false); await cacheReservaFull(referencia, { reservaData: data.reserva, pagamentos: pagamentosData, documentos: documentosData, cachedAt: now, }); } catch { const cached = await getCachedReservaFull(referencia); if (cached) { setReservaData(cached.reservaData); setPagamentos(cached.pagamentos); setDocumentos(cached.documentos); setCachedAt(cached.cachedAt); setIsFromCache(true); setError(null); } else { setError('Sem ligação à internet e sem dados guardados para esta reserva.'); } } finally { setIsLoading(false); } }; useEffect(() => { fetchReserva(); }, [referencia, token]); const onRefresh = async () => { setRefreshing(true); await fetchReserva(); setRefreshing(false); }; const parsedJsonData = useMemo((): JsonData | null => { if (!reservaData?.jsonData) return null; try { return typeof reservaData.jsonData === 'string' ? (JSON.parse(reservaData.jsonData) as JsonData) : reservaData.jsonData; } catch { return null; } }, [reservaData?.jsonData]); const hotelInfo = parsedJsonData?.hotel || []; const extrasData = parsedJsonData?.extras ?? parsedJsonData?.extra ?? []; const voosData = parsedJsonData?.voo; const getVoosFromLeg = (leg?: VooDirection): (Escala | VooSegment)[] => { if (!leg) return []; if (Array.isArray(leg)) return leg; return leg.infoEscalas ?? []; }; const voosIda = getVoosFromLeg(voosData?.departure); const voosVolta = getVoosFromLeg(voosData?.arrival); const buildQuartosPassageiros = (data: ReservaData) => { const partes: string[] = []; if (data.quartos) partes.push(`${data.quartos} Quartos`); if (data.adultos) partes.push(`${data.adultos} Adultos`); if (data.criancas && data.criancas !== '0') partes.push(`${data.criancas} Crianças`); return partes.length ? partes.join(' · ') : `${data.pessoas} Passageiros`; }; const statusCode = String(reservaData?.status ?? ''); return ( ( ), }} /> {isLoading ? ( ) : ( }> {!!error && {error}} {reservaData && ( <> {isFromCache && ( Sem ligação — a mostrar dados guardados )} {reservaData.destino}
{!!reservaData.imagemCidade && ( )} ID #{reservaData.referenciaViagem} Ref. da Reserva {reservaData.localizador || '---'} Ref. do Operador
Destino {reservaData.destino} Data Viagem {formatDateLong(reservaData.startDate)} -{' '} {formatDateLong(reservaData.endDate)} Nr. de Noites {reservaData.noites} noites Quartos e Passageiros {buildQuartosPassageiros(reservaData)} Operador {reservaData.operador || '---'}
{hotelInfo.length > 0 ? ( hotelInfo.map((hotel, idx) => ( )) ) : ( Sem dados de alojamento. )}
{voosIda.length > 0 || voosVolta.length > 0 ? ( {voosIda.length > 0 && ( )} {voosVolta.length > 0 && ( )} ) : ( Sem dados de voos. )}
{reservaData.passageiros && reservaData.passageiros.length > 0 ? ( reservaData.passageiros.map((passageiro, idx) => ( togglePassageiro(idx)} /> )) ) : ( Sem passageiros associados. )}
{extrasData.length > 0 ? ( {extrasData.map((extra) => ( {extra.name} ))} ) : ( Sem extras associados. )}
{pagamentos.length > 0 ? ( <> Data Valor Meio Pag. {pagamentos.map((pagamento, idx) => ( {formatDateShort(pagamento.data_pagamento || pagamento.data_hora)} {formatCurrency(pagamento.valor)} {pagamento.metodoPagamento} ))} ) : ( Sem pagamentos registados. )}
{documentos.length > 0 ? ( documentos.map((documento, idx) => ( )) ) : ( Sem documentos associados. )}
{!!cachedAt && ( Atualizado em: {new Date(cachedAt).toLocaleDateString('pt-PT', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', })} )} )}
)}
); }