refactor: add slug to mii like route

This commit is contained in:
trafficlunar 2025-04-14 18:10:51 +01:00
parent 4fec5f65f5
commit f00c998c30
2 changed files with 25 additions and 19 deletions

View file

@ -4,21 +4,20 @@ import { z } from "zod";
import { auth } from "@/lib/auth"; import { auth } from "@/lib/auth";
import { prisma } from "@/lib/prisma"; import { prisma } from "@/lib/prisma";
const likeSchema = z.object({ const slugSchema = z.coerce
miiId: z.coerce.number().int({ message: "Mii ID must be an integer" }).positive({ message: "Mii ID must be valid" }), .number({ message: "Mii ID must be a number" })
}); .int({ message: "Mii ID must be an integer" })
.positive({ message: "Mii ID must be valid" });
export async function PATCH(request: NextRequest) {
// todo: rate limit
export async function PATCH(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
const session = await auth(); const session = await auth();
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
const body = await request.json(); const { id: slugId } = await params;
const parsed = likeSchema.safeParse(body); const parsed = slugSchema.safeParse(slugId);
if (!parsed.success) return NextResponse.json({ error: parsed.error.errors[0].message }, { status: 400 }); if (!parsed.success) return NextResponse.json({ error: parsed.error.errors[0].message }, { status: 400 });
const { miiId } = parsed.data; const miiId = parsed.data;
const result = await prisma.$transaction(async (tx) => { const result = await prisma.$transaction(async (tx) => {
const existingLike = await tx.like.findUnique({ const existingLike = await tx.like.findUnique({

View file

@ -6,31 +6,38 @@ import { Icon } from "@iconify/react";
interface Props { interface Props {
likes: number; likes: number;
miiId: number | undefined; miiId?: number | undefined;
isLiked: boolean; isLiked: boolean;
isLoggedIn: boolean; isLoggedIn?: boolean;
disabled?: boolean;
big?: boolean; big?: boolean;
} }
export default function LikeButton({ likes, isLiked, miiId, isLoggedIn, big }: Props) { export default function LikeButton({ likes, isLiked, miiId, isLoggedIn, disabled, big }: Props) {
const [isLikedState, setIsLikedState] = useState(isLiked); const [isLikedState, setIsLikedState] = useState(isLiked);
const [likesState, setLikesState] = useState(likes); const [likesState, setLikesState] = useState(likes);
const onClick = async () => { const onClick = async () => {
if (disabled) return;
if (!isLoggedIn) redirect("/login"); if (!isLoggedIn) redirect("/login");
setIsLikedState((prev) => !prev); setIsLikedState(!isLikedState);
setLikesState((prev) => (isLiked ? prev - 1 : prev + 1)); setLikesState(isLikedState ? likesState - 1 : likesState + 1);
const response = await fetch("/api/mii/like", { method: "PATCH", body: JSON.stringify({ miiId }) }); const response = await fetch(`/api/mii/${miiId}/like`, { method: "PATCH" });
if (response.ok) {
const { liked, count } = await response.json(); const { liked, count } = await response.json();
setIsLikedState(liked); setIsLikedState(liked);
setLikesState(count); setLikesState(count);
} else {
setIsLikedState(isLikedState);
setLikesState(likesState);
}
}; };
return ( return (
<button onClick={onClick} className={`flex items-center gap-2 text-red-400 cursor-pointer ${big ? "text-3xl" : "text-xl"}`}> <button onClick={onClick} className={`flex items-center gap-2 text-red-400 ${disabled ? "" : "cursor-pointer"} ${big ? "text-3xl" : "text-xl"}`}>
<Icon icon={isLikedState ? "icon-park-solid:like" : "icon-park-outline:like"} /> <Icon icon={isLikedState ? "icon-park-solid:like" : "icon-park-outline:like"} />
<span>{likesState}</span> <span>{likesState}</span>
</button> </button>