diff --git a/frontend/api/quizzes/fetchQuizDetailStat.ts b/frontend/api/quizzes/fetchQuizDetailStat.ts new file mode 100644 index 00000000..d239f7eb --- /dev/null +++ b/frontend/api/quizzes/fetchQuizDetailStat.ts @@ -0,0 +1,19 @@ +import axios from "axios"; +import { axiosInstance } from "@/api/axiosInstance"; +import { ENDPOINTS } from "@/constants/endpoints"; +import { ApiResponse } from "@/types/apiResponseTypes"; +import { fetchQuizDetailStatResult } from "@/types/quizzes/fetchQuizDetailStatTypes"; + +export async function fetchQuizDetailStat(lectureId: string) { + try { + const response = await axiosInstance.get< + ApiResponse + >(ENDPOINTS.QUIZZES.GET_DETAIL_STAT(lectureId)); + return response.data; + } catch (error: unknown) { + if (axios.isAxiosError(error) && error.response) { + return error.response.data as ApiResponse; + } + throw error; + } +} diff --git a/frontend/api/quizzes/fetchQuizForDashboard.ts b/frontend/api/quizzes/fetchQuizForDashboard.ts new file mode 100644 index 00000000..626ae3f2 --- /dev/null +++ b/frontend/api/quizzes/fetchQuizForDashboard.ts @@ -0,0 +1,19 @@ +import axios from "axios"; +import { axiosInstance } from "@/api/axiosInstance"; +import { ENDPOINTS } from "@/constants/endpoints"; +import { ApiResponse } from "@/types/apiResponseTypes"; +import { fetchQuizForDashboardResult } from "@/types/quizzes/fetchQuizForDashboardTypes"; + +export async function fetchQuizForDashboard(lectureId: string) { + try { + const response = await axiosInstance.get< + ApiResponse + >(ENDPOINTS.QUIZZES.GET_FOR_DASHBOARD(lectureId)); + return response.data; + } catch (error: unknown) { + if (axios.isAxiosError(error) && error.response) { + return error.response.data as ApiResponse; + } + throw error; + } +} diff --git a/frontend/api/quizzes/fetchQuizInfo.ts b/frontend/api/quizzes/fetchQuizInfo.ts new file mode 100644 index 00000000..9c0cff5b --- /dev/null +++ b/frontend/api/quizzes/fetchQuizInfo.ts @@ -0,0 +1,19 @@ +import axios from "axios"; +import { axiosInstance } from "@/api/axiosInstance"; +import { ENDPOINTS } from "@/constants/endpoints"; +import { ApiResponse } from "@/types/apiResponseTypes"; +import { fetchQuizInfoResult } from "@/types/quizzes/fetchQuizInfoTypes"; + +export async function fetchQuizInfo(lectureId: string) { + try { + const response = await axiosInstance.get>( + ENDPOINTS.QUIZZES.GET_INFO(lectureId) + ); + return response.data; + } catch (error: unknown) { + if (axios.isAxiosError(error) && error.response) { + return error.response.data as ApiResponse; + } + throw error; + } +} diff --git a/frontend/api/quizzes/fetchSubmitList.ts b/frontend/api/quizzes/fetchSubmitList.ts new file mode 100644 index 00000000..6ea8c876 --- /dev/null +++ b/frontend/api/quizzes/fetchSubmitList.ts @@ -0,0 +1,19 @@ +import axios from "axios"; +import { axiosInstance } from "@/api/axiosInstance"; +import { ENDPOINTS } from "@/constants/endpoints"; +import { ApiResponse } from "@/types/apiResponseTypes"; +import { fetchQuizSubmitListResult } from "@/types/quizzes/fetchSubmitListTypes"; + +export async function fetchSubmitList(lectureId: string) { + try { + const response = await axiosInstance.get< + ApiResponse + >(ENDPOINTS.QUIZZES.GET_SUBMIT_LIST(lectureId)); + return response.data; + } catch (error: unknown) { + if (axios.isAxiosError(error) && error.response) { + return error.response.data as ApiResponse; + } + throw error; + } +} diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx index b9106c8a..100a80cb 100644 --- a/frontend/app/layout.tsx +++ b/frontend/app/layout.tsx @@ -1,4 +1,40 @@ import "./globals.scss"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "ClassLog", + manifest: "./manifest.webmanifest", + themeColor: "#ffffff", + appleWebApp: { + capable: true, + title: "ClassLog", + statusBarStyle: "default", + }, + icons: { + apple: [ + { + url: "/favicon/apple-touch-icon.png", + sizes: "180x180", + type: "image/png", + }, + ], + icon: [ + { + url: "/favicon/favicon-96x96.png", + sizes: "96x96", + type: "image/png", + }, + { + url: "/favicon/favicon.svg", + type: "image/svg+xml", + }, + { + url: "/favicon/favicon.ico", + type: "image/x-icon", + }, + ], + }, +}; export default function RootLayout({ children, @@ -7,25 +43,6 @@ export default function RootLayout({ }>) { return ( - - - ClassLog - - - - - - - {children} ); diff --git a/frontend/app/teacher/layout.tsx b/frontend/app/teacher/layout.tsx index fec58270..2c1fa8c3 100644 --- a/frontend/app/teacher/layout.tsx +++ b/frontend/app/teacher/layout.tsx @@ -44,12 +44,16 @@ export default function TeacherLayout({ const showSidebar = currentRoute?.sidebarType === SiderbarType.DEFAULT; const showHeader = currentRoute?.headerType !== TeacherHeaderType.NONE; + const bodyClassName = [ + "teacher-body", + showSidebar && "show-sidebar", + showHeader && "show-header", + ] + .filter(Boolean) + .join(" "); + return ( - + {showSidebar && } {renderHeader()}
{children}
diff --git a/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/DashboardContainer/DashboardContainer.tsx b/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/DashboardContainer/DashboardContainer.tsx index aadaefd3..121465ad 100644 --- a/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/DashboardContainer/DashboardContainer.tsx +++ b/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/DashboardContainer/DashboardContainer.tsx @@ -1,113 +1,32 @@ "use client"; -import React from "react"; + +import React, { useEffect, useState } from "react"; import styles from "./DashboardContainer.module.scss"; import QuizInfo from "../QuizInfo/QuizInfo"; import QuizSubmitList from "../QuizSubmitList/QuizSubmitList"; import QuizList from "../QuizList/QuizList"; import StatisticsContainer from "../StatisticsContainer/StatisticsContainer"; - -type Quiz = - | { - quizId: string; - quizOrder: number; - type: "multipleChoice"; - quizBody: string; - correctRate: number; - solution: string; - options: Array<{ optionOrder: number; option: string; count: number }>; - } - | { - quizId: string; - quizOrder: number; - type: "trueFalse"; - quizBody: string; - correctRate: number; - solution: string; - options: Array<{ optionOrder: null; option: string; count: number }>; - } - | { - quizId: string; - quizOrder: number; - type: "shortAnswer"; - quizBody: string; - correctRate: number; - solution: string; - count: number; - }; +import { fetchQuizForDashboardResult } from "@/types/quizzes/fetchQuizForDashboardTypes"; +import { fetchQuizForDashboard } from "@/api/quizzes/fetchQuizForDashboard"; +import { useParams } from "next/navigation"; export default function DashboardContainer() { - const statData: { - totalQuizCount: number; - averageCorrectRate: number; - quizList: Quiz[]; - } = { - totalQuizCount: 4, - averageCorrectRate: 57.5, - quizList: [ - { - quizId: "qz-001", - quizOrder: 1, - type: "multipleChoice", - quizBody: "앙상블 학습의 주요 목적 중 하나로 올바른 설명을 고르세요.", - correctRate: 70.0, - solution: "여러 모델을 결합해 오류를 줄이기 위해", - options: [ - { - optionOrder: 1, - option: "여러 모델을 결합해 오류를 줄이기 위해", - count: 7, - }, - { - optionOrder: 2, - option: "하나의 모델 성능을 극단적으로 향상시키기 위해", - count: 2, - }, - { - optionOrder: 3, - option: "모델의 학습 속도를 높이기 위해", - count: 0, - }, - { - optionOrder: 4, - option: "데이터를 줄여 모델을 간소화하기 위해", - count: 1, - }, - ], - }, - { - quizId: "qz-002", - quizOrder: 2, - type: "trueFalse", - quizBody: "Random Forest는 개별 트리의 가지치기를 수행하지 않는다.", - correctRate: 80.0, - solution: "O", - options: [ - { optionOrder: null, option: "O", count: 8 }, - { optionOrder: null, option: "X", count: 2 }, - ], - }, - { - quizId: "qz-003", - quizOrder: 3, - type: "shortAnswer", - quizBody: - "앙상블 기법 중 여러 모델이 각자 예측한 결과를 다수결로 결정하는 방법은 무엇인가요?", - correctRate: 50.0, - solution: "배깅", - count: 5, - }, - { - quizId: "qz-004", - quizOrder: 4, - type: "shortAnswer", - quizBody: - "Random Forest에서 개별 변수의 중요도를 평가할 때 사용하는 데이터 샘플링 기법은 무엇인가요?", - correctRate: 30.0, - solution: "복원 추출", - count: 3, - }, - ], - }; + const [statData, setStatData] = useState( + null + ); + const { lectureId } = useParams<{ lectureId: string }>(); + + useEffect(() => { + if (!lectureId) return; + fetchQuizForDashboard(lectureId).then((res) => { + if (res.isSuccess && res.result) { + setStatData(res.result); + } else { + setStatData(null); + } + }); + }, [lectureId]); + return (
@@ -115,11 +34,19 @@ export default function DashboardContainer() {
- +
); diff --git a/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/QuizInfo/QuizInfo.tsx b/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/QuizInfo/QuizInfo.tsx index 67837813..6a253dc8 100644 --- a/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/QuizInfo/QuizInfo.tsx +++ b/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/QuizInfo/QuizInfo.tsx @@ -1,12 +1,9 @@ "use client"; -import React from "react"; +import React, { useEffect, useState } from "react"; import styles from "./QuizInfo.module.scss"; - -const data = { - title: "Ensemble 1", - quizDate: "2025-06-03", - quizDay: "화", -}; +import { fetchQuizInfo } from "@/api/quizzes/fetchQuizInfo"; +import { useParams } from "next/navigation"; +import { fetchQuizInfoResult } from "@/types/quizzes/fetchQuizInfoTypes"; function formatDate(date: string, day: string) { const [yyyy, mm, dd] = date.split("-"); @@ -14,14 +11,33 @@ function formatDate(date: string, day: string) { } export default function QuizInfo() { + const { lectureId } = useParams<{ lectureId: string }>(); + const [data, setData] = useState(null); + + useEffect(() => { + if (!lectureId) return; + fetchQuizInfo(lectureId).then((res) => { + if (res.isSuccess && res.result) { + setData(res.result); + } else { + setData(null); + } + }); + }, [lectureId]); + return (
-
- [{data.title}] 퀴즈 대시보드 -
-
- {formatDate(data.quizDate, data.quizDay)} -
+ {data && ( + <> +
+ [{data.title}] + 퀴즈 대시보드 +
+
+ {formatDate(data.quizDate, data.quizDay)} +
+ + )}
); } diff --git a/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/QuizSubmitList/QuizSubmitList.tsx b/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/QuizSubmitList/QuizSubmitList.tsx index ad4b9086..9b51b660 100644 --- a/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/QuizSubmitList/QuizSubmitList.tsx +++ b/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/QuizSubmitList/QuizSubmitList.tsx @@ -1,22 +1,9 @@ "use client"; -import React from "react"; +import React, { useEffect, useState } from "react"; import styles from "./QuizSubmitList.module.scss"; - -const data = { - submitNum: 10, - studentList: [ - { name: "김클로", submitDate: "2025-06-03T15:23:00" }, - { name: "강백호", submitDate: "2025-06-03T15:23:50" }, - { name: "로하스", submitDate: "2025-06-03T15:26:45" }, - { name: "허경민", submitDate: "2025-06-03T15:29:23" }, - { name: "김민혁", submitDate: "2025-06-03T16:23:05" }, - { name: "장성우", submitDate: "2025-06-03T16:20:59" }, - { name: "천성호", submitDate: "2025-06-03T16:33:05" }, - { name: "배정대", submitDate: "2025-06-03T16:52:08" }, - { name: "김상수", submitDate: "2025-06-03T17:23:00" }, - { name: "윤준혁", submitDate: "2025-06-03T15:23:42" }, - ], -}; +import { fetchQuizSubmitListResult } from "@/types/quizzes/fetchSubmitListTypes"; +import { fetchSubmitList } from "@/api/quizzes/fetchSubmitList"; +import { useParams } from "next/navigation"; function formatDate(dateStr: string) { const d = new Date(dateStr); @@ -29,29 +16,46 @@ function formatDate(dateStr: string) { } export default function QuizSubmitList() { + const [data, setData] = useState(null); + const { lectureId } = useParams<{ lectureId: string }>(); + useEffect(() => { + if (!lectureId) return; + fetchSubmitList(lectureId).then((res) => { + if (res.isSuccess && res.result) { + setData(res.result); + } else { + setData(null); + } + }); + }, [lectureId]); + return (
-
- 퀴즈 제출 명단 - 응답자 총 {data.submitNum}명 -
-
- {data.studentList.map((student, idx) => ( -
- {student.name} - - {formatDate(student.submitDate)} - + {data && ( + <> +
+ 퀴즈 제출 명단 + 응답자 총 {data.submitNum}명 +
+
+ {data.studentList.map((student, idx) => ( +
+ {student.name} + + {formatDate(student.submitDate)} + +
+ ))}
- ))} -
+ + )}
); } diff --git a/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/StatisticsContainer/AverageCorrectRate/AverageCorrectRate.tsx b/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/StatisticsContainer/AverageCorrectRate/AverageCorrectRate.tsx index 2cc07a4d..9211ebab 100644 --- a/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/StatisticsContainer/AverageCorrectRate/AverageCorrectRate.tsx +++ b/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/StatisticsContainer/AverageCorrectRate/AverageCorrectRate.tsx @@ -1,5 +1,5 @@ "use client"; -import React from "react"; +import React, { useEffect, useState } from "react"; import { PieChart, Pie, Cell } from "recharts"; import styles from "./AverageCorrectRate.module.scss"; @@ -14,29 +14,40 @@ export default function AverageCorrectRate({ averageCorrectRate, totalQuizCount, }: AverageCorrectRateProps) { + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + const data = [ { name: "정답률", value: averageCorrectRate }, { name: "오답률", value: 100 - averageCorrectRate }, ]; + return (
- - - {data.map((entry, idx) => ( - - ))} - - + {mounted ? ( + + + {data.map((entry, idx) => ( + + ))} + + + ) : ( +
+ )}
{averageCorrectRate}%
diff --git a/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/StatisticsContainer/QuizDetailChart/QuizDetailChart.tsx b/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/StatisticsContainer/QuizDetailChart/QuizDetailChart.tsx index 05818c7f..416cc84d 100644 --- a/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/StatisticsContainer/QuizDetailChart/QuizDetailChart.tsx +++ b/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/StatisticsContainer/QuizDetailChart/QuizDetailChart.tsx @@ -1,23 +1,20 @@ "use client"; -import React from "react"; +import React, { useEffect, useState } from "react"; import { PieChart, Pie, Cell, Legend } from "recharts"; import styles from "./QuizDetailChart.module.scss"; - -// 타입 정의 예시 -export type QuizType = "multipleChoice" | "shortAnswer" | "trueFalse"; -export interface Quiz { - quizId: string; - quizOrder: number; - type: QuizType; - [key: string]: unknown; -} +import { + MultipleChoiceQuizDetail, + QuizDetailStat, + ShortAnswerQuizDetail, + TrueFalseQuizDetail, +} from "@/types/quizzes/fetchQuizDetailStatTypes"; // 색상 팔레트 const COLORS = ["#6C5CE7", "#4F8CFF", "#6AD1C9", "#B983FF"]; const OX_COLORS = ["#6AD1C9", "#4F8CFF"]; // MultipleChoiceChart: 파이차트 -function MultipleChoiceChart({ data }: { data: Quiz }) { +function MultipleChoiceChart({ data }: { data: MultipleChoiceQuizDetail }) { const chartData = [ { name: "1번", value: Number(data["1"] ?? 0) }, { name: "2번", value: Number(data["2"] ?? 0) }, @@ -58,7 +55,7 @@ function MultipleChoiceChart({ data }: { data: Quiz }) { } // TrueFalseChart: OX 파이차트 -function TrueFalseChart({ data }: { data: Quiz }) { +function TrueFalseChart({ data }: { data: TrueFalseQuizDetail }) { const chartData = [ { name: "O", value: Number(data.O ?? 0) }, { name: "X", value: Number(data.X ?? 0) }, @@ -100,7 +97,7 @@ function TrueFalseChart({ data }: { data: Quiz }) { } // ShortAnswerTop3: 리스트 -function ShortAnswerTop3({ data }: { data: Quiz }) { +function ShortAnswerTop3({ data }: { data: ShortAnswerQuizDetail }) { const top3 = data.top3Answers as { answer: string; rate: number }[]; const etcAnswers = data.etcAnswers as string[] | undefined; return ( @@ -135,7 +132,21 @@ function ShortAnswerTop3({ data }: { data: Quiz }) { } // 실제 QuizDetailChart 컴포넌트 -export default function QuizDetailChart({ quiz }: { quiz: Quiz }) { +export default function QuizDetailChart({ quiz }: { quiz: QuizDetailStat }) { + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + if (!mounted) { + return ( +
+
퀴즈{quiz.quizOrder}
+
+ ); + } + if (quiz.type === "multipleChoice") { return ; } diff --git a/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/StatisticsContainer/StatisticsContainer.tsx b/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/StatisticsContainer/StatisticsContainer.tsx index 9bfb5aca..c6946b84 100644 --- a/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/StatisticsContainer/StatisticsContainer.tsx +++ b/frontend/app/teacher/quiz-dashboard/[lectureId]/_components/StatisticsContainer/StatisticsContainer.tsx @@ -1,10 +1,17 @@ "use client"; -import React from "react"; + +import React, { useEffect, useState } from "react"; import QuizCorrectRates from "./QuizCorrectRates/QuizCorrectRates"; import AverageCorrectRate from "./AverageCorrectRate/AverageCorrectRate"; import QuizDetailChart from "./QuizDetailChart/QuizDetailChart"; import styles from "./StatisticsContainer.module.scss"; import Masonry from "react-masonry-css"; +import { + fetchQuizDetailStatResult, + QuizDetailStat, +} from "@/types/quizzes/fetchQuizDetailStatTypes"; +import { useParams } from "next/navigation"; +import { fetchQuizDetailStat } from "@/api/quizzes/fetchQuizDetailStat"; interface StatData { averageCorrectRate: number; @@ -23,46 +30,20 @@ export default function StatisticsContainer({ statData, }: StatisticsContainerProps) { // 두 번째 데이터: 퀴즈별 분포/상세용 - const detailData = [ - { - quizId: "qz-001", - quizOrder: 1, - type: "multipleChoice", - 1: 70.0, - 2: 20.0, - 3: 0.0, - 4: 10.0, - }, - { - quizId: "qz-002", - quizOrder: 2, - type: "trueFalse", - O: 80.0, - X: 20.0, - }, - { - quizId: "qz-003", - quizOrder: 3, - type: "shortAnswer", - top3Answers: [ - { answer: "배깅", rate: 50.0 }, - { answer: "부스팅", rate: 20.0 }, - { answer: "스태킹", rate: 10.0 }, - ], - etcAnswers: ["Voting", "랜덤포레스트"], - }, - { - quizId: "qz-004", - quizOrder: 4, - type: "shortAnswer", - top3Answers: [ - { answer: "복원 추출", rate: 30.0 }, - { answer: "순차 샘플링", rate: 20.0 }, - { answer: "K-켭 교차 검증", rate: 10.0 }, - ], - etcAnswers: ["부스트랩 샘플링", "계층 샘플링", "단순 샘플링"], - }, - ]; + const [detailData, setDetailData] = + useState(null); + const { lectureId } = useParams<{ lectureId: string }>(); + + useEffect(() => { + if (!lectureId) return; + fetchQuizDetailStat(lectureId).then((res) => { + if (res.isSuccess && res.result) { + setDetailData(res.result); + } else { + setDetailData(null); + } + }); + }, [lectureId]); return ( - {detailData.map((quiz) => ( - - ))} + {detailData && detailData.length > 0 ? ( + detailData.map((quiz: QuizDetailStat) => ( + + )) + ) : ( +
퀴즈 상세 통계 데이터가 없습니다.
+ )}
); } diff --git a/frontend/app/teacher/quiz-dashboard/[lectureId]/page.tsx b/frontend/app/teacher/quiz-dashboard/[lectureId]/page.tsx index 1bf410e3..cfc67944 100644 --- a/frontend/app/teacher/quiz-dashboard/[lectureId]/page.tsx +++ b/frontend/app/teacher/quiz-dashboard/[lectureId]/page.tsx @@ -1,4 +1,5 @@ "use client"; + import BackButtonHeader from "./_components/BackButtonHeader/BackButtonHeader"; import DashboardContainer from "./_components/DashboardContainer/DashboardContainer"; import style from "./page.module.scss"; diff --git a/frontend/constants/endpoints.ts b/frontend/constants/endpoints.ts index 963b1d19..20644009 100644 --- a/frontend/constants/endpoints.ts +++ b/frontend/constants/endpoints.ts @@ -105,12 +105,20 @@ export const ENDPOINTS = { // 퀴즈 관련 QUIZZES: { + GET_DETAIL_STAT: (lectureId: string) => + `${BASE_API}/quizzes/${lectureId}/result/statistics`, + GET_SUBMIT_LIST: (lectureId: string) => + `${BASE_API}/quizzes/${lectureId}/result/list`, + GET_INFO: (lectureId: string) => + `${BASE_API}/quizzes/${lectureId}/result/info`, CREATE: (lectureId: string) => `${BASE_API}/quizzes/${lectureId}/create`, RECREATE: (lectureId: string) => `${BASE_API}/quizzes/${lectureId}/re-create`, SAVE: (lectureId: string) => `${BASE_API}/quizzes/${lectureId}/save`, UPDATE: (lectureId: string) => `${BASE_API}/quizzes/${lectureId}`, GET: (lectureId: string) => `${BASE_API}/quizzes/${lectureId}`, + GET_FOR_DASHBOARD: (lectureId: string) => + `${BASE_API}/quizzes/${lectureId}/result`, SUBMIT: `${BASE_API}/quizzes/submit`, GET_RESULT: (lectureId: string) => `${BASE_API}/quizzes/${lectureId}/result/student`, diff --git a/frontend/types/quizzes/fetchQuizDetailStatTypes.ts b/frontend/types/quizzes/fetchQuizDetailStatTypes.ts new file mode 100644 index 00000000..cc3d38a9 --- /dev/null +++ b/frontend/types/quizzes/fetchQuizDetailStatTypes.ts @@ -0,0 +1,35 @@ +export type fetchQuizDetailStatResult = QuizDetailStat[]; + +export type QuizDetailStat = + | MultipleChoiceQuizDetail + | TrueFalseQuizDetail + | ShortAnswerQuizDetail; + +export interface MultipleChoiceQuizDetail { + quizId: string; + quizOrder: number; + type: "multipleChoice"; + "1": number; + "2": number; + "3": number; + "4": number; +} + +export interface TrueFalseQuizDetail { + quizId: string; + quizOrder: number; + type: "trueFalse"; + O: number; + X: number; +} + +export interface ShortAnswerQuizDetail { + quizId: string; + quizOrder: number; + type: "shortAnswer"; + top3Answers: Array<{ + answer: string; + rate: number; + }>; + etcAnswers: string[]; +} diff --git a/frontend/types/quizzes/fetchQuizForDashboardTypes.ts b/frontend/types/quizzes/fetchQuizForDashboardTypes.ts new file mode 100644 index 00000000..4061eab9 --- /dev/null +++ b/frontend/types/quizzes/fetchQuizForDashboardTypes.ts @@ -0,0 +1,34 @@ +export interface fetchQuizForDashboardResult { + totalQuizCount: number; + averageCorrectRate: number; + quizList: Quiz[]; +} + +type Quiz = + | { + quizId: string; + quizOrder: number; + type: "multipleChoice"; + quizBody: string; + correctRate: number; + solution: string; + options: Array<{ optionOrder: number; option: string; count: number }>; + } + | { + quizId: string; + quizOrder: number; + type: "trueFalse"; + quizBody: string; + correctRate: number; + solution: string; + options: Array<{ optionOrder: null; option: string; count: number }>; + } + | { + quizId: string; + quizOrder: number; + type: "shortAnswer"; + quizBody: string; + correctRate: number; + solution: string; + count: number; + }; diff --git a/frontend/types/quizzes/fetchQuizInfoTypes.ts b/frontend/types/quizzes/fetchQuizInfoTypes.ts new file mode 100644 index 00000000..e5a33157 --- /dev/null +++ b/frontend/types/quizzes/fetchQuizInfoTypes.ts @@ -0,0 +1,5 @@ +export interface fetchQuizInfoResult { + title: string; + quizDate: string; + quizDay: string; +} diff --git a/frontend/types/quizzes/fetchSubmitListTypes.ts b/frontend/types/quizzes/fetchSubmitListTypes.ts new file mode 100644 index 00000000..78a1fad6 --- /dev/null +++ b/frontend/types/quizzes/fetchSubmitListTypes.ts @@ -0,0 +1,7 @@ +export interface fetchQuizSubmitListResult { + submitNum: number; + studentList: { + name: string; + submitDate: string; + }[]; +}