diff --git a/src/components/input/pagination.tsx b/src/components/input/pagination.tsx
index f03f400..e8c43b2 100644
--- a/src/components/input/pagination.tsx
+++ b/src/components/input/pagination.tsx
@@ -60,9 +60,21 @@ type Props = {
* Callback function that is called when the user clicks on a page number.
*/
onPageChange: (page: number) => void;
+
+ /**
+ * Optional callback to generate the URL for each page.
+ */
+ generatePageUrl?: (page: number) => string;
};
-export default function Pagination({ mobilePagination, page, totalPages, loadingPage, onPageChange }: Props) {
+export default function Pagination({
+ mobilePagination,
+ page,
+ totalPages,
+ loadingPage,
+ onPageChange,
+ generatePageUrl,
+}: Props) {
totalPages = Math.round(totalPages);
const isLoading = loadingPage !== undefined;
const [currentPage, setCurrentPage] = useState(page);
@@ -72,7 +84,7 @@ export default function Pagination({ mobilePagination, page, totalPages, loading
}, [page]);
const handlePageChange = (newPage: number) => {
- if (newPage < 1 || newPage > totalPages || newPage == currentPage || isLoading) {
+ if (newPage < 1 || newPage > totalPages || newPage === currentPage || isLoading) {
return;
}
@@ -80,6 +92,11 @@ export default function Pagination({ mobilePagination, page, totalPages, loading
onPageChange(newPage);
};
+ const handleLinkClick = (newPage: number, event: React.MouseEvent) => {
+ event.preventDefault(); // Prevent default navigation behavior
+ handlePageChange(newPage);
+ };
+
const renderPageNumbers = () => {
const pageNumbers = [];
const maxPagesToShow = mobilePagination ? 3 : 4;
@@ -95,7 +112,9 @@ export default function Pagination({ mobilePagination, page, totalPages, loading
pageNumbers.push(
<>
- handlePageChange(1)}>1
+ handleLinkClick(1, e)}>
+ 1
+
{/* Only show ellipsis if more than 2 pages from the start */}
{startPage > 2 && (
@@ -111,7 +130,11 @@ export default function Pagination({ mobilePagination, page, totalPages, loading
for (let i = startPage; i <= endPage; i++) {
pageNumbers.push(
- handlePageChange(i)}>
+ handleLinkClick(i, e)}
+ >
{loadingPage === i ? : i}
@@ -126,7 +149,10 @@ export default function Pagination({ mobilePagination, page, totalPages, loading
{/* Previous button for mobile and desktop */}
- handlePageChange(currentPage - 1)} />
+ handleLinkClick(currentPage - 1, e)}
+ />
{renderPageNumbers()}
@@ -138,14 +164,22 @@ export default function Pagination({ mobilePagination, page, totalPages, loading
- handlePageChange(totalPages)}>{totalPages}
+ handleLinkClick(totalPages, e)}
+ >
+ {totalPages}
+
>
)}
{/* Next button for mobile and desktop */}
- handlePageChange(currentPage + 1)} />
+ handleLinkClick(currentPage + 1, e)}
+ />
diff --git a/src/components/leaderboard/leaderboard-scores.tsx b/src/components/leaderboard/leaderboard-scores.tsx
index 7dfdab7..e3f393c 100644
--- a/src/components/leaderboard/leaderboard-scores.tsx
+++ b/src/components/leaderboard/leaderboard-scores.tsx
@@ -109,9 +109,6 @@ export default function LeaderboardScores({
if (leaderboardChanged) {
leaderboardChanged(id);
}
-
- // Update the URL
- window.history.replaceState(null, "", `/leaderboard/${id}`);
},
[leaderboardChanged]
);
@@ -139,6 +136,11 @@ export default function LeaderboardScores({
}
}, [currentPage, topOfScoresRef, shouldFetch]);
+ useEffect(() => {
+ // Update the URL
+ window.history.replaceState(null, "", `/leaderboard/${selectedLeaderboardId}/${currentPage}`);
+ }, [selectedLeaderboardId, currentPage]);
+
if (currentScores === undefined) {
return undefined;
}
@@ -194,6 +196,9 @@ export default function LeaderboardScores({
page={currentPage}
totalPages={Math.ceil(currentScores.metadata.total / currentScores.metadata.itemsPerPage)}
loadingPage={isLoading ? currentPage : undefined}
+ generatePageUrl={page => {
+ return `/leaderboard/${selectedLeaderboardId}/${page}`;
+ }}
onPageChange={newPage => {
setCurrentPage(newPage);
setPreviousPage(currentPage);
diff --git a/src/components/player/player-scores.tsx b/src/components/player/player-scores.tsx
index d4542de..34b881d 100644
--- a/src/components/player/player-scores.tsx
+++ b/src/components/player/player-scores.tsx
@@ -123,12 +123,19 @@ export default function PlayerScores({ initialScoreData, initialSearch, player,
if (scores) handleScoreAnimation();
}, [scores, handleScoreAnimation]);
+ /**
+ * Gets the URL to the page.
+ */
+ const getUrl = (page: number) => {
+ return `/player/${player.id}/${pageState.sort}/${page}${isSearchActive ? `?search=${debouncedSearchTerm}` : ""}`;
+ };
+
/**
* Handle updating the URL when the page number,
* sort, or search term changes.
*/
useEffect(() => {
- const newUrl = `/player/${player.id}/${pageState.sort}/${pageState.page}${isSearchActive ? `?search=${debouncedSearchTerm}` : ""}`;
+ const newUrl = getUrl(pageState.page);
window.history.replaceState({ ...window.history.state, as: newUrl, url: newUrl }, "", newUrl);
}, [pageState, debouncedSearchTerm, player.id, isSearchActive]);
@@ -215,6 +222,9 @@ export default function PlayerScores({ initialScoreData, initialSearch, player,
page={pageState.page}
totalPages={Math.ceil(currentScores.metadata.total / currentScores.metadata.itemsPerPage)}
loadingPage={isLoading ? pageState.page : undefined}
+ generatePageUrl={page => {
+ return getUrl(page);
+ }}
onPageChange={newPage => {
setPreviousPage(pageState.page);
setPageState({ ...pageState, page: newPage });