feat(frontend): a few more tooltips (#2972)

* feat(frontend): a few more tooltips

* feat: add tooltips to status badges
pull/2973/head
TheCatLady 2 years ago committed by GitHub
parent 8a2acb7f2b
commit 815d709bcf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,4 +1,5 @@
import Link from 'next/link';
import React from 'react';
interface BadgeProps {
badgeType?:
@ -14,12 +15,10 @@ interface BadgeProps {
children: React.ReactNode;
}
const Badge = ({
badgeType = 'default',
className,
href,
children,
}: BadgeProps) => {
const Badge = (
{ badgeType = 'default', className, href, children }: BadgeProps,
ref?: React.Ref<HTMLElement>
) => {
const badgeStyle = [
'px-2 inline-flex text-xs leading-5 font-semibold rounded-full whitespace-nowrap',
];
@ -79,6 +78,7 @@ const Badge = ({
target="_blank"
rel="noopener noreferrer"
className={badgeStyle.join(' ')}
ref={ref as React.Ref<HTMLAnchorElement>}
>
{children}
</a>
@ -86,12 +86,24 @@ const Badge = ({
} else if (href) {
return (
<Link href={href}>
<a className={badgeStyle.join(' ')}>{children}</a>
<a
className={badgeStyle.join(' ')}
ref={ref as React.Ref<HTMLAnchorElement>}
>
{children}
</a>
</Link>
);
} else {
return <span className={badgeStyle.join(' ')}>{children}</span>;
return (
<span
className={badgeStyle.join(' ')}
ref={ref as React.Ref<HTMLSpanElement>}
>
{children}
</span>
);
}
};
export default Badge;
export default React.forwardRef(Badge) as typeof Badge;

@ -70,7 +70,7 @@ const ExternalLinkBlock = ({
)}
{rtUrl && (
<a
href={`${rtUrl}`}
href={rtUrl}
className="w-14 opacity-50 transition duration-300 hover:opacity-100"
target="_blank"
rel="noreferrer"

@ -80,6 +80,9 @@ const messages = defineMessages({
physicalrelease: 'Physical Release',
reportissue: 'Report an Issue',
managemovie: 'Manage Movie',
rtcriticsscore: 'Rotten Tomatoes Tomatometer',
rtaudiencescore: 'Rotten Tomatoes Audience Score',
tmdbuserscore: 'TMDB User Score',
});
interface MovieDetailsProps {
@ -322,6 +325,7 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
tmdbId={data.mediaInfo?.tmdbId}
mediaType="movie"
plexUrl={data.mediaInfo?.plexUrl}
serviceUrl={data.mediaInfo?.serviceUrl}
/>
{settings.currentSettings.movie4kEnabled &&
hasPermission(
@ -343,6 +347,7 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
tmdbId={data.mediaInfo?.tmdbId}
mediaType="movie"
plexUrl={data.mediaInfo?.plexUrl4k}
serviceUrl={data.mediaInfo?.serviceUrl4k}
/>
)}
</div>
@ -499,36 +504,55 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
(ratingData?.audienceRating && !!ratingData?.audienceScore)) && (
<div className="media-ratings">
{ratingData?.criticsRating && !!ratingData?.criticsScore && (
<>
<span className="media-rating">
<Tooltip
content={intl.formatMessage(messages.rtcriticsscore)}
>
<a
href={ratingData.url}
className="media-rating"
target="_blank"
rel="noreferrer"
>
{ratingData.criticsRating === 'Rotten' ? (
<RTRotten className="mr-1 w-6" />
<RTRotten className="w-6" />
) : (
<RTFresh className="mr-1 w-6" />
<RTFresh className="w-6" />
)}
{ratingData.criticsScore}%
</span>
</>
<span>{ratingData.criticsScore}%</span>
</a>
</Tooltip>
)}
{ratingData?.audienceRating && !!ratingData?.audienceScore && (
<>
<span className="media-rating">
<Tooltip
content={intl.formatMessage(messages.rtaudiencescore)}
>
<a
href={ratingData.url}
className="media-rating"
target="_blank"
rel="noreferrer"
>
{ratingData.audienceRating === 'Spilled' ? (
<RTAudRotten className="mr-1 w-6" />
<RTAudRotten className="w-6" />
) : (
<RTAudFresh className="mr-1 w-6" />
<RTAudFresh className="w-6" />
)}
{ratingData.audienceScore}%
</span>
</>
<span>{ratingData.audienceScore}%</span>
</a>
</Tooltip>
)}
{!!data.voteCount && (
<>
<span className="media-rating">
<TmdbLogo className="mr-2 w-6" />
{data.voteAverage}/10
</span>
</>
<Tooltip content={intl.formatMessage(messages.tmdbuserscore)}>
<a
href={`https://www.themoviedb.org/movie/${data.id}?language=${locale}`}
className="media-rating"
target="_blank"
rel="noreferrer"
>
<TmdbLogo className="mr-1 w-6" />
<span>{Math.round(data.voteAverage * 10)}%</span>
</a>
</Tooltip>
)}
</div>
)}

@ -1,5 +1,6 @@
import Badge from '@app/components/Common/Badge';
import Button from '@app/components/Common/Button';
import Tooltip from '@app/components/Common/Tooltip';
import RequestModal from '@app/components/RequestModal';
import useRequestOverride from '@app/hooks/useRequestOverride';
import { useUser } from '@app/hooks/useUser';
@ -27,6 +28,13 @@ const messages = defineMessages({
profilechanged: 'Quality Profile',
rootfolder: 'Root Folder',
languageprofile: 'Language Profile',
requestdate: 'Request Date',
requestedby: 'Requested By',
lastmodifiedby: 'Last Modified By',
approve: 'Approve Request',
decline: 'Decline Request',
edit: 'Edit Request',
delete: 'Delete Request',
});
interface RequestBlockProps {
@ -83,7 +91,9 @@ const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
<div className="flex items-center justify-between">
<div className="mr-6 min-w-0 flex-1 flex-col items-center text-sm leading-5">
<div className="white mb-1 flex flex-nowrap">
<UserIcon className="mr-1.5 h-5 w-5 min-w-0 flex-shrink-0" />
<Tooltip content={intl.formatMessage(messages.requestedby)}>
<UserIcon className="mr-1.5 h-5 w-5 min-w-0 flex-shrink-0" />
</Tooltip>
<span className="w-40 truncate md:w-auto">
<Link
href={
@ -100,7 +110,9 @@ const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
</div>
{request.modifiedBy && (
<div className="flex flex-nowrap">
<EyeIcon className="mr-1.5 h-5 w-5 flex-shrink-0" />
<Tooltip content={intl.formatMessage(messages.lastmodifiedby)}>
<EyeIcon className="mr-1.5 h-5 w-5 flex-shrink-0" />
</Tooltip>
<span className="w-40 truncate md:w-auto">
<Link
href={
@ -120,39 +132,47 @@ const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
<div className="ml-2 flex flex-shrink-0 flex-wrap">
{request.status === MediaRequestStatus.PENDING && (
<>
<Button
buttonType="success"
className="mr-1"
onClick={() => updateRequest('approve')}
disabled={isUpdating}
>
<CheckIcon className="icon-sm" />
</Button>
<Tooltip content={intl.formatMessage(messages.approve)}>
<Button
buttonType="success"
className="mr-1"
onClick={() => updateRequest('approve')}
disabled={isUpdating}
>
<CheckIcon className="icon-sm" />
</Button>
</Tooltip>
<Tooltip content={intl.formatMessage(messages.decline)}>
<Button
buttonType="danger"
className="mr-1"
onClick={() => updateRequest('decline')}
disabled={isUpdating}
>
<XIcon />
</Button>
</Tooltip>
<Tooltip content={intl.formatMessage(messages.edit)}>
<Button
buttonType="primary"
onClick={() => setShowEditModal(true)}
disabled={isUpdating}
>
<PencilIcon className="icon-sm" />
</Button>
</Tooltip>
</>
)}
{request.status !== MediaRequestStatus.PENDING && (
<Tooltip content={intl.formatMessage(messages.delete)}>
<Button
buttonType="danger"
className="mr-1"
onClick={() => updateRequest('decline')}
disabled={isUpdating}
>
<XIcon />
</Button>
<Button
buttonType="primary"
onClick={() => setShowEditModal(true)}
onClick={() => deleteRequest()}
disabled={isUpdating}
>
<PencilIcon className="icon-sm" />
<TrashIcon className="icon-sm" />
</Button>
</>
)}
{request.status !== MediaRequestStatus.PENDING && (
<Button
buttonType="danger"
onClick={() => deleteRequest()}
disabled={isUpdating}
>
<TrashIcon className="icon-sm" />
</Button>
</Tooltip>
)}
</div>
</div>
@ -187,7 +207,9 @@ const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
</div>
</div>
<div className="mt-2 flex items-center text-sm leading-5 sm:mt-0">
<CalendarIcon className="mr-1.5 h-5 w-5 flex-shrink-0" />
<Tooltip content={intl.formatMessage(messages.requestdate)}>
<CalendarIcon className="mr-1.5 h-5 w-5 flex-shrink-0" />
</Tooltip>
<span>
{intl.formatDate(request.createdAt, {
year: 'numeric',

@ -1,6 +1,7 @@
import Badge from '@app/components/Common/Badge';
import Button from '@app/components/Common/Button';
import CachedImage from '@app/components/Common/CachedImage';
import Tooltip from '@app/components/Common/Tooltip';
import RequestModal from '@app/components/RequestModal';
import StatusBadge from '@app/components/StatusBadge';
import { Permission, useUser } from '@app/hooks/useUser';
@ -31,6 +32,10 @@ const messages = defineMessages({
mediaerror: '{mediaType} Not Found',
tmdbid: 'TMDB ID',
tvdbid: 'TheTVDB ID',
approverequest: 'Approve Request',
declinerequest: 'Decline Request',
editrequest: 'Edit Request',
cancelrequest: 'Cancel Request',
deleterequest: 'Delete Request',
});
@ -139,11 +144,9 @@ const RequestCardError = ({ requestData }: RequestCardErrorProps) => {
: requestData.media.plexUrl
}
serviceUrl={
hasPermission(Permission.ADMIN)
? requestData.is4k
? requestData.media.serviceUrl4k
: requestData.media.serviceUrl
: undefined
requestData.is4k
? requestData.media.serviceUrl4k
: requestData.media.serviceUrl
}
/>
)}
@ -153,17 +156,29 @@ const RequestCardError = ({ requestData }: RequestCardErrorProps) => {
<div className="flex flex-1 items-end space-x-2">
{hasPermission(Permission.MANAGE_REQUESTS) &&
requestData?.media.id && (
<Button
buttonType="danger"
buttonSize="sm"
className="mt-4"
onClick={() => deleteRequest()}
>
<TrashIcon style={{ marginRight: '0' }} />
<span className="ml-1.5 hidden sm:block">
{intl.formatMessage(messages.deleterequest)}
</span>
</Button>
<>
<Button
buttonType="danger"
buttonSize="sm"
className="mt-4 hidden sm:block"
onClick={() => deleteRequest()}
>
<TrashIcon />
<span>{intl.formatMessage(globalMessages.delete)}</span>
</Button>
<Tooltip
content={intl.formatMessage(messages.deleterequest)}
>
<Button
buttonType="danger"
buttonSize="sm"
className="mt-4 sm:hidden"
onClick={() => deleteRequest()}
>
<TrashIcon />
</Button>
</Tooltip>
</>
)}
</div>
</div>
@ -389,7 +404,14 @@ const RequestCard = ({ request, onTitleData }: RequestCardProps) => {
tmdbId={requestData.media.tmdbId}
mediaType={requestData.type}
plexUrl={
requestData.media[requestData.is4k ? 'plexUrl4k' : 'plexUrl']
requestData.is4k
? requestData.media.plexUrl4k
: requestData.media.plexUrl
}
serviceUrl={
requestData.is4k
? requestData.media.serviceUrl4k
: requestData.media.serviceUrl
}
/>
)}
@ -415,26 +437,52 @@ const RequestCard = ({ request, onTitleData }: RequestCardProps) => {
{requestData.status === MediaRequestStatus.PENDING &&
hasPermission(Permission.MANAGE_REQUESTS) && (
<>
<Button
buttonType="success"
buttonSize="sm"
onClick={() => modifyRequest('approve')}
>
<CheckIcon style={{ marginRight: '0' }} />
<span className="ml-1.5 hidden sm:block">
{intl.formatMessage(globalMessages.approve)}
</span>
</Button>
<Button
buttonType="danger"
buttonSize="sm"
onClick={() => modifyRequest('decline')}
>
<XIcon style={{ marginRight: '0' }} />
<span className="ml-1.5 hidden sm:block">
{intl.formatMessage(globalMessages.decline)}
</span>
</Button>
<div>
<Button
buttonType="success"
buttonSize="sm"
className="hidden sm:block"
onClick={() => modifyRequest('approve')}
>
<CheckIcon />
<span>{intl.formatMessage(globalMessages.approve)}</span>
</Button>
<Tooltip
content={intl.formatMessage(messages.approverequest)}
>
<Button
buttonType="success"
buttonSize="sm"
className="sm:hidden"
onClick={() => modifyRequest('approve')}
>
<CheckIcon />
</Button>
</Tooltip>
</div>
<div>
<Button
buttonType="danger"
buttonSize="sm"
className="hidden sm:block"
onClick={() => modifyRequest('decline')}
>
<XIcon />
<span>{intl.formatMessage(globalMessages.decline)}</span>
</Button>
<Tooltip
content={intl.formatMessage(messages.declinerequest)}
>
<Button
buttonType="danger"
buttonSize="sm"
className="sm:hidden"
onClick={() => modifyRequest('decline')}
>
<XIcon />
</Button>
</Tooltip>
</div>
</>
)}
{requestData.status === MediaRequestStatus.PENDING &&
@ -442,33 +490,54 @@ const RequestCard = ({ request, onTitleData }: RequestCardProps) => {
requestData.requestedBy.id === user?.id &&
(requestData.type === 'tv' ||
hasPermission(Permission.REQUEST_ADVANCED)) && (
<Button
buttonType="primary"
buttonSize="sm"
onClick={() => setShowEditModal(true)}
className={`${
hasPermission(Permission.MANAGE_REQUESTS) ? 'sm:hidden' : ''
}`}
>
<PencilIcon style={{ marginRight: '0' }} />
<span className="ml-1.5 hidden sm:block">
{intl.formatMessage(globalMessages.edit)}
</span>
</Button>
<div>
{!hasPermission(Permission.MANAGE_REQUESTS) && (
<Button
buttonType="primary"
buttonSize="sm"
className="hidden sm:block"
onClick={() => setShowEditModal(true)}
>
<PencilIcon />
<span>{intl.formatMessage(globalMessages.edit)}</span>
</Button>
)}
<Tooltip content={intl.formatMessage(messages.editrequest)}>
<Button
buttonType="primary"
buttonSize="sm"
className="sm:hidden"
onClick={() => setShowEditModal(true)}
>
<PencilIcon />
</Button>
</Tooltip>
</div>
)}
{requestData.status === MediaRequestStatus.PENDING &&
!hasPermission(Permission.MANAGE_REQUESTS) &&
requestData.requestedBy.id === user?.id && (
<Button
buttonType="danger"
buttonSize="sm"
onClick={() => deleteRequest()}
>
<XIcon style={{ marginRight: '0' }} />
<span className="ml-1.5 hidden sm:block">
{intl.formatMessage(globalMessages.cancel)}
</span>
</Button>
<div>
<Button
buttonType="danger"
buttonSize="sm"
className="hidden sm:block"
onClick={() => deleteRequest()}
>
<XIcon />
<span>{intl.formatMessage(globalMessages.cancel)}</span>
</Button>
<Tooltip content={intl.formatMessage(messages.cancelrequest)}>
<Button
buttonType="danger"
buttonSize="sm"
className="sm:hidden"
onClick={() => deleteRequest()}
>
<XIcon />
</Button>
</Tooltip>
</div>
)}
</div>
</div>

@ -136,11 +136,9 @@ const RequestItemError = ({
: requestData.media.plexUrl
}
serviceUrl={
hasPermission(Permission.ADMIN)
? requestData.is4k
? requestData.media.serviceUrl4k
: requestData.media.serviceUrl
: undefined
requestData.is4k
? requestData.media.serviceUrl4k
: requestData.media.serviceUrl
}
/>
)}
@ -472,9 +470,14 @@ const RequestItem = ({ request, revalidateList }: RequestItemProps) => {
tmdbId={requestData.media.tmdbId}
mediaType={requestData.type}
plexUrl={
requestData.media[
requestData.is4k ? 'plexUrl4k' : 'plexUrl'
]
requestData.is4k
? requestData.media.plexUrl4k
: requestData.media.plexUrl
}
serviceUrl={
requestData.is4k
? requestData.media.serviceUrl4k
: requestData.media.serviceUrl
}
/>
)}

@ -46,7 +46,7 @@ const messages = defineMessages({
'Do NOT enable this setting unless you understand what you are doing!',
cacheImages: 'Enable Image Caching',
cacheImagesTip:
'Optimize and store all images locally (consumes a significant amount of disk space)',
'Cache and serve optimized images (requires a significant amount of disk space)',
trustProxy: 'Enable Proxy Support',
trustProxyTip:
'Allow Overseerr to correctly register client IP addresses behind a proxy',

@ -1,5 +1,6 @@
import Spinner from '@app/assets/spinner.svg';
import Badge from '@app/components/Common/Badge';
import Tooltip from '@app/components/Common/Tooltip';
import useSettings from '@app/hooks/useSettings';
import { Permission, useUser } from '@app/hooks/useUser';
import globalMessages from '@app/i18n/globalMessages';
@ -9,6 +10,9 @@ import { defineMessages, useIntl } from 'react-intl';
const messages = defineMessages({
status: '{status}',
status4k: '4K {status}',
playonplex: 'Play on Plex',
openinarr: 'Open in {arr}',
managemedia: 'Manage {mediaType}',
});
interface StatusBadgeProps {
@ -35,6 +39,7 @@ const StatusBadge = ({
const settings = useSettings();
let mediaLink: string | undefined;
let mediaLinkDescription: string | undefined;
if (
mediaType &&
@ -63,63 +68,94 @@ const StatusBadge = ({
: settings.currentSettings.series4kEnabled))
) {
mediaLink = plexUrl;
mediaLinkDescription = intl.formatMessage(messages.playonplex);
} else if (hasPermission(Permission.MANAGE_REQUESTS)) {
mediaLink =
mediaType && tmdbId ? `/${mediaType}/${tmdbId}?manage=1` : serviceUrl;
if (mediaType && tmdbId) {
mediaLink = `/${mediaType}/${tmdbId}?manage=1`;
mediaLinkDescription = intl.formatMessage(messages.managemedia, {
mediaType: intl.formatMessage(
mediaType === 'movie' ? globalMessages.movie : globalMessages.tvshow
),
});
} else if (hasPermission(Permission.ADMIN)) {
mediaLink = serviceUrl;
mediaLinkDescription = intl.formatMessage(messages.openinarr, {
arr: mediaType === 'movie' ? 'Radarr' : 'Sonarr',
});
}
}
switch (status) {
case MediaStatus.AVAILABLE:
return (
<Badge badgeType="success" href={mediaLink}>
<div className="flex items-center">
<span>
{intl.formatMessage(is4k ? messages.status4k : messages.status, {
status: intl.formatMessage(globalMessages.available),
})}
</span>
{inProgress && <Spinner className="ml-1 h-3 w-3" />}
</div>
</Badge>
<Tooltip content={mediaLinkDescription}>
<Badge badgeType="success" href={mediaLink}>
<div className="flex items-center">
<span>
{intl.formatMessage(
is4k ? messages.status4k : messages.status,
{
status: intl.formatMessage(globalMessages.available),
}
)}
</span>
{inProgress && <Spinner className="ml-1 h-3 w-3" />}
</div>
</Badge>
</Tooltip>
);
case MediaStatus.PARTIALLY_AVAILABLE:
return (
<Badge badgeType="success" href={mediaLink}>
<div className="flex items-center">
<span>
{intl.formatMessage(is4k ? messages.status4k : messages.status, {
status: intl.formatMessage(globalMessages.partiallyavailable),
})}
</span>
{inProgress && <Spinner className="ml-1 h-3 w-3" />}
</div>
</Badge>
<Tooltip content={mediaLinkDescription}>
<Badge badgeType="success" href={mediaLink}>
<div className="flex items-center">
<span>
{intl.formatMessage(
is4k ? messages.status4k : messages.status,
{
status: intl.formatMessage(
globalMessages.partiallyavailable
),
}
)}
</span>
{inProgress && <Spinner className="ml-1 h-3 w-3" />}
</div>
</Badge>
</Tooltip>
);
case MediaStatus.PROCESSING:
return (
<Badge badgeType="primary" href={mediaLink}>
<div className="flex items-center">
<span>
{intl.formatMessage(is4k ? messages.status4k : messages.status, {
status: inProgress
? intl.formatMessage(globalMessages.processing)
: intl.formatMessage(globalMessages.requested),
})}
</span>
{inProgress && <Spinner className="ml-1 h-3 w-3" />}
</div>
</Badge>
<Tooltip content={mediaLinkDescription}>
<Badge badgeType="primary" href={mediaLink}>
<div className="flex items-center">
<span>
{intl.formatMessage(
is4k ? messages.status4k : messages.status,
{
status: inProgress
? intl.formatMessage(globalMessages.processing)
: intl.formatMessage(globalMessages.requested),
}
)}
</span>
{inProgress && <Spinner className="ml-1 h-3 w-3" />}
</div>
</Badge>
</Tooltip>
);
case MediaStatus.PENDING:
return (
<Badge badgeType="warning" href={mediaLink}>
{intl.formatMessage(is4k ? messages.status4k : messages.status, {
status: intl.formatMessage(globalMessages.pending),
})}
</Badge>
<Tooltip content={mediaLinkDescription}>
<Badge badgeType="warning" href={mediaLink}>
{intl.formatMessage(is4k ? messages.status4k : messages.status, {
status: intl.formatMessage(globalMessages.pending),
})}
</Badge>
</Tooltip>
);
default:

@ -79,6 +79,9 @@ const messages = defineMessages({
episodeCount: '{episodeCount, plural, one {# Episode} other {# Episodes}}',
seasonnumber: 'Season {seasonNumber}',
status4k: '4K {status}',
rtcriticsscore: 'Rotten Tomatoes Tomatometer',
rtaudiencescore: 'Rotten Tomatoes Audience Score',
tmdbuserscore: 'TMDB User Score',
});
interface TvDetailsProps {
@ -330,6 +333,7 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
tmdbId={data.mediaInfo?.tmdbId}
mediaType="tv"
plexUrl={data.mediaInfo?.plexUrl}
serviceUrl={data.mediaInfo?.serviceUrl}
/>
{settings.currentSettings.series4kEnabled &&
hasPermission(
@ -351,6 +355,7 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
tmdbId={data.mediaInfo?.tmdbId}
mediaType="tv"
plexUrl={data.mediaInfo?.plexUrl4k}
serviceUrl={data.mediaInfo?.serviceUrl4k}
/>
)}
</div>
@ -660,30 +665,55 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
(ratingData?.audienceRating && !!ratingData?.audienceScore)) && (
<div className="media-ratings">
{ratingData?.criticsRating && !!ratingData?.criticsScore && (
<span className="media-rating">
{ratingData.criticsRating === 'Rotten' ? (
<RTRotten className="mr-1 w-6" />
) : (
<RTFresh className="mr-1 w-6" />
)}
{ratingData.criticsScore}%
</span>
<Tooltip
content={intl.formatMessage(messages.rtcriticsscore)}
>
<a
href={ratingData.url}
className="media-rating"
target="_blank"
rel="noreferrer"
>
{ratingData.criticsRating === 'Rotten' ? (
<RTRotten className="mr-1 w-6" />
) : (
<RTFresh className="mr-1 w-6" />
)}
<span>{ratingData.criticsScore}%</span>
</a>
</Tooltip>
)}
{ratingData?.audienceRating && !!ratingData?.audienceScore && (
<span className="media-rating">
{ratingData.audienceRating === 'Spilled' ? (
<RTAudRotten className="mr-1 w-6" />
) : (
<RTAudFresh className="mr-1 w-6" />
)}
{ratingData.audienceScore}%
</span>
<Tooltip
content={intl.formatMessage(messages.rtaudiencescore)}
>
<a
href={ratingData.url}
className="media-rating"
target="_blank"
rel="noreferrer"
>
{ratingData.audienceRating === 'Spilled' ? (
<RTAudRotten className="mr-1 w-6" />
) : (
<RTAudFresh className="mr-1 w-6" />
)}
<span>{ratingData.audienceScore}%</span>
</a>
</Tooltip>
)}
{!!data.voteCount && (
<span className="media-rating">
<TmdbLogo className="mr-2 w-6" />
{data.voteAverage}/10
</span>
<Tooltip content={intl.formatMessage(messages.tmdbuserscore)}>
<a
href={`https://www.themoviedb.org/tv/${data.id}?language=${locale}`}
className="media-rating"
target="_blank"
rel="noreferrer"
>
<TmdbLogo className="mr-1 w-6" />
<span>{Math.round(data.voteAverage * 10)}%</span>
</a>
</Tooltip>
)}
</div>
)}

@ -181,6 +181,8 @@
"components.MovieDetails.releasedate": "{releaseCount, plural, one {Release Date} other {Release Dates}}",
"components.MovieDetails.reportissue": "Report an Issue",
"components.MovieDetails.revenue": "Revenue",
"components.MovieDetails.rtaudiencescore": "Rotten Tomatoes Audience Score",
"components.MovieDetails.rtcriticsscore": "Rotten Tomatoes Tomatometer",
"components.MovieDetails.runtime": "{minutes} minutes",
"components.MovieDetails.showless": "Show Less",
"components.MovieDetails.showmore": "Show More",
@ -188,6 +190,7 @@
"components.MovieDetails.streamingproviders": "Currently Streaming On",
"components.MovieDetails.studio": "{studioCount, plural, one {Studio} other {Studios}}",
"components.MovieDetails.theatricalrelease": "Theatrical Release",
"components.MovieDetails.tmdbuserscore": "TMDB User Score",
"components.MovieDetails.viewfullcrew": "View Full Crew",
"components.MovieDetails.watchtrailer": "Watch Trailer",
"components.NotificationTypeSelector.adminissuecommentDescription": "Get notified when other users comment on issues.",
@ -292,8 +295,15 @@
"components.QuotaSelector.unlimited": "Unlimited",
"components.RegionSelector.regionDefault": "All Regions",
"components.RegionSelector.regionServerDefault": "Default ({region})",
"components.RequestBlock.approve": "Approve Request",
"components.RequestBlock.decline": "Decline Request",
"components.RequestBlock.delete": "Delete Request",
"components.RequestBlock.edit": "Edit Request",
"components.RequestBlock.languageprofile": "Language Profile",
"components.RequestBlock.lastmodifiedby": "Last Modified By",
"components.RequestBlock.profilechanged": "Quality Profile",
"components.RequestBlock.requestdate": "Request Date",
"components.RequestBlock.requestedby": "Requested By",
"components.RequestBlock.requestoverrides": "Request Overrides",
"components.RequestBlock.rootfolder": "Root Folder",
"components.RequestBlock.seasons": "{seasonCount, plural, one {Season} other {Seasons}}",
@ -310,7 +320,11 @@
"components.RequestButton.requestmore4k": "Request More in 4K",
"components.RequestButton.viewrequest": "View Request",
"components.RequestButton.viewrequest4k": "View 4K Request",
"components.RequestCard.approverequest": "Approve Request",
"components.RequestCard.cancelrequest": "Cancel Request",
"components.RequestCard.declinerequest": "Decline Request",
"components.RequestCard.deleterequest": "Delete Request",
"components.RequestCard.editrequest": "Edit Request",
"components.RequestCard.failedretry": "Something went wrong while retrying the request.",
"components.RequestCard.mediaerror": "{mediaType} Not Found",
"components.RequestCard.seasons": "{seasonCount, plural, one {Season} other {Seasons}}",
@ -736,7 +750,7 @@
"components.Settings.applicationTitle": "Application Title",
"components.Settings.applicationurl": "Application URL",
"components.Settings.cacheImages": "Enable Image Caching",
"components.Settings.cacheImagesTip": "Optimize and store all images locally (consumes a significant amount of disk space)",
"components.Settings.cacheImagesTip": "Cache and serve optimized images (requires a significant amount of disk space)",
"components.Settings.cancelscan": "Cancel Scan",
"components.Settings.copied": "Copied API key to clipboard.",
"components.Settings.csrfProtection": "Enable CSRF Protection",
@ -849,6 +863,9 @@
"components.Setup.signinMessage": "Get started by signing in with your Plex account",
"components.Setup.tip": "Tip",
"components.Setup.welcome": "Welcome to Overseerr",
"components.StatusBadge.managemedia": "Manage {mediaType}",
"components.StatusBadge.openinarr": "Open in {arr}",
"components.StatusBadge.playonplex": "Play on Plex",
"components.StatusBadge.status": "{status}",
"components.StatusBadge.status4k": "4K {status}",
"components.StatusChecker.appUpdated": "{applicationTitle} Updated",
@ -881,6 +898,8 @@
"components.TvDetails.productioncountries": "Production {countryCount, plural, one {Country} other {Countries}}",
"components.TvDetails.recommendations": "Recommendations",
"components.TvDetails.reportissue": "Report an Issue",
"components.TvDetails.rtaudiencescore": "Rotten Tomatoes Audience Score",
"components.TvDetails.rtcriticsscore": "Rotten Tomatoes Tomatometer",
"components.TvDetails.seasonnumber": "Season {seasonNumber}",
"components.TvDetails.seasons": "{seasonCount, plural, one {# Season} other {# Seasons}}",
"components.TvDetails.seasonstitle": "Seasons",
@ -888,6 +907,7 @@
"components.TvDetails.similar": "Similar Series",
"components.TvDetails.status4k": "4K {status}",
"components.TvDetails.streamingproviders": "Currently Streaming On",
"components.TvDetails.tmdbuserscore": "TMDB User Score",
"components.TvDetails.viewfullcrew": "View Full Crew",
"components.TvDetails.watchtrailer": "Watch Trailer",
"components.UserList.accounttype": "Type",

@ -184,11 +184,11 @@
}
.media-ratings {
@apply flex items-center justify-center border-b border-gray-700 px-4 py-2 font-medium last:border-b-0;
@apply flex items-center justify-center space-x-5 border-b border-gray-700 px-4 py-2 font-medium last:border-b-0;
}
.media-rating {
@apply mr-4 flex items-center last:mr-0;
@apply flex items-center space-x-1;
}
.error-message {

Loading…
Cancel
Save