diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 5bc8878..e177e6b 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -12,15 +12,31 @@ import ManageTask from "./pages/admin/ManageTask.jsx";
import AttendanceCode from "./pages/admin/AttendanceCode";
import Attendance from "./pages/generation/Attendance";
import AdminStudentAttendance from "./pages/admin/AdminStudentAttendance";
+<<<<<<< HEAD
+import AdminStudentAssignment from "./pages/admin/AdminStudentAssignment.jsx";
+=======
import RequireAuth from "./components/RequireAuth";
import RequireAdmin from "./components/RequireAdmin";
+>>>>>>> 08242a5045ea08b68c40b107cc871f8b3c3446eb
function App() {
return (
} />
} />
+<<<<<<< HEAD
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+=======
}
/>
+>>>>>>> 08242a5045ea08b68c40b107cc871f8b3c3446eb
);
diff --git a/frontend/src/api/adminattendance.js b/frontend/src/api/adminattendance.js
new file mode 100644
index 0000000..4506980
--- /dev/null
+++ b/frontend/src/api/adminattendance.js
@@ -0,0 +1,26 @@
+import api from "./api";
+
+// api/attendanceApi.js
+
+export const getStudentBasicInfo = async (studentId) => {
+ try {
+ const res = await api.get(`/admin/managestudent/${studentId}`);
+ return res.data;
+ } catch (error) {
+ console.error("학생 기본 정보 불러오기 실패:", error);
+ throw error;
+ }
+};
+
+export const getStudentAttendance = async (studentId) => {
+ try {
+ const res = await api.get("/admin/attendance/user", {
+ params: { userId: studentId },
+ withCredentials: true,
+ });
+ return res.data;
+ } catch (error) {
+ console.error("학생 출석 정보 불러오기 실패:", error);
+ throw error;
+ }
+};
diff --git a/frontend/src/api/assignment.js b/frontend/src/api/assignment.js
index cf1a11a..323730a 100644
--- a/frontend/src/api/assignment.js
+++ b/frontend/src/api/assignment.js
@@ -1,6 +1,16 @@
import api from "./api";
-
+/*
export const fetchAssignmentsByUser = async (userId) => {
const res = await api.get(`/assignment/grouped/${userId}`);
return res.data;
};
+*/
+export const fetchAssignmentsByUser = async (userId) => {
+ try {
+ const res = await api.get(`/api/assignment/${userId}`);
+ return res.data; // 백엔드가 반환하는 JSON 그대로
+ } catch (err) {
+ console.error("과제 데이터 불러오기 실패:", err);
+ throw err;
+ }
+};
\ No newline at end of file
diff --git a/frontend/src/pages/admin/AdminStudentAssignment.jsx b/frontend/src/pages/admin/AdminStudentAssignment.jsx
new file mode 100644
index 0000000..2114cb4
--- /dev/null
+++ b/frontend/src/pages/admin/AdminStudentAssignment.jsx
@@ -0,0 +1,125 @@
+import React, { useEffect, useState } from "react";
+import { useParams } from "react-router-dom";
+import AdminStudentHeader from "../../components/AdminStudentHeader";
+import WeeklyOpenBlock from "../../components/WeeklyOpenBlock";
+import AssignmentInfoBlock from "../../components/AssignmentInfoBlock";
+import api from "../../api/api";
+import styles from "./AdminStudentAssignment.module.css";
+
+const AdminStudentAssignment = () => {
+ const { studentId, week } = useParams();
+ const [studentInfo, setStudentInfo] = useState(null);
+ const [weeks, setWeeks] = useState([]);
+ const [highlightCard, setHighlightCard] = useState(null);
+ const [selectedWeekLabel, setSelectedWeekLabel] = useState(null);
+
+ useEffect(() => {
+ api.get(`/admin/users/${studentId}`).then((res) => {
+ setStudentInfo(res.data.data);
+ });
+
+ api
+ .get(`/admin/managestudent/{studentId}`, {
+ params: { userId: studentId },
+ withCredentials: true,
+ })
+ .then((res) => {
+ const formatted = res.data.data.map((weekItem) => ({
+ week: weekItem.week,
+ label: `${weekItem.week}주차 ${weekItem.title}`,
+ days: weekItem.days.map((dayItem) => ({
+ day: dayItem.day,
+ subject: weekItem.title,
+ tasks: dayItem.details.map((task) => ({
+ id: task.id,
+ label: task.assignmentName,
+ status: task.status,
+ modified: false,
+ })),
+ })),
+ }));
+
+ setWeeks(formatted);
+
+ const matched = formatted.find((w) => String(w.week) === String(week));
+ if (matched) {
+ setSelectedWeekLabel(matched.label);
+ if (matched.days.length > 0) {
+ setHighlightCard({
+ weekLabel: matched.label,
+ day: matched.days[0].day,
+ tasks: matched.days[0].tasks,
+ });
+ }
+ }
+ });
+ }, [studentId, week]);
+
+ const handleStatusChange = (weekIdx, dayIdx, taskIdx, newStatus) => {
+ const updated = [...weeks];
+ const task = updated[weekIdx].days[dayIdx].tasks[taskIdx];
+ task.status = newStatus;
+ task.modified = true;
+ setWeeks(updated);
+ };
+
+ const handleSave = async (taskId, status) => {
+ await api.put("/admin/assignment/status", {
+ assignmentId: taskId,
+ status,
+ });
+ };
+
+ return (
+
+
window.history.back()}
+ />
+
+ {highlightCard && (
+
+ )}
+
+
+ {weeks.map((weekItem, weekIdx) => (
+
+
{weekItem.label}
+ {weekItem.days.map((dayItem, dayIdx) => (
+
+
{dayItem.day} {dayItem.subject}
+
+ {dayItem.tasks.map((task, taskIdx) => (
+
+ {task.label}
+
+
+
+ ))}
+
+
+
+ ))}
+
+ ))}
+
+
+ );
+};
+
+export default AdminStudentAssignment;
\ No newline at end of file
diff --git a/frontend/src/pages/admin/AdminStudentAssignment.module.css b/frontend/src/pages/admin/AdminStudentAssignment.module.css
new file mode 100644
index 0000000..04e3e68
--- /dev/null
+++ b/frontend/src/pages/admin/AdminStudentAssignment.module.css
@@ -0,0 +1,112 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ padding: 20px;
+ font-family: "Inter", sans-serif;
+ color: white;
+ background-color: #1e1e1e;
+}
+
+/* 과제 개요 카드 (상단 형광 카드) */
+.info {
+ background-color: #045e07;
+ border-radius: 12px;
+ padding: 16px;
+ margin-bottom: 24px;
+}
+
+/* 주차별 목록 */
+.weekList {
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
+}
+
+/* 주차 구간 */
+.weekBlock {
+ border-left: 4px solid #00c851;
+ background-color: #2d2d2d;
+ border-radius: 10px;
+ padding: 16px;
+}
+
+.weekTitle {
+ font-size: 18px;
+ font-weight: bold;
+ color: #00ff99;
+ margin-bottom: 12px;
+}
+
+/* 요일별 카드 */
+.dayCard {
+ background-color: #3a3a3a;
+ padding: 12px 16px;
+ border-radius: 10px;
+ margin-bottom: 16px;
+}
+
+.dayLabel {
+ font-size: 16px;
+ font-weight: 600;
+ margin-bottom: 8px;
+}
+
+/* 개별 과제 */
+.taskList {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ margin-bottom: 12px;
+}
+
+.taskRow {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ background-color: #505050;
+ border-radius: 6px;
+ padding: 8px 12px;
+}
+
+.taskLabel {
+ flex: 1;
+ font-size: 14px;
+ color: white;
+}
+
+/* 드롭다운 */
+.taskRow select {
+ padding: 6px 8px;
+ border-radius: 6px;
+ background-color: #2a2a2a;
+ color: white;
+ border: 1px solid #777;
+}
+
+/* save 버튼 */
+.saveButton {
+ padding: 4px 10px;
+ border-radius: 6px;
+ background-color: #00c851;
+ color: white;
+ font-weight: bold;
+ border: none;
+ cursor: pointer;
+}
+
+.saveButton:disabled {
+ background-color: gray;
+ cursor: not-allowed;
+}
+
+/* submit 버튼 */
+.submitBtn {
+ margin-top: 8px;
+ padding: 6px 12px;
+ border-radius: 8px;
+ background-color: #1fa067;
+ color: white;
+ font-weight: bold;
+ border: none;
+ cursor: pointer;
+}
diff --git a/frontend/src/pages/admin/AdminStudentAttendance.jsx b/frontend/src/pages/admin/AdminStudentAttendance.jsx
index 827248b..6eed5d1 100644
--- a/frontend/src/pages/admin/AdminStudentAttendance.jsx
+++ b/frontend/src/pages/admin/AdminStudentAttendance.jsx
@@ -5,6 +5,7 @@ import DailyAttendanceCard from "../../components/AdminDailyAttendanceCard";
import api from "../../api/api";
import styles from "./AdminStudentAttendance.module.css";
import AdminWeeklyAttendanceList from "../../components/AdminWeeklyAttendanceList";
+import { getStudentBasicInfo, getStudentAttendance } from "../../api/adminattendance";
const AdminStudentAttendance = () => {
const { studentId } = useParams();
@@ -13,22 +14,20 @@ const AdminStudentAttendance = () => {
const [selectedDate, setSelectedDate] = useState(null);
useEffect(() => {
- // 1. 학생 정보 가져오기
- api.get(`/admin/users/${studentId}`).then((res) => {
- setStudentInfo(res.data.data);
- });
+ const fetchData = async () => {
+ try {
+ const studentRes = await getStudentBasicInfo(studentId);
+ setStudentInfo(studentRes.data);
- // 2. 주차별 출석 데이터 가공
- api
- .get("/admin/attendance/user", {
- params: { userId: studentId },
- withCredentials: true,
- })
- .then((res) => {
- const raw = res.data.data;
- const processed = processWeeklyAttendance(raw);
+ const attendanceRes = await getStudentAttendance(studentId);
+ const processed = processWeeklyAttendance(attendanceRes.data);
setAttendanceData(processed);
- });
+ } catch (err) {
+ console.error("데이터 불러오기 실패:", err);
+ }
+ };
+
+ fetchData();
}, [studentId]);
/*