mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
fix(frontend): handle media items/requests no longer having a valid tmdb id
fixes #517
This commit is contained in:
@@ -3,7 +3,7 @@ import Link from 'next/link';
|
|||||||
import React, { useContext, useEffect } from 'react';
|
import React, { useContext, useEffect } from 'react';
|
||||||
import { useInView } from 'react-intersection-observer';
|
import { useInView } from 'react-intersection-observer';
|
||||||
import { defineMessages, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import useSWR from 'swr';
|
import useSWR, { mutate } from 'swr';
|
||||||
import {
|
import {
|
||||||
MediaRequestStatus,
|
MediaRequestStatus,
|
||||||
MediaStatus,
|
MediaStatus,
|
||||||
@@ -22,6 +22,8 @@ import StatusBadge from '../StatusBadge';
|
|||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
seasons: '{seasonCount, plural, one {Season} other {Seasons}}',
|
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 => {
|
const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {
|
||||||
@@ -38,6 +40,59 @@ const RequestCardPlaceholder: React.FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface RequestCardErrorProps {
|
||||||
|
mediaId?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RequestCardError: React.FC<RequestCardErrorProps> = ({ 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 (
|
||||||
|
<div className="relative p-4 bg-gray-800 ring-1 ring-red-500 rounded-xl w-72 sm:w-96">
|
||||||
|
<div className="w-20 sm:w-28">
|
||||||
|
<div className="w-full" style={{ paddingBottom: '150%' }}>
|
||||||
|
<div className="absolute inset-0 flex flex-col items-center justify-center w-full h-full px-10">
|
||||||
|
<div className="w-full text-xs text-center text-gray-300 whitespace-normal sm:text-sm">
|
||||||
|
{intl.formatMessage(messages.mediaerror)}
|
||||||
|
</div>
|
||||||
|
{hasPermission(Permission.MANAGE_REQUESTS) && mediaId && (
|
||||||
|
<div className="mt-4">
|
||||||
|
<Button
|
||||||
|
buttonType="danger"
|
||||||
|
buttonSize="sm"
|
||||||
|
onClick={() => deleteRequest()}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="w-5 h-5 mr-1"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span>{intl.formatMessage(messages.deleterequest)}</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
interface RequestCardProps {
|
interface RequestCardProps {
|
||||||
request: MediaRequest;
|
request: MediaRequest;
|
||||||
onTitleData?: (requestId: number, title: MovieDetails | TvDetails) => void;
|
onTitleData?: (requestId: number, title: MovieDetails | TvDetails) => void;
|
||||||
@@ -88,11 +143,11 @@ const RequestCard: React.FC<RequestCardProps> = ({ request, onTitleData }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!requestData && !requestError) {
|
if (!requestData && !requestError) {
|
||||||
return <RequestCardPlaceholder />;
|
return <RequestCardError />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!title || !requestData) {
|
if (!title || !requestData) {
|
||||||
return <RequestCardPlaceholder />;
|
return <RequestCardError mediaId={requestData?.media.id} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@@ -28,12 +28,65 @@ const messages = defineMessages({
|
|||||||
requested: 'Requested',
|
requested: 'Requested',
|
||||||
modified: 'Modified',
|
modified: 'Modified',
|
||||||
modifieduserdate: '{date} by {user}',
|
modifieduserdate: '{date} by {user}',
|
||||||
|
mediaerror: 'The associated title for this request is no longer available.',
|
||||||
|
deleterequest: 'Delete Request',
|
||||||
});
|
});
|
||||||
|
|
||||||
const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {
|
const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {
|
||||||
return (movie as MovieDetails).title !== undefined;
|
return (movie as MovieDetails).title !== undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface RequestItemErroProps {
|
||||||
|
mediaId?: number;
|
||||||
|
revalidateList: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RequestItemError: React.FC<RequestItemErroProps> = ({
|
||||||
|
mediaId,
|
||||||
|
revalidateList,
|
||||||
|
}) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const { hasPermission } = useUser();
|
||||||
|
|
||||||
|
const deleteRequest = async () => {
|
||||||
|
await axios.delete(`/api/v1/media/${mediaId}`);
|
||||||
|
revalidateList();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center w-full h-64 px-10 bg-gray-800 lg:flex-row ring-1 ring-red-500 rounded-xl xl:h-32">
|
||||||
|
<span className="text-sm text-center text-gray-300 lg:text-left">
|
||||||
|
{intl.formatMessage(messages.mediaerror)}
|
||||||
|
</span>
|
||||||
|
{hasPermission(Permission.MANAGE_REQUESTS) && mediaId && (
|
||||||
|
<div className="mt-4 lg:ml-4 lg:mt-0">
|
||||||
|
<Button
|
||||||
|
buttonType="danger"
|
||||||
|
buttonSize="sm"
|
||||||
|
onClick={() => deleteRequest()}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="w-5 h-5 mr-1"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span>{intl.formatMessage(messages.deleterequest)}</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
interface RequestItemProps {
|
interface RequestItemProps {
|
||||||
request: MediaRequest;
|
request: MediaRequest;
|
||||||
revalidateList: () => void;
|
revalidateList: () => void;
|
||||||
@@ -108,9 +161,9 @@ const RequestItem: React.FC<RequestItemProps> = ({
|
|||||||
|
|
||||||
if (!title || !requestData) {
|
if (!title || !requestData) {
|
||||||
return (
|
return (
|
||||||
<div
|
<RequestItemError
|
||||||
className="w-full h-64 bg-gray-800 rounded-xl xl:h-32 animate-pulse"
|
mediaId={requestData?.media.id}
|
||||||
ref={ref}
|
revalidateList={revalidateList}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -160,8 +160,12 @@
|
|||||||
"components.RequestButton.requestmore4k": "Request More 4K",
|
"components.RequestButton.requestmore4k": "Request More 4K",
|
||||||
"components.RequestButton.viewrequest": "View Request",
|
"components.RequestButton.viewrequest": "View Request",
|
||||||
"components.RequestButton.viewrequest4k": "View 4K Request",
|
"components.RequestButton.viewrequest4k": "View 4K Request",
|
||||||
|
"components.RequestCard.deleterequest": "Delete Request",
|
||||||
|
"components.RequestCard.mediaerror": "The associated title for this request is no longer available.",
|
||||||
"components.RequestCard.seasons": "{seasonCount, plural, one {Season} other {Seasons}}",
|
"components.RequestCard.seasons": "{seasonCount, plural, one {Season} other {Seasons}}",
|
||||||
|
"components.RequestList.RequestItem.deleterequest": "Delete Request",
|
||||||
"components.RequestList.RequestItem.failedretry": "Something went wrong while retrying the request.",
|
"components.RequestList.RequestItem.failedretry": "Something went wrong while retrying the request.",
|
||||||
|
"components.RequestList.RequestItem.mediaerror": "The associated title for this request is no longer available.",
|
||||||
"components.RequestList.RequestItem.modified": "Modified",
|
"components.RequestList.RequestItem.modified": "Modified",
|
||||||
"components.RequestList.RequestItem.modifieduserdate": "{date} by {user}",
|
"components.RequestList.RequestItem.modifieduserdate": "{date} by {user}",
|
||||||
"components.RequestList.RequestItem.requested": "Requested",
|
"components.RequestList.RequestItem.requested": "Requested",
|
||||||
|
Reference in New Issue
Block a user