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 && (
-
-
-
- Rank |
- Profile |
- Performance Points |
- Total Plays |
- Total Ranked Plays |
- Avg Ranked Accuracy |
-
-
-
- {players.map((player) => (
-
-
-
- ))}
-
-
+
+
+ {country && (
+
)}
+
+ You are viewing{" "}
+ {country
+ ? "scores from " + normalizedRegionName(country.toUpperCase())
+ : "Global scores"}
+
+
+
+
+
+
+
+ Rank |
+ Profile |
+ Performance Points |
+ Total Plays |
+ Total Ranked Plays |
+ Avg Ranked Accuracy |
+
+
+
+ {players.map((player) => (
+
+
+
+ ))}
+
+
+ {/*
{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 && (
-