139 lines
4.1 KiB
TypeScript
Executable File
139 lines
4.1 KiB
TypeScript
Executable File
import {Title} from '@app/titles/models/title';
|
|
import {Episode, EPISODE_MODEL} from '@app/titles/models/episode';
|
|
import {Dialog} from '@common/ui/overlays/dialog/dialog';
|
|
import {DialogBody} from '@common/ui/overlays/dialog/dialog-body';
|
|
import {Trans} from '@common/i18n/trans';
|
|
import {TitlePoster} from '@app/titles/title-poster/title-poster';
|
|
import {useState} from 'react';
|
|
import {Button} from '@common/ui/buttons/button';
|
|
import {useCreateReview} from '@app/reviews/requests/use-create-review';
|
|
import {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';
|
|
import {useDeleteReviews} from '@app/reviews/requests/use-delete-reviews';
|
|
import {DialogHeader} from '@common/ui/overlays/dialog/dialog-header';
|
|
import {EpisodePoster} from '@app/episodes/episode-poster/episode-poster';
|
|
import {TitleLink} from '@app/titles/title-link';
|
|
import {CompactSeasonEpisode} from '@app/episodes/compact-season-episode';
|
|
import {StarSelector} from '@app/reviews/review-list/star-selector';
|
|
|
|
interface Props {
|
|
title: Title;
|
|
episode?: Episode;
|
|
initialRating?: {id: number; score: number};
|
|
}
|
|
export function RatingDialog({title, episode, initialRating}: Props) {
|
|
const item = episode || title;
|
|
const createReview = useCreateReview();
|
|
const deleteReview = useDeleteReviews();
|
|
const {close} = useDialogContext();
|
|
const [currentRating, setCurrentRating] = useState(initialRating?.score || 0);
|
|
|
|
const handleCreateReview = () => {
|
|
if (currentRating) {
|
|
createReview.mutate(
|
|
{reviewable: item, score: currentRating},
|
|
{
|
|
onSuccess: () => close(),
|
|
},
|
|
);
|
|
}
|
|
};
|
|
|
|
const handleDeleteReview = () => {
|
|
if (initialRating) {
|
|
deleteReview.mutate(
|
|
{reviewIds: [initialRating.id]},
|
|
{
|
|
onSuccess: () => close(),
|
|
},
|
|
);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Dialog size="w-auto">
|
|
<DialogHeader>
|
|
<DialogTitle item={item} />
|
|
</DialogHeader>
|
|
<DialogBody>
|
|
{item.model_type === EPISODE_MODEL ? (
|
|
<EpisodeDetails title={title} episode={episode!} />
|
|
) : (
|
|
<TitleDetails title={title} />
|
|
)}
|
|
<div className="pb-16">
|
|
<StarSelector
|
|
count={10}
|
|
value={currentRating}
|
|
onValueChange={setCurrentRating}
|
|
className="my-14"
|
|
/>
|
|
<Button
|
|
variant="flat"
|
|
color="primary"
|
|
className="w-full"
|
|
disabled={!currentRating || createReview.isPending}
|
|
onClick={handleCreateReview}
|
|
>
|
|
<Trans message="Rate" />
|
|
</Button>
|
|
{initialRating && (
|
|
<Button
|
|
className="w-full mt-14"
|
|
disabled={deleteReview.isPending}
|
|
onClick={handleDeleteReview}
|
|
>
|
|
<Trans message="Remove rating" />
|
|
</Button>
|
|
)}
|
|
</div>
|
|
</DialogBody>
|
|
</Dialog>
|
|
);
|
|
}
|
|
|
|
interface TitleDetailsProps {
|
|
title: Title;
|
|
}
|
|
function TitleDetails({title}: TitleDetailsProps) {
|
|
return (
|
|
<div className="flex items-center gap-12 mb-24">
|
|
<TitlePoster size="w-60" srcSize="sm" title={title} />
|
|
<div className="text-sm">
|
|
<div>{title.name}</div>
|
|
<div>{title.year}</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
interface EpisodeDetailsProps {
|
|
title: Title;
|
|
episode: Episode;
|
|
}
|
|
function EpisodeDetails({title, episode}: EpisodeDetailsProps) {
|
|
return (
|
|
<div className="flex items-center gap-12 mb-24">
|
|
<EpisodePoster size="w-100" title={title} episode={episode} />
|
|
<div className="text-base">
|
|
<TitleLink title={title} color="primary" />
|
|
<div className="text-sm">
|
|
{episode.name} (<CompactSeasonEpisode episode={episode} />)
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
interface DialogTitleProps {
|
|
item: Title | Episode;
|
|
}
|
|
function DialogTitle({item}: DialogTitleProps) {
|
|
if (item.model_type === EPISODE_MODEL) {
|
|
return <Trans message="Rate this episode" />;
|
|
} else if (item.is_series) {
|
|
return <Trans message="Rate this series" />;
|
|
} else {
|
|
return <Trans message="Rate this movie" />;
|
|
}
|
|
}
|