From c3822ece9021878e8ebc5d9bcd24874d3256f67e Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Thu, 4 Jan 2024 17:25:54 -0700
Subject: [PATCH 01/60] chore(components:error): add `Error` component
## what
- add `Error` component
## how
- takes in two props
- status: http status code
- message (optional): message to display under the status code
## why
- this will be displayed in a page if there's an error returned when
fetching the api server
- using `nextjs` app router `error.tsx` doesn't help
- ex: if there's an 404 error, the `error` page rendered, not
`not-found.tsx`
- ex: if there's an 400 errror, the `error` page is rendered but the
error is unhandled
## where
## usage
---
src/components/error.tsx | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 src/components/error.tsx
diff --git a/src/components/error.tsx b/src/components/error.tsx
new file mode 100644
index 0000000..e0e66fc
--- /dev/null
+++ b/src/components/error.tsx
@@ -0,0 +1,18 @@
+type Props = {
+ status: number;
+ message?: string;
+}
+
+const Error = ({status, message}: Props) => {
+ return (
+
+
{status}
+ {message && (
+
{message}
+ )}
+
+ )
+}
+
+export default Error
+
From 1861c46053882cc114a94cf170cc8486a34c0ef3 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Thu, 4 Jan 2024 17:34:31 -0700
Subject: [PATCH 02/60] refactor: move schema validation for endpoint
`/api/problems/[problemNum]` to it's own file
## what
- move schema validation for endpoint `/api/problems/[problemNum]` to it's own file
- add schema in `/api/problems/[problemNum]` via import
## how
## why
- the schema validation will also be used in the client side
- used in `/problems[problemNum]`
## where
- ./src/app/api/problems/[problemNum]/route.ts
- ./src/schema/index.ts
## usage
---
src/app/api/problems/[problemNum]/route.ts | 10 ++--------
src/schema/index.ts | 10 ++++++++++
2 files changed, 12 insertions(+), 8 deletions(-)
create mode 100644 src/schema/index.ts
diff --git a/src/app/api/problems/[problemNum]/route.ts b/src/app/api/problems/[problemNum]/route.ts
index ebd4d4b..48582f4 100644
--- a/src/app/api/problems/[problemNum]/route.ts
+++ b/src/app/api/problems/[problemNum]/route.ts
@@ -3,19 +3,13 @@ import { z } from "zod";
import { uhuntProblemNumUrl } from "@/utils/constants";
import { Problem, ProblemStatus } from "@/types";
+import { problemNumSchema as schema } from "@/schema";
type getParamsType = {
- params: {
- problemNum: string;
- };
+ params: z.infer;
};
export const GET = async (_request: Request, { params }: getParamsType) => {
- const schema = z.object({
- problemNum: z.coerce
- .number({ invalid_type_error: "Must be a number" })
- .min(1, "Must be a number greater than 0"),
- });
const schemaResponse = await schema.safeParseAsync(params);
if (!schemaResponse.success) {
diff --git a/src/schema/index.ts b/src/schema/index.ts
new file mode 100644
index 0000000..1113fbc
--- /dev/null
+++ b/src/schema/index.ts
@@ -0,0 +1,10 @@
+import { z } from "zod";
+
+/**
+ * Schema validation for endpoint `/api/problems/[problemNum]`
+ */
+export const problemNumSchema = z.object({
+ problemNum: z.coerce
+ .number({ invalid_type_error: "Problem number must be a number" })
+ .min(1, "Problem number must be a number greater than 0"),
+});
From 5d0a953b9b94bb3ecbc30317d8baa63af1eade5f Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Thu, 4 Jan 2024 17:38:50 -0700
Subject: [PATCH 03/60] chore(hooks): add react-query hook to fetch stats of
problem number
## what
- add react-query hook to fetch stats of problem number
## how
- fetch from api endpoint `/api/problems/[problemNum]`
## why
## where
- ./src/hooks/index.ts
## usage
---
src/hooks/index.ts | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
index 4502133..02649b1 100644
--- a/src/hooks/index.ts
+++ b/src/hooks/index.ts
@@ -12,6 +12,10 @@ export enum queryKey {
* Reacy query key for fetching all problems
*/
allProblems = "all-problems",
+ /**
+ * React query key for fetching a problem num
+ */
+ problemNum = "problem-num"
}
/**
@@ -44,3 +48,12 @@ export const useFetchProblems = () => {
});
};
+/**
+ * Fetch stats of a problem using problem number
+ */
+export const useFetchProblemNum = (problemNum: number) => {
+ return useQuery({
+ queryKey: [queryKey.problemNum],
+ queryFn: async () => await axios.get(`/api/problems/${problemNum}`),
+ })
+}
From 9aa19d22bb437f16cf21b0a3ed94415dc913b151 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Thu, 4 Jan 2024 17:40:47 -0700
Subject: [PATCH 04/60] chore(api:problemNum): return status 404 if problem
number is not found
## what
- return status 404 if problem number is not found
## how
## why
- this will ensure a problem number not found will be handled
## where
- ./src/app/api/problems/[problemNum]/route.ts
## usage
---
src/app/api/problems/[problemNum]/route.ts | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/src/app/api/problems/[problemNum]/route.ts b/src/app/api/problems/[problemNum]/route.ts
index 48582f4..fc3ce22 100644
--- a/src/app/api/problems/[problemNum]/route.ts
+++ b/src/app/api/problems/[problemNum]/route.ts
@@ -28,7 +28,17 @@ export const GET = async (_request: Request, { params }: getParamsType) => {
const response = await fetch(url);
const data: Problem = await response.json();
- data.status = ProblemStatus[data.status as unknown as number]
+
+ if(Object.entries(data).length === 0) {
+ const message = {
+ message: `Problem number ${problemNum} not found`
+ }
+ return NextResponse.json(message, {
+ status: 404,
+ });
+ }
+
+ data.status = ProblemStatus[data.status]
return Response.json(data);
};
From 84940658ec27ab4decdd537332733c48492248b9 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Thu, 4 Jan 2024 17:48:28 -0700
Subject: [PATCH 05/60] refactor(utils:constants): add type `number` to uhunt
urls
## what
- add type `number` to uhunt urls
## how
## why
- it's a little tedious to convert number to a string when using the
function
## where
- ./src/utils/constants.ts
## usage
---
src/utils/constants.ts | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index 618f01b..041e5e1 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -15,9 +15,9 @@ export const viewProblemUrl =
/**
* URL for viewing the details of the problem PDF using problem ID
- * @param {String} pid problem ID
+ * @param {String | Number} pid problem ID
*/
-export const uhuntViewProblemUrl = (pid: string) => `${viewProblemUrl}${pid}`;
+export const uhuntViewProblemUrl = (pid: string | number) => `${viewProblemUrl}${pid}`;
/**
* URL for fetching all problems on uva-uhunt
@@ -26,25 +26,25 @@ export const uhuntAllProblemsUrl = () => 'https://uhunt.onlinejudge.org/api/p';
/**
* URL for getting Problem data using Problem ID
- * @param {String} pid - problem ID
+ * @param {String | Number} pid - problem ID
*/
-export const uhuntProblemIdUrl = (pid: string) =>
+export const uhuntProblemIdUrl = (pid: string | number) =>
`${uhuntBaseApiUrl}/p/id/${pid}`;
/**
* URL for getting Problem data using Problem number
- * @param {String} problemNumber - problem number
+ * @param {String | Number} problemNumber - problem number
*/
-export const uhuntProblemNumUrl = (problemNumber: string) =>
+export const uhuntProblemNumUrl = (problemNumber: string | number) =>
`${uhuntBaseApiUrl}/p/num/${problemNumber}`;
/**
* URL for getting Problem ranklist using Problem ID, starting rank and number of ranks to return
- * @param {String} pid - Problem ID
+ * @param {String | Number} pid - Problem ID
* @param {Number} [start=1] - rank to start from. Default is 1
* @param {Number} [count=100] - rank to go up to. Default is 100
*/
-export const uhuntProblemRankUrl = (pid: string, start = 1, count = 100) =>
+export const uhuntProblemRankUrl = (pid: string | number, start = 1, count = 100) =>
`${uhuntBaseApiUrl}/p/rank/${pid}/${start}/${count}`;
/**
@@ -53,13 +53,13 @@ export const uhuntProblemRankUrl = (pid: string, start = 1, count = 100) =>
* represented in 20 array elements, each element represents 12 months.
* The submissionTime represents at what time should look back from,
* could be start from 5 years ago or now.
- * @param {String} pid - problem ID
+ * @param {String | Number} pid - problem ID
* @param {Number} [submissionTime=moment().unix()] - Unix timestamp. Default is current unix timestamp
* @param {Number} [back=20] - Number of years to look back. Default is 20
* @param {Number} [jump=12] - Number of months each array element will represent. Default is 12
*/
export const uhuntSubmissionCountUrl = (
- pid: string,
+ pid: string | number,
submissionTime = moment().unix(),
back = 20,
jump = 12,
@@ -74,16 +74,16 @@ export const uhuntUsername2UidUrl = (username: string) =>
/**
* URL for getting Submission list of a problem using Problem ID
- * @param {String} pid - problem ID
+ * @param {String | Number} pid - problem ID
*/
-export const uhuntProblemSubmissionListUrl = (pid: string) =>
+export const uhuntProblemSubmissionListUrl = (pid: string | number) =>
`${uhuntBaseApiUrl}/p/subs/${pid}/0/${moment().unix()}`;
/**
* Get User submissions using UserID
- * @param {Number} uid User ID
+ * @param {String | Number} uid User ID
*/
-export const uhuntUserSubmissionsUrl = (uid: string) =>
+export const uhuntUserSubmissionsUrl = (uid: string | number) =>
`${uhuntBaseApiUrl}/subs-user/${uid}`;
/**
From 00f6b71ec0446af479d9a9f4e945ec9d54fbf484 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Thu, 4 Jan 2024 17:55:45 -0700
Subject: [PATCH 06/60] feat(page:problemNum): fetch stats for
`/problems/[problemNum]` page
## what
- fetch stats for `/problems/[problemNum]` page
## how
## why
## where
- ./src/app/problems/[problemNum]/page.tsx
## usage
---
src/app/problems/[problemNum]/page.tsx | 65 ++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
create mode 100644 src/app/problems/[problemNum]/page.tsx
diff --git a/src/app/problems/[problemNum]/page.tsx b/src/app/problems/[problemNum]/page.tsx
new file mode 100644
index 0000000..c3cabc7
--- /dev/null
+++ b/src/app/problems/[problemNum]/page.tsx
@@ -0,0 +1,65 @@
+"use client";
+
+import { useFetchProblemNum } from "@/hooks";
+import { problemNumSchema } from "@/schema";
+import { AxiosError } from "axios";
+import { z } from "zod";
+import Error from "@/components/error";
+
+type problemPageProps = {
+ params: z.infer;
+};
+
+const ProblemPage = ({ params }: problemPageProps) => {
+ const {
+ isLoading: problemNumIsLoading,
+ isSuccess: problemNumIsSuccess,
+ isError: problemNumIsError,
+ data: problemNumData,
+ error: problemNumError,
+ } = useFetchProblemNum(params.problemNum);
+
+ if (problemNumIsLoading) {
+ return (
+
+
{/* */}
From c624a7867dcfd6a1667ff3d9e3ee89835c1e89a1 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Mon, 8 Jan 2024 07:20:28 -0700
Subject: [PATCH 24/60] chore(types): add `Python` as a value in `Language`
object
## what
- add `Python` as a value in `Language` object
## how
## why
- found a case where the language id was not present in the `Language`
object.
- after a little investigation, I found that this new id is for the
language `Python`
## where
- ./src/types/index.ts
## usage
---
src/types/index.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/types/index.ts b/src/types/index.ts
index baea3f9..14aecb6 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -288,6 +288,7 @@ export const Language: Record = {
3: "C++",
4: "Pascal",
5: "C++11",
+ 6: "Python",
};
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -371,4 +372,3 @@ export type Submission = {
};
///////////////////////////////////////////////////////////////////////////////////////////////////
-
From fdd935ec29b5b04dfbd13536f2dbbfbb96296dc9 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Mon, 8 Jan 2024 17:18:03 -0700
Subject: [PATCH 25/60] chore(schema:submission): add schema for endpoint
`/api/submissions/language/[problemNum]`
## what
- add schema for endpoint `/api/submissions/language/[problemNum]`
## how
## why
- this will be used to validate the data on client side and server
side
## where
- ./src/schema/index.ts
## usage
---
src/schema/index.ts | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/schema/index.ts b/src/schema/index.ts
index eb692d1..2073ae0 100644
--- a/src/schema/index.ts
+++ b/src/schema/index.ts
@@ -14,3 +14,10 @@ export const submissionOvertimeSchema = z.object({
.number({ invalid_type_error: "Problem number must be a number" })
.min(1, "Problem number must be a number greater than 0"),
})
+
+export const submissionLangSchema = z.object({
+ problemNum: z.coerce
+ .number({ invalid_type_error: "Problem number must be a number" })
+ .min(1, "Problem number must be a number greater than 0"),
+})
+
From d3c208cf791009c6e0218883d82b797f592656d4 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Mon, 8 Jan 2024 17:21:41 -0700
Subject: [PATCH 26/60] refactor(utils:constants): limit start range when
fetching submissions of a problem
## what
- limit start range when fetching submissions of a problem
- limit submissions from today to 1 year ago and return 500
submissions
- add params
- startSubmission: starting point when searching for submissions
- default to 1 year before in unix time. in other words, it will
return submissions starting from 1 year ago
- endSubmission: ending point when searching for submissions
- default to current time.
- limit: limit number of submissions to value provided
- default to 500. in other words it will always return 500
submissions of a problem
- currently not being used.
- how to use
- append the number to end
- ex: https://uhunt.onlinejudge.org/api/p/subs/36/0/1707350533/500
- the 500 in the end of url will limit number of
submissions to 500
## how
## why
- before the start range was set to 0, which would fetch every
submission for the problem
- this would fetch too many items and it would take a while to
process them
## where
- ./src/utils/constants.ts
## usage
---
src/utils/constants.ts | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index 041e5e1..2dd4a58 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -74,10 +74,19 @@ export const uhuntUsername2UidUrl = (username: string) =>
/**
* URL for getting Submission list of a problem using Problem ID
+ * NOTE: this will return a large number of array elements. Recommend to return 1 year worth of submissions
+ *
* @param {String | Number} pid - problem ID
+ * @param {Number} [startSubmission=moment().subtract(1, 'years').unix()] - Unix timestamp for what time to start searching. Default is 1 year ago
+ * @param {Number} [endSubmission=moment().unix()] - Unix timestamp for what time to end searching. Default is right now
+ * @param {Number} [limit=500] - Number of submissions to return. Default is 500 submissions
*/
-export const uhuntProblemSubmissionListUrl = (pid: string | number) =>
- `${uhuntBaseApiUrl}/p/subs/${pid}/0/${moment().unix()}`;
+export const uhuntProblemSubmissionListUrl = (
+ pid: string | number,
+ startSubmission = moment().subtract(1, 'years').unix(),
+ endSubmission = moment().unix(),
+ limit = 500
+) => `${uhuntBaseApiUrl}/p/subs/${pid}/${startSubmission}/${endSubmission}/500`;
/**
* Get User submissions using UserID
From f853c3c8f63c4074b71cf6669a0d1eabfc09b934 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Mon, 8 Jan 2024 17:50:54 -0700
Subject: [PATCH 27/60] feat(api:submission:language): add endpoint
`/api/submissions/language/[problemNum]`
## what
- add endpoint `/api/submissions/language/[problemNum]`
- get submissions language count of a problem using problem number
- if invalid `problem number` is given, a response of 400 will be returned
- if the problem doesn't exist, a response of 404 will be returned
- fetch submissions of problem number
- count submission language
## how
## why
## where
- ./src/app/api/submissions/language/[problemNum]/route.tsx
## usage
---
.../language/[problemNum]/route.tsx | 76 +++++++++++++++++++
1 file changed, 76 insertions(+)
create mode 100644 src/app/api/submissions/language/[problemNum]/route.tsx
diff --git a/src/app/api/submissions/language/[problemNum]/route.tsx b/src/app/api/submissions/language/[problemNum]/route.tsx
new file mode 100644
index 0000000..3824b98
--- /dev/null
+++ b/src/app/api/submissions/language/[problemNum]/route.tsx
@@ -0,0 +1,76 @@
+import { NextResponse } from "next/server";
+import { z } from "zod";
+
+import { submissionLangSchema as schema } from "@/schema";
+import {
+ uhuntProblemNumUrl,
+ uhuntProblemSubmissionListUrl,
+} from "@/utils/constants";
+import { Language, Problem, Submission } from "@/types";
+
+type getParamsType = {
+ params: z.infer;
+};
+
+export type getResponseType = Record;
+
+export const GET = async (_request: Request, { params }: getParamsType) => {
+ // validate params
+ const schemaResponse = await schema.safeParseAsync(params);
+ if (!schemaResponse.success) {
+ const message = {
+ message: schemaResponse.error.issues[0].message,
+ };
+
+ return NextResponse.json(message, {
+ status: 400,
+ });
+ }
+
+ //----------------------------------------------------------------------------------------------//
+
+ // fetch problem stats
+ const { problemNum } = params;
+
+ const problemUrl = uhuntProblemNumUrl(problemNum);
+ const problemResponse = await fetch(problemUrl);
+ const problemData: Problem = await problemResponse.json();
+
+ // return 404 if problem doesn't exist
+ if (Object.entries(problemData).length === 0) {
+ const message = {
+ message: `Problem number ${problemNum} not found`,
+ };
+ return NextResponse.json(message, {
+ status: 404,
+ });
+ }
+
+ //----------------------------------------------------------------------------------------------//
+
+ // fetch submissions of the problem
+ const submissionsUrl = uhuntProblemSubmissionListUrl(problemData.pid);
+ const submissionResponse = await fetch(submissionsUrl, { cache: "no-cache" });
+ const submissionData: Submission["msg"][] = await submissionResponse.json();
+
+ // map language id as key and 0 as value. (the value will be count of a submission language)
+ const languageObj = Object.keys(Language).reduce(
+ (acc: Record, cur: string) => {
+ acc[cur] = 0;
+
+ return acc;
+ },
+ {},
+ );
+
+ // increment count of key-value for their respective language ID
+ const responseData: getResponseType = submissionData.reduce((acc, cur) => {
+ const languageId = cur.lan;
+ acc[languageId] = acc[languageId] + 1;
+
+ return acc;
+ }, languageObj);
+ delete responseData["undefined"];
+
+ return Response.json(responseData);
+};
From b13d7233f83cfba5b798c68f40e042e90ff40b80 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Mon, 8 Jan 2024 17:54:30 -0700
Subject: [PATCH 28/60] chore(hooks): add react-query hook to fetch submission
language
## what
- add react-query hook to fetch submission language
## how
- fetch from api endpoint `/api/submissions/language/[problemNum]`
## why
## where
- ./src/hooks/index.ts
## usage
---
src/hooks/index.ts | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
index 5928149..8d904a4 100644
--- a/src/hooks/index.ts
+++ b/src/hooks/index.ts
@@ -20,6 +20,10 @@ export enum queryKey {
* React query key for fetching submission overtime count
*/
submissionCount = "submission-overtime",
+ /**
+ * React query key for fetching submission by language
+ */
+ submissionLang = "submission-language",
}
/**
@@ -74,3 +78,17 @@ export const useFetchSubmissionCount = (problemNum: number) => {
.then((res) => res.data),
});
}
+
+/**
+ * Fetch submissions by language
+ */
+export const useFetchSubmissionLang = (problemNum: number) => {
+ return useQuery({
+ queryKey: [queryKey.submissionLang],
+ queryFn: async () =>
+ await axios
+ .get(`/api/submissions/language/${problemNum}`)
+ .then((res) => res.data),
+ });
+}
+
From f9d73bb37ea7fbd8c95c59b2e1c66d015887327f Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Mon, 8 Jan 2024 17:58:09 -0700
Subject: [PATCH 29/60] chore(utils:processing): add function to generate data
for `recharts` radar chart
## what
- add function to generate data for `recharts` radar chart
## how
- loop through the object
- add object to array
- property `language`: string version of the language ID
- property `count`: number of submissions of that language ID
## why
- this will be used to generate the data needed for `recharts` radar
chart to render
## where
- ./src/utils/dataProcessing.ts
## usage
---
src/utils/dataProcessing.ts | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/src/utils/dataProcessing.ts b/src/utils/dataProcessing.ts
index 75b93f8..9d34205 100644
--- a/src/utils/dataProcessing.ts
+++ b/src/utils/dataProcessing.ts
@@ -1,4 +1,5 @@
-import { Problem, ProblemVerdictMap, ProblemVerdictType } from "@/types";
+import { Language, Problem, ProblemVerdictMap, ProblemVerdictType } from "@/types";
+import {getResponseType as submissionLangType} from '@/app/api/submissions/language/[problemNum]/route'
export type processedProblemVerdictBarChartType = {
/**
@@ -44,3 +45,25 @@ export const processProblemNumBarChartData = (data: Problem) => {
return processedData
}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+export type processedSubmissionLangType = {
+ language: string;
+ count: number;
+}
+
+export const processSubmissionLanguageRadarChart = (
+ data: submissionLangType,
+): processedSubmissionLangType[] => {
+ const processedData: processedSubmissionLangType[] = [];
+
+ Object.entries(data).forEach(([key, value]) => {
+ processedData.push({
+ language: Language[key],
+ count: value,
+ });
+ });
+
+ return processedData;
+};
From f88b60b496a34edd60f3e4e3edbd65afe8c52a96 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Mon, 8 Jan 2024 18:04:41 -0700
Subject: [PATCH 30/60] feat(components:charts): add
`SubmissionLanguageRadarChart` component
## what
- add `SubmissionLanguageRadarChart` component
## how
- takes a prop
- data of type `/api/submissions/language/[problemNum]` GET response
- process the data
- use Recharts `radar` chart
- use custom tooltip from `./src/components/charts/Tooltip`
- use radial gradient for color inside of the radar
## why
- this will display submissions by language of a problem using `radar`
chart
## where
- ./src/components/charts/SubmissionLanguageRadarChart.tsx
## usage
---
.../charts/SubmissionLanguageRadarChart.tsx | 60 +++++++++++++++++++
1 file changed, 60 insertions(+)
create mode 100644 src/components/charts/SubmissionLanguageRadarChart.tsx
diff --git a/src/components/charts/SubmissionLanguageRadarChart.tsx b/src/components/charts/SubmissionLanguageRadarChart.tsx
new file mode 100644
index 0000000..828c704
--- /dev/null
+++ b/src/components/charts/SubmissionLanguageRadarChart.tsx
@@ -0,0 +1,60 @@
+import {
+ Radar,
+ RadarChart,
+ PolarAngleAxis,
+ PolarGrid,
+ ResponsiveContainer,
+ Tooltip,
+} from "recharts";
+
+import ChartTooltip from "@/components/charts/Tooltip";
+import { processSubmissionLanguageRadarChart } from "@/utils/dataProcessing";
+import { getResponseType } from "@/app/api/submissions/language/[problemNum]/route";
+
+type Props = {
+ data: getResponseType;
+};
+
+const SubmissionLanguageRadarChart = ({ data }: Props) => {
+ const processedData = processSubmissionLanguageRadarChart(data);
+ return (
+
+
+
+
+ (
+
+ `${new Intl.NumberFormat("us").format(number).toString()}`
+ }
+ // labelFormatter={(payload) => payload[0].payload.tooltipTitle}
+ />
+ )}
+ />
+
+
+
+ {/* */}
+
+
+
+
+
+
+ );
+};
+
+export default SubmissionLanguageRadarChart;
From 4a32e1c7f3d709fe2dd7d9b7ddc86122942d93ef Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Mon, 8 Jan 2024 18:12:47 -0700
Subject: [PATCH 31/60] feat(page:problemNum): render
`SubmissionLanguageRadarChart` component
## what
- render `SubmissionLanguageRadarChart` component
## how
## why
## where
- ./src/app/problems/[problemNum]/page.tsx
## usage
---
src/app/problems/[problemNum]/page.tsx | 24 +++++++++++++++++++++---
1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/src/app/problems/[problemNum]/page.tsx b/src/app/problems/[problemNum]/page.tsx
index 46f095d..397b6d5 100644
--- a/src/app/problems/[problemNum]/page.tsx
+++ b/src/app/problems/[problemNum]/page.tsx
@@ -10,11 +10,12 @@ import {
CardHeader,
CardTitle,
} from "@/components/ui/card"
-import { useFetchProblemNum, useFetchSubmissionCount } from "@/hooks";
+import { useFetchProblemNum, useFetchSubmissionCount, useFetchSubmissionLang } from "@/hooks";
import { problemNumSchema } from "@/schema";
import { processProblemNumBarChartData } from "@/utils/dataProcessing";
import ProblemVerdictChart from "@/components/charts/ProblemVerdictChart";
import SubmissionsOvertimeChart from "@/components/charts/SubmissionsOvertimeChart";
+import SubmissionLanguageRadarChart from "@/components/charts/SubmissionLanguageRadarChart";
type problemPageProps = {
params: z.infer;
@@ -35,9 +36,19 @@ const ProblemPage = ({ params }: problemPageProps) => {
data: submissionCountData,
error: submissionCountError,
} = useFetchSubmissionCount(params.problemNum)
+ const {
+ isLoading: submissionLangIsLoading,
+ isSuccess: submissionLangIsSuccess,
+ isError: submissionLangIsError,
+ data: submissionLangData,
+ error: submissionLangError,
+ } = useFetchSubmissionLang(params.problemNum);
+
if (( problemNumIsLoading || !problemNumData || problemNumData.data === undefined ) ||
- ( submissionCountIsLoading || !submissionCountData)) {
+ ( submissionCountIsLoading || !submissionCountData) ||
+ ( submissionLangIsLoading || !submissionLangData)
+ ) {
return (
From 3a5c33636e774e2a4846de02ddbb773006700ee2 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Wed, 10 Jan 2024 12:42:40 -0700
Subject: [PATCH 39/60] chore(schema:problemNum:submission): add schema for
endpoint `/api/submissions/[problemNum]`
## what
- add schema for endpoint `/api/submissions/[problemNum]`
## how
## why
- this will be used to validate the data on client side and server
side
## where
- ./src/schema/index.ts
## usage
---
src/schema/index.ts | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/schema/index.ts b/src/schema/index.ts
index 460ba78..c5cbe3f 100644
--- a/src/schema/index.ts
+++ b/src/schema/index.ts
@@ -27,4 +27,8 @@ export const problemNumRanklistSchema = z.object({
.min(1, "Problem number must be a number greater than 0"),
})
-
+export const problemNumSubmissionSchema = z.object({
+ problemNum: z.coerce
+ .number({ invalid_type_error: "Problem number must be a number" })
+ .min(1, "Problem number must be a number greater than 0"),
+})
From a33642cfffa4b15d840d9129cc8b0e9a81ba2500 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Wed, 10 Jan 2024 12:45:32 -0700
Subject: [PATCH 40/60] feat(api:problemNum:submission): add endpoint
`/api/submissions/[problemNum]`
## what
- add endpoint `/api/submissions/[problemNum]`
- get submissions of a problem using problem number
- if invalid `problem number` is given, a response of 400 will be returned
- if the problem doesn't exist, a response of 404 will be returned
- fetch problem submissions
- add extra properties
- verdict
- fgColor
- bgColor
- title
- fgHex
- bgHex
- language: convert language ID into a string
- pnum: problem number
- pTitle: name of the problem
## how
## why
## where
- ./src/app/api/submissions/[problemNum]/route.ts
## usage
---
src/app/api/submissions/[problemNum]/route.ts | 77 +++++++++++++++++++
1 file changed, 77 insertions(+)
create mode 100644 src/app/api/submissions/[problemNum]/route.ts
diff --git a/src/app/api/submissions/[problemNum]/route.ts b/src/app/api/submissions/[problemNum]/route.ts
new file mode 100644
index 0000000..9de86ad
--- /dev/null
+++ b/src/app/api/submissions/[problemNum]/route.ts
@@ -0,0 +1,77 @@
+import { z } from "zod";
+
+import { problemNumSubmissionSchema as schema } from "@/schema";
+import { NextResponse } from "next/server";
+import {
+ uhuntProblemNumUrl,
+ uhuntProblemRankUrl,
+ uhuntProblemSubmissionListUrl,
+} from "@/utils/constants";
+import { Language, Problem, ProblemVerdictMap, Submission } from "@/types";
+import moment from "moment";
+
+type getParamsType = {
+ params: z.infer;
+};
+
+export const GET = async (_request: Request, { params }: getParamsType) => {
+ // validate params
+ const schemaResponse = await schema.safeParseAsync(params);
+ if (!schemaResponse.success) {
+ const message = {
+ message: schemaResponse.error.issues[0].message,
+ };
+
+ return NextResponse.json(message, {
+ status: 400,
+ });
+ }
+
+ //----------------------------------------------------------------------------------------------//
+
+ // fetch problem stats
+ const { problemNum } = params;
+
+ const problemUrl = uhuntProblemNumUrl(problemNum);
+ const problemResponse = await fetch(problemUrl);
+ const problemData: Problem = await problemResponse.json();
+
+ // return 404 if problem doesn't exist
+ if (Object.entries(problemData).length === 0) {
+ const message = {
+ message: `Problem number ${problemNum} not found`,
+ };
+ return NextResponse.json(message, {
+ status: 404,
+ });
+ }
+
+ //----------------------------------------------------------------------------------------------//
+
+ // fetch submissions of the problem
+ const submissionsUrl = uhuntProblemSubmissionListUrl(
+ problemData.pid,
+ moment().subtract(1, "years").unix(),
+ moment().unix(),
+ 20
+ );
+ const submissionResponse = await fetch(submissionsUrl, { cache: "no-cache" });
+ const submissionData: Submission["msg"][] = await submissionResponse.json();
+
+ const converted = submissionData.map((rank: Submission["msg"]) => {
+ rank.verdict = ProblemVerdictMap[rank.ver] || {
+ fgColor: "text-primary-foreground dark:text-secondary-foreground",
+ bgColor: "bg-gray-500",
+ title: "- In Queue -",
+ fgHex: "",
+ bgHex: "6b7280",
+ };
+ rank.lan = Language[rank.lan] || "--";
+ rank.pnum = problemData.num;
+ rank.pTitle = problemData.title;
+
+ return rank;
+ });
+
+ return Response.json(converted);
+};
From ea04c0fc6e75deab12e751b2e24b4cb5c5aef252 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Wed, 10 Jan 2024 12:49:32 -0700
Subject: [PATCH 41/60] chore(hooks): add react-query hook to fetch problem
submissions
## what
- add react-query hook to fetch problem submissions
## how
- fetch from endpoint `/api/submissions/[problemNum]`
## why
## where
- ./src/hooks/index.ts
## usage
---
src/hooks/index.ts | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
index 77fee1c..33e507b 100644
--- a/src/hooks/index.ts
+++ b/src/hooks/index.ts
@@ -20,6 +20,10 @@ export enum queryKey {
* React query key for fetching a problem ranklist
*/
problemRanklist = "problem-ranklist",
+ /**
+ * React query key for fetching a problem ranklist
+ */
+ problemSubmission = "problem-submission",
/**
* React query key for fetching submission overtime count
*/
@@ -67,6 +71,7 @@ export const useFetchProblemNum = (problemNum: number) => {
return useQuery({
queryKey: [queryKey.problemNum],
queryFn: async () => await axios.get(`/api/problems/${problemNum}`),
+ refetchOnWindowFocus: false
})
}
@@ -80,6 +85,7 @@ export const useFetchSubmissionCount = (problemNum: number) => {
await axios
.get(`/api/submissions/overtime/${problemNum}`)
.then((res) => res.data),
+ refetchOnWindowFocus: false
});
}
@@ -93,6 +99,7 @@ export const useFetchSubmissionLang = (problemNum: number) => {
await axios
.get(`/api/submissions/language/${problemNum}`)
.then((res) => res.data),
+ refetchOnWindowFocus: false
});
}
@@ -106,5 +113,21 @@ export const useFetchProblemRanklist = (problemNum: number) => {
await axios
.get(`/api/problems/ranklist/${problemNum}`)
.then((res) => res.data),
+ refetchOnWindowFocus: false
+ });
+}
+
+/**
+ * Fetch problem submissions
+ */
+export const useFetchProblemSubmission = (problemNum: number) => {
+ return useQuery({
+ queryKey: [queryKey.problemSubmission],
+ queryFn: async () =>
+ await axios
+ .get(`/api/submissions/${problemNum}`)
+ .then((res) => res.data),
+ refetchOnWindowFocus: false
});
}
+
From 2f41cb88ffb37e2d4c674cc0c2d008762d31f726 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Wed, 10 Jan 2024 12:55:30 -0700
Subject: [PATCH 42/60] feat(page:problemNum): render `VirtualTable` for
`Problem submissions`
## what
- render `VirtualTable` for `Problem submissions`
- fetch problem submissions using react-query hook
- render data using VirtualTable
## how
## why
## where
- ./src/app/problems/[problemNum]/page.tsx
## usage
---
src/app/problems/[problemNum]/page.tsx | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/src/app/problems/[problemNum]/page.tsx b/src/app/problems/[problemNum]/page.tsx
index bbb4ce0..04cfc04 100644
--- a/src/app/problems/[problemNum]/page.tsx
+++ b/src/app/problems/[problemNum]/page.tsx
@@ -10,7 +10,7 @@ import {
CardHeader,
CardTitle,
} from "@/components/ui/card"
-import { useFetchProblemNum, useFetchProblemRanklist, useFetchSubmissionCount, useFetchSubmissionLang } from "@/hooks";
+import { useFetchProblemNum, useFetchProblemRanklist, useFetchProblemSubmission, useFetchSubmissionCount, useFetchSubmissionLang } from "@/hooks";
import { problemNumSchema } from "@/schema";
import { processProblemNumBarChartData } from "@/utils/dataProcessing";
import ProblemVerdictChart from "@/components/charts/ProblemVerdictChart";
@@ -53,13 +53,21 @@ const ProblemPage = ({ params }: problemPageProps) => {
data: problemRanklistData,
error: problemRanklistError,
} = useFetchProblemRanklist(params.problemNum);
+ const {
+ isLoading: problemSubmissionIsLoading,
+ isSuccess: problemSubmissionIsSuccess,
+ isError: problemSubmissionIsError,
+ data: problemSubmissionData,
+ error: problemSubmissionError,
+ } = useFetchProblemSubmission(params.problemNum);
if (
(problemNumIsLoading || !problemNumData || problemNumData.data === undefined) ||
(submissionCountIsLoading || !submissionCountData) ||
(submissionLangIsLoading || !submissionLangData) ||
- (problemRanklistIsLoading || !problemRanklistData)
+ (problemRanklistIsLoading || !problemRanklistData) ||
+ (problemSubmissionIsLoading || !problemSubmissionData)
) {
return (
@@ -139,7 +147,11 @@ const ProblemPage = ({ params }: problemPageProps) => {
{/* */}
-
submissions
+
+
Submissions
+ {/* */}
+
+
);
From 8f19b98daef1ea2c7fd18a556a28c61581c0163c Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Wed, 10 Jan 2024 12:57:11 -0700
Subject: [PATCH 43/60] chore(utils:constants): use the limit value when
fetching problem submissions
## what
- use the limit value when fetching problem submissions
## how
- uses the parameter `limit` value
- default is 500
## why
- this will limit the number of submissions returned
## where
- ./src/utils/constants.ts
## usage
---
src/utils/constants.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index 2dd4a58..b481ea5 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -86,7 +86,7 @@ export const uhuntProblemSubmissionListUrl = (
startSubmission = moment().subtract(1, 'years').unix(),
endSubmission = moment().unix(),
limit = 500
-) => `${uhuntBaseApiUrl}/p/subs/${pid}/${startSubmission}/${endSubmission}/500`;
+) => `${uhuntBaseApiUrl}/p/subs/${pid}/${startSubmission}/${endSubmission}/${limit}`;
/**
* Get User submissions using UserID
From 1c40b5d12eed9427f4638343e79884f8c1b5d94d Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Wed, 10 Jan 2024 21:11:33 -0700
Subject: [PATCH 44/60] chore(components:charts): change radar chart grid
opacity depending on theme
## what
- change rader chart grid opacity depending on theme
- set radar chart grid opacity to 0.3 in dark mode
- set radar chart grid opacity to 1.0 in light mode
## how
## why
- the opacity of 0.3 is barely visible in light mode
- cant change the fill color of the radar chart grid
## where
- ./src/components/charts/SubmissionLanguageRadarChart.tsx
## usage
---
src/components/charts/SubmissionLanguageRadarChart.tsx | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/components/charts/SubmissionLanguageRadarChart.tsx b/src/components/charts/SubmissionLanguageRadarChart.tsx
index 828c704..21c3a29 100644
--- a/src/components/charts/SubmissionLanguageRadarChart.tsx
+++ b/src/components/charts/SubmissionLanguageRadarChart.tsx
@@ -6,6 +6,7 @@ import {
ResponsiveContainer,
Tooltip,
} from "recharts";
+import { useTheme } from "next-themes";
import ChartTooltip from "@/components/charts/Tooltip";
import { processSubmissionLanguageRadarChart } from "@/utils/dataProcessing";
@@ -16,11 +17,13 @@ type Props = {
};
const SubmissionLanguageRadarChart = ({ data }: Props) => {
+ const { theme } = useTheme();
const processedData = processSubmissionLanguageRadarChart(data);
+
return (
-
+
Date: Wed, 10 Jan 2024 21:22:49 -0700
Subject: [PATCH 45/60] chore(page:problemNum): render problem number and title
## what
- render problem number and title
## how
## why
## where
- ./src/app/problems/[problemNum]/page.tsx
## usage
---
src/app/problems/[problemNum]/page.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/app/problems/[problemNum]/page.tsx b/src/app/problems/[problemNum]/page.tsx
index 04cfc04..29b757c 100644
--- a/src/app/problems/[problemNum]/page.tsx
+++ b/src/app/problems/[problemNum]/page.tsx
@@ -106,7 +106,7 @@ const ProblemPage = ({ params }: problemPageProps) => {
const processedProblemVerdictData = processProblemNumBarChartData(problemNumData.data)
return (
-
Problem page: {params.problemNum}
+
{params.problemNum}: {problemNumData.data.title}
{/* Submission verdicts bar chart */}
From 1fd42fa0f53232e8f10c7323566582e3e7c59c66 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Thu, 11 Jan 2024 13:19:48 -0700
Subject: [PATCH 46/60] feat(shadcn:data-table): set DataTable height if
provided
## what
- set DataTable height if provided
## how
- take `height` as a prop
- set the height of the table if it's defined
- set the table to overflow-y if height is defined
## why
- a replacement for `VirtualTable`
- VirtualTable struggles to scroll when theres high amounts of items
to render. DataTable can handle high items without issue
- to have the ability to set the size of the DataTable
## where
- ./src/components/ui/data-table/index.tsx
## usage
---
src/components/ui/data-table/index.tsx | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/components/ui/data-table/index.tsx b/src/components/ui/data-table/index.tsx
index 30c1f7b..8bae903 100644
--- a/src/components/ui/data-table/index.tsx
+++ b/src/components/ui/data-table/index.tsx
@@ -37,11 +37,16 @@ import { DataTablePagination } from "@/components/ui/data-table/pagination"
interface DataTableProps {
columns: ColumnDef[]
data: TData[]
+ /**
+ * height of the table. If specified, it will overflow the table contents
+ */
+ height?: number
}
export function DataTable({
columns,
data,
+ height
}: DataTableProps) {
const [sorting, setSorting] = useState([])
const [columnVisibility, setColumnVisibility] = useState({})
@@ -128,7 +133,7 @@ export function DataTable({
-
+
{table.getHeaderGroups().map((headerGroup) => (
From 6a6a205ce0b096e54ae2be7885af35d999ec7a42 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Thu, 11 Jan 2024 13:25:00 -0700
Subject: [PATCH 47/60] refactor(page:problemNum): use `DataTable` to render
ranklist and submissions
## what
- use `DataTable` to render ranklist and submissions
- set a max height to the DataTable
## how
## why
- DataTable can handle high volumes of items when scrolling
## where
- ./src/app/problems/[problemNum]/page.tsx
## usage
---
src/app/problems/[problemNum]/page.tsx | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/app/problems/[problemNum]/page.tsx b/src/app/problems/[problemNum]/page.tsx
index 29b757c..1c19af8 100644
--- a/src/app/problems/[problemNum]/page.tsx
+++ b/src/app/problems/[problemNum]/page.tsx
@@ -144,13 +144,11 @@ const ProblemPage = ({ params }: problemPageProps) => {
Ranklist (Top 10)
- {/* */}
-
+
Submissions
- {/* */}
-
+
From fc9a834ff85364eb505e52b8a71b3bc88ed47190 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Thu, 11 Jan 2024 13:28:34 -0700
Subject: [PATCH 48/60] refactor(api:problemNum:submission): set submission
limit to 500
## what
- set submission limit to 500
## how
## why
- Since the DataTable is being used to display problem submissions, it
can handle a high amount of items to be rendered
## where
- ./src/app/api/submissions/[problemNum]/route.ts
## usage
---
src/app/api/submissions/[problemNum]/route.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/app/api/submissions/[problemNum]/route.ts b/src/app/api/submissions/[problemNum]/route.ts
index 9de86ad..560683d 100644
--- a/src/app/api/submissions/[problemNum]/route.ts
+++ b/src/app/api/submissions/[problemNum]/route.ts
@@ -53,7 +53,7 @@ export const GET = async (_request: Request, { params }: getParamsType) => {
problemData.pid,
moment().subtract(1, "years").unix(),
moment().unix(),
- 20
+ 500
);
const submissionResponse = await fetch(submissionsUrl, { cache: "no-cache" });
const submissionData: Submission["msg"][] = await submissionResponse.json();
From 1865362a9ab89600fbafcd7817bef4cef5529200 Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Thu, 11 Jan 2024 17:15:51 -0700
Subject: [PATCH 49/60] chore(page:problemNum): add `Loading` component for
`/problems/[problemNum]` page
## what
- add `Loading` component for `/problems/[problemNum]` page
## how
## why
- this will be used to display when fetching data on the
`/problems/[problemNum]` page
## where
- ./src/app/problems/[problemNum]/loading.tsx
## usage
---
src/app/problems/[problemNum]/loading.tsx | 28 +++++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 src/app/problems/[problemNum]/loading.tsx
diff --git a/src/app/problems/[problemNum]/loading.tsx b/src/app/problems/[problemNum]/loading.tsx
new file mode 100644
index 0000000..ae01a6d
--- /dev/null
+++ b/src/app/problems/[problemNum]/loading.tsx
@@ -0,0 +1,28 @@
+import Loading from '@/components/ui/data-table/loading'
+import { Skeleton } from '@/components/ui/skeleton'
+import React from 'react'
+
+const ProblemNumLoading = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default ProblemNumLoading
From 2df5b87ad0454115f779202705e14a91b2eaf53c Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Thu, 11 Jan 2024 17:17:39 -0700
Subject: [PATCH 50/60] chore(page:problemNum): use `Loading` component
## what
- use `Loading` component
- use component from `./src/app/problems/[problemNum]/loading.tsx`
## how
## why
- this will be used to display when fetching data for
`problems/[problemNum]` page
## where
- ./src/app/problems/[problemNum]/page.tsx
## usage
---
src/app/problems/[problemNum]/page.tsx | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/app/problems/[problemNum]/page.tsx b/src/app/problems/[problemNum]/page.tsx
index 1c19af8..e3b64b6 100644
--- a/src/app/problems/[problemNum]/page.tsx
+++ b/src/app/problems/[problemNum]/page.tsx
@@ -18,7 +18,7 @@ import SubmissionsOvertimeChart from "@/components/charts/SubmissionsOvertimeCha
import SubmissionLanguageRadarChart from "@/components/charts/SubmissionLanguageRadarChart";
import { DataTable } from "@/components/ui/data-table";
import { columns } from "./components/data-table/ranklistColumns";
-import VirtualTable from "@/components/virtual-table";
+import Loading from "./loading"
type problemPageProps = {
params: z.infer;
@@ -70,9 +70,7 @@ const ProblemPage = ({ params }: problemPageProps) => {
(problemSubmissionIsLoading || !problemSubmissionData)
) {
return (
-
-
Loading: {params.problemNum}
-
+
);
}
From 6d8b8c145218d07f50f61f5f3c280546be53c68a Mon Sep 17 00:00:00 2001
From: Clumsy-Coder <19594044+Clumsy-Coder@users.noreply.github.com>
Date: Thu, 11 Jan 2024 17:33:32 -0700
Subject: [PATCH 51/60] feat(page:problemNum): set title as link to view
problem pdf
## what
- set title as link to view problem pdf
## how
## why
- to be able to view the problem that is currently loaded
## where
- ./src/app/problems/[problemNum]/page.tsx
## usage
---
src/app/problems/[problemNum]/page.tsx | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/app/problems/[problemNum]/page.tsx b/src/app/problems/[problemNum]/page.tsx
index e3b64b6..0d963e0 100644
--- a/src/app/problems/[problemNum]/page.tsx
+++ b/src/app/problems/[problemNum]/page.tsx
@@ -19,6 +19,8 @@ import SubmissionLanguageRadarChart from "@/components/charts/SubmissionLanguage
import { DataTable } from "@/components/ui/data-table";
import { columns } from "./components/data-table/ranklistColumns";
import Loading from "./loading"
+import Link from "next/link";
+import { uhuntViewProblemUrl } from "@/utils/constants";
type problemPageProps = {
params: z.infer;
@@ -104,8 +106,10 @@ const ProblemPage = ({ params }: problemPageProps) => {
const processedProblemVerdictData = processProblemNumBarChartData(problemNumData.data)
return (
-