Files
jellyseerr/src/components/Common/ListView/index.tsx
Joaquin Olivero 818aa60aac feat: blacklist items from Discover page (#632)
* feat: blacklist media items

re #490

* feat: blacklist media items

* feat: blacklist media items

* style: formatting

* refactor: close the manage slide-over when the media item is removed from the blacklist

* fix: fix media data in the db when blacklisting an item

* refactor: refactor component to accept show boolean

* refactor: hide watchlist button in the media page when it's blacklisted. Also add a blacklist button

* style: formatting

---------

Co-authored-by: JoaquinOlivero <joaquin.olivero@hotmail.com>
2024-09-16 22:08:12 +02:00

163 lines
5.0 KiB
TypeScript

import PersonCard from '@app/components/PersonCard';
import TitleCard from '@app/components/TitleCard';
import TmdbTitleCard from '@app/components/TitleCard/TmdbTitleCard';
import { Permission, useUser } from '@app/hooks/useUser';
import useVerticalScroll from '@app/hooks/useVerticalScroll';
import globalMessages from '@app/i18n/globalMessages';
import { MediaStatus } from '@server/constants/media';
import type { WatchlistItem } from '@server/interfaces/api/discoverInterfaces';
import type {
CollectionResult,
MovieResult,
PersonResult,
TvResult,
} from '@server/models/Search';
import { useIntl } from 'react-intl';
type ListViewProps = {
items?: (TvResult | MovieResult | PersonResult | CollectionResult)[];
plexItems?: WatchlistItem[];
isEmpty?: boolean;
isLoading?: boolean;
isReachingEnd?: boolean;
onScrollBottom: () => void;
mutateParent?: () => void;
};
const ListView = ({
items,
isEmpty,
isLoading,
onScrollBottom,
isReachingEnd,
plexItems,
mutateParent,
}: ListViewProps) => {
const intl = useIntl();
const { hasPermission } = useUser();
useVerticalScroll(onScrollBottom, !isLoading && !isEmpty && !isReachingEnd);
const blacklistVisibility = hasPermission(
[Permission.MANAGE_BLACKLIST, Permission.VIEW_BLACKLIST],
{ type: 'or' }
);
return (
<>
{isEmpty && (
<div className="mt-64 w-full text-center text-2xl text-gray-400">
{intl.formatMessage(globalMessages.noresults)}
</div>
)}
<ul className="cards-vertical">
{plexItems?.map((title, index) => {
return (
<li key={`${title.ratingKey}-${index}`}>
<TmdbTitleCard
id={title.tmdbId}
tmdbId={title.tmdbId}
type={title.mediaType}
isAddedToWatchlist={true}
canExpand
mutateParent={mutateParent}
/>
</li>
);
})}
{items
?.filter((title) => {
if (!blacklistVisibility)
return (
(title as TvResult | MovieResult).mediaInfo?.status !==
MediaStatus.BLACKLISTED
);
return title;
})
.map((title, index) => {
let titleCard: React.ReactNode;
switch (title.mediaType) {
case 'movie':
titleCard = (
<TitleCard
key={title.id}
id={title.id}
isAddedToWatchlist={
title.mediaInfo?.watchlists?.length ?? 0
}
image={title.posterPath}
status={title.mediaInfo?.status}
summary={title.overview}
title={title.title}
userScore={title.voteAverage}
year={title.releaseDate}
mediaType={title.mediaType}
inProgress={
(title.mediaInfo?.downloadStatus ?? []).length > 0
}
canExpand
/>
);
break;
case 'tv':
titleCard = (
<TitleCard
key={title.id}
id={title.id}
isAddedToWatchlist={
title.mediaInfo?.watchlists?.length ?? 0
}
image={title.posterPath}
status={title.mediaInfo?.status}
summary={title.overview}
title={title.name}
userScore={title.voteAverage}
year={title.firstAirDate}
mediaType={title.mediaType}
inProgress={
(title.mediaInfo?.downloadStatus ?? []).length > 0
}
canExpand
/>
);
break;
case 'collection':
titleCard = (
<TitleCard
id={title.id}
image={title.posterPath}
summary={title.overview}
title={title.title}
mediaType={title.mediaType}
canExpand
/>
);
break;
case 'person':
titleCard = (
<PersonCard
personId={title.id}
name={title.name}
profilePath={title.profilePath}
canExpand
/>
);
break;
}
return <li key={`${title.id}-${index}`}>{titleCard}</li>;
})}
{isLoading &&
!isReachingEnd &&
[...Array(20)].map((_item, i) => (
<li key={`placeholder-${i}`}>
<TitleCard.Placeholder canExpand />
</li>
))}
</ul>
</>
);
};
export default ListView;