frontend/src/features/import-review/ImportReviewCard.tsx

131 lines
3.3 KiB
TypeScript

import { useQueryClient } from "@tanstack/react-query";
import { ExternalLink, Trash2 } from "lucide-react";
import { useState } from "react";
import { toast } from "sonner";
import type { MangaIngestReviewDTO } from "@/api/generated/api.schemas.ts";
import {
useDeleteMangaIngestReview,
useResolveMangaIngestReview,
} from "@/api/generated/manga-ingest-review/manga-ingest-review.ts";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
interface ImportReviewCardProps {
importReview: MangaIngestReviewDTO;
queryKey: any;
}
export function ImportReviewCard({
importReview,
queryKey,
}: ImportReviewCardProps) {
const queryClient = useQueryClient();
const [malId, setMalId] = useState("");
const { mutate: mutateDeleteImportReview } = useDeleteMangaIngestReview({
mutation: {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey });
toast.success("Import review removed successfully");
},
},
});
const {
mutate: mutateResolveImportReview,
isPending: isPendingResolveImportReview,
} = useResolveMangaIngestReview({
mutation: {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey });
toast.success("Import review resolved successfully");
},
},
});
const handleResolve = () => {
if (!malId.trim()) {
alert("Please enter a MyAnimeList ID");
return;
}
mutateResolveImportReview({
params: { id: importReview.id, malId },
});
};
const handleRemove = () => {
mutateDeleteImportReview({ id: importReview.id });
};
const importDate = new Date(importReview.createdAt).toLocaleDateString();
return (
<Card className="p-4">
<div className="space-y-4">
<div className="flex items-start justify-between">
<div className="flex-1">
<h3 className="font-semibold text-foreground">
{importReview.title}
</h3>
<p className="text-sm text-muted-foreground">
Provider:{" "}
<span className="capitalize">
{importReview.contentProviderName}
</span>{" "}
{importDate}
</p>
</div>
{importReview.externalUrl && (
<a
href={importReview.externalUrl}
target="_blank"
rel="noopener noreferrer"
className="ml-2 text-primary hover:underline"
>
<ExternalLink className="h-4 w-4" />
</a>
)}
</div>
<div className="rounded-md bg-destructive/10 p-3">
<p className="text-sm text-destructive">{importReview.reason}</p>
</div>
<div className="space-y-3">
<div>
<label className="text-sm font-medium">MyAnimeList Manga ID</label>
<Input
placeholder="Enter MAL ID to match manually"
value={malId}
onChange={(e) => setMalId(e.target.value)}
className="mt-2"
/>
</div>
<div className="flex gap-2">
<Button
onClick={handleResolve}
disabled={isPendingResolveImportReview || !malId.trim()}
className="flex-1"
>
{isPendingResolveImportReview ? "Resolving..." : "Resolve Import"}
</Button>
<Button
onClick={handleRemove}
variant="outline"
size="icon"
className="text-destructive hover:text-destructive bg-transparent"
>
<Trash2 className="h-4 w-4" />
</Button>
</div>
</div>
</div>
</Card>
);
}