import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import DescriptionList from 'Components/DescriptionList/DescriptionList'; import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem'; import Button from 'Components/Link/Button'; import SpinnerErrorButton from 'Components/Link/SpinnerErrorButton'; import ModalBody from 'Components/Modal/ModalBody'; import ModalContent from 'Components/Modal/ModalContent'; import ModalFooter from 'Components/Modal/ModalFooter'; import ModalHeader from 'Components/Modal/ModalHeader'; import DownloadProtocol from 'DownloadClient/DownloadProtocol'; import EpisodeLanguages from 'Episode/EpisodeLanguages'; import EpisodeQuality from 'Episode/EpisodeQuality'; import usePrevious from 'Helpers/Hooks/usePrevious'; import SelectEpisodeModal from 'InteractiveImport/Episode/SelectEpisodeModal'; import { SelectedEpisode } from 'InteractiveImport/Episode/SelectEpisodeModalContent'; import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal'; import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal'; import SelectSeasonModal from 'InteractiveImport/Season/SelectSeasonModal'; import SelectSeriesModal from 'InteractiveImport/Series/SelectSeriesModal'; import ReleaseEpisode from 'InteractiveSearch/ReleaseEpisode'; import Language from 'Language/Language'; import { QualityModel } from 'Quality/Quality'; import Series from 'Series/Series'; import { grabRelease } from 'Store/Actions/releaseActions'; import { fetchDownloadClients } from 'Store/Actions/settingsActions'; import createEnabledDownloadClientsSelector from 'Store/Selectors/createEnabledDownloadClientsSelector'; import { createSeriesSelectorForHook } from 'Store/Selectors/createSeriesSelector'; import translate from 'Utilities/String/translate'; import SelectDownloadClientModal from './DownloadClient/SelectDownloadClientModal'; import OverrideMatchData from './OverrideMatchData'; import styles from './OverrideMatchModalContent.css'; type SelectType = | 'select' | 'series' | 'season' | 'episode' | 'quality' | 'language' | 'downloadClient'; interface OverrideMatchModalContentProps { indexerId: number; title: string; guid: string; seriesId?: number; seasonNumber?: number; episodes: ReleaseEpisode[]; languages: Language[]; quality: QualityModel; protocol: DownloadProtocol; isGrabbing: boolean; grabError?: string; onModalClose(): void; } function OverrideMatchModalContent(props: OverrideMatchModalContentProps) { const modalTitle = 'Manual Grab'; const { indexerId, title, guid, protocol, isGrabbing, grabError, onModalClose, } = props; const [seriesId, setSeriesId] = useState(props.seriesId); const [seasonNumber, setSeasonNumber] = useState(props.seasonNumber); const [episodes, setEpisodes] = useState(props.episodes); const [languages, setLanguages] = useState(props.languages); const [quality, setQuality] = useState(props.quality); const [downloadClientId, setDownloadClientId] = useState(null); const [error, setError] = useState(null); const [selectModalOpen, setSelectModalOpen] = useState( null ); const previousIsGrabbing = usePrevious(isGrabbing); const dispatch = useDispatch(); const series: Series | undefined = useSelector( createSeriesSelectorForHook(seriesId) ); const { items: downloadClients } = useSelector( createEnabledDownloadClientsSelector(protocol) ); const episodeInfo = useMemo(() => { return episodes.map((episode) => { return (
{episode.episodeNumber} {series?.seriesType === 'anime' && episode.absoluteEpisodeNumber != null ? ` (${episode.absoluteEpisodeNumber})` : ''} {` - ${episode.title}`}
); }); }, [series, episodes]); const onSelectModalClose = useCallback(() => { setSelectModalOpen(null); }, [setSelectModalOpen]); const onSelectSeriesPress = useCallback(() => { setSelectModalOpen('series'); }, [setSelectModalOpen]); const onSeriesSelect = useCallback( (s: Series) => { setSeriesId(s.id); setSeasonNumber(undefined); setEpisodes([]); setSelectModalOpen(null); }, [setSeriesId, setSeasonNumber, setEpisodes, setSelectModalOpen] ); const onSelectSeasonPress = useCallback(() => { setSelectModalOpen('season'); }, [setSelectModalOpen]); const onSeasonSelect = useCallback( (s: number) => { setSeasonNumber(s); setEpisodes([]); setSelectModalOpen(null); }, [setSeasonNumber, setEpisodes, setSelectModalOpen] ); const onSelectEpisodePress = useCallback(() => { setSelectModalOpen('episode'); }, [setSelectModalOpen]); const onEpisodesSelect = useCallback( (episodeMap: SelectedEpisode[]) => { setEpisodes(episodeMap[0].episodes); setSelectModalOpen(null); }, [setEpisodes, setSelectModalOpen] ); const onSelectQualityPress = useCallback(() => { setSelectModalOpen('quality'); }, [setSelectModalOpen]); const onQualitySelect = useCallback( (quality: QualityModel) => { setQuality(quality); setSelectModalOpen(null); }, [setQuality, setSelectModalOpen] ); const onSelectLanguagesPress = useCallback(() => { setSelectModalOpen('language'); }, [setSelectModalOpen]); const onLanguagesSelect = useCallback( (languages: Language[]) => { setLanguages(languages); setSelectModalOpen(null); }, [setLanguages, setSelectModalOpen] ); const onSelectDownloadClientPress = useCallback(() => { setSelectModalOpen('downloadClient'); }, [setSelectModalOpen]); const onDownloadClientSelect = useCallback( (downloadClientId: number) => { setDownloadClientId(downloadClientId); setSelectModalOpen(null); }, [setDownloadClientId, setSelectModalOpen] ); const onGrabPress = useCallback(() => { if (!seriesId) { setError('Series must be selected'); return; } else if (!episodes.length) { setError('At least one episode must be selected'); return; } else if (!quality) { setError('Quality must be selected'); return; } else if (!languages.length) { setError('At least one language must be selected'); return; } dispatch( grabRelease({ indexerId, guid, seriesId, episodeIds: episodes.map((e) => e.id), quality, languages, downloadClientId, shouldOverride: true, }) ); }, [ indexerId, guid, seriesId, episodes, quality, languages, downloadClientId, setError, dispatch, ]); useEffect(() => { if (!isGrabbing && previousIsGrabbing) { onModalClose(); } }, [isGrabbing, previousIsGrabbing, onModalClose]); useEffect( () => { dispatch(fetchDownloadClients()); }, // eslint-disable-next-line react-hooks/exhaustive-deps [] ); return ( {translate('Override and Grab - {title}', { title })} } /> } /> } /> } onPress={onSelectQualityPress} /> } /> } onPress={onSelectLanguagesPress} /> } /> {downloadClients.length > 1 ? ( downloadClient.id === downloadClientId )?.name ?? 'Default' } onPress={onSelectDownloadClientPress} /> } /> ) : null}
{error || grabError}
{translate('Grab Release')}
1 : false} real={quality ? quality.revision.real > 0 : false} modalTitle={modalTitle} onQualitySelect={onQualitySelect} onModalClose={onSelectModalClose} /> l.id) : []} modalTitle={modalTitle} onLanguagesSelect={onLanguagesSelect} onModalClose={onSelectModalClose} />
); } export default OverrideMatchModalContent;