Skip to content

Commit 96a8269

Browse files
authored
Merge pull request #76 from INU-Software-Design/NEEIS-67-feature/grade-page
โฌ†๏ธ update : ์ž์ž˜ํ•œ ์ˆ˜์ •์‚ฌํ•ญ๋“ค ์—…๋ฐ์ดํŠธ
2 parents 3a9a40c + d01e414 commit 96a8269

8 files changed

Lines changed: 117 additions & 9 deletions

File tree

โ€Žpackage-lock.jsonโ€Ž

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

โ€Žsrc/__test__/grade/GradesPage.test.tsxโ€Ž

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,20 @@ jest.mock("@/store/grade-filter-store", () => ({
2222
default: () => ({
2323
year: "2025",
2424
semester: "1",
25-
subject: "์ˆ˜ํ•™",
25+
subject: "๋…์„œ์™€ ๋ฌธ๋ฒ•",
26+
}),
27+
}));
28+
jest.mock("@/store/teacher-store", () => ({
29+
__esModule: true,
30+
default: () => ({
31+
mysubject: "๋…์„œ์™€ ๋ฌธ๋ฒ•",
32+
setSubject: jest.fn(),
33+
setGrade: jest.fn(),
34+
setTeacherName: jest.fn(),
35+
setClassNumber: jest.fn(),
36+
grade: "1",
37+
classNumber: "1",
38+
teacherName: "๊น€์ฒ ์ˆ˜",
2639
}),
2740
}));
2841

@@ -106,8 +119,11 @@ jest.mock("@/components/shared/Header", () => ({
106119

107120
describe("<GradesPage /> ์‹ค์ œ EvalAddModal/EvalAddForm ํ…Œ์ŠคํŠธ", () => {
108121
beforeEach(() => {
109-
jest.clearAllMocks();
122+
Object.defineProperty(window, "location", {
123+
configurable: true,
124+
value: { reload: jest.fn() } as any,
110125
});
126+
});
111127

112128
it("handleAddEval์—์„œ ํ‰๊ฐ€๋ช… ์—†์ด ์ถ”๊ฐ€ ์‹œ alert๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค", async () => {
113129
window.alert = jest.fn();
@@ -119,6 +135,7 @@ describe("<GradesPage /> ์‹ค์ œ EvalAddModal/EvalAddForm ํ…Œ์ŠคํŠธ", () => {
119135
});
120136
});
121137

138+
122139
it("handleAddEval์—์„œ PostEval ์‹คํŒจ ์‹œ alert๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค", async () => {
123140
(PostEval as jest.Mock).mockRejectedValueOnce(new Error("fail"));
124141
window.alert = jest.fn();
@@ -316,7 +333,7 @@ it("handleInputBlur์—์„œ ๋นˆ ๋ฌธ์ž์—ด ์ž…๋ ฅ ์‹œ score๊ฐ€ undefined๋กœ ์„ค์ •
316333
fireEvent.click(screen.getByText("์ถ”๊ฐ€"));
317334
await waitFor(() => {
318335
expect(PostEval).toHaveBeenCalledWith(
319-
"์ˆ˜ํ•™", // subject from mock store
336+
"๋…์„œ์™€ ๋ฌธ๋ฒ•", // subject from mock store
320337
2025, // year from mock store
321338
1, // semester from mock store
322339
1, // grade from mock store
@@ -400,7 +417,7 @@ it("404 fallback fetch์—์„œ studentList์˜ studentId์™€ name์ด ์—†์œผ๋ฉด '-'
400417
fireEvent.click(screen.getByText("์ถ”๊ฐ€"));
401418
await waitFor(() => {
402419
expect(PostEval).toHaveBeenCalledWith(
403-
"์ˆ˜ํ•™", 2025, 1, 1, "WRITTEN", "์ƒˆ๋กœ์šด ํ‰๊ฐ€", 0, 0 // Number(null) === 0
420+
"๋…์„œ์™€ ๋ฌธ๋ฒ•", 2025, 1, 1, "WRITTEN", "์ƒˆ๋กœ์šด ํ‰๊ฐ€", 0, 0 // Number(null) === 0
404421
);
405422
});
406423
});
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// __tests__/store/useTeacher.test.ts
2+
import { act } from "@testing-library/react";
3+
import useTeacher from "@/store/teacher-store";
4+
5+
describe("useTeacher zustand store", () => {
6+
beforeEach(() => {
7+
// Zustand store๋ฅผ ์ดˆ๊ธฐํ™”
8+
const { getState, setState } = useTeacher;
9+
setState({
10+
grade: "1",
11+
classNumber: "1",
12+
teacherName: "๊น€์ฒ ์ˆ˜",
13+
mysubject: "๋…์„œ์™€ ๋ฌธ๋ฒ•",
14+
setGrade: getState().setGrade,
15+
setClassNumber: getState().setClassNumber,
16+
setTeacherName: getState().setTeacherName,
17+
setSubject: getState().setSubject,
18+
});
19+
});
20+
21+
it("์ดˆ๊ธฐ๊ฐ’์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
22+
const state = useTeacher.getState();
23+
expect(state.grade).toBe("1");
24+
expect(state.classNumber).toBe("1");
25+
expect(state.teacherName).toBe("๊น€์ฒ ์ˆ˜");
26+
expect(state.mysubject).toBe("๋…์„œ์™€ ๋ฌธ๋ฒ•");
27+
});
28+
29+
it("setGrade๋กœ grade๊ฐ€ ๋ณ€๊ฒฝ๋œ๋‹ค", () => {
30+
act(() => {
31+
useTeacher.getState().setGrade("3");
32+
});
33+
expect(useTeacher.getState().grade).toBe("3");
34+
});
35+
36+
it("setClassNumber๋กœ classNumber๊ฐ€ ๋ณ€๊ฒฝ๋œ๋‹ค", () => {
37+
act(() => {
38+
useTeacher.getState().setClassNumber("2");
39+
});
40+
expect(useTeacher.getState().classNumber).toBe("2");
41+
});
42+
43+
it("setTeacherName์œผ๋กœ teacherName์ด ๋ณ€๊ฒฝ๋œ๋‹ค", () => {
44+
act(() => {
45+
useTeacher.getState().setTeacherName("์ด์˜ํฌ");
46+
});
47+
expect(useTeacher.getState().teacherName).toBe("์ด์˜ํฌ");
48+
});
49+
50+
it("setSubject๋กœ mysubject๊ฐ€ ๋ณ€๊ฒฝ๋œ๋‹ค", () => {
51+
act(() => {
52+
useTeacher.getState().setSubject("์˜์–ด1");
53+
});
54+
expect(useTeacher.getState().mysubject).toBe("์˜์–ด1");
55+
});
56+
});

โ€Žsrc/components/behavior/BehaviorContent.tsxโ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const BehaviorContent = () => {
1616
const getBehavior = async () => {
1717
try {
1818
const token = localStorage.getItem("accessToken");
19-
const res = await axios.get(`${process.env.NEXT_PUBLIC_BACKEND_DOMAIN}/behavior?year=${year}&grade=${grade}&classNum=${classNumber}&studentId=${studentId}`, {
19+
const res = await axios.get(`${process.env.NEXT_PUBLIC_BACKEND_DOMAIN}/behavior?year=${year}&grade=${grade}&classNum=${classNumber}&number=${studentId}`, {
2020
headers: { Authorization: `Bearer ${token}` },
2121
});
2222
const data = res.data.response;

โ€Žsrc/components/grade/GradeTable.tsxโ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ function EditableCell({
124124
{isEditing ? (
125125
<input
126126
type="number"
127-
className="w-16 border rounded px-1 py-0.5"
127+
className="w-8 border-none rounded px-1 py-0.5 no-spinner "
128128
value={inputValue}
129129
onChange={handleInputChange}
130130
onBlur={handleInputBlur}

โ€Žsrc/pages/grade/index.tsxโ€Ž

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { GetStudentList } from "@/api/getStudentList";
1212
import { mapApiResponseToStudents, convertToApiFormat, Evaluation } from "@/utils/gradeUtils";
1313
import useStudentFilterStore from "@/store/student-filter-store";
1414
import useGradeFilterStore from "@/store/grade-filter-store";
15-
15+
import useTeacher from "@/store/teacher-store";
1616
export default function GradesPage() {
1717
const { grade, classNumber, studentNumber } = useStudentFilterStore();
1818
const { year, semester, subject } = useGradeFilterStore();
@@ -22,6 +22,7 @@ export default function GradesPage() {
2222
const [inputValue, setInputValue] = useState<string>("");
2323
const [evaluations, setEvaluations] = useState<Evaluation[]>([]);
2424
const [showEvalInput, setShowEvalInput] = useState(false);
25+
const mysubject = useTeacher().mysubject;
2526
const [evalInput, setEvalInput] = useState<{
2627
title: string;
2728
examType: "WRITTEN" | "PRACTICAL";
@@ -102,13 +103,16 @@ export default function GradesPage() {
102103

103104
const handleSave = async (e: React.MouseEvent<HTMLButtonElement>) => {
104105
e.preventDefault();
106+
if(subject != mysubject ){
107+
alert(`๋ณธ์ธ์˜ ๊ณผ๋ชฉ์ธ ${mysubject}๋งŒ ์ˆ˜์ •๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.`)
108+
}else{
105109
const payload = convertToApiFormat(students, evaluations, Number(classNumber));
106110
try {
107111
await PostScore(payload);
108112
window.location.reload();
109113
} catch {
110114
alert("์ €์žฅ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.");
111-
}
115+
}}
112116
};
113117

114118
const handleAddEval = async () => {

โ€Žsrc/pages/index.tsxโ€Ž

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { useRouter } from "next/navigation";
44
import { PostLogin } from "@/api/postLogin";
55
import useLoginStore from "@/store/login-store";
66
import useStudent from "@/store/student-store";
7+
import useTeacher from "@/store/teacher-store";
78
import { messaging, getToken } from "@/utils/firebase";
89
import { PostFCM } from "@/api/postFCM";
910

@@ -13,7 +14,7 @@ const Login = () => {
1314
const [password, setPassword] = useState<string>("");
1415
const { setName } = useLoginStore();
1516
const { setGrade, setClassNumber, setStudentNumber, setStudentId, setStudentName } = useStudent();
16-
17+
const { setTeacherName, setSubject } = useTeacher();
1718
const handleUserIdChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
1819
setUserId(e.target.value);
1920
};
@@ -68,6 +69,8 @@ const Login = () => {
6869
localStorage.setItem("accessToken", accessToken);
6970
sendFcmTokenToServer();
7071
if (role === "TEACHER") {
72+
setTeacherName(data.name);
73+
setSubject(data.subject);
7174
router.push("/student-record");
7275
} else if (role === "STUDENT") {
7376
router.push("/student/student-record");

โ€Žsrc/store/teacher-store.tsโ€Ž

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { create } from "zustand";
2+
3+
interface ITeacher {
4+
grade: string;
5+
classNumber: string;
6+
teacherName: string;
7+
mysubject: string;
8+
9+
setGrade: (grade: string) => void;
10+
setClassNumber: (classNumber: string) => void;
11+
setTeacherName: (name: string) => void;
12+
setSubject: (mysubject: string) => void;
13+
}
14+
15+
const useTeacher = create<ITeacher>((set) => ({
16+
grade: "1",
17+
classNumber: "1",
18+
teacherName: "๊น€์ฒ ์ˆ˜",
19+
mysubject: "๋…์„œ์™€ ๋ฌธ๋ฒ•",
20+
21+
setGrade: (grade: string) => set({ grade }),
22+
setClassNumber: (classNumber: string) => set({ classNumber }),
23+
setTeacherName: (teacherName: string) => set({ teacherName }),
24+
setSubject: (mysubject: string) => set({ mysubject })
25+
}));
26+
27+
export default useTeacher;

0 commit comments

Comments
ย (0)