feat: TitleStatusControls

This commit is contained in:
nihonium 2025-11-27 16:26:03 +03:00
parent 3f0456ba01
commit 8a3e14a5e5
Signed by: nihonium
GPG key ID: 0251623741027CFC
5 changed files with 179 additions and 69 deletions

View file

@ -1,20 +1,8 @@
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { useParams, Link } from "react-router-dom";
import { DefaultService } from "../../api/services/DefaultService";
import type { Title, UserTitleStatus } from "../../api";
import {
ClockIcon,
CheckCircleIcon,
PlayCircleIcon,
XCircleIcon,
} from "@heroicons/react/24/solid";
const STATUS_BUTTONS: { status: UserTitleStatus; icon: React.ReactNode; label: string }[] = [
{ status: "planned", icon: <ClockIcon className="w-6 h-6" />, label: "Planned" },
{ status: "finished", icon: <CheckCircleIcon className="w-6 h-6" />, label: "Finished" },
{ status: "in-progress", icon: <PlayCircleIcon className="w-6 h-6" />, label: "In Progress" },
{ status: "dropped", icon: <XCircleIcon className="w-6 h-6" />, label: "Dropped" },
];
import type { Title } from "../../api";
import { TitleStatusControls } from "../../components/TitleStatusControls/TitleStatusControls";
export default function TitlePage() {
const params = useParams();
@ -24,9 +12,9 @@ export default function TitlePage() {
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [userStatus, setUserStatus] = useState<UserTitleStatus | null>(null);
const [updatingStatus, setUpdatingStatus] = useState(false);
// ---------------------------
// LOAD TITLE INFO
// ---------------------------
useEffect(() => {
const fetchTitle = async () => {
setLoading(true);
@ -44,30 +32,6 @@ export default function TitlePage() {
fetchTitle();
}, [titleId]);
const handleStatusClick = async (status: UserTitleStatus) => {
if (updatingStatus || userStatus === status) return;
const userId = Number(localStorage.getItem("userId"));
if (!userId) {
alert("You must be logged in to set status.");
return;
}
setUpdatingStatus(true);
try {
await DefaultService.addUserTitle(userId, {
title_id: titleId,
status,
});
setUserStatus(status);
} catch (err: any) {
console.error(err);
alert(err?.message || "Failed to set status");
} finally {
setUpdatingStatus(false);
}
};
const getTagsString = () =>
title?.tags?.map(tag => tag.en).filter(Boolean).join(", ");
@ -78,7 +42,7 @@ export default function TitlePage() {
return (
<div className="w-full min-h-screen bg-gray-50 p-6 flex justify-center">
<div className="flex flex-col md:flex-row bg-white shadow-lg rounded-xl max-w-4xl w-full p-6 gap-6">
{/* Постер */}
{/* Poster + status buttons */}
<div className="flex flex-col items-center">
<img
src={title.poster?.image_path || "/default-poster.png"}
@ -86,48 +50,52 @@ export default function TitlePage() {
className="w-48 h-72 object-cover rounded-lg mb-4"
/>
{/* Статус кнопки с иконками */}
<div className="flex gap-2 mt-2 flex-wrap justify-center">
{STATUS_BUTTONS.map(btn => (
<button
key={btn.status}
onClick={() => handleStatusClick(btn.status)}
disabled={updatingStatus}
className={`p-2 rounded-lg transition flex items-center justify-center ${
userStatus === btn.status
? "bg-blue-600 text-white"
: "bg-gray-200 text-gray-700 hover:bg-gray-300"
}`}
title={btn.label}
>
{btn.icon}
</button>
))}
</div>
{/* Status buttons */}
<TitleStatusControls titleId={titleId} />
</div>
{/* Информация о тайтле */}
{/* Title info */}
<div className="flex-1 flex flex-col">
<h1 className="text-3xl font-bold mb-2">
{title.title_names?.en?.[0] || "Untitled"}
</h1>
{title.studio && <p className="text-gray-700 mb-1">Studio: {title.studio.name}</p>}
{title.studio && (
<p className="text-gray-700 mb-1">
Studio:{" "}
{title.studio.id ? (
<Link
to={`/studios/${title.studio.id}`}
className="text-blue-600 hover:underline"
>
{title.studio.name}
</Link>
) : (
title.studio.name
)}
</p>
)}
{title.title_status && <p className="text-gray-700 mb-1">Status: {title.title_status}</p>}
{title.rating !== undefined && (
<p className="text-gray-700 mb-1">
Rating: {title.rating} ({title.rating_count} votes)
</p>
)}
{title.release_year && (
<p className="text-gray-700 mb-1">
Released: {title.release_year} {title.release_season || ""}
</p>
)}
{title.episodes_aired !== undefined && (
<p className="text-gray-700 mb-1">
Episodes: {title.episodes_aired}/{title.episodes_all}
</p>
)}
{title.tags && title.tags.length > 0 && (
<p className="text-gray-700 mb-1">
Tags: {getTagsString()}