/* eslint-disable react-hooks/exhaustive-deps */ import { Listbox, Transition } from '@headlessui/react'; import { AdjustmentsIcon } from '@heroicons/react/outline'; import { CheckIcon, ChevronDownIcon } from '@heroicons/react/solid'; import { isEqual } from 'lodash'; import dynamic from 'next/dynamic'; import React, { useEffect, useState } from 'react'; import { defineMessages, useIntl } from 'react-intl'; import type { OptionsType, OptionTypeBase } from 'react-select'; import useSWR from 'swr'; import type { ServiceCommonServer, ServiceCommonServerWithDetails, } from '../../../../server/interfaces/api/serviceInterfaces'; import type { UserResultsResponse } from '../../../../server/interfaces/api/userInterfaces'; import { Permission, User, useUser } from '../../../hooks/useUser'; import globalMessages from '../../../i18n/globalMessages'; import { formatBytes } from '../../../utils/numberHelpers'; import { SmallLoadingSpinner } from '../../Common/LoadingSpinner'; type OptionType = { value: string; label: string; }; const Select = dynamic(() => import('react-select'), { ssr: false }); const messages = defineMessages({ advancedoptions: 'Advanced', destinationserver: 'Destination Server', qualityprofile: 'Quality Profile', rootfolder: 'Root Folder', animenote: '* This series is an anime.', default: '{name} (Default)', folder: '{path} ({space})', requestas: 'Request As', languageprofile: 'Language Profile', tags: 'Tags', selecttags: 'Select tags', notagoptions: 'No tags.', }); export type RequestOverrides = { server?: number; profile?: number; folder?: string; tags?: number[]; language?: number; user?: User; }; interface AdvancedRequesterProps { type: 'movie' | 'tv'; is4k: boolean; isAnime?: boolean; defaultOverrides?: RequestOverrides; requestUser?: User; onChange: (overrides: RequestOverrides) => void; } const AdvancedRequester: React.FC = ({ type, is4k = false, isAnime = false, defaultOverrides, requestUser, onChange, }) => { const intl = useIntl(); const { user, hasPermission } = useUser(); const { data, error } = useSWR( `/api/v1/service/${type === 'movie' ? 'radarr' : 'sonarr'}`, { refreshInterval: 0, refreshWhenHidden: false, revalidateOnFocus: false, revalidateOnMount: true, } ); const [selectedServer, setSelectedServer] = useState( defaultOverrides?.server !== undefined && defaultOverrides?.server >= 0 ? defaultOverrides?.server : null ); const [selectedProfile, setSelectedProfile] = useState( defaultOverrides?.profile ?? -1 ); const [selectedFolder, setSelectedFolder] = useState( defaultOverrides?.folder ?? '' ); const [selectedLanguage, setSelectedLanguage] = useState( defaultOverrides?.language ?? -1 ); const [selectedTags, setSelectedTags] = useState( defaultOverrides?.tags ?? [] ); const { data: serverData, isValidating } = useSWR( selectedServer !== null ? `/api/v1/service/${ type === 'movie' ? 'radarr' : 'sonarr' }/${selectedServer}` : null, { refreshInterval: 0, refreshWhenHidden: false, revalidateOnFocus: false, } ); const [selectedUser, setSelectedUser] = useState( requestUser ?? null ); const { data: userData } = useSWR( hasPermission([Permission.MANAGE_REQUESTS, Permission.MANAGE_USERS]) ? '/api/v1/user?take=1000' : null ); useEffect(() => { if (userData?.results && !requestUser) { setSelectedUser(userData.results.find((u) => u.id === user?.id) ?? null); } }, [userData?.results]); useEffect(() => { let defaultServer = data?.find( (server) => server.isDefault && is4k === server.is4k ); if (!defaultServer && (data ?? []).length > 0) { defaultServer = data?.[0]; } if ( defaultServer && defaultServer.id !== selectedServer && (!defaultOverrides || defaultOverrides.server === null) ) { setSelectedServer(defaultServer.id); } }, [data]); useEffect(() => { if (serverData) { const defaultProfile = serverData.profiles.find( (profile) => profile.id === (isAnime ? serverData.server.activeAnimeProfileId : serverData.server.activeProfileId) ); const defaultFolder = serverData.rootFolders.find( (folder) => folder.path === (isAnime ? serverData.server.activeAnimeDirectory : serverData.server.activeDirectory) ); const defaultLanguage = serverData.languageProfiles?.find( (language) => language.id === (isAnime ? serverData.server.activeAnimeLanguageProfileId : serverData.server.activeLanguageProfileId) ); const defaultTags = isAnime ? serverData.server.activeAnimeTags : serverData.server.activeTags; if ( defaultProfile && defaultProfile.id !== selectedProfile && (!defaultOverrides || defaultOverrides.profile === null) ) { setSelectedProfile(defaultProfile.id); } if ( defaultFolder && defaultFolder.path !== selectedFolder && (!defaultOverrides || defaultOverrides.folder === null) ) { setSelectedFolder(defaultFolder.path ?? ''); } if ( defaultLanguage && defaultLanguage.id !== selectedLanguage && (!defaultOverrides || defaultOverrides.language === null) ) { setSelectedLanguage(defaultLanguage.id); } if ( defaultTags && !isEqual(defaultTags, selectedTags) && (!defaultOverrides || defaultOverrides.tags === null) ) { setSelectedTags(defaultTags); } } }, [serverData]); useEffect(() => { if (defaultOverrides && defaultOverrides.server != null) { setSelectedServer(defaultOverrides.server); } if (defaultOverrides && defaultOverrides.profile != null) { setSelectedProfile(defaultOverrides.profile); } if (defaultOverrides && defaultOverrides.folder != null) { setSelectedFolder(defaultOverrides.folder); } if (defaultOverrides && defaultOverrides.language != null) { setSelectedLanguage(defaultOverrides.language); } if (defaultOverrides && defaultOverrides.tags != null) { setSelectedTags(defaultOverrides.tags); } }, [ defaultOverrides?.server, defaultOverrides?.folder, defaultOverrides?.profile, defaultOverrides?.language, defaultOverrides?.tags, ]); useEffect(() => { if (selectedServer !== null || selectedUser) { onChange({ folder: selectedFolder !== '' ? selectedFolder : undefined, profile: selectedProfile !== -1 ? selectedProfile : undefined, server: selectedServer ?? undefined, user: selectedUser ?? undefined, language: selectedLanguage ?? undefined, tags: selectedTags, }); } }, [ selectedFolder, selectedServer, selectedProfile, selectedUser, selectedLanguage, selectedTags, ]); if (!data && !error) { return (
); } if ((!data || selectedServer === null) && !selectedUser) { return null; } return ( <>
{intl.formatMessage(messages.advancedoptions)}
{!!data && selectedServer !== null && (
{data.filter((server) => server.is4k === is4k).length > 1 && (
)} {(isValidating || !serverData || serverData.profiles.length > 1) && (
)} {(isValidating || !serverData || serverData.rootFolders.length > 1) && (
)} {type === 'tv' && (isValidating || !serverData || (serverData.languageProfiles ?? []).length > 1) && (
)}
)} {selectedServer !== null && (isValidating || !serverData || !!serverData?.tags?.length) && (