From 61088950d90589edc8362cb0817173ff0f7bb7a9 Mon Sep 17 00:00:00 2001 From: trafficlunar Date: Sun, 30 Mar 2025 18:41:59 +0100 Subject: [PATCH] feat: profile pages --- src/app/components/mii-list.tsx | 133 ++++++++++++++++++++++++ src/app/components/profile-overview.tsx | 5 +- src/app/page.tsx | 111 ++------------------ src/app/profile/[slug]/page.tsx | 48 +++++++++ 4 files changed, 194 insertions(+), 103 deletions(-) create mode 100644 src/app/components/mii-list.tsx create mode 100644 src/app/profile/[slug]/page.tsx diff --git a/src/app/components/mii-list.tsx b/src/app/components/mii-list.tsx new file mode 100644 index 0000000..d801f39 --- /dev/null +++ b/src/app/components/mii-list.tsx @@ -0,0 +1,133 @@ +import { Prisma } from "@prisma/client"; + +import { auth } from "@/lib/auth"; +import { prisma } from "@/lib/prisma"; + +import LikeButton from "./like-button"; +import Link from "next/link"; + +interface Props { + searchParams: Promise<{ [key: string]: string | string[] | undefined }>; + userId?: number; +} + +export default async function MiiList({ searchParams, userId }: Props) { + const session = await auth(); + const resolvedSearchParams = await searchParams; + + // sort search param + const orderBy: { createdAt?: Prisma.SortOrder; likes?: Prisma.SortOrder } = {}; + + if (resolvedSearchParams.sort === "newest") { + orderBy.createdAt = "desc"; + } else if (resolvedSearchParams.sort === "likes") { + orderBy.likes = "desc"; + } else { + orderBy.createdAt = "desc"; // Default to newest if no valid sort is provided + } + + // tag search param + const rawTags = resolvedSearchParams.tags; + const tagFilter = + typeof rawTags === "string" + ? rawTags + .split(",") + .map((tag) => tag.trim()) + .filter((tag) => tag.length > 0) + : []; + const whereTags = tagFilter.length > 0 ? { tags: { hasSome: tagFilter } } : undefined; + + // If the mii list is on a user's profile, don't query for the username + const include = + userId == null + ? { + user: { + select: { + id: true, + username: true, + }, + }, + } + : {}; + + const totalMiiCount = await prisma.mii.count({ where: { userId } }); + const shownMiiCount = await prisma.mii.count({ + where: { + ...whereTags, + userId, + }, + }); + const miis = await prisma.mii.findMany({ + where: { + ...whereTags, + userId, + }, + orderBy, + include, + }); + + return ( +
+
+

+ {totalMiiCount == shownMiiCount ? ( + <> + {totalMiiCount} Miis + + ) : ( + <> + {shownMiiCount} of {totalMiiCount} Miis + + )} +

+ +
+ {/* todo: replace with react-select */} +
+ + todo +
+ +
+ + +
+
+
+ +
+ {miis.map((mii) => ( +
+ mii +
+

+ {mii.name} +

+
+ {mii.tags.map((tag) => ( + {tag} + ))} +
+ +
+ + + {userId == null && ( + + @{mii.user?.username} + + )} +
+
+
+ ))} +
+
+ ); +} diff --git a/src/app/components/profile-overview.tsx b/src/app/components/profile-overview.tsx index 97b42a2..c43f758 100644 --- a/src/app/components/profile-overview.tsx +++ b/src/app/components/profile-overview.tsx @@ -1,12 +1,13 @@ import Image from "next/image"; import { auth } from "@/lib/auth"; +import Link from "next/link"; export default async function ProfileOverview() { const session = await auth(); return (
  • - +
  • ); } diff --git a/src/app/page.tsx b/src/app/page.tsx index 69842a4..a580911 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,113 +1,22 @@ import { redirect } from "next/navigation"; -import { Prisma } from "@prisma/client"; - import { auth } from "@/lib/auth"; -import { prisma } from "@/lib/prisma"; - -import LikeButton from "./components/like-button"; +import MiiList from "./components/mii-list"; export default async function Page({ searchParams }: { searchParams: Promise<{ [key: string]: string | string[] | undefined }> }) { const session = await auth(); - const resolvedSearchParams = await searchParams; - - // sort search param - const orderBy: { createdAt?: Prisma.SortOrder; likes?: Prisma.SortOrder } = {}; - - if (resolvedSearchParams.sort === "newest") { - orderBy.createdAt = "desc"; - } else if (resolvedSearchParams.sort === "likes") { - orderBy.likes = "desc"; - } else { - orderBy.createdAt = "desc"; // Default to newest if no valid sort is provided - } - - // tag search param - const rawTags = resolvedSearchParams.tags; - const tagFilter = - typeof rawTags === "string" - ? rawTags - .split(",") - .map((tag) => tag.trim()) - .filter((tag) => tag.length > 0) - : []; - const where = tagFilter.length > 0 ? { tags: { hasSome: tagFilter } } : undefined; - - const totalMiiCount = await prisma.mii.count(); - const shownMiiCount = await prisma.mii.count({ where }); - const miis = await prisma.mii.findMany({ - where: where, - orderBy, - include: { - user: { - select: { - username: true, - }, - }, - }, - }); if (session?.user && !session.user.username) { redirect("/create-username"); } - return ( -
    -
    -

    - {totalMiiCount == shownMiiCount ? ( - <> - {totalMiiCount} Miis - - ) : ( - <> - {shownMiiCount} of {totalMiiCount} Miis - - )} -

    + // await prisma.mii.create({ + // data: { + // userId: 1, + // name: "Himmel", + // pictures: ["https://placehold.co/600x400", "/missing.webp"], + // tags: ["Anime", "Osaka"], + // }, + // }); -
    - {/* todo: replace with react-select */} -
    - - todo -
    - -
    - - -
    -
    -
    - -
    - {miis.map((mii) => ( -
    - mii -
    -

    - {mii.name} -

    -
    - {mii.tags.map((tag) => ( - {tag} - ))} -
    - -
    - - - @{mii.user?.username} -
    -
    -
    - ))} -
    -
    - ); + return ; } diff --git a/src/app/profile/[slug]/page.tsx b/src/app/profile/[slug]/page.tsx new file mode 100644 index 0000000..5e6fc42 --- /dev/null +++ b/src/app/profile/[slug]/page.tsx @@ -0,0 +1,48 @@ +import Image from "next/image"; +import { prisma } from "@/lib/prisma"; +import MiiList from "@/app/components/mii-list"; + +interface Props { + params: Promise<{ slug: string }>; + searchParams: Promise<{ [key: string]: string | string[] | undefined }>; +} + +export default async function ProfilePage({ params, searchParams }: Props) { + const { slug } = await params; + + const user = await prisma.user.findFirst({ + where: { + id: Number(slug), + }, + }); + + const likedMiis = await prisma.like.count({ where: { userId: Number(slug) } }); + + return ( +
    +
    + profile picture + +
    +

    {user?.name}

    +

    @{user?.username}

    + +

    + Liked {likedMiis} Miis +

    +

    + Created: {user?.createdAt.toLocaleDateString("en-GB", { month: "long", day: "2-digit", year: "numeric" })} +

    +
    +
    + + +
    + ); +}