show total watched to details modal

This commit is contained in:
Pas 2026-01-17 12:08:28 -07:00
parent e544334bea
commit 310a7839ef
4 changed files with 40 additions and 3 deletions

View file

@ -489,6 +489,7 @@
"seasons": "Season/s",
"season": "Season",
"episode": "Episode",
"watched": "Watched {{watched}} of {{total}} ({{percentage}}%)",
"airs": "Airs",
"endsAt": "Ends at {{time}}",
"trailer": "Trailer",

View file

@ -23,6 +23,7 @@ export function EpisodeCarousel({
mediaId,
mediaTitle,
mediaPosterUrl,
totalEpisodes,
}: EpisodeCarouselProps) {
const [showEpisodeMenu, setShowEpisodeMenu] = useState(false);
const [customSeason, setCustomSeason] = useState("");
@ -250,6 +251,30 @@ export function EpisodeCarousel({
[mediaId, getFavoriteEpisodes],
);
// Calculate watched episodes count and percentage
const watchedStats = useMemo(() => {
if (!mediaId || !totalEpisodes) return { watched: 0, percentage: 0 };
let watchedCount = 0;
episodes.forEach((episode) => {
const episodeProgress =
progress[mediaId.toString()]?.episodes?.[episode.id];
const percentage = episodeProgress
? getProgressPercentage(
episodeProgress.progress.watched,
episodeProgress.progress.duration,
)
: 0;
if (percentage > 90) {
watchedCount += 1;
}
});
const percentage = Math.round((watchedCount / totalEpisodes) * 100);
return { watched: watchedCount, percentage };
}, [episodes, progress, mediaId, totalEpisodes]);
// Load favorite episodes when favorites is selected
useEffect(() => {
if (showFavorites && mediaId && favoriteEpisodeIds.length > 0) {
@ -423,7 +448,7 @@ export function EpisodeCarousel({
{showEpisodeMenu && (
<div
ref={episodeMenuRef}
className="absolute top-full left-0 mt-2 p-4 bg-background-main rounded-lg shadow-lg border border-white/10 z-50 min-w-[250px]"
className="absolute top-full left-0 mt-2 p-4 bg-background-main rounded-xl shadow-lg z-50 min-w-[250px]"
>
<div className="space-y-4">
<div>
@ -436,7 +461,7 @@ export function EpisodeCarousel({
onChange={(e) => setCustomSeason(e.target.value)}
min="1"
max={seasons.length}
className="w-full px-3 py-2 bg-white/5 rounded border border-white/10 text-white focus:outline-none focus:border-white/30"
className="w-full px-3 py-2 bg-white/5 rounded-xl text-white focus:outline-none focus:border-white/30"
placeholder={t("details.season")}
/>
</div>
@ -449,7 +474,7 @@ export function EpisodeCarousel({
value={customEpisode}
onChange={(e) => setCustomEpisode(e.target.value)}
min="1"
className="w-full px-3 py-2 bg-white/5 rounded border border-white/10 text-white focus:outline-none focus:border-white/30"
className="w-full px-3 py-2 bg-white/5 rounded-xl text-white focus:outline-none focus:border-white/30"
placeholder={t("details.episode")}
/>
</div>
@ -464,6 +489,15 @@ export function EpisodeCarousel({
</div>
)}
</div>
{totalEpisodes && (
<span className="text-xs md:text-sm text-white/70">
{t("details.watched", {
watched: watchedStats.watched,
total: totalEpisodes,
percentage: watchedStats.percentage,
})}
</span>
)}
</div>
{/* Season Watched Confirmation */}

View file

@ -411,6 +411,7 @@ export function DetailsContent({ data, minimal = false }: DetailsContentProps) {
mediaId={data.id}
mediaTitle={data.title}
mediaPosterUrl={data.posterUrl}
totalEpisodes={data.episodes}
/>
)}

View file

@ -105,6 +105,7 @@ export interface EpisodeCarouselProps {
mediaId?: number;
mediaTitle?: string;
mediaPosterUrl?: string;
totalEpisodes?: number;
}
export interface DetailsBodyProps {