import React, { useState, useCallback, useEffect } from 'react'; import { View, Text, StyleSheet, ScrollView, TouchableOpacity, ImageBackground, Alert, ActivityIndicator } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { NavigationProp, useFocusEffect } from '@react-navigation/native'; import { Navigation, Clock, MapPin } from 'lucide-react-native'; import { colors } from '../../utils/colors'; import { useAuth } from '../../contexts/AuthContext'; import { supabase } from '../../services/supabase'; import { getDestinationLandmarkImage } from '../../services/destinationImage'; interface Props { navigation: NavigationProp; } type TripCardProps = { trip: any; }; const maskGoogleKeyInImageUrl = (url: string | null) => url?.replace(/([?&]key=)[^&]+/, '$1[REDACTED]') || null; function TripCard({ trip }: TripCardProps) { const [imageUrl, setImageUrl] = useState(trip.destination_image_url || null); const [landmarkName, setLandmarkName] = useState(trip.destination_landmark_name || null); const [placeId, setPlaceId] = useState(trip.destination_place_id || trip.place_id || null); const tripTitle = trip.title || trip.destination || 'Viagem'; useEffect(() => { let isMounted = true; console.log('[TripCardImageDebug] initial', { tripName: tripTitle, destination: trip.destination, placeId: trip.destination_place_id || trip.place_id || null, imageUrl: trip.destination_image_url || null, }); if (trip.destination_image_url || !trip.destination) return; getDestinationLandmarkImage(trip.destination, { tripTitle }).then(result => { if (!isMounted) return; setImageUrl(result.imageUrl); setLandmarkName(result.landmarkName); setPlaceId(result.placeId); console.log('[TripCardImageDebug] fetched', { tripName: tripTitle, destination: trip.destination, placeId: result.placeId, imageUrl: maskGoogleKeyInImageUrl(result.imageUrl), source: result.source, fallbackReason: result.fallbackReason, }); }); return () => { isMounted = false; }; }, [trip.destination, trip.destination_image_url, trip.destination_place_id, trip.place_id, tripTitle]); useEffect(() => { console.log('[TripCardImageDebug] render_image_uri', { tripName: tripTitle, destination: trip.destination, placeId, imageUrl: maskGoogleKeyInImageUrl(imageUrl), hasValidRemoteUri: Boolean(imageUrl?.startsWith('https://')), fallbackReason: imageUrl ? null : 'missing_image_url', }); }, [trip.destination, tripTitle, placeId, imageUrl]); const imageContent = ( {tripTitle} {landmarkName || trip.destination} ); return ( {imageUrl ? ( {imageContent} ) : ( {imageContent} )} {trip.distance} {trip.duration} {trip.origin} {trip.destination} ); } export default function HomeScreen({ navigation }: Props) { const { user } = useAuth(); const userName = user?.user_metadata?.display_name || user?.user_metadata?.name || user?.email || user?.user_metadata?.email || 'Viajante'; const initial = userName.charAt(0).toUpperCase(); const [trips, setTrips] = useState([]); const [loading, setLoading] = useState(true); const fetchTrips = useCallback(async () => { setLoading(true); try { console.log('[HomeScreen] Fetching trips. User exists:', !!user); let query = supabase.from('trips').select('*').order('created_at', { ascending: false }); if (user) { query = query.eq('user_id', user.id); } else { query = query.is('user_id', null); } const { data, error } = await query; if (error) { console.error('[HomeScreen] Supabase error fetching trips:', error); throw error; } console.log(`[HomeScreen] Fetched ${data?.length || 0} trips`); setTrips(data || []); } catch (error: any) { console.error('[HomeScreen] Error loading trips:', error.message); } finally { setLoading(false); } }, [user]); useFocusEffect( useCallback(() => { fetchTrips(); }, [fetchTrips]) ); return ( {/* Header Section */} As Tuas Viagens {initial} {loading ? ( ) : trips.length > 0 ? ( trips.map(trip => ( navigation.navigate('TripDetails', { trip })} > )) ) : ( Pronto para a próxima? Descobre a melhor rota e a banda sonora{'\n'}perfeita para o caminho. navigation.navigate('NewTripModal')} > Criar Nova Viagem )} ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: colors.background, }, scrollContent: { paddingHorizontal: 20, paddingTop: 10, paddingBottom: 120, // Extra space for bottom tab bar and floating button }, header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 24, }, title: { fontSize: 26, fontWeight: '800', color: colors.textMain, }, avatar: { width: 44, height: 44, borderRadius: 22, backgroundColor: '#FFE5D4', // Light orange justifyContent: 'center', alignItems: 'center', }, avatarText: { color: colors.primaryDark, fontWeight: 'bold', fontSize: 16, }, mainTripCard: { backgroundColor: colors.white, borderRadius: 24, shadowColor: '#000', shadowOffset: { width: 0, height: 8 }, shadowOpacity: 0.05, shadowRadius: 12, elevation: 4, marginBottom: 24, }, tripImage: { height: 180, justifyContent: 'flex-end', overflow: 'hidden', borderTopLeftRadius: 24, borderTopRightRadius: 24, }, tripImageStyle: { borderTopLeftRadius: 24, borderTopRightRadius: 24, }, tripImageFallback: { backgroundColor: '#2B2018', position: 'relative', }, tripImageFallbackGlow: { position: 'absolute', top: -50, right: -40, width: 180, height: 180, borderRadius: 90, backgroundColor: 'rgba(255, 122, 0, 0.35)', }, tripImageFallbackAccent: { position: 'absolute', left: -30, bottom: -60, width: 190, height: 190, borderRadius: 95, backgroundColor: 'rgba(255, 214, 180, 0.16)', }, imageOverlay: { padding: 20, paddingTop: 80, backgroundColor: 'rgba(0,0,0,0.42)', borderTopLeftRadius: 24, borderTopRightRadius: 24, }, tripImageTitle: { color: colors.white, fontSize: 24, fontWeight: '800', marginBottom: 6, }, tripImageSubtitle: { color: colors.white, fontSize: 15, fontWeight: '600', opacity: 0.92, }, tripContent: { padding: 20, }, statsRow: { flexDirection: 'row', alignItems: 'center', marginBottom: 20, }, statItem: { flexDirection: 'row', alignItems: 'center', gap: 6, }, statText: { fontSize: 15, fontWeight: 'bold', color: colors.textSecondary, }, statDot: { width: 4, height: 4, borderRadius: 2, backgroundColor: colors.inputBorder, marginHorizontal: 12, }, itinerarySnippet: { flexDirection: 'row', backgroundColor: colors.background, padding: 16, borderRadius: 16, }, timeline: { alignItems: 'center', marginRight: 12, paddingVertical: 4, }, dot: { width: 8, height: 8, borderRadius: 4, backgroundColor: colors.primary, }, dotEmpty: { backgroundColor: 'transparent', borderWidth: 2, borderColor: colors.primary, }, line: { width: 2, height: 20, backgroundColor: colors.inputBorder, marginVertical: 2, }, locations: { justifyContent: 'space-between', }, locationText: { fontSize: 15, fontWeight: '600', color: colors.textSecondary, }, promptCard: { backgroundColor: '#FFF5EB', // Very light orange borderRadius: 24, padding: 24, borderWidth: 2, borderColor: '#FFD4B8', // Dashed border color approx borderStyle: 'dashed', alignItems: 'center', }, promptTitle: { fontSize: 20, fontWeight: 'bold', color: '#8C3800', // Dark brownish orange marginBottom: 8, }, promptSubtitle: { fontSize: 14, color: '#B34700', textAlign: 'center', marginBottom: 20, lineHeight: 20, }, promptButton: { backgroundColor: colors.primary, paddingHorizontal: 24, paddingVertical: 14, borderRadius: 20, width: '100%', alignItems: 'center', }, promptButtonText: { color: colors.white, fontWeight: 'bold', fontSize: 16, }, });