import { colors } from '@/assets/styles/colors'; import { useAuth } from '@/assets/contexts/useAuth'; import { API_ENDPOINTS, buildApiUrl } from '@/assets/config/api'; import { cacheReservas, getCachedReservas } from '@/assets/services/offlineStorage'; import { downloadDocumentos, getDocumentosChecksums, verificarDocumentosParaDownload } from '@/assets/services/documentSync'; import { Reserva, ReservasResponse } from '@/assets/types'; import { Href, router } from 'expo-router'; import styles from '@/styles/screens/tabs/home.styles'; import { useEffect, useMemo, useState } from 'react'; import { LoadingSpinner } from '@/assets/components/LoadingSpinner'; import { Alert, Image, Pressable, RefreshControl, ScrollView, Text, View, } from 'react-native'; import { FontAwesome } from '@expo/vector-icons'; const getStatusPriority = (statusCode: string): number => { switch (statusCode) { case '10': return 1; // Em viagem case '1': case '5': return 2; // Confirmada case '-1': return 3; // Em pagamento case '-2': case '-3': return 4; // Pendente case '99': return 5; // Viagem realizada case '-5': return 7; // Cancelada — sempre no fim default: return 6; } }; export default function Home() { const { token } = useAuth(); const [reservas, setReservas] = useState([]); const [isLoading, setIsLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const [error, setError] = useState(null); const [isFromCache, setIsFromCache] = useState(false); const syncDocumentos = async () => { if (!token) return; try { const checksumsData = await getDocumentosChecksums(token); if (!checksumsData || checksumsData.status !== 200 || !checksumsData.documentos?.length) return; const documentosParaDownload = await verificarDocumentosParaDownload(checksumsData.documentos); if (!documentosParaDownload.length) return; Alert.alert( 'Documentos disponíveis', `Existem ${documentosParaDownload.length} ficheiro${documentosParaDownload.length === 1 ? '' : 's'} novo${documentosParaDownload.length === 1 ? '' : 's'} para descarregar/atualizar. Pretende descarregá-los agora?`, [ { text: 'Não', style: 'cancel' }, { text: 'Sim', onPress: () => downloadDocumentos(documentosParaDownload), }, ], ); } catch { // sync de documentos é silencioso — não bloqueia o utilizador } }; const fetchReservas = async () => { try { setError(null); if (!token) { setReservas([]); setIsFromCache(false); return; } const url = buildApiUrl(API_ENDPOINTS.USER_RESERVAS); const formData = new FormData(); formData.append('token', token); const response = await fetch(url, { method: 'POST', headers: { Accept: 'application/json', }, body: formData, }); const data: ReservasResponse = await response.json(); if (!response.ok || (data.status !== 200 && data.status !== '200')) { throw new Error(data.message || 'Erro ao carregar reservas'); } const orderedReservas = [...(data.reservas || [])].sort((a, b) => { const priorityDiff = getStatusPriority(a.statusCode) - getStatusPriority(b.statusCode); if (priorityDiff !== 0) return priorityDiff; return new Date(a.startDate).getTime() - new Date(b.startDate).getTime(); }); setReservas(orderedReservas); setIsFromCache(false); await cacheReservas(orderedReservas); syncDocumentos(); } catch { const cached = await getCachedReservas(); if (cached && cached.length > 0) { setReservas(cached); setIsFromCache(true); setError(null); } else { setError('Sem ligação à internet e sem dados guardados.'); } } finally { setIsLoading(false); } }; useEffect(() => { setReservas([]); setIsFromCache(false); setIsLoading(true); fetchReservas(); }, [token]); const onRefresh = async () => { setRefreshing(true); await fetchReservas(); setRefreshing(false); }; const stats = useMemo(() => { const now = new Date(); const proximas = reservas.filter((reserva) => new Date(reserva.startDate) >= now); const total = reservas.length; const confirmadas = reservas.filter((reserva) => reserva.statusCode === '1').length; const proxima = proximas[0]; let dias = '--'; if (proxima) { const diff = new Date(proxima.startDate).getTime() - now.getTime(); dias = `${Math.max(0, Math.ceil(diff / (1000 * 60 * 60 * 24)))}`; } const reservaEmViagem = reservas.find((reserva) => reserva.statusCode === '10'); return { dias, total, confirmadas, emViagem: Boolean(reservaEmViagem), destinoEmViagem: reservaEmViagem?.destino?.trim() || '—', }; }, [reservas]); const getStatusType = (statusCode: string) => { if (statusCode === '1' || statusCode === '5') return 'verde'; if (statusCode === '-5') return 'vermelho'; if (statusCode === '10' || statusCode === '99') return 'roxo'; if (statusCode === '-2' || statusCode === '-1' || statusCode === '-3') return 'amarelo'; return 'neutral'; }; const getStatusColor = (statusType: string) => { switch (statusType) { case 'verde': return '#13AE45'; case 'vermelho': return '#E6463B'; case 'roxo': return '#B138E6'; case 'amarelo': return '#C99700'; default: return '#4A6592'; } }; const getStatusConfig = (statusCode: string) => { switch (statusCode) { case '1': return { label: 'Confirmada', icon: 'check-circle' as const }; case '5': return { label: 'Confirmada*', icon: 'check-circle' as const }; case '-5': return { label: 'Cancelada', icon: 'times-circle' as const }; case '10': return { label: 'Em Viagem', icon: 'ship' as const }; case '99': return { label: 'Viagem Realizada', icon: 'ship' as const }; case '-2': case '-3': return { label: 'Pendente', icon: 'clock-o' as const }; case '-1': return { label: 'Em pagamento', icon: 'clock-o' as const }; default: return { label: 'Não definido', icon: 'question-circle' as const }; } }; if (isLoading) { return ( ); } console.log(reservas); return ( }> {stats.emViagem ? ( ) : ( )} {stats.emViagem ? 'Em viagem' : 'Proxima Viagem'} {stats.emViagem ? stats.destinoEmViagem : `${stats.dias} dias`} Total Reservas {stats.total} Confirmadas {stats.confirmadas} {isFromCache && ( Sem ligação — a mostrar dados guardados )} As minhas Reservas {!!error && {error}} {!error && reservas.length === 0 && ( Sem reservas para apresentar. )} {!error && reservas.map((reserva, index) => { const statusType = getStatusType(reserva.statusCode); const statusConfig = getStatusConfig(reserva.statusCode); const statusColor = getStatusColor(statusType); return ( router.push(`/reserva/${encodeURIComponent(reserva.referenciaViagem || '')}` as Href) }> {reserva.referenciaViagem || '---'} {statusConfig.label} {reserva.destino} {reserva.pais} {reserva.startDate} ); })} ); }