From 6c53cd0aff121ceee4498f4aa177de472ab02600 Mon Sep 17 00:00:00 2001 From: minkyung00 Date: Thu, 9 Feb 2023 13:22:58 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20contest=20problem=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EC=A1=B0=ED=9A=8C=20API=20(#55)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/queryKeys.ts | 1 + src/pages/Class/Problem/api/index.ts | 6 ++++- .../hooks/query/useContestProblemQuery.ts | 24 +++++++++++++++++++ src/types/problem.d.ts | 15 ++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/pages/Class/Problem/hooks/query/useContestProblemQuery.ts diff --git a/src/constants/queryKeys.ts b/src/constants/queryKeys.ts index 73d0821..8fdd565 100644 --- a/src/constants/queryKeys.ts +++ b/src/constants/queryKeys.ts @@ -10,4 +10,5 @@ export const QUERY_KEYS = { CLASS_STUDENT: 'class-student', CLASS_TA: 'class-ta', CLASS_CONTEST: 'class-contest', + CLASS_CONTEST_PROBLEM: 'class-contest-problem', }; diff --git a/src/pages/Class/Problem/api/index.ts b/src/pages/Class/Problem/api/index.ts index 6f0333e..9f69195 100644 --- a/src/pages/Class/Problem/api/index.ts +++ b/src/pages/Class/Problem/api/index.ts @@ -10,4 +10,8 @@ const createProblem = (payload: FormData) => { return fileApi.post(`${API_URL}/`, payload); }; -export { getProblem, createProblem }; +const getContestProblem = ({ classId, contestId, contestProblemId }: ContestProblemRequest) => { + return api.get(`/class/${classId}/contests/${contestId}/${contestProblemId}`); +}; + +export { getProblem, createProblem, getContestProblem }; diff --git a/src/pages/Class/Problem/hooks/query/useContestProblemQuery.ts b/src/pages/Class/Problem/hooks/query/useContestProblemQuery.ts new file mode 100644 index 0000000..776189b --- /dev/null +++ b/src/pages/Class/Problem/hooks/query/useContestProblemQuery.ts @@ -0,0 +1,24 @@ +import { AxiosError } from 'axios'; +import { UseQueryOptions } from 'react-query'; + +import { useSuspenseQuery } from '@/hooks/useSuspenseQuery'; +import { QUERY_KEYS } from '@/constants'; + +import { getContestProblem } from '../../api'; + +export const useContestProblemQuery = ( + params: ContestProblemRequest, + options?: UseQueryOptions +) => { + const { classId, contestId, contestProblemId } = params; + return useSuspenseQuery( + [QUERY_KEYS.CLASS_CONTEST_PROBLEM, classId, contestId, contestProblemId], + async () => { + const { data } = await getContestProblem(params); + return data; + }, + { + ...options, + } + ); +}; diff --git a/src/types/problem.d.ts b/src/types/problem.d.ts index 98c9762..83403b9 100644 --- a/src/types/problem.d.ts +++ b/src/types/problem.d.ts @@ -21,3 +21,18 @@ type ProblemRequest = { public: boolean; solution: 파일; }; + +type ContestProblem = { + id: number; + contest_id: number; + problem_id: number; + title: string; + description: string; + data_description: string; + start_time: string; + end_time: string; + evaluation: string; + problem_data: string; +}; + +type ContestProblemRequest = { classId: string; contestId: string; contestProblemId: string }; From 618a91364a00fa746b53fd69262ef6035c14fb3d Mon Sep 17 00:00:00 2001 From: minkyung00 Date: Thu, 9 Feb 2023 13:28:59 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20=EB=AC=B8=EC=A0=9C=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=A0=9C=EC=B6=9C=20/=20=EC=A0=9C=EC=B6=9C=20?= =?UTF-8?q?=EB=82=B4=EC=97=AD=20=EC=A1=B0=ED=9A=8C=20/=20=EC=A0=9C?= =?UTF-8?q?=EC=B6=9C=20=EB=82=B4=EC=97=AD=20=EC=84=A0=ED=83=9D=20API=20(#5?= =?UTF-8?q?5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/queryKeys.ts | 1 + src/pages/Class/Problem/api/index.ts | 38 ++++++++++++++++++- src/pages/Class/Problem/hooks/query/index.ts | 4 ++ .../query/useContestProblemSubmissionQuery.ts | 29 ++++++++++++++ ...teContestProblemSubmissionCheckMutation.ts | 22 +++++++++++ ...eCreateContestProblemSubmissionMutation.ts | 22 +++++++++++ src/types/problem.d.ts | 20 +++++++++- 7 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 src/pages/Class/Problem/hooks/query/useContestProblemSubmissionQuery.ts create mode 100644 src/pages/Class/Problem/hooks/query/useCreateContestProblemSubmissionCheckMutation.ts create mode 100644 src/pages/Class/Problem/hooks/query/useCreateContestProblemSubmissionMutation.ts diff --git a/src/constants/queryKeys.ts b/src/constants/queryKeys.ts index 8fdd565..df01a8a 100644 --- a/src/constants/queryKeys.ts +++ b/src/constants/queryKeys.ts @@ -11,4 +11,5 @@ export const QUERY_KEYS = { CLASS_TA: 'class-ta', CLASS_CONTEST: 'class-contest', CLASS_CONTEST_PROBLEM: 'class-contest-problem', + CLASS_CONTEST_PROBLEM_SUBMISSION: 'class-contest-problem-submission', }; diff --git a/src/pages/Class/Problem/api/index.ts b/src/pages/Class/Problem/api/index.ts index 9f69195..391a791 100644 --- a/src/pages/Class/Problem/api/index.ts +++ b/src/pages/Class/Problem/api/index.ts @@ -14,4 +14,40 @@ const getContestProblem = ({ classId, contestId, contestProblemId }: ContestProb return api.get(`/class/${classId}/contests/${contestId}/${contestProblemId}`); }; -export { getProblem, createProblem, getContestProblem }; +/** FIXME: 페이지네이션, username */ +const getContestProblemSubmission = ({ + classId, + contestId, + contestProblemId, +}: ContestProblemRequest) => { + return api.get(`/class/${classId}/contests/${contestId}/${contestProblemId}/submissions`); +}; + +const createContestProblemSubmission = ({ + classId, + contestId, + contestProblemId, + payload, +}: ContestProblemRequest & { payload: FormData }) => { + return fileApi.post( + `/class/${classId}/contests/${contestId}/${contestProblemId}/submission/`, + payload + ); +}; + +const createContestProblemSumbissionCheck = ({ + classId, + contestId, + contestProblemId, +}: ContestProblemRequest) => { + return api.patch(`/class/${classId}/contests/${contestId}/${contestProblemId}/check/`); +}; + +export { + getProblem, + createProblem, + getContestProblem, + getContestProblemSubmission, + createContestProblemSubmission, + createContestProblemSumbissionCheck, +}; diff --git a/src/pages/Class/Problem/hooks/query/index.ts b/src/pages/Class/Problem/hooks/query/index.ts index 02f2e24..b25562f 100644 --- a/src/pages/Class/Problem/hooks/query/index.ts +++ b/src/pages/Class/Problem/hooks/query/index.ts @@ -1,2 +1,6 @@ export * from './useProblemQuery'; export * from './useCreateProblemMutation'; +export * from './useContestProblemQuery'; +export * from './useContestProblemSubmissionQuery'; +export * from './useCreateContestProblemSubmissionMutation'; +export * from './useCreateContestProblemSubmissionCheckMutation'; diff --git a/src/pages/Class/Problem/hooks/query/useContestProblemSubmissionQuery.ts b/src/pages/Class/Problem/hooks/query/useContestProblemSubmissionQuery.ts new file mode 100644 index 0000000..2bd86db --- /dev/null +++ b/src/pages/Class/Problem/hooks/query/useContestProblemSubmissionQuery.ts @@ -0,0 +1,29 @@ +import { AxiosError } from 'axios'; +import { UseQueryOptions } from 'react-query'; + +import { useSuspenseQuery } from '@/hooks/useSuspenseQuery'; +import { QUERY_KEYS } from '@/constants'; + +import { getContestProblemSubmission } from '../../api'; + +export const useContestProblemSubmissionQuery = ( + params: ContestProblemRequest, + options?: UseQueryOptions< + ContestProblemSubmissionResponse, + AxiosError, + ContestProblemSubmissionResponse, + string[] + > +) => { + const { classId, contestId, contestProblemId } = params; + return useSuspenseQuery( + [QUERY_KEYS.CLASS_CONTEST_PROBLEM_SUBMISSION, classId, contestId, contestProblemId], + async () => { + const { data } = await getContestProblemSubmission(params); + return data; + }, + { + ...options, + } + ); +}; diff --git a/src/pages/Class/Problem/hooks/query/useCreateContestProblemSubmissionCheckMutation.ts b/src/pages/Class/Problem/hooks/query/useCreateContestProblemSubmissionCheckMutation.ts new file mode 100644 index 0000000..39ac4a0 --- /dev/null +++ b/src/pages/Class/Problem/hooks/query/useCreateContestProblemSubmissionCheckMutation.ts @@ -0,0 +1,22 @@ +import { useMutation, UseMutationOptions } from 'react-query'; +import { AxiosError, AxiosResponse } from 'axios'; + +import { createContestProblemSumbissionCheck } from '../../api'; + +type createContestProblemSumbissionCheck = { + classId: string; + contestId: string; + contestProblemId: string; + payload: { id: string }; +}; + +export const useCreateContestProblemSubmissionCheckMutation = ( + options?: UseMutationOptions +) => { + return useMutation((payload) => createContestProblemSumbissionCheck(payload), { + ...options, + onSuccess: () => { + alert('성공'); + }, + }); +}; diff --git a/src/pages/Class/Problem/hooks/query/useCreateContestProblemSubmissionMutation.ts b/src/pages/Class/Problem/hooks/query/useCreateContestProblemSubmissionMutation.ts new file mode 100644 index 0000000..2052090 --- /dev/null +++ b/src/pages/Class/Problem/hooks/query/useCreateContestProblemSubmissionMutation.ts @@ -0,0 +1,22 @@ +import { useMutation, UseMutationOptions } from 'react-query'; +import { AxiosError, AxiosResponse } from 'axios'; + +import { createContestProblemSubmission } from '../../api'; + +type createContestProblemSubmissionRequest = { + classId: string; + contestId: string; + contestProblemId: string; + payload: FormData; +}; + +export const useCreateContestProblemSubmissionMutation = ( + options?: UseMutationOptions +) => { + return useMutation((payload) => createContestProblemSubmission(payload), { + ...options, + onSuccess: () => { + alert('성공'); + }, + }); +}; diff --git a/src/types/problem.d.ts b/src/types/problem.d.ts index 83403b9..1152232 100644 --- a/src/types/problem.d.ts +++ b/src/types/problem.d.ts @@ -15,11 +15,11 @@ type ProblemRequest = { title: string; class_id: number; description: string; - data: 파일; + data: Blob; data_description: string; evaluation: string; public: boolean; - solution: 파일; + solution: Blob; }; type ContestProblem = { @@ -36,3 +36,19 @@ type ContestProblem = { }; type ContestProblemRequest = { classId: string; contestId: string; contestProblemId: string }; + +type ContestProblemSubmission = { + id: nubmer; + username: string; + score: number; + status: number; + on_leaderboard: boolean; + created_time: string; +}[]; + +type ContestProblemSubmissionResponse = ApiResponse; + +type ContestProblemSubmissionRequest = { + csv: Blob; + ipynb: Blob; +}; From eb6d63cb3cd4e11e0a1b82343eb1b638f3b65ed9 Mon Sep 17 00:00:00 2001 From: minkyung00 Date: Thu, 9 Feb 2023 13:34:04 +0900 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20contest=20problem=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EC=A1=B0=ED=9A=8C=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?(#55)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Class/Problem/ContestProblemDetail.tsx | 25 +++++++++++++++++++ src/pages/Class/Problem/index.ts | 1 + 2 files changed, 26 insertions(+) create mode 100644 src/pages/Class/Problem/ContestProblemDetail.tsx diff --git a/src/pages/Class/Problem/ContestProblemDetail.tsx b/src/pages/Class/Problem/ContestProblemDetail.tsx new file mode 100644 index 0000000..62ef9b9 --- /dev/null +++ b/src/pages/Class/Problem/ContestProblemDetail.tsx @@ -0,0 +1,25 @@ +import { useParams } from 'react-router-dom'; + +import { SUB_PATH } from '@/constants'; + +import { Problem } from './components'; +import { useContestProblemQuery } from './hooks'; + +export function ContestProblemDetail() { + const { classId, contestId, contestProblemId } = useParams() as { + classId: string; + contestId: string; + contestProblemId: string; + }; + + const { data } = useContestProblemQuery({ classId, contestId, contestProblemId }); + + const menuList = [ + { name: '문제 설명', to: SUB_PATH.DESCRIPTION }, + { name: '데이터', to: SUB_PATH.DATA }, + { name: '리더보드', to: SUB_PATH.LEADERBOARD }, + { name: '제출', to: SUB_PATH.SUBMISSON }, + ]; + + return ; +} diff --git a/src/pages/Class/Problem/index.ts b/src/pages/Class/Problem/index.ts index 1be1ca3..b999143 100644 --- a/src/pages/Class/Problem/index.ts +++ b/src/pages/Class/Problem/index.ts @@ -1,6 +1,7 @@ export * from './ProblemForm'; export * from './AllProblemDetail'; +export * from './ContestProblemDetail'; export * from './ProblemDescription'; export * from './ProblemData'; From 7da578786bc87e265dfb07927e9741bb5ad4e04a Mon Sep 17 00:00:00 2001 From: minkyung00 Date: Thu, 9 Feb 2023 13:48:41 +0900 Subject: [PATCH 4/6] =?UTF-8?q?refactor:=20contest=20problem=20=EC=A0=9C?= =?UTF-8?q?=EC=B6=9C=20=ED=8E=98=EC=9D=B4=EC=A7=80=20(#55)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 파일 제출 / 리더보드 제출 분리 --- src/pages/Class/Problem/ProblemSubmission.tsx | 61 +++++++++++-------- .../Problem/components/FileSubmissionForm.tsx | 19 ++++++ .../components/LeaderboardSubmissionForm.tsx | 47 ++++++++++++++ src/pages/Class/Problem/components/index.ts | 2 + 4 files changed, 104 insertions(+), 25 deletions(-) create mode 100644 src/pages/Class/Problem/components/FileSubmissionForm.tsx create mode 100644 src/pages/Class/Problem/components/LeaderboardSubmissionForm.tsx diff --git a/src/pages/Class/Problem/ProblemSubmission.tsx b/src/pages/Class/Problem/ProblemSubmission.tsx index 99f47e2..6c16cf7 100644 --- a/src/pages/Class/Problem/ProblemSubmission.tsx +++ b/src/pages/Class/Problem/ProblemSubmission.tsx @@ -1,34 +1,45 @@ -import { Button, Heading, Table, Input } from '@/components'; +import { useParams } from 'react-router-dom'; + +import { + useCreateContestProblemSubmissionCheckMutation, + useCreateContestProblemSubmissionMutation, +} from './hooks'; + +import { FileSubmissionForm, LeaderboardSubmissionForm } from './components'; export function ProblemSubmission() { - const column = [ - { Header: '#', accessor: 'id' }, - { Header: 'csv 파일', accessor: 'csvFile' }, - { Header: 'ipynb 파일', accessor: 'ipynbFile' }, - { Header: '점수', accessor: 'score' }, - { Header: 'status', accessor: 'status' }, - { Header: '제출 날짜', accessor: 'submissionDate' }, - ]; - /** FIXME: 수업 상세 정보 */ - const data = [{ id: 1 }]; + const { classId, contestId, contestProblemId } = useParams() as { + classId: string; + contestId: string; + contestProblemId: string; + }; - return ( - <> -
- csv 파일 제출 -

하나의 csv 파일만 업로드 가능합니다

- + const { mutate: createSubmission } = useCreateContestProblemSubmissionMutation(); + const { mutate: createSubmissionCheck } = useCreateContestProblemSubmissionCheckMutation(); + + const handleFileSumbit = (e: React.FormEvent) => { + e.preventDefault(); - ipynb 파일 제출 -

하나의 ipynb 파일만 업로드 가능합니다

- + const [csv, ipynb] = Object.values(e.target).map(({ files }) => files && files[0]); - - + const formData = new FormData(); + formData.append('csv', csv); + formData.append('ipynb', ipynb); - 제출 내역 -

선택한 제출 내역이 리더보드에 표시됩니다.

- + createSubmission({ classId, contestId, contestProblemId, payload: formData }); + }; + + const handleCheckSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + const { id } = Object.values(e.target).find(({ checked }) => checked); + createSubmissionCheck({ classId, contestId, contestProblemId, payload: { id } }); + }; + + return ( + <> + + ); } diff --git a/src/pages/Class/Problem/components/FileSubmissionForm.tsx b/src/pages/Class/Problem/components/FileSubmissionForm.tsx new file mode 100644 index 0000000..04fa277 --- /dev/null +++ b/src/pages/Class/Problem/components/FileSubmissionForm.tsx @@ -0,0 +1,19 @@ +import { Heading, Input, Button } from '@/components'; + +type FileSubmissionFormProps = Component; + +export function FileSubmissionForm({ ...props }: FileSubmissionFormProps<'form'>) { + return ( +
+ csv 파일 제출 +

하나의 csv 파일만 업로드 가능합니다

+ + + ipynb 파일 제출 +

하나의 ipynb 파일만 업로드 가능합니다

+ + + + + ); +} diff --git a/src/pages/Class/Problem/components/LeaderboardSubmissionForm.tsx b/src/pages/Class/Problem/components/LeaderboardSubmissionForm.tsx new file mode 100644 index 0000000..d224b95 --- /dev/null +++ b/src/pages/Class/Problem/components/LeaderboardSubmissionForm.tsx @@ -0,0 +1,47 @@ +import { useParams } from 'react-router-dom'; + +import { Heading, Table, Button } from '@/components'; +import { formatTime } from '@/utils/time'; + +import { useContestProblemSubmissionQuery } from '../hooks'; + +type FileSubmissionFormProps = Component; + +export function LeaderboardSubmissionForm({ ...props }: FileSubmissionFormProps<'form'>) { + const { classId, contestId, contestProblemId } = useParams() as { + classId: string; + contestId: string; + contestProblemId: string; + }; + + const column = [ + { Header: 'check', accessor: 'check' }, + { Header: 'csv 파일', accessor: 'csvFile' }, + { Header: 'ipynb 파일', accessor: 'ipynbFile' }, + { Header: '점수', accessor: 'score' }, + { Header: 'status', accessor: 'status' }, + { Header: '제출 날짜', accessor: 'submissionDate' }, + ]; + + const { + data: { results }, + } = useContestProblemSubmissionQuery({ classId, contestId, contestProblemId }); + + const data = results + .sort(({ score: prev }, { score: next }) => next - prev) + .sort(({ created_time: prev }, { created_time: next }) => +new Date(prev) - +new Date(next)) + .map((submission) => ({ + ...submission, + check: , + submissionDate: formatTime(submission.created_time), + })); + + return ( +
+ 제출 내역 +

선택한 제출 내역이 리더보드에 표시됩니다.

+
+ + + ); +} diff --git a/src/pages/Class/Problem/components/index.ts b/src/pages/Class/Problem/components/index.ts index 575fbe4..ef243d0 100644 --- a/src/pages/Class/Problem/components/index.ts +++ b/src/pages/Class/Problem/components/index.ts @@ -1 +1,3 @@ export * from './Problem'; +export * from './FileSubmissionForm'; +export * from './LeaderboardSubmissionForm'; From 36a181572a7ee4342fae478853ad1f74dd699609 Mon Sep 17 00:00:00 2001 From: minkyung00 Date: Thu, 9 Feb 2023 13:51:48 +0900 Subject: [PATCH 5/6] =?UTF-8?q?feat:=20contest=20problem=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EB=9D=BC=EC=9A=B0=ED=8C=85=20(#53)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 9 ++++++++- src/constants/paths.ts | 3 ++- src/pages/Class/ClassContestProblemList.tsx | 9 +++++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 7e77562..45af3b7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -18,6 +18,7 @@ import { ClassContestProblemList, ClassStudentManagement, AllProblemDetail, + ContestProblemDetail, ProblemDescription, ProblemData, ProblemLeaderBoard, @@ -45,6 +46,13 @@ export default function App() { } /> }> } /> + }> + } /> + } /> + } /> + } /> + + }> }> } /> @@ -52,7 +60,6 @@ export default function App() { } /> } /> - }> }> BoardList} /> diff --git a/src/constants/paths.ts b/src/constants/paths.ts index 7caeb59..bd669bb 100644 --- a/src/constants/paths.ts +++ b/src/constants/paths.ts @@ -22,7 +22,7 @@ export const SUB_PATH = { SUBMISSON: 'submission', PROBLEM: ':problemId', - PROBLEM_CREATE: 'create', + PROBLEM_CREATE: ':contestId/create', ALL_PROBLEMS: 'all-problems', ALL_CLASSES: 'all-classes', ANNOUNCEMENTS: 'announcements', @@ -32,6 +32,7 @@ export const SUB_PATH = { STUDENT_MANAGEMENT: 'student-management', CONTEST: 'contest', CONTEST_DETAIL: ':contestId', + CONTEST_PROBLEM: ':contestId/:contestProblemId', }; export const PATH: { [key: string]: string } = { diff --git a/src/pages/Class/ClassContestProblemList.tsx b/src/pages/Class/ClassContestProblemList.tsx index 751a6c9..69573c9 100644 --- a/src/pages/Class/ClassContestProblemList.tsx +++ b/src/pages/Class/ClassContestProblemList.tsx @@ -1,9 +1,10 @@ -import { useParams } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; import { Button, Heading, Table } from '@/components'; import { useContestProblemListTable, useClassContestListQuery } from './hooks'; export function ClassContestProblemList() { + const navigate = useNavigate(); const { classId, contestId } = useParams() as { classId: string; contestId: string }; const { data: { results }, @@ -12,11 +13,15 @@ export function ClassContestProblemList() { const tableProps = useContestProblemListTable(classId, contestId); + const handleCreateButtonClick = () => { + navigate('create'); + }; + return ( <>
{title} - +
From 1704d6e9d831e52991e00886b056c4de10c1f886 Mon Sep 17 00:00:00 2001 From: minkyung00 Date: Thu, 9 Feb 2023 13:53:28 +0900 Subject: [PATCH 6/6] =?UTF-8?q?feat:=20=EC=88=98=EC=97=85=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=EB=A6=AC=EB=8D=94=EB=B3=B4=EB=93=9C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=ED=8E=98=EC=9D=B4=EC=A7=80=20(#55)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Class/Problem/ProblemLeaderBoard.tsx | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/pages/Class/Problem/ProblemLeaderBoard.tsx b/src/pages/Class/Problem/ProblemLeaderBoard.tsx index ecafda5..7e50d4c 100644 --- a/src/pages/Class/Problem/ProblemLeaderBoard.tsx +++ b/src/pages/Class/Problem/ProblemLeaderBoard.tsx @@ -1,17 +1,33 @@ +import { useParams } from 'react-router-dom'; + import { Table } from '@/components'; +import { formatTime } from '@/utils/time'; + +import { useContestProblemSubmissionQuery } from './hooks'; export function ProblemLeaderBoard() { + const { classId, contestId, contestProblemId } = useParams() as { + classId: string; + contestId: string; + contestProblemId: string; + }; + /** TODO: 파일 다운로드 부분 추가 */ const column = [ { Header: '#', accessor: 'id' }, - { Header: '이름', accessor: 'name' }, + { Header: '이름', accessor: 'username' }, { Header: '점수', accessor: 'score' }, - { Header: '제출 날짜', accessor: 'time' }, - { Header: '코드(.ipynb)', accessor: 'ipynbFile' }, - { Header: '답안(.csv)', accessor: 'csvFile' }, + { Header: '제출 날짜', accessor: 'submissionDate' }, ]; - /** FIXME: 수업 상세 정보 */ - const data = [{ id: 1 }]; + /** FIXME: 새로운 api로 교체해야함 */ + const { + data: { results }, + } = useContestProblemSubmissionQuery({ classId, contestId, contestProblemId }); + + const data = results + .sort(({ score: prev }, { score: next }) => next - prev) + .sort(({ created_time: prev }, { created_time: next }) => +new Date(prev) - +new Date(next)) + .map((submission) => ({ ...submission, submissionDate: formatTime(submission.created_time) })); return
; }