import {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger'; import {IconButton} from '@common/ui/buttons/icon-button'; import {Dialog} from '@common/ui/overlays/dialog/dialog'; import {DialogHeader} from '@common/ui/overlays/dialog/dialog-header'; import {Trans} from '@common/i18n/trans'; import {DialogBody} from '@common/ui/overlays/dialog/dialog-body'; import {useDarkThemeVariables} from '@common/ui/themes/use-dark-theme-variables'; import {Title} from '@app/titles/models/title'; import {Episode} from '@app/titles/models/episode'; import {Accordion, AccordionItem} from '@common/ui/accordion/accordion'; import {EpisodePoster} from '@app/episodes/episode-poster/episode-poster'; import {MediaPlayIcon} from '@common/icons/media/media-play'; import React, {Fragment, ReactElement, ReactNode, useState} from 'react'; import {ArrowBackIcon} from '@common/icons/material/ArrowBack'; import {List, ListItem} from '@common/ui/list/list'; import {FullPageLoader} from '@common/ui/progress/full-page-loader'; import {ArrowForwardIcon} from '@common/icons/material/ArrowForward'; import {IllustratedMessage} from '@common/ui/images/illustrated-message'; import {TvIcon} from '@common/icons/material/Tv'; import {AnimatePresence, m} from 'framer-motion'; import {useSeasonEpisodes} from '@app/titles/requests/use-season-episodes'; import {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel'; import {useDialogContext} from '@common/ui/overlays/dialog/dialog-context'; import {Tooltip} from '@common/ui/tooltip/tooltip'; import {MediaEpisodesIcon} from '@common/icons/media/media-episodes'; interface Props { title: Title; currentEpisode: Episode; onSelected: (episode: Episode) => void; trigger?: ReactElement; } export function EpisodeSelector(props: Props) { const trigger = props.trigger || ( }> ); return ( {trigger} ); } type SelectorPanel = 'episodes' | 'seasons'; function EpisodeSelectorDialog({title, currentEpisode, onSelected}: Props) { const {close} = useDialogContext(); const darkThemeVars = useDarkThemeVariables(); const [activeTab, setActiveTab] = useState('episodes'); const [selectedSeason, setSelectedSeason] = useState( currentEpisode.season_number ); const heading = activeTab === 'episodes' ? ( ) : ( title.name ); const showBackButton = activeTab === 'episodes' && title.seasons_count > 1; return ( setActiveTab('seasons')}> ) : null } > {heading} {activeTab === 'episodes' ? ( { close(); onSelected(episode); }} selectedEpisodeId={ currentEpisode.season_number === selectedSeason ? currentEpisode.id : undefined } /> ) : ( { setSelectedSeason(number); setActiveTab('episodes'); }} /> )} ); } interface SeasonListProps { title: Title; onSelected: (number: number) => void; selectedSeason?: number; } function SeasonList({title, onSelected, selectedSeason}: SeasonListProps) { return ( {[...new Array(title.seasons_count).keys()].map(season => { const seasonNumber = season + 1; return ( } showCheckmark isSelected={selectedSeason === seasonNumber} onSelected={() => onSelected(seasonNumber)} key={seasonNumber} onClick={() => onSelected(seasonNumber)} > ); })} ); } interface EpisodeListProps { title: Title; season: number; onSelected: (episode: Episode) => void; selectedEpisodeId: number | undefined; } function EpisodeList({ title, season, selectedEpisodeId, onSelected, }: EpisodeListProps) { const query = useSeasonEpisodes( undefined, {truncateDescriptions: 'true'}, {titleId: title.id, season} ); let content: ReactNode; if (query.noResults) { content = ( } imageHeight="h-auto" title={} /> ); } else if (query.isInitialLoading) { content = ; } else { content = ( {query.items.map(episode => (
{episode.episode_number}
{episode.name}
} > onSelected(episode)} />
))}
); } return {content}; } interface EpisodeItemProps { title: Title; episode: Episode; isSelected: boolean; onSelected: () => void; } function EpisodeItem({ episode, title, isSelected, onSelected, }: EpisodeItemProps) { const isPlayable = !isSelected && episode.primary_video; return (
onSelected() : undefined} > {isPlayable ? ( ) : undefined}

{episode.description}

); } const variants = { enter: (activeTab: SelectorPanel) => { return { x: activeTab === 'episodes' ? 608 : -608, opacity: 0, }; }, center: { x: 0, opacity: 1, }, exit: (direction: SelectorPanel) => { return { zIndex: 0, x: direction === 'seasons' ? 608 : -608, opacity: 0, }; }, }; interface AnimatedPanelProps { name: SelectorPanel; children: ReactNode; } function AnimatedPanel({name, children}: AnimatedPanelProps) { return ( {children} ); }