import { DownloadIcon, DuplicateIcon } from '@heroicons/react/outline'; import axios from 'axios'; import { uniq } from 'lodash'; import Link from 'next/link'; import { useRouter } from 'next/router'; import React, { useState } from 'react'; import { defineMessages, useIntl } from 'react-intl'; import { useToasts } from 'react-toast-notifications'; import useSWR from 'swr'; import { MediaStatus } from '../../../server/constants/media'; import type { MediaRequest } from '../../../server/entity/MediaRequest'; import type { Collection } from '../../../server/models/Collection'; import useSettings from '../../hooks/useSettings'; import { Permission, useUser } from '../../hooks/useUser'; import globalMessages from '../../i18n/globalMessages'; import Error from '../../pages/_error'; import ButtonWithDropdown from '../Common/ButtonWithDropdown'; import CachedImage from '../Common/CachedImage'; import LoadingSpinner from '../Common/LoadingSpinner'; import Modal from '../Common/Modal'; import PageTitle from '../Common/PageTitle'; import Slider from '../Slider'; import StatusBadge from '../StatusBadge'; import TitleCard from '../TitleCard'; import Transition from '../Transition'; const messages = defineMessages({ overview: 'Overview', numberofmovies: '{count} Movies', requestcollection: 'Request Collection', requestswillbecreated: 'The following titles will have requests created for them:', requestcollection4k: 'Request Collection in 4K', requestswillbecreated4k: 'The following titles will have 4K requests created for them:', requestSuccess: '{title} requested successfully!', }); interface CollectionDetailsProps { collection?: Collection; } const CollectionDetails: React.FC = ({ collection, }) => { const intl = useIntl(); const router = useRouter(); const settings = useSettings(); const { addToast } = useToasts(); const { hasPermission } = useUser(); const [requestModal, setRequestModal] = useState(false); const [isRequesting, setRequesting] = useState(false); const [is4k, setIs4k] = useState(false); const { data, error, revalidate } = useSWR( `/api/v1/collection/${router.query.collectionId}`, { initialData: collection, revalidateOnMount: true, } ); const { data: genres } = useSWR<{ id: number; name: string }[]>(`/api/v1/genres/movie`); if (!data && !error) { return ; } if (!data) { return ; } let collectionStatus = MediaStatus.UNKNOWN; let collectionStatus4k = MediaStatus.UNKNOWN; if ( data.parts.every( (part) => part.mediaInfo && part.mediaInfo.status === MediaStatus.AVAILABLE ) ) { collectionStatus = MediaStatus.AVAILABLE; } else if ( data.parts.some( (part) => part.mediaInfo && part.mediaInfo.status === MediaStatus.AVAILABLE ) ) { collectionStatus = MediaStatus.PARTIALLY_AVAILABLE; } if ( data.parts.every( (part) => part.mediaInfo && part.mediaInfo.status4k === MediaStatus.AVAILABLE ) ) { collectionStatus4k = MediaStatus.AVAILABLE; } else if ( data.parts.some( (part) => part.mediaInfo && part.mediaInfo.status4k === MediaStatus.AVAILABLE ) ) { collectionStatus4k = MediaStatus.PARTIALLY_AVAILABLE; } const hasRequestable = hasPermission([Permission.REQUEST, Permission.REQUEST_MOVIE], { type: 'or', }) && data.parts.filter( (part) => !part.mediaInfo || part.mediaInfo.status === MediaStatus.UNKNOWN ).length > 0; const hasRequestable4k = settings.currentSettings.movie4kEnabled && hasPermission([Permission.REQUEST_4K, Permission.REQUEST_4K_MOVIE], { type: 'or', }) && data.parts.filter( (part) => !part.mediaInfo || part.mediaInfo.status4k === MediaStatus.UNKNOWN ).length > 0; const requestableParts = data.parts.filter( (part) => !part.mediaInfo || part.mediaInfo[is4k ? 'status4k' : 'status'] === MediaStatus.UNKNOWN ); const requestBundle = async () => { try { setRequesting(true); await Promise.all( requestableParts.map(async (part) => { await axios.post('/api/v1/request', { mediaId: part.id, mediaType: 'movie', is4k, }); }) ); addToast( {intl.formatMessage(messages.requestSuccess, { title: data?.name, strong: function strong(msg) { return {msg}; }, })} , { appearance: 'success', autoDismiss: true } ); } catch (e) { addToast('Something went wrong requesting the collection.', { appearance: 'error', autoDismiss: true, }); } finally { setRequesting(false); setRequestModal(false); revalidate(); } }; const collectionAttributes: React.ReactNode[] = []; collectionAttributes.push( intl.formatMessage(messages.numberofmovies, { count: data.parts.length, }) ); if (genres && data.parts.some((part) => part.genreIds.length)) { collectionAttributes.push( uniq( data.parts.reduce( (genresList: number[], curr) => genresList.concat(curr.genreIds), [] ) ) .map((genreId) => ( {genres.find((g) => g.id === genreId)?.name} )) .reduce((prev, curr) => ( <> {intl.formatMessage(globalMessages.delimitedlist, { a: prev, b: curr, })} )) ); } return (
{data.backdropPath && (
)} requestBundle()} okText={ isRequesting ? intl.formatMessage(globalMessages.requesting) : intl.formatMessage( is4k ? globalMessages.request4k : globalMessages.request ) } okDisabled={isRequesting} okButtonType="primary" onCancel={() => setRequestModal(false)} title={intl.formatMessage( is4k ? messages.requestcollection4k : messages.requestcollection )} iconSvg={} >

{intl.formatMessage( is4k ? messages.requestswillbecreated4k : messages.requestswillbecreated )}

    {data.parts .filter( (part) => !part.mediaInfo || part.mediaInfo[is4k ? 'status4k' : 'status'] === MediaStatus.UNKNOWN ) .map((part) => (
  • {part.title}
  • ))}
(part.mediaInfo?.downloadStatus ?? []).length > 0 )} /> {settings.currentSettings.movie4kEnabled && hasPermission( [Permission.REQUEST_4K, Permission.REQUEST_4K_MOVIE], { type: 'or', } ) && ( (part.mediaInfo?.downloadStatus4k ?? []).length > 0 )} /> )}

{data.name}

{collectionAttributes.length > 0 && collectionAttributes .map((t, k) => {t}) .reduce((prev, curr) => ( <> {prev} | {curr} ))}
{(hasRequestable || hasRequestable4k) && ( { setRequestModal(true); setIs4k(!hasRequestable); }} text={ <> {intl.formatMessage( hasRequestable ? messages.requestcollection : messages.requestcollection4k )} } > {hasRequestable && hasRequestable4k && ( { setRequestModal(true); setIs4k(true); }} > {intl.formatMessage(messages.requestcollection4k)} )} )}
{data.overview && (

{intl.formatMessage(messages.overview)}

{data.overview}

)}
{intl.formatMessage(globalMessages.movies)}
( ))} />
); }; export default CollectionDetails;