mirror of
https://github.com/fallenbagel/jellyseerr.git
synced 2026-01-01 20:28:40 -05:00
feat: add quotas, advanced options, and toggles to collection request modal (#1742)
* feat: add quotas, advanced options, and toggles to collection request modal * fix: use correct requiredquota strings * refactor: clean up collection part request status logic * revert: undo changes to effect dependencies * fix(lang): tweak TV request modal request button strings * fix: don't try to fetch other users' quotas without MANAGE_USERS perm
This commit is contained in:
@@ -1,14 +1,11 @@
|
||||
import { DownloadIcon, DuplicateIcon } from '@heroicons/react/outline';
|
||||
import axios from 'axios';
|
||||
import { DownloadIcon } from '@heroicons/react/outline';
|
||||
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';
|
||||
@@ -17,23 +14,17 @@ 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 RequestModal from '../RequestModal';
|
||||
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: '<strong>{title}</strong> requested successfully!',
|
||||
});
|
||||
|
||||
interface CollectionDetailsProps {
|
||||
@@ -46,10 +37,8 @@ const CollectionDetails: React.FC<CollectionDetailsProps> = ({
|
||||
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<Collection>(
|
||||
@@ -124,48 +113,6 @@ const CollectionDetails: React.FC<CollectionDetailsProps> = ({
|
||||
!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<MediaRequest>('/api/v1/request', {
|
||||
mediaId: part.id,
|
||||
mediaType: 'movie',
|
||||
is4k,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
addToast(
|
||||
<span>
|
||||
{intl.formatMessage(messages.requestSuccess, {
|
||||
title: data?.name,
|
||||
strong: function strong(msg) {
|
||||
return <strong>{msg}</strong>;
|
||||
},
|
||||
})}
|
||||
</span>,
|
||||
{ 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(
|
||||
@@ -229,53 +176,17 @@ const CollectionDetails: React.FC<CollectionDetailsProps> = ({
|
||||
</div>
|
||||
)}
|
||||
<PageTitle title={data.name} />
|
||||
<Transition
|
||||
enter="opacity-0 transition duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="opacity-100 transition duration-300"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
<RequestModal
|
||||
tmdbId={data.id}
|
||||
show={requestModal}
|
||||
>
|
||||
<Modal
|
||||
onOk={() => 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={<DuplicateIcon />}
|
||||
>
|
||||
<p>
|
||||
{intl.formatMessage(
|
||||
is4k
|
||||
? messages.requestswillbecreated4k
|
||||
: messages.requestswillbecreated
|
||||
)}
|
||||
</p>
|
||||
<ul className="py-4 pl-8 list-disc">
|
||||
{data.parts
|
||||
.filter(
|
||||
(part) =>
|
||||
!part.mediaInfo ||
|
||||
part.mediaInfo[is4k ? 'status4k' : 'status'] ===
|
||||
MediaStatus.UNKNOWN
|
||||
)
|
||||
.map((part) => (
|
||||
<li key={`request-part-${part.id}`}>{part.title}</li>
|
||||
))}
|
||||
</ul>
|
||||
</Modal>
|
||||
</Transition>
|
||||
type="collection"
|
||||
is4k={is4k}
|
||||
onComplete={() => {
|
||||
revalidate();
|
||||
setRequestModal(false);
|
||||
}}
|
||||
onCancel={() => setRequestModal(false)}
|
||||
/>
|
||||
<div className="media-header">
|
||||
<div className="media-poster">
|
||||
<CachedImage
|
||||
|
||||
Reference in New Issue
Block a user