import React, { useState } from 'react'; import Modal from '../Common/Modal'; import { useUser } from '../../hooks/useUser'; import { Permission } from '../../../server/lib/permissions'; import { defineMessages, useIntl } from 'react-intl'; import { MediaRequest } from '../../../server/entity/MediaRequest'; import useSWR from 'swr'; import { useToasts } from 'react-toast-notifications'; import axios from 'axios'; import { MediaStatus, MediaRequestStatus, } from '../../../server/constants/media'; import { TvDetails, SeasonWithEpisodes } from '../../../server/models/Tv'; import type SeasonRequest from '../../../server/entity/SeasonRequest'; import Badge from '../Common/Badge'; const messages = defineMessages({ requestadmin: 'Your request will be immediately approved.', cancelrequest: 'This will remove your request. Are you sure you want to continue?', }); interface RequestModalProps extends React.HTMLAttributes { tmdbId: number; onCancel?: () => void; onComplete?: (newStatus: MediaStatus) => void; onUpdating?: (isUpdating: boolean) => void; } const TvRequestModal: React.FC = ({ onCancel, onComplete, tmdbId, onUpdating, ...props }) => { const { addToast } = useToasts(); const { data, error } = useSWR(`/api/v1/tv/${tmdbId}`); const [selectedSeasons, setSelectedSeasons] = useState([]); const intl = useIntl(); const { hasPermission } = useUser(); const sendRequest = async () => { if (selectedSeasons.length === 0) { return; } if (onUpdating) { onUpdating(true); } const response = await axios.post('/api/v1/request', { mediaId: data?.id, tvdbId: data?.externalIds.tvdbId, mediaType: 'tv', seasons: selectedSeasons, }); if (response.data) { if (onComplete) { onComplete(response.data.media.status); } addToast( {data?.name} succesfully requested! , { appearance: 'success', autoDismiss: true } ); if (onUpdating) { onUpdating(false); } } }; const getAllRequestedSeasons = (): number[] => { const requestedSeasons = (data?.mediaInfo?.requests ?? []).reduce( (requestedSeasons, request) => { return [ ...requestedSeasons, ...request.seasons.map((sr) => sr.seasonNumber), ]; }, [] as number[] ); const availableSeasons = (data?.mediaInfo?.seasons ?? []) .filter( (season) => (season.status === MediaStatus.AVAILABLE || season.status === MediaStatus.PARTIALLY_AVAILABLE) && !requestedSeasons.includes(season.seasonNumber) ) .map((season) => season.seasonNumber); return [...requestedSeasons, ...availableSeasons]; }; const isSelectedSeason = (seasonNumber: number): boolean => selectedSeasons.includes(seasonNumber); const toggleSeason = (seasonNumber: number): void => { // If this season already has a pending request, don't allow it to be toggled if (getAllRequestedSeasons().includes(seasonNumber)) { return; } if (selectedSeasons.includes(seasonNumber)) { setSelectedSeasons((seasons) => seasons.filter((sn) => sn !== seasonNumber) ); } else { setSelectedSeasons((seasons) => [...seasons, seasonNumber]); } }; const toggleAllSeasons = (): void => { if ( data && selectedSeasons.length >= 0 && selectedSeasons.length < data?.seasons .filter((season) => season.seasonNumber !== 0) .filter( (season) => !getAllRequestedSeasons().includes(season.seasonNumber) ).length ) { setSelectedSeasons( data.seasons .filter((season) => season.seasonNumber !== 0) .filter( (season) => !getAllRequestedSeasons().includes(season.seasonNumber) ) .map((season) => season.seasonNumber) ); } else { setSelectedSeasons([]); } }; const isAllSeasons = (): boolean => { if (!data) { return false; } return ( selectedSeasons.length === data.seasons .filter((season) => season.seasonNumber !== 0) .filter( (season) => !getAllRequestedSeasons().includes(season.seasonNumber) ).length ); }; const text = hasPermission(Permission.MANAGE_REQUESTS) ? intl.formatMessage(messages.requestadmin) : undefined; const getSeasonRequest = ( seasonNumber: number ): SeasonRequest | undefined => { let seasonRequest: SeasonRequest | undefined; if (data?.mediaInfo && (data.mediaInfo.requests || []).length > 0) { data.mediaInfo.requests.forEach((request) => { if (!seasonRequest) { seasonRequest = request.seasons.find( (season) => season.seasonNumber === seasonNumber ); } }); } return seasonRequest; }; return ( sendRequest()} title={`Request ${data?.name}`} okText={ selectedSeasons.length === 0 ? 'Select a season' : `Request ${selectedSeasons.length} seasons` } okDisabled={selectedSeasons.length === 0} okButtonType="primary" iconSvg={ } {...props} >
{data?.seasons .filter((season) => season.seasonNumber !== 0) .map((season) => { const seasonRequest = getSeasonRequest( season.seasonNumber ); const mediaSeason = data?.mediaInfo?.seasons.find( (sn) => sn.seasonNumber === season.seasonNumber ); return ( ); })}
toggleAllSeasons()} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === 'Space') { toggleAllSeasons(); } }} className="group relative inline-flex items-center justify-center flex-shrink-0 h-5 w-10 cursor-pointer focus:outline-none" > Season # Of Episodes Status
toggleSeason(season.seasonNumber)} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === 'Space') { toggleSeason(season.seasonNumber); } }} className={`group relative inline-flex items-center justify-center flex-shrink-0 h-5 w-10 cursor-pointer focus:outline-none ${ mediaSeason || seasonRequest ? 'opacity-50' : '' }`} > {season.seasonNumber === 0 ? 'Extras' : `Season ${season.seasonNumber}`} {season.episodeCount} {!seasonRequest && !mediaSeason && ( Not Requested )} {!mediaSeason && seasonRequest?.status === MediaRequestStatus.PENDING && ( Pending )} {!mediaSeason && seasonRequest?.status === MediaRequestStatus.APPROVED && ( Unavailable )} {!mediaSeason && seasonRequest?.status === MediaRequestStatus.AVAILABLE && ( Available )} {mediaSeason?.status === MediaStatus.PARTIALLY_AVAILABLE && ( Partially Available )} {mediaSeason?.status === MediaStatus.AVAILABLE && ( Available )}

{text}

); }; export default TvRequestModal;