-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #58 from sos-sejong-opensource-software/problem
feat: 수업 문제 상세 조회 - 리더보드 / 제출
- Loading branch information
Showing
18 changed files
with
346 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <Problem menuList={menuList} data={data} />; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <Table column={column} data={data} />; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 ( | ||
<> | ||
<form className="flex flex-col gap-2 mb-10"> | ||
<Heading as="h4">csv 파일 제출</Heading> | ||
<p>하나의 csv 파일만 업로드 가능합니다</p> | ||
<Input type="file" accept=".csv" /> | ||
const { mutate: createSubmission } = useCreateContestProblemSubmissionMutation(); | ||
const { mutate: createSubmissionCheck } = useCreateContestProblemSubmissionCheckMutation(); | ||
|
||
const handleFileSumbit = (e: React.FormEvent<HTMLFormElement>) => { | ||
e.preventDefault(); | ||
|
||
<Heading as="h4">ipynb 파일 제출</Heading> | ||
<p>하나의 ipynb 파일만 업로드 가능합니다</p> | ||
<Input type="file" accept=".ipynb" /> | ||
const [csv, ipynb] = Object.values(e.target).map(({ files }) => files && files[0]); | ||
|
||
<Button className="inline-block">파일 제출</Button> | ||
</form> | ||
const formData = new FormData(); | ||
formData.append('csv', csv); | ||
formData.append('ipynb', ipynb); | ||
|
||
<Heading as="h4">제출 내역</Heading> | ||
<p>선택한 제출 내역이 리더보드에 표시됩니다.</p> | ||
<Table column={column} data={data} /> | ||
createSubmission({ classId, contestId, contestProblemId, payload: formData }); | ||
}; | ||
|
||
const handleCheckSubmit = (e: React.FormEvent<HTMLFormElement>) => { | ||
e.preventDefault(); | ||
|
||
const { id } = Object.values(e.target).find(({ checked }) => checked); | ||
createSubmissionCheck({ classId, contestId, contestProblemId, payload: { id } }); | ||
}; | ||
|
||
return ( | ||
<> | ||
<FileSubmissionForm onSubmit={handleFileSumbit} /> | ||
<LeaderboardSubmissionForm onSubmit={handleCheckSubmit} /> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Heading, Input, Button } from '@/components'; | ||
|
||
type FileSubmissionFormProps<T extends React.ElementType> = Component<T>; | ||
|
||
export function FileSubmissionForm({ ...props }: FileSubmissionFormProps<'form'>) { | ||
return ( | ||
<form className="flex flex-col gap-2 mb-10" {...props}> | ||
<Heading as="h4">csv 파일 제출</Heading> | ||
<p>하나의 csv 파일만 업로드 가능합니다</p> | ||
<Input type="file" accept=".csv" /> | ||
|
||
<Heading as="h4">ipynb 파일 제출</Heading> | ||
<p>하나의 ipynb 파일만 업로드 가능합니다</p> | ||
<Input type="file" accept=".ipynb" /> | ||
|
||
<Button className="inline-block">파일 제출</Button> | ||
</form> | ||
); | ||
} |
47 changes: 47 additions & 0 deletions
47
src/pages/Class/Problem/components/LeaderboardSubmissionForm.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<T extends React.ElementType> = Component<T>; | ||
|
||
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: <input type="checkbox" id={submission.id} />, | ||
submissionDate: formatTime(submission.created_time), | ||
})); | ||
|
||
return ( | ||
<form className="flex flex-col gap-2 mb-10" {...props}> | ||
<Heading as="h4">제출 내역</Heading> | ||
<p>선택한 제출 내역이 리더보드에 표시됩니다.</p> | ||
<Table column={column} data={data} /> | ||
<Button>제출</Button> | ||
</form> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
export * from './Problem'; | ||
export * from './FileSubmissionForm'; | ||
export * from './LeaderboardSubmissionForm'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,6 @@ | ||
export * from './useProblemQuery'; | ||
export * from './useCreateProblemMutation'; | ||
export * from './useContestProblemQuery'; | ||
export * from './useContestProblemSubmissionQuery'; | ||
export * from './useCreateContestProblemSubmissionMutation'; | ||
export * from './useCreateContestProblemSubmissionCheckMutation'; |
24 changes: 24 additions & 0 deletions
24
src/pages/Class/Problem/hooks/query/useContestProblemQuery.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<Problem, AxiosError, Problem, string[]> | ||
) => { | ||
const { classId, contestId, contestProblemId } = params; | ||
return useSuspenseQuery( | ||
[QUERY_KEYS.CLASS_CONTEST_PROBLEM, classId, contestId, contestProblemId], | ||
async () => { | ||
const { data } = await getContestProblem(params); | ||
return data; | ||
}, | ||
{ | ||
...options, | ||
} | ||
); | ||
}; |
29 changes: 29 additions & 0 deletions
29
src/pages/Class/Problem/hooks/query/useContestProblemSubmissionQuery.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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, | ||
} | ||
); | ||
}; |
Oops, something went wrong.