import React, { useEffect, useState, useCallback, useMemo } from 'react'; import { View, Text, StyleSheet, FlatList, TouchableOpacity, ActivityIndicator, Dimensions } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import { NavigationProp } from '@react-navigation/native'; import { Image } from 'expo-image'; import { LinearGradient } from 'expo-linear-gradient'; import { MaterialIcons } from '@expo/vector-icons'; import { useTheme } from '../../contexts/ThemeContext'; import { useTraktContext } from '../../contexts/TraktContext'; import { stremioService } from '../../services/stremioService'; import { tmdbService } from '../../services/tmdbService'; import { useLibrary } from '../../hooks/useLibrary'; import { RootStackParamList } from '../../navigation/AppNavigator'; import { parseISO, isThisWeek, format, isAfter, isBefore } from 'date-fns'; import Animated, { FadeIn } from 'react-native-reanimated'; import { useCalendarData } from '../../hooks/useCalendarData'; const { width } = Dimensions.get('window'); const ITEM_WIDTH = width * 0.75; // Reduced width for better spacing const ITEM_HEIGHT = 180; // Compact height for cleaner design interface ThisWeekEpisode { id: string; seriesId: string; seriesName: string; title: string; poster: string; releaseDate: string; season: number; episode: number; isReleased: boolean; overview: string; vote_average: number; still_path: string | null; season_poster_path: string | null; } export const ThisWeekSection = React.memo(() => { const navigation = useNavigation>(); const { libraryItems, loading: libraryLoading } = useLibrary(); const { isAuthenticated: traktAuthenticated, isLoading: traktLoading, watchedShows, watchlistShows, continueWatching, loadAllCollections } = useTraktContext(); const { currentTheme } = useTheme(); const { calendarData, loading } = useCalendarData(); const thisWeekEpisodes = useMemo(() => { const thisWeekSection = calendarData.find(section => section.title === 'This Week'); if (!thisWeekSection) return []; return thisWeekSection.data.map(episode => ({ ...episode, isReleased: isBefore(parseISO(episode.releaseDate), new Date()), })); }, [calendarData]); const handleEpisodePress = (episode: ThisWeekEpisode) => { // For upcoming episodes, go to the metadata screen if (!episode.isReleased) { const episodeId = `${episode.seriesId}:${episode.season}:${episode.episode}`; navigation.navigate('Metadata', { id: episode.seriesId, type: 'series', episodeId }); return; } // For released episodes, go to the streams screen const episodeId = `${episode.seriesId}:${episode.season}:${episode.episode}`; navigation.navigate('Streams', { id: episode.seriesId, type: 'series', episodeId }); }; const handleViewAll = () => { navigation.navigate('Calendar' as any); }; if (thisWeekEpisodes.length === 0) { return null; } const renderEpisodeItem = ({ item, index }: { item: ThisWeekEpisode, index: number }) => { const releaseDate = parseISO(item.releaseDate); const formattedDate = format(releaseDate, 'E, MMM d'); const isReleased = item.isReleased; // Use episode still image if available, fallback to series poster const imageUrl = item.still_path ? tmdbService.getImageUrl(item.still_path) : (item.season_poster_path ? tmdbService.getImageUrl(item.season_poster_path) : item.poster); return ( handleEpisodePress(item)} activeOpacity={0.8} > {/* Enhanced gradient overlay */} {/* Content area */} {item.seriesName} {item.title} {item.overview && ( {item.overview} )} S{item.season}:E{item.episode} • {formattedDate} ); }; return ( This Week View All item.id} renderItem={renderEpisodeItem} horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles.listContent} snapToInterval={ITEM_WIDTH + 16} decelerationRate="fast" snapToAlignment="start" ItemSeparatorComponent={() => } /> ); }); const styles = StyleSheet.create({ container: { marginVertical: 20, }, header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: 16, marginBottom: 16, }, titleContainer: { position: 'relative', }, title: { fontSize: 24, fontWeight: '800', letterSpacing: 0.5, marginBottom: 4, }, titleUnderline: { position: 'absolute', bottom: -2, left: 0, width: 40, height: 3, borderRadius: 2, opacity: 0.8, }, viewAllButton: { flexDirection: 'row', alignItems: 'center', paddingVertical: 8, paddingHorizontal: 10, borderRadius: 20, backgroundColor: 'rgba(255,255,255,0.1)', marginRight: -10, }, viewAllText: { fontSize: 14, fontWeight: '600', marginRight: 4, }, listContent: { paddingLeft: 16, paddingRight: 16, paddingBottom: 8, }, loadingContainer: { padding: 32, alignItems: 'center', }, loadingText: { marginTop: 12, fontSize: 16, fontWeight: '500', }, episodeItemContainer: { width: ITEM_WIDTH, height: ITEM_HEIGHT, }, episodeItem: { width: '100%', height: '100%', borderRadius: 16, overflow: 'hidden', shadowOffset: { width: 0, height: 8 }, shadowOpacity: 0.3, shadowRadius: 12, elevation: 12, }, imageContainer: { width: '100%', height: '100%', position: 'relative', }, poster: { width: '100%', height: '100%', borderRadius: 16, }, gradient: { position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, justifyContent: 'flex-end', padding: 12, borderRadius: 16, }, contentArea: { width: '100%', }, seriesName: { fontSize: 16, fontWeight: '700', marginBottom: 6, }, episodeTitle: { fontSize: 14, fontWeight: '600', marginBottom: 4, lineHeight: 18, }, overview: { fontSize: 12, lineHeight: 16, marginBottom: 6, opacity: 0.9, }, dateContainer: { flexDirection: 'row', alignItems: 'center', marginTop: 4, }, episodeInfo: { fontSize: 12, fontWeight: '600', marginRight: 4, }, releaseDate: { fontSize: 13, fontWeight: '600', marginLeft: 6, letterSpacing: 0.3, }, });