import axios from 'axios'; import Link from 'next/link'; import React, { useContext, useEffect } from 'react'; import { useInView } from 'react-intersection-observer'; import { defineMessages, useIntl } from 'react-intl'; import useSWR, { mutate } from 'swr'; import { MediaRequestStatus, MediaStatus, } from '../../../server/constants/media'; import type { MediaRequest } from '../../../server/entity/MediaRequest'; import type { MovieDetails } from '../../../server/models/Movie'; import type { TvDetails } from '../../../server/models/Tv'; import { LanguageContext } from '../../context/LanguageContext'; import { Permission, useUser } from '../../hooks/useUser'; import globalMessages from '../../i18n/globalMessages'; import { withProperties } from '../../utils/typeHelpers'; import Badge from '../Common/Badge'; import Button from '../Common/Button'; import CachedImage from '../Common/CachedImage'; import StatusBadge from '../StatusBadge'; const messages = defineMessages({ seasons: '{seasonCount, plural, one {Season} other {Seasons}}', mediaerror: 'The associated title for this request is no longer available.', deleterequest: 'Delete Request', }); const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => { return (movie as MovieDetails).title !== undefined; }; const RequestCardPlaceholder: React.FC = () => { return (
); }; interface RequestCardErrorProps { mediaId?: number; } const RequestCardError: React.FC = ({ mediaId }) => { const { hasPermission } = useUser(); const intl = useIntl(); const deleteRequest = async () => { await axios.delete(`/api/v1/media/${mediaId}`); mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0'); }; return (
{intl.formatMessage(messages.mediaerror)}
{hasPermission(Permission.MANAGE_REQUESTS) && mediaId && (
)}
); }; interface RequestCardProps { request: MediaRequest; onTitleData?: (requestId: number, title: MovieDetails | TvDetails) => void; } const RequestCard: React.FC = ({ request, onTitleData }) => { const { ref, inView } = useInView({ triggerOnce: true, }); const intl = useIntl(); const { hasPermission } = useUser(); const { locale } = useContext(LanguageContext); const url = request.type === 'movie' ? `/api/v1/movie/${request.media.tmdbId}` : `/api/v1/tv/${request.media.tmdbId}`; const { data: title, error } = useSWR( inView ? `${url}?language=${locale}` : null ); const { data: requestData, error: requestError, revalidate, } = useSWR(`/api/v1/request/${request.id}`, { initialData: request, }); const modifyRequest = async (type: 'approve' | 'decline') => { const response = await axios.post(`/api/v1/request/${request.id}/${type}`); if (response) { revalidate(); } }; useEffect(() => { if (title && onTitleData) { onTitleData(request.id, title); } }, [title, onTitleData, request]); if (!title && !error) { return (
); } if (!requestData && !requestError) { return ; } if (!title || !requestData) { return ; } return (
{title.backdropPath && (
)}
{isMovie(title) ? title.title : title.name} {!isMovie(title) && request.seasons.length > 0 && (
{intl.formatMessage(messages.seasons, { seasonCount: title.seasons.filter((season) => season.seasonNumber !== 0) .length === request.seasons.length ? 0 : request.seasons.length, })} {title.seasons.filter((season) => season.seasonNumber !== 0) .length === request.seasons.length ? ( {intl.formatMessage(globalMessages.all)} ) : (
{request.seasons.map((season) => ( {season.seasonNumber} ))}
)}
)}
{intl.formatMessage(globalMessages.status)} {requestData.media[requestData.is4k ? 'status4k' : 'status'] === MediaStatus.UNKNOWN || requestData.status === MediaRequestStatus.DECLINED ? ( {requestData.status === MediaRequestStatus.DECLINED ? intl.formatMessage(globalMessages.declined) : intl.formatMessage(globalMessages.failed)} ) : ( 0 } is4k={requestData.is4k} plexUrl={requestData.media.plexUrl} plexUrl4k={requestData.media.plexUrl4k} /> )}
{requestData.status === MediaRequestStatus.PENDING && hasPermission(Permission.MANAGE_REQUESTS) && (
)}
); }; export default withProperties(RequestCard, { Placeholder: RequestCardPlaceholder, });