diff --git a/src/modules/overseerr/OverseerrMediaDisplay.tsx b/src/modules/overseerr/OverseerrMediaDisplay.tsx index 0af4c31a4..2e160030f 100644 --- a/src/modules/overseerr/OverseerrMediaDisplay.tsx +++ b/src/modules/overseerr/OverseerrMediaDisplay.tsx @@ -1,18 +1,18 @@ import { MediaDisplay } from '../common'; +import { Result } from './SearchResult'; export default function OverseerrMediaDisplay(props: any) { - const { media }: { media: any } = props; + const { media }: { media: Result } = props; return ( ); diff --git a/src/modules/overseerr/RequestModal.tsx b/src/modules/overseerr/RequestModal.tsx new file mode 100644 index 000000000..81b76091c --- /dev/null +++ b/src/modules/overseerr/RequestModal.tsx @@ -0,0 +1,198 @@ +import { Alert, Checkbox, createStyles, Group, LoadingOverlay, Stack, Table } from '@mantine/core'; +import { openConfirmModal } from '@mantine/modals'; +import { showNotification, updateNotification } from '@mantine/notifications'; +import { IconAlertCircle, IconCheck, IconDownload } from '@tabler/icons'; +import axios from 'axios'; +import { useEffect, useState } from 'react'; +import { useColorTheme } from '../../tools/color'; +import { MovieResult } from './Movie.d'; +import { MediaType, Result } from './SearchResult.d'; +import { TvShowResult, TvShowResultSeason } from './TvShow.d'; + +interface RequestModalProps { + base: Result; +} + +const useStyles = createStyles((theme) => ({ + rowSelected: { + backgroundColor: + theme.colorScheme === 'dark' + ? theme.fn.rgba(theme.colors[theme.primaryColor][7], 0.2) + : theme.colors[theme.primaryColor][0], + }, +})); + +export default function RequestModal({ base }: RequestModalProps) { + const [result, setResult] = useState(); + + useEffect(() => { + // Use the overseerr API get the media info. + axios.get(`/api/modules/overseerr/${base.id}?type=${base.mediaType}`).then((res) => { + setResult(res.data); + }); + }, [base]); + + const { secondaryColor } = useColorTheme(); + if (!result) { + return ; + } + return base.mediaType === 'movie' ? ( + + ) : ( + + ); +} + +function MovieRequestModal({ result }: { result: MovieResult }) { + const { secondaryColor } = useColorTheme(); + openConfirmModal({ + title: ( + + + Ask for {result.title} + + ), + radius: 'lg', + labels: { confirm: 'Request', cancel: 'Cancel' }, + onConfirm: () => { + askForMedia(MediaType.Movie, result.id, result.title); + }, + size: 'lg', + children: ( + + } + title="Using API key" + color={secondaryColor} + radius="md" + variant="filled" + > + This request will be automatically approved + + + ), + }); + return null; +} + +function TvRequestModal({ result }: { result: TvShowResult }) { + const [selection, setSelection] = useState(result.seasons); + const { classes, cx } = useStyles(); + + const toggleRow = (container: TvShowResultSeason) => + setSelection((current: TvShowResultSeason[]) => + current.includes(container) ? current.filter((c) => c !== container) : [...current, container] + ); + const toggleAll = () => + setSelection((current: any) => + current.length === result.seasons.length ? [] : result.seasons.map((c) => c) + ); + + const rows = result.seasons.map((element) => { + const selected = selection.includes(element); + return ( + + + toggleRow(element)} + transitionDuration={0} + /> + + {element.name} + {element.episodeCount} + + ); + }); + const { secondaryColor } = useColorTheme(); + + openConfirmModal({ + title: ( + + + Ask for {result.name} + + ), + radius: 'lg', + labels: { confirm: 'Request', cancel: 'Cancel' }, + confirmProps: { + disabled: selection.length === 0, + }, + onConfirm: () => { + askForMedia( + MediaType.Tv, + result.id, + result.name, + selection.map((s) => s.seasonNumber) + ); + }, + size: 'lg', + children: ( + + } + title="Using API key" + color={secondaryColor} + radius="md" + variant="filled" + > + This request will be automatically approved + + + Tick the seasons that you want to be downloaded + + + + 0 && selection.length !== result.seasons.length} + transitionDuration={0} + /> + + Season + Number of episodes + + + {rows} + + + ), + }); + return null; +} + +function askForMedia(type: MediaType, id: number, name: string, seasons?: number[]) { + showNotification({ + title: 'Request', + id: id.toString(), + message: `Requesting media ${name}`, + color: 'orange', + loading: true, + autoClose: false, + disallowClose: true, + icon: , + }); + axios + .post(`/api/modules/overseerr/${id}`, { type, seasons }) + .then(() => { + updateNotification({ + id: id.toString(), + title: '', + color: 'green', + message: ` ${name} requested`, + icon: , + autoClose: 2000, + }); + }) + .catch((err) => { + updateNotification({ + id: id.toString(), + color: 'red', + title: 'There was an error', + message: err.message, + autoClose: 2000, + }); + }); +}