import React, { useState, useContext } from 'react'; import { FormattedMessage, defineMessages, FormattedNumber, FormattedDate, useIntl, } from 'react-intl'; import type { MovieDetails as MovieDetailsType } from '../../../server/models/Movie'; import useSWR from 'swr'; import { useRouter } from 'next/router'; import Button from '../Common/Button'; import type { MovieResult } from '../../../server/models/Search'; import Link from 'next/link'; import Slider from '../Slider'; import TitleCard from '../TitleCard'; import PersonCard from '../PersonCard'; import { LanguageContext } from '../../context/LanguageContext'; import LoadingSpinner from '../Common/LoadingSpinner'; import { useUser, Permission } from '../../hooks/useUser'; import { MediaStatus, MediaRequestStatus, } from '../../../server/constants/media'; import RequestModal from '../RequestModal'; import Badge from '../Common/Badge'; import ButtonWithDropdown from '../Common/ButtonWithDropdown'; import axios from 'axios'; import SlideOver from '../Common/SlideOver'; import RequestBlock from '../RequestBlock'; import TmdbLogo from '../../assets/tmdb_logo.svg'; import RTFresh from '../../assets/rt_fresh.svg'; import RTRotten from '../../assets/rt_rotten.svg'; import RTAudFresh from '../../assets/rt_aud_fresh.svg'; import RTAudRotten from '../../assets/rt_aud_rotten.svg'; import type { RTRating } from '../../../server/api/rottentomatoes'; import Error from '../../pages/_error'; const messages = defineMessages({ releasedate: 'Release Date', userrating: 'User Rating', status: 'Status', revenue: 'Revenue', budget: 'Budget', originallanguage: 'Original Language', overview: 'Overview', runtime: '{minutes} minutes', cast: 'Cast', recommendations: 'Recommendations', similar: 'Similar Titles', cancelrequest: 'Cancel Request', available: 'Available', unavailable: 'Unavailable', request: 'Request', viewrequest: 'View Request', pending: 'Pending', overviewunavailable: 'Overview unavailable', }); interface MovieDetailsProps { movie?: MovieDetailsType; } interface SearchResult { page: number; totalResults: number; totalPages: number; results: MovieResult[]; } const MovieDetails: React.FC = ({ movie }) => { const { hasPermission } = useUser(); const router = useRouter(); const intl = useIntl(); const { locale } = useContext(LanguageContext); const [showRequestModal, setShowRequestModal] = useState(false); const [showManager, setShowManager] = useState(false); const { data, error, revalidate } = useSWR( `/api/v1/movie/${router.query.movieId}?language=${locale}`, { initialData: movie, } ); const { data: recommended, error: recommendedError } = useSWR( `/api/v1/movie/${router.query.movieId}/recommendations?language=${locale}` ); const { data: similar, error: similarError } = useSWR( `/api/v1/movie/${router.query.movieId}/similar?language=${locale}` ); const { data: ratingData } = useSWR( `/api/v1/movie/${router.query.movieId}/ratings` ); if (!data && !error) { return ; } if (!data) { return ; } const activeRequest = data?.mediaInfo?.requests?.find( (request) => request.status === MediaRequestStatus.PENDING ); const modifyRequest = async (type: 'approve' | 'decline') => { const response = await axios.get( `/api/v1/request/${activeRequest?.id}/${type}` ); if (response) { revalidate(); } }; const deleteMedia = async () => { if (data?.mediaInfo?.id) { await axios.delete(`/api/v1/media/${data?.mediaInfo?.id}`); revalidate(); } }; return (
{ revalidate(); setShowRequestModal(false); }} onCancel={() => setShowRequestModal(false)} /> setShowManager(false)} subText={data.title} >

Requests

    {data.mediaInfo?.requests?.map((request) => (
  • revalidate()} />
  • ))} {(data.mediaInfo?.requests ?? []).length === 0 && (
  • No requests
  • )}
{data?.mediaInfo && (
This will remove all media data including all requests for this item. This action is irreversible. If this item exists in your Plex library, the media information will be recreated next sync.
)}
{data.mediaInfo?.status === MediaStatus.AVAILABLE && ( Available )} {data.mediaInfo?.status === MediaStatus.PROCESSING && ( Unavailable )} {data.mediaInfo?.status === MediaStatus.PENDING && ( Pending )}

{data.title}{' '} ({data.releaseDate.slice(0, 4)})

{(data.runtime ?? 0) > 0 && ( <> {' '} |{' '} )} {data.genres.map((g) => g.name).join(', ')}
{(!data.mediaInfo || data.mediaInfo?.status === MediaStatus.UNKNOWN) && ( )} {activeRequest && ( } text={ <> } onClick={() => setShowRequestModal(true)} > {hasPermission(Permission.MANAGE_REQUESTS) && ( <> modifyRequest('approve')} > Approve modifyRequest('decline')} > Decline )} )} {hasPermission(Permission.MANAGE_REQUESTS) && ( )}

{data.overview ? data.overview : intl.formatMessage(messages.overviewunavailable)}

{(data.voteCount > 0 || ratingData) && (
{ratingData?.criticsRating && ( <> {ratingData.criticsRating === 'Rotten' ? ( ) : ( )} {ratingData.criticsScore}% )} {ratingData?.audienceRating && ( <> {ratingData.audienceRating === 'Spilled' ? ( ) : ( )} {ratingData.audienceScore}% )} {data.voteCount > 0 && ( <> {data.voteAverage}/10 )}
)}
{data.status}
{data.revenue > 0 && (
)} {data.budget > 0 && (
)}
{data.originalLanguage}
( ))} /> {(recommended?.results ?? []).length > 0 && ( <> ( ))} /> )} {(similar?.results ?? []).length > 0 && ( <> ( ))} /> )}
); }; export default MovieDetails;