From fbeefbc3c42a8bded24d6ff45f5cb0f8752ef86d Mon Sep 17 00:00:00 2001 From: Nathaniel Tampus Date: Fri, 7 Apr 2023 14:20:13 +0800 Subject: [PATCH] add user profile page --- client/src/app/user/[name]/not-found.tsx | 8 ++ client/src/app/user/[name]/page.tsx | 158 +++++++++++++++++++++++ client/src/components/user/CopyLink.tsx | 37 ++++++ 3 files changed, 203 insertions(+) create mode 100644 client/src/app/user/[name]/not-found.tsx create mode 100644 client/src/app/user/[name]/page.tsx create mode 100644 client/src/components/user/CopyLink.tsx diff --git a/client/src/app/user/[name]/not-found.tsx b/client/src/app/user/[name]/not-found.tsx new file mode 100644 index 0000000..e967d00 --- /dev/null +++ b/client/src/app/user/[name]/not-found.tsx @@ -0,0 +1,8 @@ +export default function NotFound() { + return ( +
+
Error 404
+
User not found
+
+ ); +} diff --git a/client/src/app/user/[name]/page.tsx b/client/src/app/user/[name]/page.tsx new file mode 100644 index 0000000..7a768b5 --- /dev/null +++ b/client/src/app/user/[name]/page.tsx @@ -0,0 +1,158 @@ +import CopyLink from "@/components/user/CopyLink"; +import { fetchProfileData } from "@/lib/user"; +import { notFound } from "next/navigation"; + +export async function generateMetadata({ params }: { params: { name: string } }) { + const data = await fetchProfileData(params.name); + if (!data) { + return { + description: "User not found", + robots: { + index: false, + follow: false, + nocache: true, + noarchive: true + } + }; + } + return { + title: `${data.name} | chessu`, + description: `${data.name}'s profile`, + openGraph: { + title: `${data.name} | chessu`, + description: `${data.name}'s profile on chessu`, + url: `https://ches.su/user/${data.name}`, + siteName: "chessu", + locale: "en_US", + type: "website" + }, + robots: { + index: true, + follow: false, + nocache: true + } + }; +} + +export default async function Profile({ params }: { params: { name: string } }) { + const data = await fetchProfileData(params.name); + if (!data) { + notFound(); + } + + return ( +
+
+

{data.name}

+
+
+ Wins + {data.wins} +
+
+ Draws + {data.draws} +
+
+ Losses + {data.losses} +
+
+ +
+ +
+

Recent games

+
    + {data.recentGames.map((game) => ( +
  • +
    +
    + + White + {game.winner === "white" && ( + winner + )} + + + {game.white?.name} + +
    +
    + + {game.winner === "black" && ( + winner + )} + Black + + + {game.black?.name} + +
    +
    + +
    {game.endReason}
    + +
    + + Started + + {" "} + {new Date(game.startedAt as number).toLocaleString()} + + + + Ended + + {" "} + {new Date(game.endedAt as number).toLocaleString()} + + +
    + + + Review game + +
  • + ))} +
+
+
+ ); +} diff --git a/client/src/components/user/CopyLink.tsx b/client/src/components/user/CopyLink.tsx new file mode 100644 index 0000000..e47521d --- /dev/null +++ b/client/src/components/user/CopyLink.tsx @@ -0,0 +1,37 @@ +"use client"; + +import { useState } from "react"; +import { IconCopy } from "@tabler/icons-react"; + +export default function CopyLink({ name }: { name: string }) { + const [copiedLink, setCopiedLink] = useState(false); + + function copyLink() { + const text = `https://ches.su/user/${name}`; + + if ("clipboard" in navigator) { + navigator.clipboard.writeText(text); + } else { + document.execCommand("copy", true, text); + } + setCopiedLink(true); + setTimeout(() => { + setCopiedLink(false); + }, 5000); + } + return ( +
+ +
+ copied to clipboard +
+
+ ); +}