-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* feat: recharts 설치 * feat: 총제출 수를 표현하는 그래프 컴포넌트 * feat: 최근 제출 답안 컴포넌트 추가 * feat: 통계 카드 추가 * feat: 마스터 퀴즈 세션 추가
- Loading branch information
Showing
41 changed files
with
946 additions
and
4 deletions.
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added
BIN
+24.9 KB
.yarn/cache/@types-d3-interpolate-npm-3.0.4-e863f31b1c-066ebb8da5.zip
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added
BIN
+247 KB
.yarn/cache/react-transition-group-npm-4.4.5-98ea4ef96e-2ba754ba74.zip
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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
113 changes: 113 additions & 0 deletions
113
packages/client/src/pages/quiz-master-session/index.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,113 @@ | ||
import { useParams } from 'react-router-dom'; | ||
import StatisticsCard from './ui/StatisticsCard'; | ||
|
||
import { useEffect, useState } from 'react'; | ||
import ProgressBar from '@/shared/ui/progress-bar/ProgressBar'; | ||
import { CustomButton } from '@/shared/ui/buttons'; | ||
import AnswerGraph from '@/pages/quiz-master-session/ui/AnswerChart'; | ||
import RecentSubmittedAnswers from './ui/RecentSubmittedAnswers'; | ||
|
||
interface AnswerStat { | ||
answer: string; | ||
count: number; | ||
color: string; | ||
} | ||
|
||
const statisticsCardItems = [ | ||
{ | ||
title: '총 제출', | ||
value: 35, | ||
unit: '명', | ||
color: 'text-green-500', | ||
subDescription: '+22명 남음', | ||
}, | ||
{ | ||
title: '정답률', | ||
value: 65, | ||
unit: '%', | ||
color: 'text-blue-500', | ||
subDescription: '평균 대비 +5%', | ||
}, | ||
{ | ||
title: '평균 풀이 시간', | ||
value: 5, | ||
unit: '초', | ||
color: 'text-orange-500', | ||
subDescription: '목표 시간 내 해결', | ||
}, | ||
{ | ||
title: '평균 정답률', | ||
value: 60, | ||
unit: '%', | ||
color: 'text-purple-500', | ||
subDescription: '목표 85% 미달성', | ||
}, | ||
]; | ||
|
||
const limitedTime = 20; | ||
|
||
export default function QuizMasterSession() { | ||
const { quizId } = useParams(); | ||
|
||
const [answerStats, setAnswerStats] = useState<AnswerStat[]>([ | ||
{ answer: '1번', count: 10, color: '#3B82F6' }, | ||
{ answer: '2번', count: 20, color: '#F87171' }, | ||
{ answer: '3번', count: 15, color: '#34D399' }, | ||
{ answer: '4번', count: 25, color: '#FBBF24' }, | ||
]); | ||
|
||
const [time, setTime] = useState<number | string>(limitedTime); | ||
|
||
const tick = () => { | ||
setTime((prev) => { | ||
if (typeof prev === 'string') return '종료'; | ||
if (prev === 0) return '종료'; | ||
return prev - 1; | ||
}); | ||
// 랜덤 데이터 생성 | ||
setAnswerStats((prev) => { | ||
return prev.map((item) => { | ||
return { | ||
...item, | ||
count: Math.floor(Math.random() * 100), | ||
}; | ||
}); | ||
}); | ||
}; | ||
|
||
useEffect(() => { | ||
const timer = setInterval(() => { | ||
tick(); | ||
}, 1000); | ||
return () => clearInterval(timer); | ||
}, []); | ||
return ( | ||
<div className="w-screen min-h-screen"> | ||
<div className="p-5"> | ||
<div className="flex justify-between"> | ||
<div> | ||
<h1 className="text-xl font-bold mb-2">실시간 통계</h1> | ||
<p className="text-2xl font-bold mb-2">{quizId}Q. 퀴즈 제목</p> | ||
</div> | ||
<div> | ||
<p className="font-bold text-gray-500 mb-2">제한 시간 {time}</p> | ||
<div className="mb-2"> | ||
<CustomButton label="다음 퀴즈" type="full" /> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<ProgressBar time={limitedTime} type="info" /> | ||
</div> | ||
<div className="grid grid-cols-4 gap-6 mb-8 mx-5"> | ||
{statisticsCardItems.map((item) => ( | ||
<StatisticsCard key={item.title} {...item} /> | ||
))} | ||
</div> | ||
<div className="grid grid-cols-[3fr_1fr] gap-4 mx-5"> | ||
<AnswerGraph answerStats={answerStats} /> | ||
<RecentSubmittedAnswers answerStats={answerStats} /> | ||
</div> | ||
</div> | ||
); | ||
} |
35 changes: 35 additions & 0 deletions
35
packages/client/src/pages/quiz-master-session/ui/AnswerChart.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,35 @@ | ||
import { | ||
ResponsiveContainer, | ||
BarChart, | ||
CartesianGrid, | ||
XAxis, | ||
YAxis, | ||
Tooltip, | ||
Bar, | ||
Legend, | ||
} from 'recharts'; | ||
|
||
interface AnswerStat { | ||
answer: string; | ||
count: number; | ||
color: string; | ||
} | ||
|
||
interface AnswerStatProps { | ||
answerStats: AnswerStat[]; | ||
} | ||
|
||
export default function AnswerGraph({ answerStats }: AnswerStatProps) { | ||
return ( | ||
<ResponsiveContainer width="100%" height="100%"> | ||
<BarChart data={answerStats} barSize={60}> | ||
<CartesianGrid strokeDasharray="3 3" /> | ||
<XAxis dataKey="answer" axisLine={false} tickLine={false} /> | ||
<YAxis axisLine={false} tickLine={false} tickCount={6} /> | ||
<Tooltip /> | ||
<Legend /> | ||
<Bar dataKey="count" fill="primary" fillOpacity={0.8} /> | ||
</BarChart> | ||
</ResponsiveContainer> | ||
); | ||
} |
64 changes: 64 additions & 0 deletions
64
packages/client/src/pages/quiz-master-session/ui/RecentSubmittedAnswers.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,64 @@ | ||
import { useEffect, useState } from 'react'; | ||
|
||
interface AnswerStat { | ||
answer: string; | ||
count: number; | ||
color: string; | ||
} | ||
|
||
// TODO: 실시간으로 변경되는 데이터를 받아야 함 | ||
interface RecentSubmittedAnswersProps { | ||
answerStats: AnswerStat[]; | ||
} | ||
|
||
const MAX_RECENT_SUBMITTED_ANSWERS = 8; | ||
export default function RecentSubmittedAnswers({ answerStats }: RecentSubmittedAnswersProps) { | ||
const [time, setTime] = useState(0); | ||
|
||
const tick = () => { | ||
setTime((prev) => prev + 1); | ||
}; | ||
|
||
useEffect(() => { | ||
const timer = setInterval(tick, 1000); | ||
return () => clearInterval(timer); | ||
}, []); | ||
return ( | ||
<div> | ||
<div className="col-span-2 bg-white rounded-xl shadow-sm border border-gray-100"> | ||
<div className="p-4 border-b border-gray-100"> | ||
<h3 className="font-semibold">최근 제출 답안</h3> | ||
</div> | ||
<div className="divide-y"> | ||
{[...Array(MAX_RECENT_SUBMITTED_ANSWERS)].map((_, i) => ( | ||
<div | ||
key={i} | ||
className="p-4 flex items-center justify-between hover:bg-gray-50 transition-colors" | ||
> | ||
<div className="flex items-center space-x-4"> | ||
<div | ||
className="w-8 h-8 rounded-full flex items-center justify-center text-white font-medium" | ||
style={{ | ||
backgroundColor: answerStats[Math.floor(Math.random() * 4)].color, | ||
}} | ||
> | ||
{String.fromCharCode(65 + Math.floor(Math.random() * 4))} | ||
</div> | ||
<div> | ||
<p className="font-medium">학생 {i + 1}</p> | ||
<p className="text-sm text-gray-500">{time}초 전 제출</p> | ||
</div> | ||
</div> | ||
<div className="flex items-center space-x-4"> | ||
{/* 제출 시 걸리는 시간 */} | ||
<span className="px-2 py-1 rounded-full text-sm bg-gray-100 text-gray-600"> | ||
45초 | ||
</span> | ||
</div> | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
27 changes: 27 additions & 0 deletions
27
packages/client/src/pages/quiz-master-session/ui/StatisticsCard.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,27 @@ | ||
interface StatisticsCardProps { | ||
title: string; | ||
value: number; | ||
unit: string; | ||
color: string; | ||
subDescription: string; | ||
} | ||
|
||
export default function StatisticsCard({ | ||
title, | ||
value, | ||
unit, | ||
color, | ||
subDescription, | ||
}: StatisticsCardProps) { | ||
return ( | ||
<div className="bg-white rounded-xl p-6 shadow-sm border border-gray-100"> | ||
<div className="flex justify-between items-center"> | ||
<div> | ||
<p className="text-gray-500 text-md">{title}</p> | ||
<p className="text-2xl font-bold">{`${value}${unit}`}</p> | ||
<p className={`${color} text-md`}>{subDescription}</p> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.