Merge branch 'fe/studentReport' into 'frontend'

[Front-end] feat: 학생 퀴즈성적 전체 조회페이지 추가

See merge request s11-webmobile1-sub2/S11P12A701!89
This commit is contained in:
정기영 2024-08-07 16:06:31 +09:00
commit 69c6cee3ab
10 changed files with 206 additions and 1 deletions

View File

@ -37,6 +37,7 @@ const CreateFreeboardPage = lazy(async () => await import('./pages/CreateFreeboa
const FreeboardDetailPage = lazy(async () => await import('./pages/FreeboardDetailPage')); const FreeboardDetailPage = lazy(async () => await import('./pages/FreeboardDetailPage'));
const EditFreeboardPage = lazy(async () => await import('./pages/EditFreeboardPage')); const EditFreeboardPage = lazy(async () => await import('./pages/EditFreeboardPage'));
const PasswordResetAuthPage = lazy(async () => await import('./pages/PasswordResetAuthPage')); const PasswordResetAuthPage = lazy(async () => await import('./pages/PasswordResetAuthPage'));
const StudentReportPage = lazy(async () => await import('./pages/StudentReportPage'));
const LivePage = lazy(async () => await import('./pages/LivePage')); const LivePage = lazy(async () => await import('./pages/LivePage'));
const router = createBrowserRouter([ const router = createBrowserRouter([
@ -77,6 +78,14 @@ const router = createBrowserRouter([
index: true, index: true,
element: <LearningLectureDetailPage />, element: <LearningLectureDetailPage />,
}, },
{
path: 'report',
element: <StudentReportPage />,
},
// {
// path: 'report/:reportId',
// element:
// },
{ {
path: 'edit', path: 'edit',
element: <LectureEditPage />, element: <LectureEditPage />,

View File

@ -54,7 +54,8 @@ export default function LectureLayout() {
<SideLink to={'notice'}>공지사항</SideLink> <SideLink to={'notice'}>공지사항</SideLink>
<SideLink to={'qna'}>Q&A</SideLink> <SideLink to={'qna'}>Q&A</SideLink>
<SideLink to={'freeboard'}>자유게시판</SideLink> <SideLink to={'freeboard'}>자유게시판</SideLink>
<SideLink to={'quiz'}>퀴즈</SideLink> {userType === 'student' && <SideLink to={'report'}>퀴즈 성적</SideLink>}
{userType === 'teacher' && <SideLink to={'quiz'}>퀴즈</SideLink>}
{userType === 'teacher' && <SideLink to={'enroll'}>수강신청관리</SideLink>} {userType === 'teacher' && <SideLink to={'enroll'}>수강신청관리</SideLink>}
</SideBar> </SideBar>
{userType === 'teacher' && ( {userType === 'teacher' && (

View File

@ -0,0 +1,44 @@
import styles from './ReportCard.module.css';
export default function ReportCard({ allCount = 10, correctCount = 7 }) {
const radius = 2 * Math.PI * 100;
const percentage = allCount > 0 ? (correctCount / allCount) * 100 : 0;
const strokeDashoffset = radius - (percentage / 100) * radius;
return (
<div className={styles.wrapper}>
<div className={styles.svgWrapper}>
<svg
width="220"
height="220"
viewBox="0 0 220 220"
>
<circle
cx="110"
cy="110"
r="100"
strokeDasharray={radius}
strokeDashoffset={strokeDashoffset}
transform="rotate(-90 110 110)"
className={styles.circle}
/>
<text
x="50%"
y="50%"
textAnchor="middle"
dominantBaseline="middle"
className={`${styles.bodyStrong} ${styles.centerText}`}
>
{`점수 : ${Math.round(percentage)}`}
</text>
</svg>
</div>
<div className={styles.stats}>
<span className={styles.bodyStrong}> 성적</span>
<span className={styles.body}>
{correctCount} / {allCount}
</span>
</div>
</div>
);
}

View File

@ -0,0 +1,44 @@
.wrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
border: 1px solid var(--border-color);
border-radius: 16px;
gap: 20px;
padding: 36px 40px;
width: 295px;
height: 388px;
}
.svgWrapper {
position: relative;
text-align: center;
}
.circle {
fill: none;
stroke: var(--success-color);
stroke-width: 20px;
stroke-linecap: round;
border-radius: 10px;
}
.stats {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.bodyStrong {
font-size: 16px;
line-height: 1.4;
font-weight: 700;
}
.body {
font-size: 16px;
line-height: 1.4;
font-weight: 400;
}

View File

@ -0,0 +1 @@
export { default as ReportCard } from './ReportCard';

View File

@ -0,0 +1,10 @@
import { useSuspenseQuery } from '@tanstack/react-query';
import instance from '../../utils/axios/instance';
import { API_URL } from '../../constants';
export function useStudentReportDetail(reportId) {
return useSuspenseQuery({
queryKey: ['studentreportdetail', reportId],
queryFn: () => instance.get(`${API_URL}/report/myreportdetail/${reportId}`),
});
}

View File

@ -0,0 +1,10 @@
import { useSuspenseQuery } from '@tanstack/react-query';
import instance from '../../utils/axios/instance';
import { API_URL } from '../../constants';
export function useStudentReports() {
return useSuspenseQuery({
queryKey: ['studentreports'],
queryFn: () => instance.get(`${API_URL}/report/myreport`),
});
}

View File

@ -0,0 +1,71 @@
import { ArticleLink } from '../../components/ArticleLink';
import ArticleBoard from '../../components/ArticleBoard/ArticleBoard';
import { ReportCard } from '../../components/ReportCard';
import styles from './StudentReportPage.module.css';
import { useStudentReports } from '../../hooks/api/useStudentReports';
export default function StudentReportPage() {
const { data } = useStudentReports();
// const reports = data?.data;
const reports = [
{
reportId: 1,
title: '퀴즈 1',
correctCount: 8,
allCount: 10,
},
{
reportId: 2,
title: '퀴즈 2',
correctCount: 7,
allCount: 10,
},
{
reportId: 3,
title: '퀴즈 3',
correctCount: 9,
allCount: 10,
},
{
reportId: 4,
title: '퀴즈 4',
correctCount: 6,
allCount: 10,
},
];
const totalCounts = reports.reduce(
(acc, report) => {
acc.correctCount += report.correctCount;
acc.allCount += report.allCount;
return acc;
},
{ correctCount: 0, allCount: 0 }
);
return (
<ArticleBoard
title="퀴즈 성적"
canCreate={false}
>
<div className={styles.wrapper}>
<div className={styles.LinksContainer}>
{reports.map?.((report) => (
<ArticleLink
key={`${report.reportId}`}
title={report.title}
sub={`${Math.round((report.correctCount / report.allCount) * 100)}%`}
to={`${report.reportId}`}
/>
))}
</div>
<div className={styles.reportCardContainer}>
<ReportCard
correctCount={totalCounts.correctCount}
allCount={totalCounts.allCount}
/>
</div>
</div>
</ArticleBoard>
);
}

View File

@ -0,0 +1,14 @@
.wrapper {
display: flex;
justify-content: space-between;
gap: 40px;
flex: 1 0 0;
}
.LinksContainer {
flex: 1;
}
.reportCardContainer {
flex: 0 0 auto;
}

View File

@ -0,0 +1 @@
export { default } from './StudentReportPage';