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/api.js b/frontend/src/api/api.js index 60d0af3..1950026 100644 --- a/frontend/src/api/api.js +++ b/frontend/src/api/api.js @@ -2,10 +2,8 @@ import axios from "axios"; const api = axios.create({ baseURL: "http://api.pirocheck.org:8080/api", - // 수정 필요한지 재검 필요함 // "http://api.pirocheck.org:8080/api" - withCredentials: true, }); 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/components/Header.jsx b/frontend/src/components/Header.jsx index 1a38ba6..50af6bf 100644 --- a/frontend/src/components/Header.jsx +++ b/frontend/src/components/Header.jsx @@ -50,9 +50,7 @@ const Header = () => { height={30} /> - ) : ( -
- )} + ) : null} {showRightMagageStudent ? ( +
+ ))} + + + + ))} + + ))} + + + ); +}; + +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]); /* diff --git a/frontend/src/pages/admin/AttendanceCode.jsx b/frontend/src/pages/admin/AttendanceCode.jsx index 8806d0e..d93ea52 100644 --- a/frontend/src/pages/admin/AttendanceCode.jsx +++ b/frontend/src/pages/admin/AttendanceCode.jsx @@ -1,11 +1,33 @@ -import { useState } from "react"; import api from "../../api/api"; import Header from "../../components/Header"; import style from "./AttendanceCode.module.css"; +import { useState, useEffect } from "react"; const AttendanceCode = () => { const [code, setCode] = useState(""); + useEffect(() => { + const expireIfNeeded = async () => { + try { + const res = await api.get("admin/attendance/active-code"); + const activeCode = res.data.data.code; + + await api.put("admin/attendance/expire", null, { + params: { code: activeCode }, + }); + + console.log("기존 출석코드 자동 만료됨"); + } catch (error) { + if (error.response?.status !== 404) { + alert( + "초기화 중 오류: " + (error.response?.data?.message || "서버 오류") + ); + } + } + }; + + expireIfNeeded(); + }, []); // 출석코드 생성 const generateCode = async () => { try { diff --git a/frontend/src/pages/admin/DetailManageStudent.jsx b/frontend/src/pages/admin/DetailManageStudent.jsx index f932ea9..70266a2 100644 --- a/frontend/src/pages/admin/DetailManageStudent.jsx +++ b/frontend/src/pages/admin/DetailManageStudent.jsx @@ -6,12 +6,13 @@ import { getStudentDetail } from "../../api/students"; const DetailManageStudent = () => { const { studentId } = useParams(); + const numericId = Number(studentId); const [student, setStudent] = useState(null); useEffect(() => { const fetchStudent = async () => { try { - const data = await getStudentDetail(studentId); + const data = await getStudentDetail(numericId); setStudent(data); } catch (err) { console.error("학생 상세 정보 불러오기 실패:", err); @@ -19,10 +20,13 @@ const DetailManageStudent = () => { }; fetchStudent(); - }, [studentId]); + }, [numericId]); if (!student) return
loading...
; + console.log("studentId from URL:", studentId); + console.log("numericId:", numericId); + return (
diff --git a/frontend/src/pages/admin/ManageStudent.jsx b/frontend/src/pages/admin/ManageStudent.jsx index 80a02e3..525a021 100644 --- a/frontend/src/pages/admin/ManageStudent.jsx +++ b/frontend/src/pages/admin/ManageStudent.jsx @@ -55,15 +55,18 @@ const ManageStudent = () => { onChange={handleChange} />
- {paginatedStudents.map((student, index) => ( - - ))} + {paginatedStudents.map((student, index) => { + console.log("student to show:", student); // 🔍 여기 추가 + return ( + + ); + })}
{students.length > studentsPerPage && (