import Link from "next/link"; import { Prisma } from "@prisma/client"; import { Icon } from "@iconify/react"; import crypto from "crypto"; import seedrandom from "seedrandom"; import { searchSchema } from "@/lib/schemas"; import { auth } from "@/lib/auth"; import { prisma } from "@/lib/prisma"; import GenderSelect from "./gender-select"; import TagFilter from "./tag-filter"; import SortSelect from "./sort-select"; import Carousel from "../carousel"; import LikeButton from "../like-button"; import DeleteMiiButton from "../delete-mii"; import Pagination from "./pagination"; interface Props { searchParams: { [key: string]: string | string[] | undefined }; userId?: number; // Profiles inLikesPage?: boolean; // Self-explanatory } export default async function MiiList({ searchParams, userId, inLikesPage }: Props) { const session = await auth(); const parsed = searchSchema.safeParse(searchParams); if (!parsed.success) return

{parsed.error.issues[0].message}

; const { q: query, sort, tags, gender, page = 1, limit = 24, seed } = parsed.data; // My Likes page let miiIdsLiked: number[] | undefined = undefined; if (inLikesPage && session?.user.id) { const likedMiis = await prisma.like.findMany({ where: { userId: Number(session.user.id) }, select: { miiId: true }, }); miiIdsLiked = likedMiis.map((like) => like.miiId); } const where: Prisma.MiiWhereInput = { // Only show liked miis on likes page ...(inLikesPage && miiIdsLiked && { id: { in: miiIdsLiked } }), // Searching ...(query && { OR: [{ name: { contains: query, mode: "insensitive" } }, { tags: { has: query } }, { description: { contains: query, mode: "insensitive" } }], }), // Tag filtering ...(tags && tags.length > 0 && { tags: { hasEvery: tags } }), // Gender ...(gender && { gender: { equals: gender } }), // Profiles ...(userId && { userId }), }; const select: Prisma.MiiSelect = { id: true, // Don't show when userId is specified ...(!userId && { user: { select: { id: true, username: true, }, }, }), name: true, imageCount: true, tags: true, createdAt: true, gender: true, // Mii liked check ...(session?.user?.id && { likedBy: { where: { userId: Number(session.user.id) }, select: { userId: true }, }, }), // Like count _count: { select: { likedBy: true }, }, }; const skip = (page - 1) * limit; let totalCount: number; let filteredCount: number; let list: Prisma.MiiGetPayload<{ select: typeof select }>[]; if (sort === "random") { // Use seed for consistent random results const randomSeed = seed || crypto.randomInt(0, 1_000_000_000); // Get all IDs that match the where conditions const matchingIds = await prisma.mii.findMany({ where, select: { id: true }, }); totalCount = matchingIds.length; filteredCount = Math.min(matchingIds.length, limit); if (matchingIds.length === 0) return; const rng = seedrandom(randomSeed.toString()); // Randomize all IDs using the Durstenfeld algorithm for (let i = matchingIds.length - 1; i > 0; i--) { const j = Math.floor(rng() * (i + 1)); [matchingIds[i], matchingIds[j]] = [matchingIds[j], matchingIds[i]]; } // Convert to number[] array const selectedIds = matchingIds.slice(0, limit).map((i) => i.id); list = await prisma.mii.findMany({ where: { id: { in: selectedIds }, }, select, }); } else { // Sorting by likes, newest, or oldest let orderBy: Prisma.MiiOrderByWithRelationInput[]; if (sort === "likes") { orderBy = [{ likedBy: { _count: "desc" } }, { name: "asc" }]; } else if (sort === "oldest") { orderBy = [{ createdAt: "asc" }, { name: "asc" }]; } else { // default to newest orderBy = [{ createdAt: "desc" }, { name: "asc" }]; } [totalCount, filteredCount, list] = await Promise.all([ prisma.mii.count({ where: { ...where, userId } }), prisma.mii.count({ where, skip, take: limit }), prisma.mii.findMany({ where, orderBy, select, skip: (page - 1) * limit, take: limit }), ]); } const lastPage = Math.ceil(totalCount / limit); const miis = list.map(({ _count, likedBy, ...rest }) => ({ ...rest, likes: _count.likedBy, isLiked: session?.user?.id ? likedBy.length > 0 : false, })); return (
{totalCount == filteredCount ? ( <> {totalCount} {totalCount === 1 ? "Mii" : "Miis"} ) : ( <> {filteredCount} of {totalCount} Miis )}
{miis.map((mii) => (
`/mii/${mii.id}/image?type=image${index}`), ]} />
{mii.name}
{mii.tags.map((tag) => ( {tag} ))}
{!userId && ( @{mii.user?.username} )} {userId && Number(session?.user.id) == userId && (
)}
))}
); }