mirror of
https://github.com/sct/overseerr.git
synced 2025-12-29 17:16:18 +01:00
refactor: modal redesign and fix for transitions (#2987)
This commit is contained in:
@@ -5,7 +5,6 @@ import { Permission, useUser } from '@app/hooks/useUser';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import { formatBytes } from '@app/utils/numberHelpers';
|
||||
import { Listbox, Transition } from '@headlessui/react';
|
||||
import { AdjustmentsIcon } from '@heroicons/react/outline';
|
||||
import { CheckIcon, ChevronDownIcon } from '@heroicons/react/solid';
|
||||
import type {
|
||||
ServiceCommonServer,
|
||||
@@ -281,11 +280,10 @@ const AdvancedRequester = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mt-4 mb-2 flex items-center font-bold tracking-wider">
|
||||
<AdjustmentsIcon className="mr-1.5 h-5 w-5" />
|
||||
<div className="mt-4 mb-2 flex items-center text-lg font-semibold">
|
||||
{intl.formatMessage(messages.advancedoptions)}
|
||||
</div>
|
||||
<div className="rounded-md bg-gray-600 p-4 shadow">
|
||||
<div className="rounded-md">
|
||||
{!!data && selectedServer !== null && (
|
||||
<div className="flex flex-col md:flex-row">
|
||||
{data.filter((server) => server.is4k === is4k).length > 1 && (
|
||||
@@ -561,7 +559,7 @@ const AdvancedRequester = ({
|
||||
leave="transition ease-in duration-100"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
className="mt-1 w-full rounded-md bg-gray-800 shadow-lg"
|
||||
className="mt-1 w-full rounded-md border border-gray-700 bg-gray-800 shadow-lg"
|
||||
>
|
||||
<Listbox.Options
|
||||
static
|
||||
|
||||
@@ -7,7 +7,6 @@ import AdvancedRequester from '@app/components/RequestModal/AdvancedRequester';
|
||||
import QuotaDisplay from '@app/components/RequestModal/QuotaDisplay';
|
||||
import { useUser } from '@app/hooks/useUser';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import { DownloadIcon } from '@heroicons/react/outline';
|
||||
import { MediaRequestStatus, MediaStatus } from '@server/constants/media';
|
||||
import type { MediaRequest } from '@server/entity/MediaRequest';
|
||||
import type { QuotaResponse } from '@server/interfaces/api/userInterfaces';
|
||||
@@ -22,8 +21,8 @@ import useSWR from 'swr';
|
||||
const messages = defineMessages({
|
||||
requestadmin: 'This request will be approved automatically.',
|
||||
requestSuccess: '<strong>{title}</strong> requested successfully!',
|
||||
requesttitle: 'Request {title}',
|
||||
request4ktitle: 'Request {title} in 4K',
|
||||
requestcollectiontitle: 'Request Collection',
|
||||
requestcollection4ktitle: 'Request Collection in 4K',
|
||||
requesterror: 'Something went wrong while submitting the request.',
|
||||
selectmovies: 'Select Movie(s)',
|
||||
requestmovies: 'Request {count} {count, plural, one {Movie} other {Movies}}',
|
||||
@@ -249,9 +248,11 @@ const CollectionRequestModal = ({
|
||||
onCancel={onCancel}
|
||||
onOk={sendRequest}
|
||||
title={intl.formatMessage(
|
||||
is4k ? messages.request4ktitle : messages.requesttitle,
|
||||
{ title: data?.name }
|
||||
is4k
|
||||
? messages.requestcollection4ktitle
|
||||
: messages.requestcollectiontitle
|
||||
)}
|
||||
subTitle={data?.name}
|
||||
okText={
|
||||
isUpdating
|
||||
? intl.formatMessage(globalMessages.requesting)
|
||||
@@ -266,7 +267,6 @@ const CollectionRequestModal = ({
|
||||
}
|
||||
okDisabled={selectedParts.length === 0}
|
||||
okButtonType={'primary'}
|
||||
iconSvg={<DownloadIcon />}
|
||||
backdrop={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data?.backdropPath}`}
|
||||
>
|
||||
{hasAutoApprove && !quota?.movie.restricted && (
|
||||
@@ -292,11 +292,11 @@ const CollectionRequestModal = ({
|
||||
<div className="flex flex-col">
|
||||
<div className="-mx-4 sm:mx-0">
|
||||
<div className="inline-block min-w-full py-2 align-middle">
|
||||
<div className="overflow-hidden shadow sm:rounded-lg">
|
||||
<div className="overflow-hidden border border-gray-700 backdrop-blur sm:rounded-lg">
|
||||
<table className="min-w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="w-16 bg-gray-500 px-4 py-3">
|
||||
<th className="w-16 bg-gray-700 bg-opacity-80 px-4 py-3">
|
||||
<span
|
||||
role="checkbox"
|
||||
tabIndex={0}
|
||||
@@ -328,15 +328,15 @@ const CollectionRequestModal = ({
|
||||
></span>
|
||||
</span>
|
||||
</th>
|
||||
<th className="bg-gray-500 px-1 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6">
|
||||
<th className="bg-gray-700 bg-opacity-80 px-1 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6">
|
||||
{intl.formatMessage(globalMessages.movie)}
|
||||
</th>
|
||||
<th className="bg-gray-500 px-2 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6">
|
||||
<th className="bg-gray-700 bg-opacity-80 px-2 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6">
|
||||
{intl.formatMessage(globalMessages.status)}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-700 bg-gray-600">
|
||||
<tbody className="divide-y divide-gray-700">
|
||||
{data?.parts.map((part) => {
|
||||
const partRequest = getPartRequest(part.id);
|
||||
const partMedia =
|
||||
@@ -378,7 +378,7 @@ const CollectionRequestModal = ({
|
||||
partRequest ||
|
||||
isSelectedPart(part.id)
|
||||
? 'bg-indigo-500'
|
||||
: 'bg-gray-800'
|
||||
: 'bg-gray-700'
|
||||
} absolute mx-auto h-4 w-9 rounded-full transition-colors duration-200 ease-in-out`}
|
||||
></span>
|
||||
<span
|
||||
|
||||
@@ -5,7 +5,6 @@ import AdvancedRequester from '@app/components/RequestModal/AdvancedRequester';
|
||||
import QuotaDisplay from '@app/components/RequestModal/QuotaDisplay';
|
||||
import { useUser } from '@app/hooks/useUser';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import { DownloadIcon } from '@heroicons/react/outline';
|
||||
import { MediaStatus } from '@server/constants/media';
|
||||
import type { MediaRequest } from '@server/entity/MediaRequest';
|
||||
import type { QuotaResponse } from '@server/interfaces/api/userInterfaces';
|
||||
@@ -21,13 +20,13 @@ const messages = defineMessages({
|
||||
requestadmin: 'This request will be approved automatically.',
|
||||
requestSuccess: '<strong>{title}</strong> requested successfully!',
|
||||
requestCancel: 'Request for <strong>{title}</strong> canceled.',
|
||||
requesttitle: 'Request {title}',
|
||||
request4ktitle: 'Request {title} in 4K',
|
||||
requestmovietitle: 'Request Movie',
|
||||
requestmovie4ktitle: 'Request Movie in 4K',
|
||||
edit: 'Edit Request',
|
||||
approve: 'Approve Request',
|
||||
cancel: 'Cancel Request',
|
||||
pendingrequest: 'Pending Request for {title}',
|
||||
pending4krequest: 'Pending 4K Request for {title}',
|
||||
pendingrequest: 'Pending Movie Request',
|
||||
pending4krequest: 'Pending 4K Movie Request',
|
||||
requestfrom: "{username}'s request is pending approval.",
|
||||
errorediting: 'Something went wrong while editing the request.',
|
||||
requestedited: 'Request for <strong>{title}</strong> edited successfully!',
|
||||
@@ -218,9 +217,9 @@ const MovieRequestModal = ({
|
||||
backgroundClickable
|
||||
onCancel={onCancel}
|
||||
title={intl.formatMessage(
|
||||
is4k ? messages.pending4krequest : messages.pendingrequest,
|
||||
{ title: data?.title }
|
||||
is4k ? messages.pending4krequest : messages.pendingrequest
|
||||
)}
|
||||
subTitle={data?.title}
|
||||
onOk={() =>
|
||||
hasPermission(Permission.MANAGE_REQUESTS)
|
||||
? updateRequest(true)
|
||||
@@ -264,7 +263,6 @@ const MovieRequestModal = ({
|
||||
}
|
||||
secondaryButtonType="danger"
|
||||
cancelText={intl.formatMessage(globalMessages.close)}
|
||||
iconSvg={<DownloadIcon />}
|
||||
backdrop={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data?.backdropPath}`}
|
||||
>
|
||||
{isOwner
|
||||
@@ -310,9 +308,9 @@ const MovieRequestModal = ({
|
||||
onOk={sendRequest}
|
||||
okDisabled={isUpdating || quota?.movie.restricted}
|
||||
title={intl.formatMessage(
|
||||
is4k ? messages.request4ktitle : messages.requesttitle,
|
||||
{ title: data?.title }
|
||||
is4k ? messages.requestmovie4ktitle : messages.requestmovietitle
|
||||
)}
|
||||
subTitle={data?.title}
|
||||
okText={
|
||||
isUpdating
|
||||
? intl.formatMessage(globalMessages.requesting)
|
||||
@@ -321,7 +319,6 @@ const MovieRequestModal = ({
|
||||
)
|
||||
}
|
||||
okButtonType={'primary'}
|
||||
iconSvg={<DownloadIcon />}
|
||||
backdrop={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data?.backdropPath}`}
|
||||
>
|
||||
{hasAutoApprove && !quota?.movie.restricted && (
|
||||
|
||||
@@ -46,7 +46,7 @@ const QuotaDisplay = ({
|
||||
const [showDetails, setShowDetails] = useState(false);
|
||||
return (
|
||||
<div
|
||||
className="my-4 flex flex-col rounded-md bg-gray-800 p-4"
|
||||
className="my-4 flex flex-col rounded-md border border-gray-700 p-4 backdrop-blur"
|
||||
onClick={() => setShowDetails((s) => !s)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
|
||||
@@ -2,7 +2,6 @@ import Alert from '@app/components/Common/Alert';
|
||||
import { SmallLoadingSpinner } from '@app/components/Common/LoadingSpinner';
|
||||
import Modal from '@app/components/Common/Modal';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import { DownloadIcon } from '@heroicons/react/outline';
|
||||
import type { SonarrSeries } from '@server/api/servarr/sonarr';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import useSWR from 'swr';
|
||||
@@ -20,6 +19,7 @@ interface SearchByNameModalProps {
|
||||
onCancel?: () => void;
|
||||
closeModal: () => void;
|
||||
modalTitle: string;
|
||||
modalSubTitle: string;
|
||||
tmdbId: number;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ const SearchByNameModal = ({
|
||||
onCancel,
|
||||
closeModal,
|
||||
modalTitle,
|
||||
modalSubTitle,
|
||||
tmdbId,
|
||||
}: SearchByNameModalProps) => {
|
||||
const intl = useIntl();
|
||||
@@ -48,10 +49,10 @@ const SearchByNameModal = ({
|
||||
onCancel={onCancel}
|
||||
onOk={closeModal}
|
||||
title={modalTitle}
|
||||
subTitle={modalSubTitle}
|
||||
okText={intl.formatMessage(globalMessages.next)}
|
||||
okDisabled={!tvdbId}
|
||||
okButtonType="primary"
|
||||
iconSvg={<DownloadIcon />}
|
||||
>
|
||||
<Alert
|
||||
title={intl.formatMessage(messages.notvdbiddescription)}
|
||||
|
||||
@@ -8,7 +8,6 @@ import SearchByNameModal from '@app/components/RequestModal/SearchByNameModal';
|
||||
import useSettings from '@app/hooks/useSettings';
|
||||
import { useUser } from '@app/hooks/useUser';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import { DownloadIcon } from '@heroicons/react/outline';
|
||||
import { ANIME_KEYWORD_ID } from '@server/api/themoviedb/constants';
|
||||
import { MediaRequestStatus, MediaStatus } from '@server/constants/media';
|
||||
import type { MediaRequest } from '@server/entity/MediaRequest';
|
||||
@@ -25,13 +24,13 @@ import useSWR, { mutate } from 'swr';
|
||||
const messages = defineMessages({
|
||||
requestadmin: 'This request will be approved automatically.',
|
||||
requestSuccess: '<strong>{title}</strong> requested successfully!',
|
||||
requesttitle: 'Request {title}',
|
||||
request4ktitle: 'Request {title} in 4K',
|
||||
requestseriestitle: 'Request Series',
|
||||
requestseries4ktitle: 'Request Series in 4K',
|
||||
edit: 'Edit Request',
|
||||
approve: 'Approve Request',
|
||||
cancel: 'Cancel Request',
|
||||
pendingrequest: 'Pending Request for {title}',
|
||||
pending4krequest: 'Pending 4K Request for {title}',
|
||||
pendingrequest: 'Pending Request',
|
||||
pending4krequest: 'Pending 4K Request',
|
||||
requestfrom: "{username}'s request is pending approval.",
|
||||
requestseasons:
|
||||
'Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}',
|
||||
@@ -367,9 +366,9 @@ const TvRequestModal = ({
|
||||
loading={!error}
|
||||
onCancel={onCancel}
|
||||
modalTitle={intl.formatMessage(
|
||||
is4k ? messages.request4ktitle : messages.requesttitle,
|
||||
{ title: data?.name }
|
||||
is4k ? messages.requestseries4ktitle : messages.requestseriestitle
|
||||
)}
|
||||
modalSubTitle={data.name}
|
||||
tmdbId={tmdbId}
|
||||
/>
|
||||
) : (
|
||||
@@ -390,10 +389,10 @@ const TvRequestModal = ({
|
||||
? messages.pending4krequest
|
||||
: messages.pendingrequest
|
||||
: is4k
|
||||
? messages.request4ktitle
|
||||
: messages.requesttitle,
|
||||
{ title: data?.name }
|
||||
? messages.requestseries4ktitle
|
||||
: messages.requestseriestitle
|
||||
)}
|
||||
subTitle={data?.name}
|
||||
okText={
|
||||
editRequest
|
||||
? selectedSeasons.length === 0
|
||||
@@ -444,7 +443,6 @@ const TvRequestModal = ({
|
||||
? intl.formatMessage(globalMessages.back)
|
||||
: intl.formatMessage(globalMessages.cancel)
|
||||
}
|
||||
iconSvg={<DownloadIcon />}
|
||||
backdrop={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data?.backdropPath}`}
|
||||
>
|
||||
{editRequest
|
||||
@@ -502,12 +500,12 @@ const TvRequestModal = ({
|
||||
<div className="flex flex-col">
|
||||
<div className="-mx-4 sm:mx-0">
|
||||
<div className="inline-block min-w-full py-2 align-middle">
|
||||
<div className="overflow-hidden shadow sm:rounded-lg">
|
||||
<div className="overflow-hidden border border-gray-700 shadow backdrop-blur sm:rounded-lg">
|
||||
<table className="min-w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
className={`w-16 bg-gray-500 px-4 py-3 ${
|
||||
className={`w-16 bg-gray-700 bg-opacity-80 px-4 py-3 ${
|
||||
!settings.currentSettings.partialRequestsEnabled &&
|
||||
'hidden'
|
||||
}`}
|
||||
@@ -544,18 +542,18 @@ const TvRequestModal = ({
|
||||
></span>
|
||||
</span>
|
||||
</th>
|
||||
<th className="bg-gray-500 px-1 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6">
|
||||
<th className="bg-gray-700 bg-opacity-80 px-1 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6">
|
||||
{intl.formatMessage(messages.season)}
|
||||
</th>
|
||||
<th className="bg-gray-500 px-5 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6">
|
||||
<th className="bg-gray-700 bg-opacity-80 px-5 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6">
|
||||
{intl.formatMessage(messages.numberofepisodes)}
|
||||
</th>
|
||||
<th className="bg-gray-500 px-2 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6">
|
||||
<th className="bg-gray-700 bg-opacity-80 px-2 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6">
|
||||
{intl.formatMessage(globalMessages.status)}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-700 bg-gray-600">
|
||||
<tbody className="divide-y divide-gray-700">
|
||||
{data?.seasons
|
||||
.filter((season) => season.seasonNumber !== 0)
|
||||
.map((season) => {
|
||||
@@ -614,7 +612,7 @@ const TvRequestModal = ({
|
||||
)) ||
|
||||
isSelectedSeason(season.seasonNumber)
|
||||
? 'bg-indigo-500'
|
||||
: 'bg-gray-800'
|
||||
: 'bg-gray-700'
|
||||
} absolute mx-auto h-4 w-9 rounded-full transition-colors duration-200 ease-in-out`}
|
||||
></span>
|
||||
<span
|
||||
|
||||
Reference in New Issue
Block a user