diff --git a/src/app/player/[id]/page.tsx b/src/app/player/[id]/page.tsx index cfa0559..8945c65 100644 --- a/src/app/player/[id]/page.tsx +++ b/src/app/player/[id]/page.tsx @@ -1,102 +1,34 @@ -"use client"; - -import Card from "@/components/Card"; -import Container from "@/components/Container"; -import Error from "@/components/Error"; -import { Spinner } from "@/components/Spinner"; -import PlayerInfo from "@/components/player/PlayerInfo"; -import Scores from "@/components/player/Scores"; -import { ScoresaberPlayer } from "@/schemas/scoresaber/player"; -import { useSettingsStore } from "@/store/settingsStore"; -import { SortType, SortTypes } from "@/types/SortTypes"; +import PlayerPage from "@/components/player/PlayerPage"; import { ScoreSaberAPI } from "@/utils/scoresaber/api"; -import { useSearchParams } from "next/navigation"; -import { useEffect, useState } from "react"; +import { Metadata } from "next"; -type PlayerInfo = { - loading: boolean; - player: ScoresaberPlayer | undefined; +type Props = { + params: { id: string }; }; -const DEFAULT_SORT_TYPE = SortTypes.top; - -export default function Player({ params }: { params: { id: string } }) { - const searchParams = useSearchParams(); - - const [mounted, setMounted] = useState(false); - const [error, setError] = useState(false); - const [errorMessage, setErrorMessage] = useState(""); - - const [player, setPlayer] = useState({ - loading: true, - player: undefined, - }); - - let page; - const pageString = searchParams.get("page"); - if (pageString == null) { - page = 1; - } else { - page = Number.parseInt(pageString) || 1; +export async function generateMetadata({ + params: { id }, +}: Props): Promise { + const player = await ScoreSaberAPI.fetchPlayerData(id); + if (!player) { + return { + title: "Player not found", + }; } - let sortType: SortType; - const sortTypeString = searchParams.get("sort"); - if (sortTypeString == null) { - sortType = - useSettingsStore.getState().lastUsedSortType || DEFAULT_SORT_TYPE; - } else { - sortType = SortTypes[sortTypeString] || DEFAULT_SORT_TYPE; - } - - useEffect(() => { - setMounted(true); - if (error || !player.loading) { - return; - } - - if (mounted == true) { - return; - } - - ScoreSaberAPI.fetchPlayerData(params.id).then((playerResponse) => { - if (!playerResponse) { - setError(true); - setErrorMessage("Failed to fetch player. Is the ID correct?"); - setPlayer({ ...player, loading: false }); - return; - } - setPlayer({ ...player, player: playerResponse, loading: false }); - }); - }, [error, mounted, params.id, player]); - - if (player.loading || error || !player.player) { - return ( -
- - -
-
-
- {error && } - {!error && } -
-
-
-
-
-
- ); - } - - const playerData = player.player; - - return ( -
- - - - -
- ); + return { + title: `${player.name} - Scoresaber Leaderboards`, + description: `View ${player.name}'s scores, top plays, and more., test`, + openGraph: { + images: [ + { + url: player.profilePicture, + }, + ], + }, + }; +} + +export default function Player({ params: { id } }: Props) { + return ; } diff --git a/src/components/player/PlayerPage.tsx b/src/components/player/PlayerPage.tsx new file mode 100644 index 0000000..2c74b89 --- /dev/null +++ b/src/components/player/PlayerPage.tsx @@ -0,0 +1,106 @@ +"use client"; + +import Card from "@/components/Card"; +import Container from "@/components/Container"; +import Error from "@/components/Error"; +import { Spinner } from "@/components/Spinner"; +import PlayerInfo from "@/components/player/PlayerInfo"; +import Scores from "@/components/player/Scores"; +import { ScoresaberPlayer } from "@/schemas/scoresaber/player"; +import { useSettingsStore } from "@/store/settingsStore"; +import { SortType, SortTypes } from "@/types/SortTypes"; +import { ScoreSaberAPI } from "@/utils/scoresaber/api"; +import { useSearchParams } from "next/navigation"; +import { useEffect, useState } from "react"; + +type PlayerInfo = { + loading: boolean; + player: ScoresaberPlayer | undefined; +}; + +type PlayerPageProps = { + id: string; +}; + +const DEFAULT_SORT_TYPE = SortTypes.top; + +export default function PlayerPage({ id }: PlayerPageProps) { + const searchParams = useSearchParams(); + + const [mounted, setMounted] = useState(false); + const [error, setError] = useState(false); + const [errorMessage, setErrorMessage] = useState(""); + + const [player, setPlayer] = useState({ + loading: true, + player: undefined, + }); + + let page; + const pageString = searchParams.get("page"); + if (pageString == null) { + page = 1; + } else { + page = Number.parseInt(pageString) || 1; + } + + let sortType: SortType; + const sortTypeString = searchParams.get("sort"); + if (sortTypeString == null) { + sortType = + useSettingsStore.getState().lastUsedSortType || DEFAULT_SORT_TYPE; + } else { + sortType = SortTypes[sortTypeString] || DEFAULT_SORT_TYPE; + } + + useEffect(() => { + setMounted(true); + if (error || !player.loading) { + return; + } + + if (mounted == true) { + return; + } + + ScoreSaberAPI.fetchPlayerData(id).then((playerResponse) => { + if (!playerResponse) { + setError(true); + setErrorMessage("Failed to fetch player. Is the ID correct?"); + setPlayer({ ...player, loading: false }); + return; + } + setPlayer({ ...player, player: playerResponse, loading: false }); + }); + }, [error, mounted, id, player]); + + if (player.loading || error || !player.player) { + return ( +
+ + +
+
+
+ {error && } + {!error && } +
+
+
+
+
+
+ ); + } + + const playerData = player.player; + + return ( +
+ + + + +
+ ); +}