From d2e513510a2d2f0515160e6de7d589c8a8d08315 Mon Sep 17 00:00:00 2001 From: Imggaggu Date: Wed, 18 Jun 2025 12:34:23 +0900 Subject: [PATCH 01/26] =?UTF-8?q?[Fix]=20=EC=83=81=ED=83=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/admin/AdminStudentAssignment.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/admin/AdminStudentAssignment.jsx b/frontend/src/pages/admin/AdminStudentAssignment.jsx index c24110f..98af493 100644 --- a/frontend/src/pages/admin/AdminStudentAssignment.jsx +++ b/frontend/src/pages/admin/AdminStudentAssignment.jsx @@ -64,7 +64,7 @@ const AdminStudentAssignment = () => { }); }, [studentId, week]); - const handleStatusChange = (weekIdx, dayIdx, taskIdx, newStatus) => { + const handleStatusChange = (weekNum, dayIdx, taskIdx, newStatus) => { const weekIdx = weeks.findIndex(w => Number(w.week) === Number(weekNum)); if (weekIdx === -1) return; @@ -137,7 +137,7 @@ const AdminStudentAssignment = () => { value={task.status} onChange={(e) => handleStatusChange( - weekIdx, + weekItem.week, dayIdx, taskIdx, e.target.value From e22644955103e0441027064a78c1dd8d9bc9a152 Mon Sep 17 00:00:00 2001 From: NamKyeongMin Date: Sat, 21 Jun 2025 02:43:54 +0900 Subject: [PATCH 02/26] =?UTF-8?q?[add]:=20data=20=EA=B5=AC=EC=A1=B0=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=EC=9A=A9=20=EB=A1=9C=EA=B7=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/AttendanceWeekInfo.jsx | 7 ++++--- frontend/src/pages/generation/Attendance.jsx | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/AttendanceWeekInfo.jsx b/frontend/src/components/AttendanceWeekInfo.jsx index 10f1b3b..6c033ff 100644 --- a/frontend/src/components/AttendanceWeekInfo.jsx +++ b/frontend/src/components/AttendanceWeekInfo.jsx @@ -6,9 +6,10 @@ const AttendanceWeekInfo = ({ week, classes }) => {

{week}주차

- {classes.map((cls, idx) => ( - {`${idx - ))} + {classes.map((cls, idx) => { + console.log(`✅ week ${week}, idx ${idx}, image:`, cls.image); + return {`${idx; + })}
); diff --git a/frontend/src/pages/generation/Attendance.jsx b/frontend/src/pages/generation/Attendance.jsx index 8ef8334..a096d19 100644 --- a/frontend/src/pages/generation/Attendance.jsx +++ b/frontend/src/pages/generation/Attendance.jsx @@ -192,6 +192,8 @@ const Attendance = () => { } }; + console.log("📊 attendanceData: ", attendanceData); + return (
From 8d3cdc5da1f9d6205e7276361e374e0f97f04528 Mon Sep 17 00:00:00 2001 From: NamKyeongMin Date: Sat, 21 Jun 2025 03:06:19 +0900 Subject: [PATCH 03/26] =?UTF-8?q?[fix]:=20=EB=82=A0=EC=A7=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EC=8B=9C=20=EB=A6=AC=EB=A1=9C=EB=94=A9=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/generation/Attendance.jsx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/generation/Attendance.jsx b/frontend/src/pages/generation/Attendance.jsx index a096d19..8d6d1ac 100644 --- a/frontend/src/pages/generation/Attendance.jsx +++ b/frontend/src/pages/generation/Attendance.jsx @@ -14,6 +14,11 @@ const Attendance = () => { "not_started", ]); + // 오늘 날짜 비교용 state + const [currentDate, setCurrentDate] = useState( + new Date().toISOString().split("T")[0] + ); + const getSubImage = (count) => { switch (count) { case 3: @@ -148,7 +153,19 @@ const Attendance = () => { }); }, 10000); - return () => clearInterval(interval); + // 매 분마다 현재 날짜를 확인해서 달라졌으면 상태 업데이트 + const dateCheckInterval = setInterval(() => { + const todayStr = new Date().toISOString().split("T")[0]; + if (todayStr !== currentDate) { + setCurrentDate(todayStr); // 날짜 변경 감지 + fetchTodayAttendance(); // 새로운 날짜 기준으로 다시 가져오기 + } + }, 60000); // 60초마다 확인 + + return () => { + clearInterval(interval); + clearInterval(dateCheckInterval); + }; }, []); const handleChange = (index, value) => { From 5fd41b3bbbdaeb3d6eef160db7ee9b5cf928d7a0 Mon Sep 17 00:00:00 2001 From: NamKyeongMin Date: Sat, 21 Jun 2025 03:34:06 +0900 Subject: [PATCH 04/26] =?UTF-8?q?[fix]:=20=EB=82=A0=EC=A7=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EB=A6=AC=EB=A1=9C=EB=94=A9=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95(useRef=EB=A1=9C=20=EB=B3=80=EA=B2=BD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/generation/Attendance.jsx | 24 ++++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/frontend/src/pages/generation/Attendance.jsx b/frontend/src/pages/generation/Attendance.jsx index 8d6d1ac..32a379f 100644 --- a/frontend/src/pages/generation/Attendance.jsx +++ b/frontend/src/pages/generation/Attendance.jsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState, useRef } from "react"; import Header from "../../components/Header"; import InputBlock from "../../components/InputBlock"; import AttendanceWeekInfo from "../../components/AttendanceWeekInfo"; @@ -14,10 +14,7 @@ const Attendance = () => { "not_started", ]); - // 오늘 날짜 비교용 state - const [currentDate, setCurrentDate] = useState( - new Date().toISOString().split("T")[0] - ); + const currentDateRef = useRef(new Date().toISOString().split("T")[0]); const getSubImage = (count) => { switch (count) { @@ -156,8 +153,14 @@ const Attendance = () => { // 매 분마다 현재 날짜를 확인해서 달라졌으면 상태 업데이트 const dateCheckInterval = setInterval(() => { const todayStr = new Date().toISOString().split("T")[0]; - if (todayStr !== currentDate) { - setCurrentDate(todayStr); // 날짜 변경 감지 + if (todayStr !== currentDateRef.current) { + console.log( + "날짜 변경 감지 / 이전:", + currentDateRef.current, + "→ 현재:", + todayStr + ); + currentDateRef.current = todayStr; // 날짜 갱신 fetchTodayAttendance(); // 새로운 날짜 기준으로 다시 가져오기 } }, 60000); // 60초마다 확인 @@ -230,11 +233,12 @@ const Attendance = () => { )}
- {todayStatuses.map((status, idx) => ( + {todayStatuses.map((status, idx) => { + console.log(`렌더링된 이미지 ${idx + 1}:`, getBoomImage(status));
{`attendance-${idx}`} -
- ))} +
; + })}
{attendanceData.map(({ week, classes }) => ( From bac5050c2e9211105d758c013cd4f68987796c38 Mon Sep 17 00:00:00 2001 From: NamKyeongMin Date: Sat, 21 Jun 2025 03:55:14 +0900 Subject: [PATCH 05/26] =?UTF-8?q?[fix]:=20=EB=82=A0=EC=A7=9C=20=EB=B9=84?= =?UTF-8?q?=EA=B5=90=20=EA=B8=B0=EC=A4=80=20=ED=99=95=EC=9D=B8=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/generation/Attendance.jsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/generation/Attendance.jsx b/frontend/src/pages/generation/Attendance.jsx index 32a379f..3ef0a59 100644 --- a/frontend/src/pages/generation/Attendance.jsx +++ b/frontend/src/pages/generation/Attendance.jsx @@ -107,6 +107,8 @@ const Attendance = () => { try { const user = JSON.parse(localStorage.getItem("user")); const userId = user?.id; + console.log("fetchTodayAttendance() called"); + if (!userId) return; const today = new Date().toISOString().split("T")[0]; // YYYY-MM-DD @@ -153,6 +155,14 @@ const Attendance = () => { // 매 분마다 현재 날짜를 확인해서 달라졌으면 상태 업데이트 const dateCheckInterval = setInterval(() => { const todayStr = new Date().toISOString().split("T")[0]; + console.log("dateCheckInterval 실행됨 / 현재 시간:", new Date()); + console.log( + "currentDateRef:", + currentDateRef.current, + "| todayStr:", + todayStr + ); + if (todayStr !== currentDateRef.current) { console.log( "날짜 변경 감지 / 이전:", @@ -235,9 +245,11 @@ const Attendance = () => {
{todayStatuses.map((status, idx) => { console.log(`렌더링된 이미지 ${idx + 1}:`, getBoomImage(status)); -
- {`attendance-${idx}`} -
; + return ( +
+ {`attendance-${idx}`} +
+ ); })}
From a0da5f6834870960ebdcb9dde11538e01a40b5f9 Mon Sep 17 00:00:00 2001 From: seonjuuu Date: Sat, 21 Jun 2025 04:10:10 +0900 Subject: [PATCH 06/26] [fix]deposit update --- .../Assignment/service/AssignmentService.java | 11 +++++- .../repository/AttendanceRepository.java | 1 + .../Attendance/service/AttendanceService.java | 12 +++++++ .../Deposit/service/DepositService.java | 35 ++++++++++++------- 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/Assignment/service/AssignmentService.java b/backend/pirocheck/src/main/java/backend/pirocheck/Assignment/service/AssignmentService.java index 489d3fa..a1f9a3c 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/Assignment/service/AssignmentService.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/Assignment/service/AssignmentService.java @@ -13,6 +13,9 @@ import backend.pirocheck.Assignment.entity.AssignmentStatus; import backend.pirocheck.Assignment.repository.AssignmentItemRepository; import backend.pirocheck.Assignment.repository.AssignmentRepository; +import backend.pirocheck.Deposit.entity.Deposit; +import backend.pirocheck.Deposit.repository.DepositRepository; +import backend.pirocheck.Deposit.service.DepositService; import backend.pirocheck.User.entity.Role; import backend.pirocheck.User.entity.User; import backend.pirocheck.User.repository.UserRepository; @@ -33,6 +36,7 @@ public class AssignmentService { private final AssignmentItemRepository assignmentItemRepository; private final AssignmentRepository assignmentRepository; private final UserRepository userRepository; + private final DepositService depositService; public List search(Long userId) { @@ -163,6 +167,9 @@ public AssignmentStatus createAssignmentItem(Long userId, Long assignmentId, Ass assignmentItemRepository.save(assignmentItem); + // 보증금 즉시 재계산 + depositService.recalculateDeposit(userId); + return assignmentItem.getSubmitted(); } @@ -177,10 +184,12 @@ public AssignmentStatus updateAssignmentItem(Long userId, Long assignmentId, Ass AssignmentItem assignmentItem = assignmentItemRepository.findByUserAndAssignment(user, assignment) .orElseThrow(() -> new IllegalArgumentException("해당 유저의 과제 채점 결과가 없습니다.")); - assignmentItem.update(req.getStatus()); // 상태 업데이트 + assignmentItem.update(req.getStatus()); // 상태 업데이트 assignmentItemRepository.save(assignmentItem); // 상태 저장 + // 보증금 즉시 재계산 + depositService.recalculateDeposit(userId); return assignmentItem.getSubmitted(); } } diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/repository/AttendanceRepository.java b/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/repository/AttendanceRepository.java index 783b90b..938c8af 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/repository/AttendanceRepository.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/repository/AttendanceRepository.java @@ -20,4 +20,5 @@ public interface AttendanceRepository extends JpaRepository { // 특정 날짜와 차수에 대한 모든 출석 기록 조회 List findByDateAndOrder(LocalDate date, int order); + } diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/service/AttendanceService.java b/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/service/AttendanceService.java index ae0dec4..927411d 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/service/AttendanceService.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/service/AttendanceService.java @@ -1,5 +1,8 @@ package backend.pirocheck.Attendance.service; +import backend.pirocheck.Deposit.entity.Deposit; +import backend.pirocheck.Deposit.repository.DepositRepository; +import backend.pirocheck.Deposit.service.DepositService; import backend.pirocheck.User.entity.Role; import backend.pirocheck.User.entity.User; import backend.pirocheck.User.repository.UserRepository; @@ -30,6 +33,7 @@ public class AttendanceService { private final AttendanceRepository attendanceRepository; private final AttendanceCodeRepository attendanceCodeRepository; private final UserRepository userRepository; + private final DepositService depositService; // 출석코드 생성 함수 @Transactional @@ -121,6 +125,7 @@ public String expireAttendanceCode(String code) { attendanceCode.setExpired(true); attendanceCodeRepository.save(attendanceCode); + return "출석 코드가 성공적으로 만료되었습니다"; } @@ -171,6 +176,9 @@ public AttendanceMarkResponse markAttendance(Long userId, String inputCode) { attendance.setStatus(true); attendanceRepository.save(attendance); + //보증금 재계산 + depositService.recalculateDeposit(userId); + return AttendanceMarkResponse.success(); } @@ -223,6 +231,10 @@ public boolean updateAttendanceStatus(Long attendanceId, boolean status) { Attendance attendance = attendanceOpt.get(); attendance.setStatus(status); attendanceRepository.save(attendance); + + // 출석 변경 → 보증금 재계산 + depositService.recalculateDeposit(attendance.getUser().getId()); + return true; } diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/Deposit/service/DepositService.java b/backend/pirocheck/src/main/java/backend/pirocheck/Deposit/service/DepositService.java index 66eafb1..194dbaf 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/Deposit/service/DepositService.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/Deposit/service/DepositService.java @@ -28,29 +28,40 @@ public DepositResDto getDeposit(Long userId) { .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 유저입니다.")); Deposit deposit = depositRepository.findByUser(user); + calculateAndSave(user, deposit); - // 출석 실패 + return DepositResDto.builder() + .amount(deposit.getAmount()) + .descentAssignment(deposit.getDescentAssignment()) + .descentAttendance(deposit.getDescentAttendance()) + .ascentDefence(deposit.getAscentDefence()) + .build(); + } + + // 보증금 재계산 (내부 로직만 수행) + @Transactional + public void recalculateDeposit(Long userId) { + User user = userRepository.findById(userId) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 유저입니다.")); + + Deposit deposit = depositRepository.findByUser(user); + calculateAndSave(user, deposit); + } + + // 공통 계산 로직 + private void calculateAndSave(User user, Deposit deposit) { + //출석 int failAttendanceCount = attendanceRepository.countByUserAndStatusFalse(user); int descentAttendance = failAttendanceCount * 10_000; - // 과제 실패 + //과제 int failAssignmentCount = assignmentItemRepository.countByUserAndSubmitted(user, AssignmentStatus.FAILURE); int weakAssignmentCount = assignmentItemRepository.countByUserAndSubmitted(user, AssignmentStatus.INSUFFICIENT); int descentAssignment = failAssignmentCount * 20_000 + weakAssignmentCount * 10_000; - // 방어권 int ascentDefence = deposit.getAscentDefence(); - // 보증금 업데이트 deposit.updateAmounts(descentAssignment, descentAttendance, ascentDefence); depositRepository.save(deposit); - - return DepositResDto.builder() - .amount(deposit.getAmount()) - .descentAssignment(deposit.getDescentAssignment()) - .descentAttendance(deposit.getDescentAttendance()) - .ascentDefence(deposit.getAscentDefence()) - .build(); - } } \ No newline at end of file From 8daf0401a87458e7c4ff64066b3c465fa0349e08 Mon Sep 17 00:00:00 2001 From: NamKyeongMin Date: Sat, 21 Jun 2025 04:21:27 +0900 Subject: [PATCH 07/26] =?UTF-8?q?[fix]:=20currentDateRef=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/generation/Attendance.jsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/generation/Attendance.jsx b/frontend/src/pages/generation/Attendance.jsx index 3ef0a59..78fc06a 100644 --- a/frontend/src/pages/generation/Attendance.jsx +++ b/frontend/src/pages/generation/Attendance.jsx @@ -14,7 +14,7 @@ const Attendance = () => { "not_started", ]); - const currentDateRef = useRef(new Date().toISOString().split("T")[0]); + const currentDateRef = useRef(null); const getSubImage = (count) => { switch (count) { @@ -138,6 +138,11 @@ const Attendance = () => { }; useEffect(() => { + if (!currentDateRef.current) { + currentDateRef.current = new Date().toISOString().split("T")[0]; + } + console.log("currentDateRef 할당 갱신:", currentDateRef.current); + fetchAttendance(); fetchTodayAttendance(); @@ -222,7 +227,7 @@ const Attendance = () => { } }; - console.log("📊 attendanceData: ", attendanceData); + console.log("attendanceData: ", attendanceData); return (
From 6a43284d0578bb45f562c945f105264d99131098 Mon Sep 17 00:00:00 2001 From: seonjuuu Date: Sat, 21 Jun 2025 04:45:28 +0900 Subject: [PATCH 08/26] [fix] deposit update --- .../Attendance/repository/AttendanceRepository.java | 2 ++ .../pirocheck/Attendance/service/AttendanceService.java | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/repository/AttendanceRepository.java b/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/repository/AttendanceRepository.java index 938c8af..5de470f 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/repository/AttendanceRepository.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/repository/AttendanceRepository.java @@ -21,4 +21,6 @@ public interface AttendanceRepository extends JpaRepository { // 특정 날짜와 차수에 대한 모든 출석 기록 조회 List findByDateAndOrder(LocalDate date, int order); + // 보증금 + List findByDateAndOrderAndStatusFalse(LocalDate date, int order); } diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/service/AttendanceService.java b/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/service/AttendanceService.java index 927411d..b1ffe29 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/service/AttendanceService.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/service/AttendanceService.java @@ -125,7 +125,13 @@ public String expireAttendanceCode(String code) { attendanceCode.setExpired(true); attendanceCodeRepository.save(attendanceCode); + // 보증금 + List absents = attendanceRepository.findByDateAndOrderAndStatusFalse( + attendanceCode.getDate(), attendanceCode.getOrder()); + for (Attendance attendance : absents) { + depositService.recalculateDeposit(attendance.getUser().getId()); + } return "출석 코드가 성공적으로 만료되었습니다"; } From ae530c11a351cb070da206acdda1ad47ccfff4de Mon Sep 17 00:00:00 2001 From: NamKyeongMin Date: Sat, 21 Jun 2025 04:46:56 +0900 Subject: [PATCH 09/26] =?UTF-8?q?[fix]:=20=EA=B8=B0=EC=A1=B4=20UTC(KST+9)?= =?UTF-8?q?=20->=20KST(=ED=95=9C=EA=B5=AD=20=EA=B8=B0=EC=A4=80=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84)=EB=A1=9C=20=EC=8B=9C=EA=B0=84=EB=8C=80=20=20?= =?UTF-8?q?=EB=B3=80=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/generation/Attendance.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/generation/Attendance.jsx b/frontend/src/pages/generation/Attendance.jsx index 78fc06a..f08b0b5 100644 --- a/frontend/src/pages/generation/Attendance.jsx +++ b/frontend/src/pages/generation/Attendance.jsx @@ -111,7 +111,7 @@ const Attendance = () => { if (!userId) return; - const today = new Date().toISOString().split("T")[0]; // YYYY-MM-DD + const today = new Date().toLocaleDateString("sv-SE"); // → KST(한국 시간 기준) const res = await api.get(`/attendance/user/date`, { params: { userId, date: today }, withCredentials: true, // 세션 기반 인증 요청처리 @@ -139,7 +139,7 @@ const Attendance = () => { useEffect(() => { if (!currentDateRef.current) { - currentDateRef.current = new Date().toISOString().split("T")[0]; + currentDateRef.current = new Date().toLocaleDateString("sv-SE"); // → KST(한국 시간 기준) } console.log("currentDateRef 할당 갱신:", currentDateRef.current); @@ -159,7 +159,7 @@ const Attendance = () => { // 매 분마다 현재 날짜를 확인해서 달라졌으면 상태 업데이트 const dateCheckInterval = setInterval(() => { - const todayStr = new Date().toISOString().split("T")[0]; + const todayStr = new Date().toLocaleDateString("sv-SE"); // → KST(한국 시간 기준) console.log("dateCheckInterval 실행됨 / 현재 시간:", new Date()); console.log( "currentDateRef:", From 51cd458d6139f52512d30c5a4ab359b3d0522e5a Mon Sep 17 00:00:00 2001 From: seonjuuu Date: Sat, 21 Jun 2025 05:06:32 +0900 Subject: [PATCH 10/26] [fix] deposit update --- .../pirocheck/Assignment/service/AssignmentService.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/Assignment/service/AssignmentService.java b/backend/pirocheck/src/main/java/backend/pirocheck/Assignment/service/AssignmentService.java index a1f9a3c..c06a605 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/Assignment/service/AssignmentService.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/Assignment/service/AssignmentService.java @@ -136,6 +136,13 @@ public List searchAssignment(AssignmentRes assignmentRes) { // 과제 삭제 public String deleteAssignment(Long assignmentId) { assignmentRepository.deleteById(assignmentId); + + // 모든 MEMBER 유저 보증금 재계산 + List members = userRepository.findByRole(Role.MEMBER); + for (User user : members) { + depositService.recalculateDeposit(user.getId()); + } + return "과제가 성공적으로 삭제되었습니다."; } From 59c01e513cfbf62fed9d34e85736e1be9ebe6655 Mon Sep 17 00:00:00 2001 From: NamKyeongMin Date: Sat, 21 Jun 2025 09:46:46 +0900 Subject: [PATCH 11/26] =?UTF-8?q?[fix]:=20console=20log=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20weekly=20count=20=ED=98=84=ED=99=A9=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20console=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/AttendanceWeekInfo.jsx | 2 +- frontend/src/pages/generation/Attendance.jsx | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/AttendanceWeekInfo.jsx b/frontend/src/components/AttendanceWeekInfo.jsx index 6c033ff..ea071f0 100644 --- a/frontend/src/components/AttendanceWeekInfo.jsx +++ b/frontend/src/components/AttendanceWeekInfo.jsx @@ -7,7 +7,7 @@ const AttendanceWeekInfo = ({ week, classes }) => {

{week}주차

{classes.map((cls, idx) => { - console.log(`✅ week ${week}, idx ${idx}, image:`, cls.image); + console.log(`week ${week}, idx ${idx}, image:`, cls.image); return {`${idx; })}
diff --git a/frontend/src/pages/generation/Attendance.jsx b/frontend/src/pages/generation/Attendance.jsx index f08b0b5..4089b6d 100644 --- a/frontend/src/pages/generation/Attendance.jsx +++ b/frontend/src/pages/generation/Attendance.jsx @@ -65,6 +65,8 @@ const Attendance = () => { weekSlotMap.set(week, [...existing, ...presentSlots]); }); + console.log("주차별 출석 (weekSlotMap):", weekSlotMap); + return Array.from({ length: 5 }, (_, i) => { const week = i + 1; const all9 = weekSlotMap.get(week) || []; // 총 9개의 출석 슬롯 (3번의 출석체크*주차당 3번의 세션) @@ -95,6 +97,7 @@ const Attendance = () => { withCredentials: true, // 세션 기반 인증 요청처리 }); const rawData = res.data.data; + console.log("출석 rawData:", rawData); const weekly = processWeeklyAttendance(rawData); setAttendanceData(weekly); } catch (error) { @@ -160,11 +163,11 @@ const Attendance = () => { // 매 분마다 현재 날짜를 확인해서 달라졌으면 상태 업데이트 const dateCheckInterval = setInterval(() => { const todayStr = new Date().toLocaleDateString("sv-SE"); // → KST(한국 시간 기준) - console.log("dateCheckInterval 실행됨 / 현재 시간:", new Date()); + console.log("dateCheckInterval 실행 시간:", new Date()); console.log( - "currentDateRef:", + "현재 로드해오는 시간:", currentDateRef.current, - "| todayStr:", + "| 현재 날짜:", todayStr ); @@ -204,7 +207,6 @@ const Attendance = () => { const res = await api.post( "/attendance/mark", - { userId, code: attendanceCode[0], From d7f982990dd4bbcebee8e4115306008a1e20d34f Mon Sep 17 00:00:00 2001 From: seonjuuu Date: Sat, 21 Jun 2025 12:13:37 +0900 Subject: [PATCH 12/26] [fix] deposit update --- .../pirocheck/Assignment/service/AssignmentService.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/Assignment/service/AssignmentService.java b/backend/pirocheck/src/main/java/backend/pirocheck/Assignment/service/AssignmentService.java index c06a605..650e482 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/Assignment/service/AssignmentService.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/Assignment/service/AssignmentService.java @@ -107,6 +107,10 @@ public String createAssignment(AssignmentCreateReq assignmentCreateReq) { // assignmentItemRepository.save(item); // Cascade 설정이 되어있으므로 assignment = assignmentRepository.save(assignment); 이 코드를 실행할 때 연관된 AssignmentItem도 함께 저장 됨 } + // assignment 저장 후 모든 유저 보증금 재계산 + for (User user : users) { + depositService.recalculateDeposit(user.getId()); + } return assignment.getAssignmentName(); } From bd374719a2b5f327c64fec652a1827b932bad10b Mon Sep 17 00:00:00 2001 From: seonjuuu Date: Sat, 21 Jun 2025 13:01:01 +0900 Subject: [PATCH 13/26] =?UTF-8?q?[fix]=EA=B3=BC=EC=A0=9C=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=20=EC=84=B8=ED=8C=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/pirocheck/Assignment/service/AssignmentService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/Assignment/service/AssignmentService.java b/backend/pirocheck/src/main/java/backend/pirocheck/Assignment/service/AssignmentService.java index 650e482..13c0bfe 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/Assignment/service/AssignmentService.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/Assignment/service/AssignmentService.java @@ -99,7 +99,7 @@ public String createAssignment(AssignmentCreateReq assignmentCreateReq) { for (User user : users) { - AssignmentItem item = AssignmentItem.create(user, assignment, AssignmentStatus.INSUFFICIENT); + AssignmentItem item = AssignmentItem.create(user, assignment, AssignmentStatus.SUCCESS); assignment.addAssignmentItem(item); user.addAssignmentItem(item); From aec638e3cec14de7369fd27a37a52a22311947a9 Mon Sep 17 00:00:00 2001 From: seonjuuu Date: Sat, 21 Jun 2025 13:47:46 +0900 Subject: [PATCH 14/26] [fix] deposit update --- .../Attendance/service/AttendanceService.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/service/AttendanceService.java b/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/service/AttendanceService.java index b1ffe29..c936c41 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/service/AttendanceService.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/service/AttendanceService.java @@ -297,8 +297,14 @@ public boolean deleteAttendance(Long attendanceId) { if (attendanceOpt.isEmpty()) { return false; } - - attendanceRepository.delete(attendanceOpt.get()); + + Attendance attendance = attendanceOpt.get(); // 변수로 저장 + Long userId = attendance.getUser().getId(); + + attendanceRepository.delete(attendance); + + // 출석 삭제 후 보증금 재계산 + depositService.recalculateDeposit(userId); return true; } From 8c0950b184c804f63d316b93cd152672deb36a6f Mon Sep 17 00:00:00 2001 From: Suhjung Park <145967352+Imggaggu@users.noreply.github.com> Date: Mon, 23 Jun 2025 17:02:46 +0900 Subject: [PATCH 15/26] Update ManageTask.module.css --- frontend/src/pages/admin/ManageTask.module.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/pages/admin/ManageTask.module.css b/frontend/src/pages/admin/ManageTask.module.css index 6eff7e2..27daf83 100644 --- a/frontend/src/pages/admin/ManageTask.module.css +++ b/frontend/src/pages/admin/ManageTask.module.css @@ -111,6 +111,8 @@ flex-direction: column; justify-content: center; align-items: center; + overflow-y: auto; + scrollbar-width: none; } .plus { cursor: pointer; From 7d856bf70f032daba11326e9ccb4d45359458b51 Mon Sep 17 00:00:00 2001 From: Suhjung Park <145967352+Imggaggu@users.noreply.github.com> Date: Mon, 23 Jun 2025 17:19:12 +0900 Subject: [PATCH 16/26] Update ManageTask.module.css --- frontend/src/pages/admin/ManageTask.module.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/pages/admin/ManageTask.module.css b/frontend/src/pages/admin/ManageTask.module.css index 27daf83..2b7d3f9 100644 --- a/frontend/src/pages/admin/ManageTask.module.css +++ b/frontend/src/pages/admin/ManageTask.module.css @@ -46,6 +46,8 @@ display: flex; justify-content: center; align-items: center; + overflow-y: auto; + scrollbar-width: none; } .modal { background-color: #333; From ae176496fc04a7c44b7e4c5078aeac777cc2ee14 Mon Sep 17 00:00:00 2001 From: Imggaggu Date: Sun, 29 Jun 2025 18:01:42 +0900 Subject: [PATCH 17/26] update root.css --- frontend/src/root.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/root.css b/frontend/src/root.css index a01e08f..f417cbc 100644 --- a/frontend/src/root.css +++ b/frontend/src/root.css @@ -43,6 +43,6 @@ body{ flex-direction: column; align-items: center; justify-content: flex-start; - overflow: hidden; + overflow: scroll; background-color: #000000; } \ No newline at end of file From c8ec7588cc0faafc72f4069740b0bce4668c4dbd Mon Sep 17 00:00:00 2001 From: Imggaggu Date: Sun, 29 Jun 2025 18:46:27 +0900 Subject: [PATCH 18/26] [Fix] attendance update --- .../pages/admin/AdminStudentAttendance.jsx | 77 +++++++++---------- 1 file changed, 35 insertions(+), 42 deletions(-) diff --git a/frontend/src/pages/admin/AdminStudentAttendance.jsx b/frontend/src/pages/admin/AdminStudentAttendance.jsx index 9a70692..ccd9e1a 100644 --- a/frontend/src/pages/admin/AdminStudentAttendance.jsx +++ b/frontend/src/pages/admin/AdminStudentAttendance.jsx @@ -72,59 +72,52 @@ const processWeeklyAttendance = (rawData) => { const diffDays = Math.floor((d - startDate) / (1000 * 60 * 60 * 24)); return Math.floor(diffDays / 7) + 1; }; + + const dateMap = new Map(); + + rawData.forEach(({ date, status }) => { + const week = getWeekFromDate(date); + const dayKey = `${week}-${date}`; + if (!dateMap.has(dayKey)) dateMap.set(dayKey, []); + dateMap.get(dayKey).push(status); + }); + /* const getDateForClass = (week, classIdx) => { const base = new Date(startDate); base.setDate(base.getDate() + (week - 1) * 7 + offsetDays[classIdx]); return base.toISOString().split("T")[0]; // 'YYYY-MM-DD' 형식 }; - +*/ // 주차별 출석 정보 묶기 - const weekMap = new Map(); - rawData.forEach(({ date, order, status }) => { - const week = getWeekFromDate(date); - const entry = { date, order, status: status ? "SUCCESS" : "FAILURE" }; + dateMap.forEach((statusList, key) => { + const [week, date] = key.split("-"); + const trueCount = statusList.filter(Boolean).length; + + let status = "EMPTY"; + switch (trueCount) { + case 3: + status = "SUCCESS"; + break; + case 2: + status = "INSUFFICIENT"; + break; + case 1: + status = "FAILURE"; + break; + default: + status = "EMPTY"; + } if (!weekMap.has(week)) weekMap.set(week, []); - weekMap.get(week).push(entry); + weekMap.get(week).push({ date, status }); }); - return Array.from({ length: 5 }, (_, i) => { const week = i + 1; - const entries = (weekMap.get(week) || []).sort((a, b) => a.order - b.order); - - const classes = [0, 1, 2].map((classIdx) => { - const order = classIdx + 1; - const slice = entries.slice(classIdx * 3, classIdx * 3 + 3); - const entry = entries.find((e) => e.order === order); - const fallbackDate = getDateForClass(week, classIdx); - - - const trueCount = slice.filter((e) => e.status === "SUCCESS").length; - - let status; - switch (trueCount) { - case 3: - status = "SUCCESS"; - break; - case 2: - status = "INSUFFICIENT"; - break; - case 1: - status = "FAILURE"; - break; - default: - status = "EMPTY"; - } - - return { - order, - status: entry?.status ?? "EMPTY", - date: entry?.date ?? fallbackDate, - }; - }); - - return { week, classes }; + const days = (weekMap.get(String(week)) || []).sort((a, b) => + a.date.localeCompare(b.date) + ); + return { week, days }; }); }; @@ -156,7 +149,7 @@ const processWeeklyAttendance = (rawData) => { setSelectedDate(null)} onRefresh={fetchData} /> From 9d491f4de39a76bff96a014fd0941084dd530f48 Mon Sep 17 00:00:00 2001 From: Imggaggu Date: Sun, 29 Jun 2025 18:49:14 +0900 Subject: [PATCH 19/26] [Fix] add week map --- frontend/src/pages/admin/AdminStudentAttendance.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/admin/AdminStudentAttendance.jsx b/frontend/src/pages/admin/AdminStudentAttendance.jsx index ccd9e1a..0e3eac1 100644 --- a/frontend/src/pages/admin/AdminStudentAttendance.jsx +++ b/frontend/src/pages/admin/AdminStudentAttendance.jsx @@ -65,7 +65,7 @@ const AdminStudentAttendance = () => { const processWeeklyAttendance = (rawData) => { const startDate = new Date("2025-06-24"); const offsetDays = [0, 2, 4]; - + const weekMap = new Map(); const getWeekFromDate = (dateStr) => { const d = new Date(dateStr); From 0ab9bb3356383fe763bc844c761ae523db621569 Mon Sep 17 00:00:00 2001 From: Imggaggu Date: Sun, 29 Jun 2025 19:01:54 +0900 Subject: [PATCH 20/26] [Fix] classes=> date --- .../components/AdminWeeklyAttendanceList.jsx | 25 ++++----- .../pages/admin/AdminStudentAttendance.jsx | 53 +++++++++++++++---- 2 files changed, 54 insertions(+), 24 deletions(-) diff --git a/frontend/src/components/AdminWeeklyAttendanceList.jsx b/frontend/src/components/AdminWeeklyAttendanceList.jsx index c8edeae..50af57a 100644 --- a/frontend/src/components/AdminWeeklyAttendanceList.jsx +++ b/frontend/src/components/AdminWeeklyAttendanceList.jsx @@ -11,24 +11,19 @@ const statusImageMap = { const AdminWeeklyAttendanceList = ({ attendanceData, onSelectDate }) => { return (
- {attendanceData.map(({ week, classes }) => ( + {attendanceData.map(({ week, days}) => (
onSelectWeek(week)}*/>

{week}주차

- {classes.map((cls, idx) => ( - { - console.log("🧪 클릭됨!", cls.date); - cls.date && onSelectDate(cls.date); - }} - */ - onClick={() => { - console.log("🧪 클릭됨!", cls.date, cls.order); - if (cls.date) onSelectDate({ date: cls.date, order: cls.order }); - }} + {days.map((day, idx) => ( + { + console.log("🧪 클릭됨!", day.date); + if (day.date) onSelectDate({ date: day.date }); + }} /> ))}
diff --git a/frontend/src/pages/admin/AdminStudentAttendance.jsx b/frontend/src/pages/admin/AdminStudentAttendance.jsx index 0e3eac1..6def6e6 100644 --- a/frontend/src/pages/admin/AdminStudentAttendance.jsx +++ b/frontend/src/pages/admin/AdminStudentAttendance.jsx @@ -65,30 +65,30 @@ const AdminStudentAttendance = () => { const processWeeklyAttendance = (rawData) => { const startDate = new Date("2025-06-24"); const offsetDays = [0, 2, 4]; - const weekMap = new Map(); + const getWeekFromDate = (dateStr) => { const d = new Date(dateStr); const diffDays = Math.floor((d - startDate) / (1000 * 60 * 60 * 24)); return Math.floor(diffDays / 7) + 1; }; + const getDateForClass = (week, classIdx) => { + const base = new Date(startDate); + base.setDate(base.getDate() + (week - 1) * 7 + offsetDays[classIdx]); + return base.toISOString().split("T")[0]; // 'YYYY-MM-DD' 형식 + }; const dateMap = new Map(); - rawData.forEach(({ date, status }) => { const week = getWeekFromDate(date); const dayKey = `${week}-${date}`; if (!dateMap.has(dayKey)) dateMap.set(dayKey, []); dateMap.get(dayKey).push(status); }); - /* - const getDateForClass = (week, classIdx) => { - const base = new Date(startDate); - base.setDate(base.getDate() + (week - 1) * 7 + offsetDays[classIdx]); - return base.toISOString().split("T")[0]; // 'YYYY-MM-DD' 형식 - }; -*/ + // 주차별 출석 정보 묶기 + const weekMap = new Map(); + dateMap.forEach((statusList, key) => { const [week, date] = key.split("-"); @@ -112,11 +112,46 @@ const processWeeklyAttendance = (rawData) => { if (!weekMap.has(week)) weekMap.set(week, []); weekMap.get(week).push({ date, status }); }); + return Array.from({ length: 5 }, (_, i) => { const week = i + 1; const days = (weekMap.get(String(week)) || []).sort((a, b) => a.date.localeCompare(b.date) ); + /* + const entries = (weekMap.get(week) || []).sort((a, b) => a.order - b.order); + + const classes = [0, 1, 2].map((classIdx) => { + const order = classIdx + 1; + const slice = entries.slice(classIdx * 3, classIdx * 3 + 3); + const entry = entries.find((e) => e.order === order); + const fallbackDate = getDateForClass(week, classIdx); + + + const trueCount = slice.filter((e) => e.status === "SUCCESS").length; + + let status; + switch (trueCount) { + case 3: + status = "SUCCESS"; + break; + case 2: + status = "INSUFFICIENT"; + break; + case 1: + status = "FAILURE"; + break; + default: + status = "EMPTY"; + } + + return { + order, + status: entry?.status ?? "EMPTY", + date: entry?.date ?? fallbackDate, + }; + }); +*/ return { week, days }; }); }; From 0f0d1501826b351a96541f7e7c4540e0e79c40a8 Mon Sep 17 00:00:00 2001 From: Imggaggu Date: Sun, 29 Jun 2025 20:39:28 +0900 Subject: [PATCH 21/26] =?UTF-8?q?[Fix]=20=EC=B6=9C=EC=84=9D=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=AA=A8=EB=8B=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/AdminDailyAttendanceCard.jsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/AdminDailyAttendanceCard.jsx b/frontend/src/components/AdminDailyAttendanceCard.jsx index f4f0f25..20c2dfc 100644 --- a/frontend/src/components/AdminDailyAttendanceCard.jsx +++ b/frontend/src/components/AdminDailyAttendanceCard.jsx @@ -34,11 +34,11 @@ const AdminDailyAttendanceCard = ({ date, order,studentId, onClose, onRefresh } */ const rawSlots = rawData .filter((d) => d.date === date) // 해당 날짜의 출석만 필터 - .sort((a, b) => a.order - b.order) // order 순으로 정렬 + //.sort((a, b) => a.order - b.order) // order 순으로 정렬 .map((d) => ({ - date: d.date, + //date: d.date, id: d.attendanceId, // 출석 ID - order: d.order, // 회차 표시용 + //order: d.order, // 회차 표시용 status: d.status ? "SUCCESS" : "FAILURE", // 드롭다운에 맞게 변환 })); @@ -46,9 +46,9 @@ const AdminDailyAttendanceCard = ({ date, order,studentId, onClose, onRefresh } rawSlots.length > 0 ? rawSlots : [1, 2, 3].map((order) => ({ - date, + //date, id: null, // 새 출석이므로 아직 id 없음 - order, + //order, status: "EMPTY",//기본값 })); @@ -63,9 +63,9 @@ const AdminDailyAttendanceCard = ({ date, order,studentId, onClose, onRefresh } } }; - fetchSlots(); + if (date) fetchSlots(); }, [date, studentId]); - + const handleChange = (idx, newValue) => { const newSlots = [...slots]; newSlots[idx].status = newValue; @@ -126,7 +126,7 @@ const AdminDailyAttendanceCard = ({ date, order,studentId, onClose, onRefresh }
{slots.map((slot, idx) => ( -
+
{idx + 1}차 출석