import React, { useContext, useState } from 'react'; import { useInView } from 'react-intersection-observer'; import type { MediaRequest } from '../../../../server/entity/MediaRequest'; import { useIntl, FormattedRelativeTime, defineMessages } from 'react-intl'; import { useUser, Permission } from '../../../hooks/useUser'; import { LanguageContext } from '../../../context/LanguageContext'; import type { MovieDetails } from '../../../../server/models/Movie'; import type { TvDetails } from '../../../../server/models/Tv'; import useSWR from 'swr'; import Badge from '../../Common/Badge'; import StatusBadge from '../../StatusBadge'; import { MediaRequestStatus, MediaStatus, } from '../../../../server/constants/media'; import Button from '../../Common/Button'; import axios from 'axios'; import globalMessages from '../../../i18n/globalMessages'; import Link from 'next/link'; import { useToasts } from 'react-toast-notifications'; import RequestModal from '../../RequestModal'; import ConfirmButton from '../../Common/ConfirmButton'; import CachedImage from '../../Common/CachedImage'; const messages = defineMessages({ seasons: '{seasonCount, plural, one {Season} other {Seasons}}', all: 'All', notavailable: 'N/A', failedretry: 'Something went wrong while retrying the request.', areyousure: 'Are you sure?', status: 'Status', requested: 'Requested', modified: 'Modified', modifieduserdate: '{date} by {user}', }); const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => { return (movie as MovieDetails).title !== undefined; }; interface RequestItemProps { request: MediaRequest; revalidateList: () => void; } const RequestItem: React.FC = ({ request, revalidateList, }) => { const { ref, inView } = useInView({ triggerOnce: true, }); const { addToast } = useToasts(); const intl = useIntl(); const { hasPermission } = useUser(); const [showEditModal, setShowEditModal] = useState(false); 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, revalidate, mutate } = useSWR( `/api/v1/request/${request.id}`, { initialData: request, } ); const [isRetrying, setRetrying] = useState(false); const modifyRequest = async (type: 'approve' | 'decline') => { const response = await axios.post(`/api/v1/request/${request.id}/${type}`); if (response) { revalidate(); } }; const deleteRequest = async () => { await axios.delete(`/api/v1/request/${request.id}`); revalidateList(); }; const retryRequest = async () => { setRetrying(true); try { const result = await axios.post(`/api/v1/request/${request.id}/retry`); mutate(result.data); } catch (e) { addToast(intl.formatMessage(messages.failedretry), { autoDismiss: true, appearance: 'error', }); } finally { setRetrying(false); } }; if (!title && !error) { return (
); } if (!title || !requestData) { return (
); } return ( <> setShowEditModal(false)} onComplete={() => { revalidateList(); setShowEditModal(false); }} />
{title.backdropPath && (
)}
{!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(messages.all)} ) : (
{request.seasons.map((season) => ( {season.seasonNumber} ))}
)}
)}
{intl.formatMessage(messages.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} /> )}
{intl.formatMessage(messages.requested)} {intl.formatDate(requestData.createdAt, { year: 'numeric', month: 'long', day: 'numeric', })}
{intl.formatMessage(messages.modified)} {requestData.modifiedBy ? ( {intl.formatMessage(messages.modifieduserdate, { date: ( ), user: ( {requestData.modifiedBy.displayName} ), })} ) : ( N/A )}
{requestData.media[requestData.is4k ? 'status4k' : 'status'] === MediaStatus.UNKNOWN && requestData.status !== MediaRequestStatus.DECLINED && hasPermission(Permission.MANAGE_REQUESTS) && ( )} {requestData.status !== MediaRequestStatus.PENDING && hasPermission(Permission.MANAGE_REQUESTS) && ( deleteRequest()} confirmText={intl.formatMessage(messages.areyousure)} className="w-full" > {intl.formatMessage(globalMessages.delete)} )} {requestData.status === MediaRequestStatus.PENDING && hasPermission(Permission.MANAGE_REQUESTS) && ( <>
)}
); }; export default RequestItem;