From b29dd94f6e2b25dbef28461aa8194e8a4671d6a2 Mon Sep 17 00:00:00 2001 From: Yechan Jung Date: Fri, 8 Mar 2024 16:09:34 +0900 Subject: [PATCH] feat:ranking-UI (#283) --- client/src/apis/scoreBoard.ts | 24 +++++++++ client/src/apis/scores.ts | 15 ------ client/src/pages/Room/ScoreBoard/Players.tsx | 21 ++++++-- .../src/pages/Room/ScoreBoard/ScoreBoard.tsx | 49 +++++++++++++------ .../Room/ScoreBoard/ScoreBoardButton.tsx | 8 +-- .../pages/Room/ScoreBoard/ScoreBoardModal.tsx | 7 ++- client/src/types/Ranking.ts | 3 +- client/src/types/Score.ts | 13 ----- client/src/types/ScoreBoardInformation.ts | 7 +++ client/src/types/Submission.ts | 13 +++++ 10 files changed, 101 insertions(+), 59 deletions(-) create mode 100644 client/src/apis/scoreBoard.ts delete mode 100644 client/src/apis/scores.ts delete mode 100644 client/src/types/Score.ts create mode 100644 client/src/types/ScoreBoardInformation.ts create mode 100644 client/src/types/Submission.ts diff --git a/client/src/apis/scoreBoard.ts b/client/src/apis/scoreBoard.ts new file mode 100644 index 0000000..ab363ee --- /dev/null +++ b/client/src/apis/scoreBoard.ts @@ -0,0 +1,24 @@ +import { apiClient } from './apiClient'; +import { ScoreBoardInformation } from '../types/ScoreBoardInformation'; + +export async function getScoreBoardInformation( + roomCode: string, +): Promise { + try { + const { data: submissionData } = await apiClient.get('/submission', { + params: { + roomCode, + }, + }); + + const { data: rankingData } = await apiClient.get('/submission/ranking', { + params: { + roomCode, + }, + }); + + return { submissions: submissionData, rankings: rankingData }; + } catch (error) { + throw new Error('getScores error'); + } +} diff --git a/client/src/apis/scores.ts b/client/src/apis/scores.ts deleted file mode 100644 index eaf3b9c..0000000 --- a/client/src/apis/scores.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Score } from '../types/Score'; -import { apiClient } from './apiClient'; - -export async function getScores(roomCode: string): Promise { - try { - const { data } = await apiClient.get('/submission', { - params: { - roomCode, - }, - }); - return data; - } catch (error) { - throw new Error('getScores error'); - } -} diff --git a/client/src/pages/Room/ScoreBoard/Players.tsx b/client/src/pages/Room/ScoreBoard/Players.tsx index de67bdb..7697521 100644 --- a/client/src/pages/Room/ScoreBoard/Players.tsx +++ b/client/src/pages/Room/ScoreBoard/Players.tsx @@ -1,22 +1,33 @@ import { RxBorderSolid, RxCheck, RxCross1 } from 'react-icons/rx'; -import { Score, Status } from '../../../types/Score'; +import { Submission, Status } from '../../../types/Submission'; interface PlayersProps { index: number; playerName: string; - results: Score[]; + results: Submission[]; } export default function Players({ index, playerName, results }: PlayersProps) { + const getOrdinal = (n: number) => { + if (n === 1) return '1st'; + else if (n === 2) return '2nd'; + else if (n === 3) return '3rd'; + else return n + 'th'; + }; return (
  • -
    {playerName}
    +
    + {getOrdinal(index + 1)} +
    +
    {playerName}
      - {results.map((result,index) => ( -
    1. + {results.map((result, index) => ( +
    2. {result.status === Status.ACCEPTED ? ( ) : result.status === Status.WRONG ? ( diff --git a/client/src/pages/Room/ScoreBoard/ScoreBoard.tsx b/client/src/pages/Room/ScoreBoard/ScoreBoard.tsx index 8502e5e..7b01910 100644 --- a/client/src/pages/Room/ScoreBoard/ScoreBoard.tsx +++ b/client/src/pages/Room/ScoreBoard/ScoreBoard.tsx @@ -1,36 +1,53 @@ import { useRoom } from '../../../hooks/useRoom'; -import { Score } from '../../../types/Score'; +import { ScoreBoardInformation } from '../../../types/ScoreBoardInformation'; +import { Submission } from '../../../types/Submission'; import Players from './Players'; interface ScoreBoardProps { - scores: Score[]; + scores: ScoreBoardInformation; +} + +interface PlayerScore { + playerName: string; + results: Submission[]; } export default function ScoreBoard({ scores }: ScoreBoardProps) { const { participantNames, problems } = useRoom().roomInfo; - const playerNames: string[] = participantNames; const problemIds: number[] = problems.map((problem) => problem.bojProblemId); - const playerScores: Array<{ playerName: string; results: Score[] }> = - playerNames.map((playerName) => { - const results: Score[] = problemIds.map((problemId) => { - const score = scores.find( - (score) => - score.username === playerName && score.bojProblemId === problemId, - ); - return score - ? score - : { username: playerName, bojProblemId: problemId, status: 'WAITING' }; - }); - return { playerName: playerName, results: results }; + const playerScores: PlayerScore[] = playerNames.map((playerName) => { + const results: Submission[] = problemIds.map((problemId) => { + const submissions = scores.submissions.find( + (score) => + score.username === playerName && score.bojProblemId === problemId, + ); + return ( + submissions || { + username: playerName, + bojProblemId: problemId, + status: 'WAITING', + } + ); }); + return { playerName, results }; + }); + const sortedPlayerScores: PlayerScore[] = scores.rankings + .map((ranking) => + playerScores.find( + (playerScore) => playerScore.playerName === ranking.username, + ), + ) + .filter( + (playerScore): playerScore is PlayerScore => playerScore !== undefined, + ); return (
        - {playerScores.map((playerScore, index) => ( + {sortedPlayerScores.map((playerScore, index) => ( ([]); + const [scores, setScores] = useState({submissions: [], rankings: []}); const modalOverlayRef = useRef(null); const { roomCode, roomInfo } = useRoom(); const openModal = async () => { try { - const res = await getScores(roomCode); + const res : ScoreBoardInformation = await getScoreBoardInformation(roomCode); setScores(res); } catch (e) { console.log(e); diff --git a/client/src/pages/Room/ScoreBoard/ScoreBoardModal.tsx b/client/src/pages/Room/ScoreBoard/ScoreBoardModal.tsx index d331287..716a3a3 100644 --- a/client/src/pages/Room/ScoreBoard/ScoreBoardModal.tsx +++ b/client/src/pages/Room/ScoreBoard/ScoreBoardModal.tsx @@ -2,16 +2,15 @@ import ScoreBoard from './ScoreBoard'; import { FaChartSimple, FaXmark } from 'react-icons/fa6'; import { RefObject } from 'react'; import { useTheme } from '../../../hooks/useTheme'; -import { Score } from '../../../types/Score'; +import { ScoreBoardInformation } from '../../../types/ScoreBoardInformation'; interface ModalProps { - scores: Score[]; + scores: ScoreBoardInformation; modalOverlayRef: RefObject; closeModal: () => void; modalOutsideClick: (arg: React.MouseEvent) => void; } - const iconStyle = { fontSize: '1.5rem', }; @@ -44,7 +43,7 @@ export default function ScoreBoardModal({
        3 online
        - + ); diff --git a/client/src/types/Ranking.ts b/client/src/types/Ranking.ts index dd075ef..3693dcf 100644 --- a/client/src/types/Ranking.ts +++ b/client/src/types/Ranking.ts @@ -1,6 +1,5 @@ export interface Ranking { - id: number; username: string; numberOfProblemsSolved: number; - mostRecentCorrectSubmissionTime: string | null; // is nullable? + mostRecentCorrectSubmissionTime: string | null; } \ No newline at end of file diff --git a/client/src/types/Score.ts b/client/src/types/Score.ts deleted file mode 100644 index 37f3721..0000000 --- a/client/src/types/Score.ts +++ /dev/null @@ -1,13 +0,0 @@ -export interface Score { - "username": string, - "bojProblemId": number, - "status" : Status -} - -export const Status = { - ACCEPTED : "ACCEPTED", - WRONG : "WRONG", - WAITING : "WAITING" -} as const; - -type Status = typeof Status[keyof typeof Status]; \ No newline at end of file diff --git a/client/src/types/ScoreBoardInformation.ts b/client/src/types/ScoreBoardInformation.ts new file mode 100644 index 0000000..82e13dc --- /dev/null +++ b/client/src/types/ScoreBoardInformation.ts @@ -0,0 +1,7 @@ +import { Submission } from './Submission'; +import { Ranking } from './Ranking'; + +export interface ScoreBoardInformation { + submissions: Submission[]; + rankings: Ranking[]; +} diff --git a/client/src/types/Submission.ts b/client/src/types/Submission.ts new file mode 100644 index 0000000..c6288b2 --- /dev/null +++ b/client/src/types/Submission.ts @@ -0,0 +1,13 @@ +export interface Submission { + username: string; + bojProblemId: number; + status: Status; +} + +export const Status = { + ACCEPTED: 'ACCEPTED', + WRONG: 'WRONG', + WAITING: 'WAITING', +} as const; + +type Status = (typeof Status)[keyof typeof Status];