diff --git a/src/app/api/mii/has-liked/route.ts b/src/app/api/mii/has-liked/route.ts
new file mode 100644
index 0000000..ecb0e87
--- /dev/null
+++ b/src/app/api/mii/has-liked/route.ts
@@ -0,0 +1,28 @@
+import { NextRequest, NextResponse } from "next/server";
+import { auth } from "@/lib/auth";
+import { prisma } from "@/lib/prisma";
+import { RateLimit } from "@/lib/rate-limit";
+
+export async function GET(request: NextRequest) {
+ const session = await auth();
+ if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
+
+ const rateLimit = new RateLimit(request, 50, "/api/mii/like_get");
+ const check = await rateLimit.handle();
+ if (check) return check;
+
+ const idsParam = new URL(request.url).searchParams.get("ids");
+ if (!idsParam) return NextResponse.json({ error: "Missing IDs parameter" }, { status: 400 });
+
+ const ids = idsParam.split(",").map(Number).filter(Boolean);
+ if (!ids.length) return NextResponse.json({ error: "No valid IDs provided" }, { status: 400 });
+ if (ids.length > 100) return NextResponse.json({ error: "Too many IDs, maximum is 100" }, { status: 400 });
+
+ const liked = await prisma.like.findMany({
+ where: { userId: Number(session.user?.id), miiId: { in: ids } },
+ select: { miiId: true },
+ });
+
+ // Return only Miis that are liked
+ return NextResponse.json(liked.map((l) => l.miiId));
+}
diff --git a/src/app/mii/[id]/page.tsx b/src/app/mii/[id]/page.tsx
index 8747124..491944b 100644
--- a/src/app/mii/[id]/page.tsx
+++ b/src/app/mii/[id]/page.tsx
@@ -11,7 +11,7 @@ import { MiiPlatform } from "@prisma/client";
import LikeButton from "@/components/like-button";
import ImageViewer from "@/components/image-viewer";
-import DeleteMiiButton from "@/components/mii/delete-mii-button";
+import AuthorButtons from "@/components/mii/author-buttons";
import ShareMiiButton from "@/components/mii/share-mii-button";
import ThreeDsScanTutorialButton from "@/components/tutorial/3ds-scan";
import SwitchScanTutorialButton from "@/components/tutorial/switch-add-mii";
@@ -359,15 +359,7 @@ export default async function MiiPage({ params }: Props) {
{/* Buttons */}
- {session && (Number(session.user?.id) === mii.userId || Number(session.user?.id) === Number(process.env.NEXT_PUBLIC_ADMIN_USER_ID)) && (
- <>
-
-
-
Edit
-
-
- >
- )}
+
diff --git a/src/components/like-button.tsx b/src/components/like-button.tsx
index f264092..7628beb 100644
--- a/src/components/like-button.tsx
+++ b/src/components/like-button.tsx
@@ -56,6 +56,10 @@ export default function LikeButton({ likes, isLiked, miiId, disabled, abbreviate
loadIcons(["icon-park-solid:like", "icon-park-outline:like"]);
}, []);
+ useEffect(() => {
+ setIsLikedState(isLiked);
+ }, [isLiked]);
+
return (
-
- {miis.map((mii) => (
-
-
`/mii/${mii.id}/image?type=image${index}`),
- ]}
- />
-
-
-
-
- {mii.name}
-
-
- {mii.platform === "SWITCH" ? (
-
- ) : (
-
- )}
-
-
-
- {mii.tags.map((tag) => (
-
- {tag}
-
- ))}
-
-
-
-
-
- {!userId && (
-
- @{mii.user?.name}
-
- )}
-
- {userId && Number(session?.user?.id) == userId && (
-
-
-
-
-
-
- )}
-
-
-
- ))}
-
-
+
);
diff --git a/src/components/mii/list/mii-grid.tsx b/src/components/mii/list/mii-grid.tsx
new file mode 100644
index 0000000..fd346de
--- /dev/null
+++ b/src/components/mii/list/mii-grid.tsx
@@ -0,0 +1,88 @@
+"use client";
+
+import Link from "next/link";
+import useSWR from "swr";
+import { Prisma } from "@prisma/client";
+import { useSession } from "next-auth/react";
+import { Icon } from "@iconify/react";
+
+import LikeButton from "@/components/like-button";
+import DeleteMiiButton from "../delete-mii-button";
+import Carousel from "@/components/carousel";
+
+interface Props {
+ miis: Prisma.MiiGetPayload<{ include: { user: { select: { id: true; name: true } }; _count: { select: { likedBy: true } } } }>[];
+ userId?: number;
+}
+
+const fetcher = (url: string) => fetch(url).then((res) => res.json());
+
+export default function MiiGrid({ miis, userId }: Props) {
+ const session = useSession();
+ const ids = miis.map((m) => m.id).join(",");
+ const { data } = useSWR(session.data?.user && miis.length > 0 ? `/api/mii/has-liked?ids=${ids}` : null, fetcher, {
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ });
+ const likedIds = new Set(data ?? []);
+
+ return (
+
+ {miis.map((mii) => (
+
+
`/mii/${mii.id}/image?type=image${index}`),
+ ]}
+ />
+
+
+
+
+ {mii.name}
+
+
+ {mii.platform === "SWITCH" ? (
+
+ ) : (
+
+ )}
+
+
+
+ {mii.tags.map((tag) => (
+
+ {tag}
+
+ ))}
+
+
+
+
+
+ {!userId && (
+
+ @{mii.user?.name}
+
+ )}
+
+ {userId && Number(session.data?.user?.id) == userId && (
+
+
+
+
+
+
+ )}
+
+
+
+ ))}
+
+ );
+}