Files
mtdb_movie/resources/client/reviews/rating-dialog.tsx
maher 703f50a09d
Some checks failed
Build / run (push) Has been cancelled
first commit
2025-10-29 11:42:25 +01:00

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" />;
}
}