diff --git a/next.config.js b/next.config.js index 6137917..bdf75d2 100644 --- a/next.config.js +++ b/next.config.js @@ -60,41 +60,41 @@ const nextConfig = { }, }; -module.exports = withBundleAnalyzer(nextConfig); +// module.exports = withBundleAnalyzer(nextConfig); // // Injected content via Sentry wizard below -const { withSentryConfig } = require("@sentry/nextjs"); +// const { withSentryConfig } = require("@sentry/nextjs"); -module.exports = withSentryConfig( - module.exports, - { - // For all available options, see: - // https://github.com/getsentry/sentry-webpack-plugin#options +// module.exports = withSentryConfig( +// module.exports, +// { +// // For all available options, see: +// // https://github.com/getsentry/sentry-webpack-plugin#options - // Suppresses source map uploading logs during build - silent: true, - org: "sentry", - project: "scoresaber-reloaded", - url: "https://sentry.fascinated.cc/", - }, - { - // For all available options, see: - // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/ +// // Suppresses source map uploading logs during build +// silent: true, +// org: "sentry", +// project: "scoresaber-reloaded", +// url: "https://sentry.fascinated.cc/", +// }, +// { +// // For all available options, see: +// // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/ - // Upload a larger set of source maps for prettier stack traces (increases build time) - widenClientFileUpload: false, +// // Upload a larger set of source maps for prettier stack traces (increases build time) +// widenClientFileUpload: false, - // Transpiles SDK to be compatible with IE11 (increases bundle size) - transpileClientSDK: false, +// // Transpiles SDK to be compatible with IE11 (increases bundle size) +// transpileClientSDK: false, - // Routes browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers (increases server load) - tunnelRoute: "/monitoring", +// // Routes browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers (increases server load) +// tunnelRoute: "/monitoring", - // Hides source maps from generated client bundles - hideSourceMaps: true, +// // Hides source maps from generated client bundles +// hideSourceMaps: true, - // Automatically tree-shake Sentry logger statements to reduce bundle size - disableLogger: true, - }, -); +// // Automatically tree-shake Sentry logger statements to reduce bundle size +// disableLogger: true, +// }, +// ); diff --git a/src/app/player/[id]/[sort]/[page]/page.tsx b/src/app/player/[id]/[sort]/[page]/page.tsx index ffc9702..0f374ae 100644 --- a/src/app/player/[id]/[sort]/[page]/page.tsx +++ b/src/app/player/[id]/[sort]/[page]/page.tsx @@ -47,6 +47,24 @@ export async function generateMetadata({ }; } -export default function Player({ params: { id, sort, page } }: Props) { - return ; +/** + * Gets the player's data on the server side. + * + * @param id the player's id + * @returns the player's data + */ +async function getData(id: string) { + const response = await ScoreSaberAPI.fetchPlayerData(id); + return { + data: response, + }; +} + +export default async function Player({ params: { id, sort, page } }: Props) { + const { data } = await getData(id); + if (!data) { + return
Player not found
; + } + + return ; } diff --git a/src/app/ranking/country/[country]/[page]/page.tsx b/src/app/ranking/country/[country]/[page]/page.tsx index ef5dabd..e8b17dd 100644 --- a/src/app/ranking/country/[country]/[page]/page.tsx +++ b/src/app/ranking/country/[country]/[page]/page.tsx @@ -1,4 +1,8 @@ +import Card from "@/components/Card"; +import Container from "@/components/Container"; +import Error from "@/components/Error"; import GlobalRanking from "@/components/GlobalRanking"; +import { ScoreSaberAPI } from "@/utils/scoresaber/api"; import { Metadata } from "next"; export const metadata: Metadata = { @@ -9,6 +13,43 @@ type Props = { params: { page: string; country: string }; }; -export default function RankingGlobal({ params: { page, country } }: Props) { - return ; +async function getData(page: number, country: string) { + const response = await ScoreSaberAPI.fetchTopPlayers(page, country); + return { + data: response, + }; +} + +export default async function RankingGlobal({ + params: { page, country }, +}: Props) { + const { data } = await getData(Number(page), country); + if (!data) { + return ( +
+ + +
+
+
+ +
+
+
+
+
+
+ ); + } + + return ( + + ); } diff --git a/src/app/ranking/global/[page]/page.tsx b/src/app/ranking/global/[page]/page.tsx index 86e7cd1..b7a558f 100644 --- a/src/app/ranking/global/[page]/page.tsx +++ b/src/app/ranking/global/[page]/page.tsx @@ -1,4 +1,8 @@ +import Card from "@/components/Card"; +import Container from "@/components/Container"; +import Error from "@/components/Error"; import GlobalRanking from "@/components/GlobalRanking"; +import { ScoreSaberAPI } from "@/utils/scoresaber/api"; import { Metadata } from "next"; export const metadata: Metadata = { @@ -9,6 +13,40 @@ type Props = { params: { page: string }; }; -export default function RankingGlobal({ params: { page } }: Props) { - return ; +async function getData(page: number) { + const response = await ScoreSaberAPI.fetchTopPlayers(page); + return { + data: response, + }; +} + +export default async function RankingGlobal({ params: { page } }: Props) { + const { data } = await getData(Number(page)); + if (!data) { + return ( +
+ + +
+
+
+ +
+
+
+
+
+
+ ); + } + + return ( + + ); } diff --git a/src/components/GlobalRanking.tsx b/src/components/GlobalRanking.tsx index b09d2a3..86889ac 100644 --- a/src/components/GlobalRanking.tsx +++ b/src/components/GlobalRanking.tsx @@ -1,163 +1,70 @@ "use client"; import { ScoresaberPlayer } from "@/schemas/scoresaber/player"; -import { ScoreSaberAPI } from "@/utils/scoresaber/api"; import { normalizedRegionName } from "@/utils/utils"; -import dynamic from "next/dynamic"; -import Link from "next/link"; -import { useRouter, useSearchParams } from "next/navigation"; -import { useCallback, useEffect, useState } from "react"; import Card from "./Card"; import Container from "./Container"; import CountyFlag from "./CountryFlag"; import Pagination from "./Pagination"; -import Spinner from "./Spinner"; import PlayerRanking from "./player/PlayerRanking"; -import PlayerRankingMobile from "./player/PlayerRankingMobile"; import { Separator } from "./ui/separator"; -const Error = dynamic(() => import("@/components/Error")); - -type PageInfo = { - loading: boolean; - page: number; - totalPages: number; - players: ScoresaberPlayer[]; -}; - type GlobalRankingProps = { - page: number; + players: ScoresaberPlayer[]; country?: string; + pageInfo: { + page: number; + totalPages: number; + }; }; -export default function GlobalRanking({ page, country }: GlobalRankingProps) { - const router = useRouter(); - const searchQuery = useSearchParams(); - const isMobile = searchQuery.get("mobile") == "true"; - - const [error, setError] = useState(false); - const [errorMessage, setErrorMessage] = useState(""); - - const [pageInfo, setPageInfo] = useState({ - loading: true, - page: page, - totalPages: 1, - players: [], - }); - - const updatePage = useCallback( - (page: any) => { - const windowSize = document.documentElement.clientWidth; - if (windowSize < 768 && !isMobile) { - router.push(`/ranking/global/${page}?mobile=true`); - router.refresh(); - return; - } - - console.log("Switching page to", page); - ScoreSaberAPI.fetchTopPlayers(page, country).then((response) => { - if (!response) { - setError(true); - setErrorMessage("No players found"); - setPageInfo({ ...pageInfo, loading: false }); - return; - } - setPageInfo({ - ...pageInfo, - players: response.players, - totalPages: response.pageInfo.totalPages, - loading: false, - page: page, - }); - window.history.pushState( - {}, - "", - country - ? `/ranking/country/${country}/${page}` - : `/ranking/global/${page}`, - ); - }); - }, - [country, isMobile, pageInfo, router], - ); - - useEffect(() => { - if (!pageInfo.loading || error) return; - - updatePage(pageInfo.page); - }, [error, country, updatePage, pageInfo.page, pageInfo.loading]); - - if (pageInfo.loading || error) { - return ( -
- - -
-
-
- {error && } - {!error && } -
-
-
-
-
-
- ); - } - - const players = pageInfo.players; - +export default function GlobalRanking({ + players, + country, + pageInfo, +}: GlobalRankingProps) { return (
- {pageInfo.loading ? ( -
- -
- ) : ( -
-
- {country && ( - - )} -

- You are viewing{" "} - {country - ? "scores from " + - normalizedRegionName(country.toUpperCase()) - : "Global scores"} -

-
- - - - {!isMobile && ( - - - - - - - - - - - - - {players.map((player) => ( - - - - ))} - -
RankProfilePerformance PointsTotal PlaysTotal Ranked PlaysAvg Ranked Accuracy
+
+
+ {country && ( + )} +

+ You are viewing{" "} + {country + ? "scores from " + normalizedRegionName(country.toUpperCase()) + : "Global scores"} +

+
+ + + + + + + + + + + + + + + {players.map((player) => ( + + + + ))} + +
RankProfilePerformance PointsTotal PlaysTotal Ranked PlaysAvg Ranked Accuracy
+ {/* {isMobile && (
{players.map((player) => ( @@ -171,22 +78,18 @@ export default function GlobalRanking({ page, country }: GlobalRankingProps) {
))}
- )} + )} */} - {/* Pagination */} -
-
- { - updatePage(page); - }} - /> -
+ {/* Pagination */} +
+
+
- )} +
diff --git a/src/components/Pagination.tsx b/src/components/Pagination.tsx index 931596c..b0bae6d 100644 --- a/src/components/Pagination.tsx +++ b/src/components/Pagination.tsx @@ -2,15 +2,17 @@ import { ArrowUturnLeftIcon, ArrowUturnRightIcon, } from "@heroicons/react/20/solid"; +import Link from "next/link"; type PaginationProps = { currentPage: number; totalPages: number; - onPageChange: (pageNumber: number) => void; + useHref?: boolean; + onPageChange?: (pageNumber: number) => void; }; export default function Pagination(props: PaginationProps) { - const { currentPage, totalPages, onPageChange } = props; + const { currentPage, totalPages, useHref, onPageChange } = props; // Calculate the range of page numbers to display const rangeStart = Math.max(1, currentPage - 2); @@ -28,26 +30,48 @@ export default function Pagination(props: PaginationProps) {
    {currentPage > 1 && (
  • - + {useHref ? ( + + + + + + ) : ( + + )}
  • )} {currentPage !== 1 && currentPage - 2 > 1 && ( <>
  • - + {useHref ? ( + + + 1 + + + ) : ( + + )}
  • ...

    @@ -57,17 +81,32 @@ export default function Pagination(props: PaginationProps) { {pageNumbers.map((pageNumber) => (
  • - + {useHref ? ( + + + {pageNumber} + + + ) : ( + + )}
  • ))} @@ -78,26 +117,48 @@ export default function Pagination(props: PaginationProps) {
  • - + {useHref ? ( + + + {totalPages} + + + ) : ( + + )}
  • )} {currentPage < totalPages && (
  • - + {useHref ? ( + + + + + + ) : ( + + )}
  • )}
diff --git a/src/components/player/PlayerChart.tsx b/src/components/player/PlayerChart.tsx index cae4771..3177168 100644 --- a/src/components/player/PlayerChart.tsx +++ b/src/components/player/PlayerChart.tsx @@ -1,3 +1,5 @@ +"use client"; + import { ScoresaberPlayer } from "@/schemas/scoresaber/player"; import { formatNumber } from "@/utils/numberUtils"; import { diff --git a/src/components/player/PlayerInfo.tsx b/src/components/player/PlayerInfo.tsx index 2d7a90a..ebbe627 100644 --- a/src/components/player/PlayerInfo.tsx +++ b/src/components/player/PlayerInfo.tsx @@ -1,3 +1,5 @@ +"use client"; + import { ScoresaberPlayer } from "@/schemas/scoresaber/player"; import { useScoresaberScoresStore } from "@/store/scoresaberScoresStore"; import { useSettingsStore } from "@/store/settingsStore"; @@ -11,7 +13,7 @@ import { XMarkIcon, } from "@heroicons/react/20/solid"; import dynamic from "next/dynamic"; -import { useRef } from "react"; +import { useEffect, useRef, useState } from "react"; import { toast } from "react-toastify"; import { useStore } from "zustand"; import Avatar from "../Avatar"; @@ -27,6 +29,7 @@ type PlayerInfoProps = { }; export default function PlayerInfo({ playerData }: PlayerInfoProps) { + const [mounted, setMounted] = useState(false); const playerId = playerData.id; const settingsStore = useStore(useSettingsStore, (store) => store); const playerScoreStore = useStore(useScoresaberScoresStore, (store) => store); @@ -36,6 +39,10 @@ export default function PlayerInfo({ playerData }: PlayerInfoProps) { const toastId: any = useRef(null); + useEffect(() => { + setMounted(true); + }, []); + async function claimProfile() { settingsStore?.setProfile(playerData); addProfile(false); @@ -122,32 +129,36 @@ export default function PlayerInfo({ playerData }: PlayerInfoProps) { {/* Settings Buttons */}
- {!isOwnProfile && ( -