Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion js/src/app/_component/MiniLeaderboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useCurrentLeaderboardUsersQuery } from "@/lib/api/queries/leaderboard";
import { Tag } from "@/lib/api/types/autogen/schema";
import { tagFF } from "@/lib/ff";
import getOrdinal from "@/lib/helper/ordinal";
import { useLeaderboardSubmissionsUrl } from "@/lib/hooks/useLeaderboardSubmissionsUrl";
import { theme } from "@/lib/theme";
import {
Button,
Expand All @@ -26,6 +27,9 @@ export default function MiniLeaderboardDesktop() {
const { data, status, filters, toggleFilter, isPlaceholderData } =
useCurrentLeaderboardUsersQuery({ pageSize: 5, tieToUrl: false });

const { getUserSubmissionsUrl, startDate, endDate } =
useLeaderboardSubmissionsUrl();

if (status === "pending") {
return <MiniLeaderboardSkeleton />;
}
Expand Down Expand Up @@ -85,6 +89,8 @@ export default function MiniLeaderboardDesktop() {
width={"200px"}
userId={second.id}
isLoading={isPlaceholderData}
startDate={startDate}
endDate={endDate}
/>
)}
{first && (
Expand All @@ -98,6 +104,8 @@ export default function MiniLeaderboardDesktop() {
width={"200px"}
userId={first.id}
isLoading={isPlaceholderData}
startDate={startDate}
endDate={endDate}
/>
)}
{third && (
Expand All @@ -111,6 +119,8 @@ export default function MiniLeaderboardDesktop() {
width={"200px"}
userId={third.id}
isLoading={isPlaceholderData}
startDate={startDate}
endDate={endDate}
/>
)}
</Flex>
Expand All @@ -122,7 +132,7 @@ export default function MiniLeaderboardDesktop() {
<Card
key={entry.id}
component={Link}
to={`/user/${entry.id}`}
to={getUserSubmissionsUrl(entry.id)}
withBorder
radius="md"
padding="lg"
Expand Down
12 changes: 11 additions & 1 deletion js/src/app/_component/MiniLeaderboardMobile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Toast from "@/components/ui/toast/Toast";
import { useCurrentLeaderboardUsersQuery } from "@/lib/api/queries/leaderboard";
import { Tag } from "@/lib/api/types/autogen/schema";
import getOrdinal from "@/lib/helper/ordinal";
import { useLeaderboardSubmissionsUrl } from "@/lib/hooks/useLeaderboardSubmissionsUrl";
import { theme } from "@/lib/theme";
import {
Button,
Expand All @@ -23,6 +24,9 @@ export default function MiniLeaderboardMobile() {
const { data, status, filters, toggleFilter, isPlaceholderData } =
useCurrentLeaderboardUsersQuery({ pageSize: 5, tieToUrl: false });

const { getUserSubmissionsUrl, startDate, endDate } =
useLeaderboardSubmissionsUrl();

if (status === "pending") {
return <MiniLeaderboardMobileSkeleton />;
}
Expand Down Expand Up @@ -83,6 +87,8 @@ export default function MiniLeaderboardMobile() {
width={"300px"}
userId={first.id}
isLoading={isPlaceholderData}
startDate={startDate}
endDate={endDate}
/>
)}
{second && (
Expand All @@ -96,6 +102,8 @@ export default function MiniLeaderboardMobile() {
width={"300px"}
userId={second.id}
isLoading={isPlaceholderData}
startDate={startDate}
endDate={endDate}
/>
)}
{third && (
Expand All @@ -109,6 +117,8 @@ export default function MiniLeaderboardMobile() {
width={"300px"}
userId={third.id}
isLoading={isPlaceholderData}
startDate={startDate}
endDate={endDate}
/>
)}
</Flex>
Expand All @@ -120,7 +130,7 @@ export default function MiniLeaderboardMobile() {
<Card
key={entry.id}
component={Link}
to={`/user/${entry.id}`}
to={getUserSubmissionsUrl(entry.id)}
withBorder
radius="md"
padding="lg"
Expand Down
16 changes: 12 additions & 4 deletions js/src/app/leaderboard/_components/Leaderboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { ApiUtils } from "@/lib/api/utils";
import { schoolFF, tagFF } from "@/lib/ff";
import getOrdinal from "@/lib/helper/ordinal";
import { useLeaderboardSubmissionsUrl } from "@/lib/hooks/useLeaderboardSubmissionsUrl";
import { theme } from "@/lib/theme";
import {
Box,
Expand Down Expand Up @@ -64,9 +65,10 @@ function LeaderboardIndex({
globalIndex,
toggleGlobalIndex,
isPlaceholderData,
isAnyFilterEnabled,
onFilterReset,
} = query;
} = useCurrentLeaderboardUsersQuery();

const { getUserSubmissionsUrl, startDate, endDate } =
useLeaderboardSubmissionsUrl();

if (status === "pending") {
return <LeaderboardSkeleton />;
Expand Down Expand Up @@ -120,6 +122,8 @@ function LeaderboardIndex({
userId={second.id}
tags={second.tags}
isLoading={isPlaceholderData}
startDate={startDate}
endDate={endDate}
/>
)}
{page === 1 && first && !debouncedQuery && (
Expand All @@ -134,6 +138,8 @@ function LeaderboardIndex({
userId={first.id}
tags={first.tags}
isLoading={isPlaceholderData}
startDate={startDate}
endDate={endDate}
/>
)}
{page === 1 && third && !debouncedQuery && (
Expand All @@ -148,6 +154,8 @@ function LeaderboardIndex({
userId={third.id}
tags={third.tags}
isLoading={isPlaceholderData}
startDate={startDate}
endDate={endDate}
/>
)}
</Flex>
Expand Down Expand Up @@ -222,7 +230,7 @@ function LeaderboardIndex({
<PossibleTooltip key={entry.id}>
<Card
component={Link}
to={isPrevious ? "#" : `/user/${entry.id}`}
to={isPrevious ? "#" : getUserSubmissionsUrl(entry.id)}
shadow="sm"
padding="lg"
radius="md"
Expand Down
18 changes: 17 additions & 1 deletion js/src/components/ui/LeaderboardCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export default function LeaderboardCard({
tags,
isLoading = false,
embedded = false,
startDate,
endDate,
}: {
placeString: OrdinalString;
sizeOrder: 1 | 2 | 3;
Expand All @@ -41,6 +43,8 @@ export default function LeaderboardCard({
tags?: UserTag[];
isLoading?: boolean;
embedded?: boolean;
startDate?: string;
endDate?: string;
}) {
const isTopThree = sizeOrder <= 3;
const borderColor = (() => {
Expand Down Expand Up @@ -72,6 +76,18 @@ export default function LeaderboardCard({
})();
const displayTags = tags?.slice(0, 3);

const getUserSubmissionsUrl = () => {
const params = new URLSearchParams();
if (startDate) {
params.set("startDate", startDate);
}
if (endDate) {
params.set("endDate", endDate);
}
const queryString = params.toString();
return `/user/${userId}/submissions${queryString ? `?${queryString}` : ""}`;
};

return (
<Card
withBorder
Expand All @@ -85,7 +101,7 @@ export default function LeaderboardCard({
boxShadow,
}}
component={Link}
to={`/user/${userId}`}
to={getUserSubmissionsUrl()}
reloadDocument={embedded}
target={embedded ? "_blank" : undefined}
rel={embedded ? "noopener noreferrer" : undefined}
Expand Down
76 changes: 76 additions & 0 deletions js/src/lib/hooks/useLeaderboardSubmissionsUrl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import {
useCurrentLeaderboardMetadataQuery,
useLeaderboardMetadataByIdQuery,
} from "@/lib/api/queries/leaderboard";
import { useCallback } from "react";

/**
* React hook that provides a function to generate user submissions URLs
* with leaderboard date range parameters.
*
* @param {Object} options - Configuration options for the hook.
* @param {string} options.leaderboardId - (Optional) The leaderboard ID to fetch metadata for.
* If not provided, uses the current active leaderboard.
*
* @returns An object containing:
* - `getUserSubmissionsUrl`: a function that takes a userId and returns the submissions URL with date params
* - `startDate`: the leaderboard start date (createdAt), or undefined if not loaded
* - `endDate`: the leaderboard end date (shouldExpireBy), or undefined if not loaded
*
* @example
* ```tsx
* // For current leaderboard
* const { getUserSubmissionsUrl, startDate, endDate } = useLeaderboardSubmissionsUrl();
*
* // For specific leaderboard
* const { getUserSubmissionsUrl, startDate, endDate } = useLeaderboardSubmissionsUrl({
* leaderboardId: "some-id"
* });
*
* return (
* <Link to={getUserSubmissionsUrl(userId)}>View Submissions</Link>
* );
* ```
*/
export function useLeaderboardSubmissionsUrl(
options: { leaderboardId?: string } = {},
) {
const { leaderboardId } = options;

const currentLeaderboardQuery = useCurrentLeaderboardMetadataQuery();
const leaderboardByIdQuery = useLeaderboardMetadataByIdQuery(
leaderboardId ?? "",
);

const metadataData = leaderboardId
? leaderboardByIdQuery.data
: currentLeaderboardQuery.data;

const startDate =
metadataData?.success ? metadataData.payload.createdAt : undefined;
const endDate =
metadataData?.success
? (metadataData.payload.shouldExpireBy ?? undefined)
: undefined;

const getUserSubmissionsUrl = useCallback(
(userId: string) => {
const params = new URLSearchParams();
if (startDate) {
params.set("startDate", startDate);
}
if (endDate) {
params.set("endDate", endDate);
}
const queryString = params.toString();
return `/user/${userId}/submissions${queryString ? `?${queryString}` : ""}`;
},
[startDate, endDate],
);

return {
getUserSubmissionsUrl,
startDate,
endDate,
};
}
Loading