Skip to content

Commit b47f99d

Browse files
authored
Merge pull request #48 from INU-Software-Design/feature/student-record-page
🐛 fix: 다른 반으로 변경 시 적용되지 않던 버그 수정
2 parents 09ac8da + c165d7b commit b47f99d

4 files changed

Lines changed: 94 additions & 19 deletions

File tree

src/components/shared/StudentFilter.tsx

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import React, { useMemo, useCallback } from "react";
1+
import React, { useMemo, useCallback, useEffect } from "react";
22
import useStudentFilterStore from "@/store/student-filter-store";
3+
import axios from "axios";
34

45
interface SelectInputProps {
56
value: string;
@@ -13,6 +14,33 @@ export default function StudentFilter(): React.ReactElement {
1314
const classOptions: string[] = useMemo(() => Array.from({ length: 10 }, (_, i) => (i + 1).toString()), []);
1415
const numberOptions: string[] = useMemo(() => Array.from({ length: 30 }, (_, i) => (i + 1).toString()), []);
1516

17+
const setStudentFilter = useStudentFilterStore.setState;
18+
useEffect(() => {
19+
const accessToken = localStorage.getItem("accessToken");
20+
21+
const getStudentList = async () => {
22+
try {
23+
const res = await axios.get(`${process.env.NEXT_PUBLIC_BACKEND_DOMAIN}/teachers/students`, {
24+
headers: { Authorization: `Bearer ${accessToken}` },
25+
});
26+
const data = res.data.response;
27+
// ✅ 상태를 한 번에 업데이트
28+
setStudentFilter({
29+
grade: data.grade,
30+
classNumber: data.classNum,
31+
studentNumber: data.students[0]?.number?.toString() ?? "1",
32+
studentId: data.students[0]?.studentId ?? "1",
33+
isReady: true,
34+
});
35+
} catch (error) {
36+
alert(`존재하지 않는 데이터입니다:${error}`);
37+
console.error("학생 목록 가져오기 오류:", error);
38+
}
39+
};
40+
41+
getStudentList();
42+
}, []);
43+
1644
const { grade, classNumber, studentNumber, setGrade, setClassNumber, setStudentNumber } = useStudentFilterStore();
1745

1846
const handleGradeChange = useCallback((event: React.ChangeEvent<HTMLSelectElement>) => setGrade(event.target.value), []);
@@ -42,4 +70,4 @@ export default function StudentFilter(): React.ReactElement {
4270
<SelectInput value={studentNumber} onChange={handleNumberChange} options={numberOptions} label="번" />
4371
</div>
4472
);
45-
}
73+
}

src/components/shared/StudentList.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import useSelectedDate from "@/store/selected-date-store";
12
import useStudentFilterStore from "@/store/student-filter-store";
23
import axios from "axios";
34
import React, { useEffect, useMemo, useState } from "react";
45

56
export default function StudentList() {
67
const setStudentFilter = useStudentFilterStore.setState;
78
const { grade, classNumber, studentNumber, setStudentNumber, setStudentId } = useStudentFilterStore();
9+
const { year } = useSelectedDate();
810

911
const [studentList, setStudentList] = useState([]);
1012

@@ -13,7 +15,7 @@ export default function StudentList() {
1315

1416
const getStudentList = async () => {
1517
try {
16-
const res = await axios.get(`${process.env.NEXT_PUBLIC_BACKEND_DOMAIN}/teachers/students`, {
18+
const res = await axios.get(`${process.env.NEXT_PUBLIC_BACKEND_DOMAIN}/teachers/students?year=${year}&grade=${grade}&classNum=${classNumber}`, {
1719
headers: { Authorization: `Bearer ${accessToken}` },
1820
});
1921
const data = res.data.response;
@@ -34,7 +36,7 @@ export default function StudentList() {
3436
};
3537

3638
getStudentList();
37-
}, []);
39+
}, [grade, classNumber, studentNumber]);
3840

3941
const currentList = useMemo(() => {
4042
return studentList;
@@ -66,4 +68,4 @@ export default function StudentList() {
6668
)}
6769
</div>
6870
);
69-
}
71+
}

src/components/student-record/Modal.tsx

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,86 @@ import axios from "axios";
55
interface ModalProps {
66
name: string;
77
onClose: () => void;
8+
scoreSummaryId: number;
89
}
910

10-
export default function Modal({ name, onClose }: ModalProps) {
11+
export default function Modal({ name, onClose, scoreSummaryId }: ModalProps) {
1112
const [feedback, setFeedback] = useState("");
13+
const [initialFeedback, setInitialFeedback] = useState<string | null>(null);
1214

1315
useEffect(() => {
1416
const token = localStorage.getItem("accessToken");
1517
const getFeedback = async () => {
1618
try {
17-
const res = await axios.get(`${process.env.NEXT_PUBLIC_BACKEND_DOMAIN}`, {
18-
headers: { Authorization: `Bearer ${token}` },
19-
});
20-
const data = res.data;
21-
console.log(data);
22-
// 초기 피드백 데이터를 여기서 넣고 싶으면:
23-
// setFeedback(data.feedback);
19+
const res = await axios.get(`${process.env.NEXT_PUBLIC_BACKEND_DOMAIN}/score-summary/feedback/${scoreSummaryId}`, { headers: { Authorization: `Bearer ${token}` } });
20+
const feedbackData = res.data.response.feedback;
21+
setInitialFeedback(feedbackData);
22+
setFeedback(feedbackData || ""); // null이면 빈 문자열로
2423
} catch (err) {
25-
console.error(err);
24+
console.error("피드백 불러오기 실패:", err);
2625
}
2726
};
2827
getFeedback();
29-
}, []);
28+
}, [scoreSummaryId]);
29+
30+
const token = localStorage.getItem("accessToken");
31+
32+
const postFeedback = async () => {
33+
try {
34+
const res = await axios.post(
35+
`${process.env.NEXT_PUBLIC_BACKEND_DOMAIN}/score-summary/feedback`,
36+
{
37+
scoreSummaryId,
38+
feedback,
39+
},
40+
{ headers: { Authorization: `Bearer ${token}` } }
41+
);
42+
console.log("POST 성공:", res.data);
43+
} catch (err) {
44+
console.error("POST 실패:", err);
45+
}
46+
};
47+
48+
const putFeedback = async () => {
49+
try {
50+
const res = await axios.put(
51+
`${process.env.NEXT_PUBLIC_BACKEND_DOMAIN}/score-summary/feedback/${scoreSummaryId}`,
52+
{ feedback },
53+
{ headers: { Authorization: `Bearer ${token}` } }
54+
);
55+
console.log("PUT 성공:", res.data);
56+
} catch (err) {
57+
console.error("PUT 실패:", err);
58+
}
59+
};
60+
61+
const handleSave = async () => {
62+
// 변경 사항 없으면 요청 없이 닫기
63+
if (feedback === (initialFeedback ?? "")) {
64+
onClose();
65+
return;
66+
}
67+
68+
if (initialFeedback === null) {
69+
await postFeedback();
70+
} else {
71+
await putFeedback();
72+
}
73+
onClose();
74+
};
3075

3176
return (
3277
<div className="fixed inset-0 bg-black bg-opacity-40 flex justify-center items-center z-50" onClick={onClose}>
3378
<div className="flex flex-col bg-white p-6 rounded shadow-lg w-[600px] min-h-[300px] z-100" onClick={(e) => e.stopPropagation()}>
3479
<h2 className="text-xl font-bold mb-2">{name}</h2>
3580
<div className="flex flex-col justify-between h-80">
3681
<textarea
37-
className="w-full h-full resize-none border border-gray-300 rounded p-2 select-none"
82+
className="w-full h-full resize-none border border-gray-300 rounded p-2"
3883
placeholder="피드백을 작성해주세요"
3984
value={feedback}
4085
onChange={(e) => setFeedback(e.target.value)}
4186
/>
42-
<Button className="mt-4 h-12" onClick={onClose}>
87+
<Button className="mt-4 h-12" onClick={handleSave}>
4388
닫기
4489
</Button>
4590
</div>

src/components/student-record/category/Grade.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ export default function Grade() {
1010
const [dataList, setDataList] = useState<any[]>([]);
1111
const [modalOpen, setModalOpen] = useState<boolean[]>([]);
1212
const { grade, classNumber, studentNumber } = useStudentFilterStore();
13-
1413
useEffect(() => {
1514
const token = localStorage.getItem("accessToken");
1615

@@ -45,6 +44,7 @@ export default function Grade() {
4544
석차등급: `${subject.grade}등급`,
4645
석차: `${subject.rank}등`,
4746
피드백: subject.feedback || "",
47+
scoreSummaryId: subject.scoreSummaryId,
4848
};
4949
});
5050

@@ -90,7 +90,7 @@ export default function Grade() {
9090
<Cell>{data.석차등급}</Cell>
9191
<Cell>{data.석차}</Cell>
9292

93-
{modalOpen[index] && <Modal name={data.name} onClose={() => closeModal(index)} />}
93+
{modalOpen[index] && <Modal scoreSummaryId={data.scoreSummaryId} name={data.name} onClose={() => closeModal(index)} />}
9494
</div>
9595
))}
9696
{/* 전체 과목차트 */}

0 commit comments

Comments
 (0)