|
|
|
@ -20,12 +20,11 @@ import type { TvDetails } from '@server/models/Tv';
|
|
|
|
|
import Link from 'next/link';
|
|
|
|
|
import { useRouter } from 'next/router';
|
|
|
|
|
import { useCallback, useEffect, useState } from 'react';
|
|
|
|
|
import { defineMessages, FormattedNumber, useIntl } from 'react-intl';
|
|
|
|
|
import { defineMessages, useIntl } from 'react-intl';
|
|
|
|
|
import useSWR from 'swr';
|
|
|
|
|
|
|
|
|
|
const messages = defineMessages({
|
|
|
|
|
recentrequests: 'Recent Requests',
|
|
|
|
|
norequests: 'No requests.',
|
|
|
|
|
limit: '{remaining} of {limit}',
|
|
|
|
|
requestsperdays: '{limit} remaining',
|
|
|
|
|
unlimited: 'Unlimited',
|
|
|
|
@ -35,6 +34,8 @@ const messages = defineMessages({
|
|
|
|
|
seriesrequest: 'Series Requests',
|
|
|
|
|
recentlywatched: 'Recently Watched',
|
|
|
|
|
plexwatchlist: 'Plex Watchlist',
|
|
|
|
|
emptywatchlist:
|
|
|
|
|
'Media added to your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> will appear here.',
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
type MediaTitle = MovieDetails | TvDetails;
|
|
|
|
@ -70,22 +71,24 @@ const UserProfile = () => {
|
|
|
|
|
? `/api/v1/user/${user.id}/quota`
|
|
|
|
|
: null
|
|
|
|
|
);
|
|
|
|
|
const { data: watchData } = useSWR<UserWatchDataResponse>(
|
|
|
|
|
user?.userType === UserType.PLEX &&
|
|
|
|
|
(user.id === currentUser?.id || currentHasPermission(Permission.ADMIN))
|
|
|
|
|
? `/api/v1/user/${user.id}/watch_data`
|
|
|
|
|
: null
|
|
|
|
|
);
|
|
|
|
|
const { data: watchData, error: watchDataError } =
|
|
|
|
|
useSWR<UserWatchDataResponse>(
|
|
|
|
|
user?.userType === UserType.PLEX &&
|
|
|
|
|
(user.id === currentUser?.id || currentHasPermission(Permission.ADMIN))
|
|
|
|
|
? `/api/v1/user/${user.id}/watch_data`
|
|
|
|
|
: null
|
|
|
|
|
);
|
|
|
|
|
const { data: watchlistItems, error: watchlistError } =
|
|
|
|
|
useSWR<WatchlistResponse>(
|
|
|
|
|
user?.id === currentUser?.id ||
|
|
|
|
|
currentHasPermission(
|
|
|
|
|
[Permission.MANAGE_REQUESTS, Permission.WATCHLIST_VIEW],
|
|
|
|
|
{
|
|
|
|
|
type: 'or',
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
? `/api/v1/user/${user?.id}/watchlist`
|
|
|
|
|
user?.userType === UserType.PLEX &&
|
|
|
|
|
(user.id === currentUser?.id ||
|
|
|
|
|
currentHasPermission(
|
|
|
|
|
[Permission.MANAGE_REQUESTS, Permission.WATCHLIST_VIEW],
|
|
|
|
|
{
|
|
|
|
|
type: 'or',
|
|
|
|
|
}
|
|
|
|
|
))
|
|
|
|
|
? `/api/v1/user/${user.id}/watchlist`
|
|
|
|
|
: null,
|
|
|
|
|
{
|
|
|
|
|
revalidateOnMount: true,
|
|
|
|
@ -146,7 +149,15 @@ const UserProfile = () => {
|
|
|
|
|
{intl.formatMessage(messages.totalrequests)}
|
|
|
|
|
</dt>
|
|
|
|
|
<dd className="mt-1 text-3xl font-semibold text-white">
|
|
|
|
|
<FormattedNumber value={user.requestCount} />
|
|
|
|
|
<Link
|
|
|
|
|
href={
|
|
|
|
|
user.id === currentUser?.id
|
|
|
|
|
? '/profile/requests?filter=all'
|
|
|
|
|
: `/users/${user?.id}/requests?filter=all`
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
<a>{intl.formatNumber(user.requestCount)}</a>
|
|
|
|
|
</Link>
|
|
|
|
|
</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
@ -266,40 +277,49 @@ const UserProfile = () => {
|
|
|
|
|
currentHasPermission(
|
|
|
|
|
[Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],
|
|
|
|
|
{ type: 'or' }
|
|
|
|
|
)) && (
|
|
|
|
|
<>
|
|
|
|
|
<div className="slider-header">
|
|
|
|
|
<Link href={`/users/${user?.id}/requests?filter=all`}>
|
|
|
|
|
<a className="slider-title">
|
|
|
|
|
<span>{intl.formatMessage(messages.recentrequests)}</span>
|
|
|
|
|
<ArrowCircleRightIcon />
|
|
|
|
|
</a>
|
|
|
|
|
</Link>
|
|
|
|
|
</div>
|
|
|
|
|
<Slider
|
|
|
|
|
sliderKey="requests"
|
|
|
|
|
isLoading={!requests && !requestError}
|
|
|
|
|
isEmpty={
|
|
|
|
|
!!requests && !requestError && requests.results.length === 0
|
|
|
|
|
}
|
|
|
|
|
items={(requests?.results ?? []).map((request) => (
|
|
|
|
|
<RequestCard
|
|
|
|
|
key={`request-slider-item-${request.id}`}
|
|
|
|
|
request={request}
|
|
|
|
|
onTitleData={updateAvailableTitles}
|
|
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
placeholder={<RequestCard.Placeholder />}
|
|
|
|
|
emptyMessage={intl.formatMessage(messages.norequests)}
|
|
|
|
|
/>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
{(user.id === currentUser?.id ||
|
|
|
|
|
currentHasPermission(
|
|
|
|
|
[Permission.MANAGE_REQUESTS, Permission.WATCHLIST_VIEW],
|
|
|
|
|
{ type: 'or' }
|
|
|
|
|
)) &&
|
|
|
|
|
(!watchlistItems || !!watchlistItems.results.length) &&
|
|
|
|
|
(!requests || !!requests.results.length) &&
|
|
|
|
|
!requestError && (
|
|
|
|
|
<>
|
|
|
|
|
<div className="slider-header">
|
|
|
|
|
<Link
|
|
|
|
|
href={
|
|
|
|
|
user.id === currentUser?.id
|
|
|
|
|
? '/profile/requests?filter=all'
|
|
|
|
|
: `/users/${user?.id}/requests?filter=all`
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
<a className="slider-title">
|
|
|
|
|
<span>{intl.formatMessage(messages.recentrequests)}</span>
|
|
|
|
|
<ArrowCircleRightIcon />
|
|
|
|
|
</a>
|
|
|
|
|
</Link>
|
|
|
|
|
</div>
|
|
|
|
|
<Slider
|
|
|
|
|
sliderKey="requests"
|
|
|
|
|
isLoading={!requests}
|
|
|
|
|
items={(requests?.results ?? []).map((request) => (
|
|
|
|
|
<RequestCard
|
|
|
|
|
key={`request-slider-item-${request.id}`}
|
|
|
|
|
request={request}
|
|
|
|
|
onTitleData={updateAvailableTitles}
|
|
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
placeholder={<RequestCard.Placeholder />}
|
|
|
|
|
/>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
{user.userType === UserType.PLEX &&
|
|
|
|
|
(user.id === currentUser?.id ||
|
|
|
|
|
currentHasPermission(
|
|
|
|
|
[Permission.MANAGE_REQUESTS, Permission.WATCHLIST_VIEW],
|
|
|
|
|
{ type: 'or' }
|
|
|
|
|
)) &&
|
|
|
|
|
(!watchlistItems ||
|
|
|
|
|
!!watchlistItems.results.length ||
|
|
|
|
|
(user.id === currentUser?.id &&
|
|
|
|
|
(user.settings?.watchlistSyncMovies ||
|
|
|
|
|
user.settings?.watchlistSyncTv))) &&
|
|
|
|
|
!watchlistError && (
|
|
|
|
|
<>
|
|
|
|
|
<div className="slider-header">
|
|
|
|
@ -318,7 +338,20 @@ const UserProfile = () => {
|
|
|
|
|
</div>
|
|
|
|
|
<Slider
|
|
|
|
|
sliderKey="watchlist"
|
|
|
|
|
isLoading={!watchlistItems && !watchlistError}
|
|
|
|
|
isLoading={!watchlistItems}
|
|
|
|
|
isEmpty={!!watchlistItems && watchlistItems.results.length === 0}
|
|
|
|
|
emptyMessage={intl.formatMessage(messages.emptywatchlist, {
|
|
|
|
|
PlexWatchlistSupportLink: (msg: React.ReactNode) => (
|
|
|
|
|
<a
|
|
|
|
|
href="https://support.plex.tv/articles/universal-watchlist/"
|
|
|
|
|
className="text-white transition duration-300 hover:underline"
|
|
|
|
|
target="_blank"
|
|
|
|
|
rel="noreferrer"
|
|
|
|
|
>
|
|
|
|
|
{msg}
|
|
|
|
|
</a>
|
|
|
|
|
),
|
|
|
|
|
})}
|
|
|
|
|
items={watchlistItems?.results.map((item) => (
|
|
|
|
|
<TmdbTitleCard
|
|
|
|
|
id={item.tmdbId}
|
|
|
|
@ -330,9 +363,11 @@ const UserProfile = () => {
|
|
|
|
|
/>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
{(user.id === currentUser?.id ||
|
|
|
|
|
currentHasPermission(Permission.ADMIN)) &&
|
|
|
|
|
!!watchData?.recentlyWatched.length && (
|
|
|
|
|
{user.userType === UserType.PLEX &&
|
|
|
|
|
(user.id === currentUser?.id ||
|
|
|
|
|
currentHasPermission(Permission.ADMIN)) &&
|
|
|
|
|
(!watchData || !!watchData.recentlyWatched.length) &&
|
|
|
|
|
!watchDataError && (
|
|
|
|
|
<>
|
|
|
|
|
<div className="slider-header">
|
|
|
|
|
<div className="slider-title">
|
|
|
|
@ -342,8 +377,7 @@ const UserProfile = () => {
|
|
|
|
|
<Slider
|
|
|
|
|
sliderKey="media"
|
|
|
|
|
isLoading={!watchData}
|
|
|
|
|
isEmpty={!watchData?.recentlyWatched.length}
|
|
|
|
|
items={watchData.recentlyWatched.map((item) => (
|
|
|
|
|
items={watchData?.recentlyWatched.map((item) => (
|
|
|
|
|
<TmdbTitleCard
|
|
|
|
|
key={`media-slider-item-${item.id}`}
|
|
|
|
|
id={item.id}
|
|
|
|
|