import React, { useState, useEffect } from 'react'; import { View, Text, TouchableOpacity, ScrollView, ActivityIndicator, Dimensions, Platform, } from 'react-native'; import { MaterialIcons } from '@expo/vector-icons'; import { BlurView } from 'expo-blur'; import { Image } from 'expo-image'; import Animated, { FadeIn, FadeOut, useAnimatedStyle, useSharedValue, withTiming, withSpring, runOnJS, } from 'react-native-reanimated'; import { LinearGradient } from 'expo-linear-gradient'; import { useTheme } from '../../contexts/ThemeContext'; import { Cast } from '../../types/cast'; import { tmdbService } from '../../services/tmdbService'; import { useNavigation } from '@react-navigation/native'; import { NavigationProp } from '@react-navigation/native'; import { RootStackParamList } from '../../navigation/AppNavigator'; interface CastDetailsModalProps { visible: boolean; onClose: () => void; castMember: Cast | null; } const { width, height } = Dimensions.get('window'); const isTablet = width >= 768; const MODAL_WIDTH = isTablet ? Math.min(width * 0.8, 800) : Math.min(width - 40, 400); const MODAL_HEIGHT = isTablet ? Math.min(height * 0.85, 700) : height * 0.7; interface PersonDetails { id: number; name: string; biography: string; birthday: string | null; place_of_birth: string | null; known_for_department: string; profile_path: string | null; also_known_as: string[]; } export const CastDetailsModal: React.FC = ({ visible, onClose, castMember, }) => { const { currentTheme } = useTheme(); const navigation = useNavigation>(); const [personDetails, setPersonDetails] = useState(null); const [loading, setLoading] = useState(false); const [hasFetched, setHasFetched] = useState(false); const modalOpacity = useSharedValue(0); const modalScale = useSharedValue(0.9); useEffect(() => { if (visible && castMember) { modalOpacity.value = withTiming(1, { duration: 250 }); modalScale.value = withSpring(1, { damping: 20, stiffness: 200 }); if (!hasFetched || personDetails?.id !== castMember.id) { fetchPersonDetails(); } } else { modalOpacity.value = withTiming(0, { duration: 200 }); modalScale.value = withTiming(0.9, { duration: 200 }); if (!visible) { setHasFetched(false); setPersonDetails(null); } } }, [visible, castMember]); const fetchPersonDetails = async () => { if (!castMember || loading) return; setLoading(true); try { const details = await tmdbService.getPersonDetails(castMember.id); setPersonDetails(details); setHasFetched(true); } catch (error) { if (__DEV__) console.error('Error fetching person details:', error); } finally { setLoading(false); } }; const modalStyle = useAnimatedStyle(() => ({ opacity: modalOpacity.value, transform: [{ scale: modalScale.value }], })); const handleClose = () => { modalOpacity.value = withTiming(0, { duration: 200 }); modalScale.value = withTiming(0.9, { duration: 200 }, () => { runOnJS(onClose)(); }); }; const handleViewMovies = () => { if (castMember) { handleClose(); // Navigate after modal is closed setTimeout(() => { navigation.navigate('CastMovies', { castMember }); }, 300); } }; const formatDate = (dateString: string | null) => { if (!dateString) return null; const date = new Date(dateString); return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric', }); }; const calculateAge = (birthday: string | null) => { if (!birthday) return null; const today = new Date(); const birthDate = new Date(birthday); let age = today.getFullYear() - birthDate.getFullYear(); const monthDiff = today.getMonth() - birthDate.getMonth(); if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { age--; } return age; }; if (!visible || !castMember) return null; return ( {Platform.OS === 'ios' ? ( {renderContent()} ) : ( renderContent() )} ); function renderContent() { return ( <> {/* Header */} {castMember?.profile_path ? ( ) : ( {castMember?.name?.split(' ').reduce((prev: string, current: string) => prev + current[0], '').substring(0, 2)} )} {castMember?.name} {castMember?.character && ( as {castMember.character} )} {/* Content */} {loading ? ( Loading details... ) : ( {/* Basic Info */} {(personDetails?.birthday || personDetails?.place_of_birth) && ( {personDetails?.birthday && ( {calculateAge(personDetails.birthday)} years old )} {personDetails?.place_of_birth && ( Born in {personDetails.place_of_birth} )} )} {/* View Movies Button */} View Filmography {/* Biography */} {personDetails?.biography && ( {personDetails.biography} )} {/* Also Known As - Minimalistic */} {personDetails?.also_known_as && personDetails.also_known_as.length > 0 && ( Also Known As {personDetails.also_known_as.slice(0, 3).join(' • ')} )} {/* No details available */} {!loading && !personDetails?.biography && !personDetails?.birthday && !personDetails?.place_of_birth && !personDetails?.also_known_as?.length && ( No additional information available )} )} ); } }; export default CastDetailsModal;