|
|
|
import React from 'react'; |
|
import { Check, Play, X } from 'lucide-react'; |
|
|
|
interface Episode { |
|
episode_number: number; |
|
name: string; |
|
fileName?: string; |
|
} |
|
|
|
interface Season { |
|
season_number: number; |
|
name: string; |
|
episodes: Episode[]; |
|
} |
|
|
|
interface PlaybackProgress { |
|
[key: string]: { |
|
currentTime: number; |
|
duration: number; |
|
lastPlayed: string; |
|
completed: boolean; |
|
}; |
|
} |
|
|
|
interface EpisodesPanelProps { |
|
seasons: Season[]; |
|
selectedSeason: string; |
|
selectedEpisode: string; |
|
playbackProgress: PlaybackProgress; |
|
onSelectEpisode: (seasonName: string, episode: Episode) => void; |
|
onClose: () => void; |
|
showTitle?: string; |
|
} |
|
|
|
const EpisodesPanel: React.FC<EpisodesPanelProps> = ({ |
|
seasons, |
|
selectedSeason, |
|
selectedEpisode, |
|
playbackProgress, |
|
onSelectEpisode, |
|
onClose, |
|
showTitle = 'Episodes' |
|
}) => { |
|
|
|
const getEpisodeProgress = (seasonName: string, episodeFileName: string) => { |
|
const episodeId = `${seasonName}-${episodeFileName}`; |
|
return playbackProgress[episodeId] || null; |
|
}; |
|
|
|
return ( |
|
<div className="h-full flex flex-col"> |
|
<div className="p-6 flex justify-between items-center border-b border-gray-800"> |
|
<h2 className="text-2xl font-bold text-white">{showTitle}</h2> |
|
<button |
|
onClick={onClose} |
|
className="text-white hover:text-gray-300 transition-colors" |
|
aria-label="Close episodes panel" |
|
> |
|
<X className="h-6 w-6" /> |
|
</button> |
|
</div> |
|
|
|
<div className="flex-1 overflow-y-auto p-6 space-y-8"> |
|
{seasons.map((season) => ( |
|
<div key={season.name} className="mb-6"> |
|
<h3 className="text-xl font-bold mb-3 text-white">{season.name}</h3> |
|
<div className="space-y-2"> |
|
{season.episodes.map((episode) => { |
|
const progress = getEpisodeProgress(season.name, episode.fileName || ''); |
|
const progressPercent = progress |
|
? Math.min(100, Math.floor((progress.currentTime / progress.duration) * 100)) |
|
: 0; |
|
|
|
return ( |
|
<div |
|
key={episode.fileName} |
|
className={`p-3 rounded-md flex items-start hover:bg-gray-800 cursor-pointer transition-colors ${selectedEpisode === episode.fileName ? 'bg-gray-800' : 'bg-gray-900/60'}`} |
|
onClick={() => onSelectEpisode(season.name, episode)} |
|
> |
|
<div className="flex-shrink-0 mr-3"> |
|
{selectedEpisode === episode.fileName ? ( |
|
<div className="w-4 h-4 rounded-full bg-red-600 flex items-center justify-center"> |
|
<Play size={8} className="text-white ml-0.5" /> |
|
</div> |
|
) : ( |
|
<div className="w-4 h-4 rounded-full bg-gray-700 flex items-center justify-center"> |
|
<span className="text-xs text-white">{episode.episode_number}</span> |
|
</div> |
|
)} |
|
</div> |
|
<div className="flex-1"> |
|
<div className="flex justify-between"> |
|
<h4 className="font-medium text-white">{episode.name}</h4> |
|
{progress?.completed && ( |
|
<Check size={16} className="text-green-500" /> |
|
)} |
|
</div> |
|
<div className="relative w-full h-1 bg-gray-700 mt-2 rounded overflow-hidden"> |
|
<div |
|
className="absolute left-0 top-0 h-full bg-red-600" |
|
style={{ width: `${progressPercent}%` }} |
|
/> |
|
</div> |
|
</div> |
|
</div> |
|
); |
|
})} |
|
</div> |
|
</div> |
|
))} |
|
</div> |
|
</div> |
|
); |
|
}; |
|
|
|
export default EpisodesPanel; |
|
|