'use client'; import { useState, useRef, useEffect } from 'react'; import Image from 'next/image'; import Link from 'next/link'; import AnimeRow from './AnimeRow'; import SeasonRow from './SeasonRow'; import { fetchAnimeEpisodes } from '@/lib/api'; export default function AnimeDetails({ anime }) { const [isExpanded, setIsExpanded] = useState(false); const [activeVideo, setActiveVideo] = useState(null); const [activeTab, setActiveTab] = useState('synopsis'); const [synopsisOverflows, setSynopsisOverflows] = useState(false); const [firstEpisodeId, setFirstEpisodeId] = useState(null); const [isLoadingEpisodes, setIsLoadingEpisodes] = useState(false); const synopsisRef = useRef(null); // Check if synopsis overflows when component mounts or when content changes useEffect(() => { if (synopsisRef.current) { const element = synopsisRef.current; setSynopsisOverflows(element.scrollHeight > element.clientHeight); } }, [anime?.info?.description, activeTab]); // Fetch first episode ID when component mounts useEffect(() => { const fetchFirstEpisode = async () => { if (anime?.info?.id) { setIsLoadingEpisodes(true); try { console.log(`[AnimeDetails] Fetching episodes for anime: ${anime.info.id}`); const response = await fetchAnimeEpisodes(anime.info.id); console.log('[AnimeDetails] Episodes response:', response); if (response.episodes && response.episodes.length > 0) { // Log the first episode to check its structure console.log('[AnimeDetails] First episode:', response.episodes[0]); // Get the first episode's id const firstEp = response.episodes[0]; if (firstEp.id) { setFirstEpisodeId(firstEp.id); console.log(`[AnimeDetails] First episode ID found: ${firstEp.id}`); } else if (firstEp.episodeId) { // Fallback to episodeId if id is not available setFirstEpisodeId(firstEp.episodeId); console.log(`[AnimeDetails] Falling back to episodeId: ${firstEp.episodeId}`); } else { // If no episode ID is found in the API response, create a fallback ID const fallbackId = `${anime.info.id}?ep=1`; setFirstEpisodeId(fallbackId); console.log(`[AnimeDetails] Using fallback ID: ${fallbackId}`); } } else if (anime.info.id) { // If no episodes found but anime ID is available, use fallback const fallbackId = `${anime.info.id}?ep=1`; setFirstEpisodeId(fallbackId); console.log(`[AnimeDetails] No episodes found, using fallback ID: ${fallbackId}`); } else { console.warn('[AnimeDetails] No episodes found and no anime ID available'); } } catch (error) { console.error('[AnimeDetails] Error fetching episodes:', error); // Even on error, try to use fallback if (anime.info.id) { const fallbackId = `${anime.info.id}?ep=1`; setFirstEpisodeId(fallbackId); console.log(`[AnimeDetails] Error occurred, using fallback ID: ${fallbackId}`); } } finally { setIsLoadingEpisodes(false); } } }; fetchFirstEpisode(); }, [anime?.info?.id]); // Add a useEffect to debug when and why firstEpisodeId changes useEffect(() => { console.log('[AnimeDetails] firstEpisodeId changed:', firstEpisodeId); }, [firstEpisodeId]); if (!anime?.info) { return null; } const { info, moreInfo, relatedAnime, recommendations, seasons } = anime; const hasCharacters = info.characterVoiceActor?.length > 0 || info.charactersVoiceActors?.length > 0; const hasVideos = info.promotionalVideos && info.promotionalVideos.length > 0; // Build the watch URL based on the first episode ID const watchUrl = firstEpisodeId ? `/watch/${firstEpisodeId}` : ''; // Empty string if no episodes available - this shouldn't happen with our fallback // Add debug log here console.log('[AnimeDetails] Rendered with watchUrl:', watchUrl, 'firstEpisodeId:', firstEpisodeId); // Video modal for promotional videos const VideoModal = ({ video, onClose }) => { if (!video) return null; return (
); }; // Format status with aired date const getStatusWithAired = () => { let status = moreInfo?.status || ''; if (moreInfo?.aired) { status += ` (${moreInfo.aired})`; } return status; }; return (
{/* Video Modal */} {activeVideo && setActiveVideo(null)} />} {/* Background Image with Gradient Overlay - Desktop Only */}
{info.poster && ( <> {info.name}
)}
{/* Main Content */}
{/* MOBILE LAYOUT - Only visible on mobile */}
{/* Mobile Header with Title + Rating */}

{info.name}

{info.stats?.rating && (
{info.stats.rating}
)}
{/* Japanese Title */} {moreInfo?.japanese && (

{moreInfo.japanese}

)} {/* Mobile Two-Column Layout */}
{/* Left Column - Poster */}
{info.name}
{/* Right Column - Info Card */}
{/* Type & Episodes on same row */}
{info.stats?.type && (
{info.stats.type}
)} {info.stats?.episodes && (
{info.stats.episodes.sub > 0 && `Sub: ${info.stats.episodes.sub}`} {info.stats.episodes.dub > 0 && info.stats.episodes.sub > 0 && ' • '} {info.stats.episodes.dub > 0 && `Dub: ${info.stats.episodes.dub}`}
)}
{/* Clean Info Layout */}
{/* Status */} {moreInfo?.status && (
Status: {getStatusWithAired()}
)} {/* Quality */} {info.stats?.quality && (
Quality: {info.stats.quality}
)} {/* Duration */} {info.stats?.duration && (
Duration: {info.stats.duration}
)} {/* Studio */} {moreInfo?.studios && (
Studio: {moreInfo.studios}
)}
{/* Mobile Genres */} {moreInfo?.genres && moreInfo.genres.length > 0 && (
{moreInfo.genres.slice(0, 5).map((genre, index) => ( {genre} ))} {moreInfo.genres.length > 5 && ( +{moreInfo.genres.length - 5} )}
)}
{/* Watch Button - Mobile */} {firstEpisodeId && ( Start Watching )}
{/* DESKTOP LAYOUT - Only visible on desktop */}
{/* Poster */}
{info.name}
{/* Watch Button - Desktop */} {firstEpisodeId && ( Start Watching )}
{/* Title and Metadata */}
{/* Title Section */}

{info.name}

{moreInfo?.japanese && (

{moreInfo.japanese}

)} {/* Synonyms */} {moreInfo?.synonyms && (

{moreInfo.synonyms}

)}
{/* Status Badges */}
{info.stats?.rating && (
{info.stats.rating}
)} {/* Status with Aired Date */} {moreInfo?.status && (
{getStatusWithAired()}
)} {info.stats?.type && (
{info.stats.type}
)} {info.stats?.episodes && (
{info.stats.episodes.sub > 0 && `SUB ${info.stats.episodes.sub}`} {info.stats.episodes.dub > 0 && info.stats.episodes.sub > 0 && ' | '} {info.stats.episodes.dub > 0 && `DUB ${info.stats.episodes.dub}`}
)} {info.stats?.quality && (
{info.stats.quality}
)} {info.stats?.duration && (
{info.stats.duration}
)}
{/* Genres & Studios */}
{/* Genres */} {moreInfo?.genres && moreInfo.genres.length > 0 && (

Genres

{moreInfo.genres.map((genre, index) => ( {genre} ))}
)} {/* Studios */} {moreInfo?.studios && (

Studios

{moreInfo.studios}
)}
{/* Tabs Section - Different for Mobile/Desktop */}
{/* Tab Navigation */}
{/* Synopsis Tab */} {/* Characters Tab */} {hasCharacters && ( )} {/* Videos Tab */} {hasVideos && ( )}
{/* Tab Content */}
{/* Synopsis Tab */} {activeTab === 'synopsis' && (

{info.description || 'No description available for this anime.'}

{synopsisOverflows && ( )}
)} {/* Characters Tab */} {activeTab === 'characters' && hasCharacters && (
{(info.characterVoiceActor || info.charactersVoiceActors || []).map((item, index) => (
{/* Character Image */}
{item.character.name}
{/* Text content in the middle */}
{/* Character Name */}

{item.character.name}

{item.character.cast || 'Main'}

{/* Voice Actor Name */}

{item.voiceActor.name}

{item.voiceActor.cast || 'Japanese'}

{/* Voice Actor Image */}
{item.voiceActor.name}
))}
)} {/* Videos Tab */} {activeTab === 'videos' && hasVideos && (
{info.promotionalVideos.map((video, index) => (
setActiveVideo(video)} >
{video.title
))}
)}
{/* Seasons Section */} {seasons && seasons.length > 0 && ( )} {/* Related Anime Section */} {relatedAnime && relatedAnime.length > 0 && ( )} {/* Recommendations Section */} {recommendations && recommendations.length > 0 && ( )}
); }