Skip to content

Commit 7c4e40d

Browse files
committed
[FIX] attendence admin page 수정
1 parent 61be37a commit 7c4e40d

1 file changed

Lines changed: 70 additions & 68 deletions

File tree

frontend/src/pages/generation/Attendance.jsx

Lines changed: 70 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const Attendance = () => {
1717
const currentDateRef = useRef(null);
1818

1919
const getSubImage = (count) => {
20+
// ✅ 절대 경로(/) 사용으로 이미지 엑박 해결
2021
switch (count) {
2122
case 3:
2223
return "/assets/img/full_coin_green.png";
@@ -31,6 +32,7 @@ const Attendance = () => {
3132

3233
// 세션별 상단 이미지 handling
3334
const getBoomImage = (status) => {
35+
// ✅ 절대 경로(/) 사용
3436
switch (status) {
3537
case "success":
3638
return "/assets/img/boom-fill-green.png";
@@ -41,10 +43,13 @@ const Attendance = () => {
4143
}
4244
};
4345

44-
// 날짜 기반 주차 계산
46+
// 날짜 기반 주차 계산 (0시 기준 초기화로 오차 제거)
4547
const getWeekFromDate = (dateStr) => {
4648
const startDate = new Date("2025-12-21"); // 세션 시작일
49+
startDate.setHours(0, 0, 0, 0);
50+
4751
const currentDate = new Date(dateStr);
52+
currentDate.setHours(0, 0, 0, 0);
4853

4954
// 두 날짜 사이 일수 차이 계산
5055
const diffTime = currentDate.getTime() - startDate.getTime();
@@ -54,82 +59,97 @@ const Attendance = () => {
5459
return Math.floor(diffDays / 7) + 1;
5560
};
5661

62+
// ✅ 화/목/토 요일별 데이터 매핑 로직 적용
5763
const processWeeklyAttendance = (rawData) => {
58-
const weekSlotMap = new Map();
59-
// { weekNum: [boolean, boolean, ...] }
60-
61-
rawData.forEach(({ date, slots }) => {
62-
const week = getWeekFromDate(date); // 날짜 기준 주차 계산
63-
const presentSlots = slots.map((slot) => slot.status); // T/F 목록 생성
64-
const existing = weekSlotMap.get(week) || [];
65-
weekSlotMap.set(week, [...existing, ...presentSlots]);
66-
});
64+
// 화(0), 목(1), 토(2) 인덱스 반환 함수
65+
const getDayIndex = (dateStr) => {
66+
const day = new Date(dateStr).getDay();
67+
if (day === 2) return 0; // 화
68+
if (day === 4) return 1; // 목
69+
if (day === 6) return 2; // 토
70+
return -1;
71+
};
6772

68-
console.log("주차별 출석 (weekSlotMap):", weekSlotMap);
73+
// 5주차 x 3세션 빈 데이터 생성
74+
const weeklyData = Array.from({ length: 5 }, (_, i) => ({
75+
week: i + 1,
76+
classes: [
77+
{ count: 0, image: getSubImage(0) }, // 화
78+
{ count: 0, image: getSubImage(0) }, // 목
79+
{ count: 0, image: getSubImage(0) } // 토
80+
]
81+
}));
6982

70-
return Array.from({ length: 5 }, (_, i) => {
71-
const week = i + 1;
72-
const all9 = weekSlotMap.get(week) || []; // 총 9개의 출석 슬롯 (3번의 출석체크*주차당 3번의 세션)
83+
if (!rawData || !Array.isArray(rawData)) return weeklyData;
7384

74-
const classes = [0, 1, 2].map((classIdx) => {
75-
// 0,1,2 -> 세션당 3번의 출석체크
76-
const slice = all9.slice(classIdx * 3, classIdx * 3 + 3);
77-
const count = slice.filter(Boolean).length; // 출석 성공(True) 카운트
78-
return {
79-
image: getSubImage(count),
80-
count,
85+
rawData.forEach(({ date, slots }) => {
86+
const week = getWeekFromDate(date);
87+
const dayIdx = getDayIndex(date);
88+
89+
// 유효한 주차(1~5)이고, 화/목/토 세션인 경우만 처리
90+
if (week >= 1 && week <= 5 && dayIdx !== -1) {
91+
92+
// ✅ DB의 "t"(문자열)와 true(불리언) 모두 출석으로 인정
93+
const presentCount = slots.filter(
94+
(slot) => slot.status === true || slot.status === "t"
95+
).length;
96+
97+
weeklyData[week - 1].classes[dayIdx] = {
98+
count: presentCount,
99+
image: getSubImage(presentCount),
81100
};
82-
});
83-
84-
return { week, classes }; // week: 1, classes: [ {image, count}, ... ]
101+
}
85102
});
103+
104+
return weeklyData;
86105
};
87106

107+
// 주간 출석 정보 가져오기
88108
const fetchAttendance = async () => {
89109
try {
110+
// ✅ [배포용] 실제 로그인 유저 ID 사용
90111
const user = JSON.parse(localStorage.getItem("user"));
91112
const userId = user?.id;
113+
92114
if (!userId) return;
93115

94-
// 유저 전체 출석 데이터 불러오기
95116
const res = await api.get(`/attendance/user`, {
96117
params: { userId },
97-
withCredentials: true, // 세션 기반 인증 요청처리
118+
withCredentials: true,
98119
});
120+
99121
const rawData = res.data.data;
100-
console.log("출석 rawData:", rawData);
101122
const weekly = processWeeklyAttendance(rawData);
102123
setAttendanceData(weekly);
103124
} catch (error) {
104125
console.error("출석 정보 가져오기 실패:", error);
105126
}
106127
};
107128

108-
// 세션별 출석체크(총 3번) 진행 정보 불러오기
129+
// 오늘 세션(3회) 출석 정보 가져오기
109130
const fetchTodayAttendance = async () => {
110131
try {
132+
// ✅ [배포용] 실제 로그인 유저 ID 사용
111133
const user = JSON.parse(localStorage.getItem("user"));
112134
const userId = user?.id;
113-
console.log("fetchTodayAttendance() called");
114135

115136
if (!userId) return;
116137

117-
const today = new Date().toLocaleDateString("sv-SE"); // → KST(한국 시간 기준)
138+
const today = new Date().toLocaleDateString("sv-SE");
118139
const res = await api.get(`/attendance/user/date`, {
119140
params: { userId, date: today },
120-
withCredentials: true, // 세션 기반 인증 요청처리
141+
withCredentials: true,
121142
});
122143

123-
// api 응답 수정에 따라 업데이트
124-
// 서버 응답이 순서대로 오지 않을 수 있으므로 order 기준으로 정렬
125144
const slots = (res.data.data || []).sort((a, b) => a.order - b.order);
126145

127146
const statuses = slots.map((slot) => {
128-
if (slot.status === true) return "success";
147+
// ✅ DB 데이터 타입 호환성(t/true) 체크
148+
if (slot.status === true || slot.status === "t") return "success";
129149
else return "fail";
130150
});
131151

132-
// 출석체크 진행안된 것 처리
152+
// 아직 진행되지 않은 출석체크 처리
133153
while (statuses.length < 3) {
134154
statuses.push("not_started");
135155
}
@@ -142,16 +162,14 @@ const Attendance = () => {
142162

143163
useEffect(() => {
144164
if (!currentDateRef.current) {
145-
currentDateRef.current = new Date().toLocaleDateString("sv-SE"); // → KST(한국 시간 기준)
165+
currentDateRef.current = new Date().toLocaleDateString("sv-SE");
146166
}
147-
console.log("currentDateRef 할당 갱신:", currentDateRef.current);
148167

149168
fetchAttendance();
150169
fetchTodayAttendance();
151170

152-
// 10초마다 출석체크 활성화 여부 확인 및 UI 업데이트
171+
// 10초마다 상태 갱신 (미진행 건이 있을 때만)
153172
const interval = setInterval(() => {
154-
// 출석 미진행 상태가 하나라도 있을 때만 호출
155173
setTodayStatuses((prev) => {
156174
if (prev.includes("not_started")) {
157175
fetchTodayAttendance();
@@ -160,28 +178,15 @@ const Attendance = () => {
160178
});
161179
}, 10000);
162180

163-
// 매 분마다 현재 날짜를 확인해서 달라졌으면 상태 업데이트
181+
// 1분마다 날짜 변경 체크
164182
const dateCheckInterval = setInterval(() => {
165-
const todayStr = new Date().toLocaleDateString("sv-SE"); // → KST(한국 시간 기준)
166-
console.log("dateCheckInterval 실행 시간:", new Date());
167-
console.log(
168-
"현재 로드해오는 시간:",
169-
currentDateRef.current,
170-
"| 현재 날짜:",
171-
todayStr
172-
);
173-
183+
const todayStr = new Date().toLocaleDateString("sv-SE");
184+
174185
if (todayStr !== currentDateRef.current) {
175-
console.log(
176-
"날짜 변경 감지 / 이전:",
177-
currentDateRef.current,
178-
"→ 현재:",
179-
todayStr
180-
);
181-
currentDateRef.current = todayStr; // 날짜 갱신
182-
fetchTodayAttendance(); // 새로운 날짜 기준으로 다시 가져오기
186+
currentDateRef.current = todayStr;
187+
fetchTodayAttendance();
183188
}
184-
}, 60000); // 60초마다 확인
189+
}, 60000);
185190

186191
return () => {
187192
clearInterval(interval);
@@ -190,36 +195,36 @@ const Attendance = () => {
190195
}, []);
191196

192197
const handleChange = (index, value) => {
193-
// 숫자만 입력 허용
194198
if (/^\d*$/.test(value)) {
195199
const userCodes = [...attendanceCode];
196200
userCodes[index] = value;
197201
setAttendanceCode(userCodes);
198202
}
199203
};
204+
200205
const handleSubmit = async () => {
201206
try {
207+
// ✅ [배포용] 실제 로그인 유저 ID 사용
202208
const user = JSON.parse(localStorage.getItem("user"));
203209
const userId = user?.id;
210+
204211
if (!userId) return;
205212

206-
// 유저가 입력한 출석 코드 서버에 전달(서버에서 출석코드 체크)
207-
208213
const res = await api.post(
209214
"/attendance/mark",
210215
{
211216
userId,
212217
code: attendanceCode[0],
213218
},
214219
{
215-
withCredentials: true, // 세션 기반 인증 요청처리
220+
withCredentials: true,
216221
}
217222
);
218223

219224
if (res.data.success) {
220225
alert(res.data.data.message);
221-
fetchAttendance(); // 서버 출석체크 전달 후 UI 반영
222-
fetchTodayAttendance(); // 세션별 상단 이미지 UI 반영
226+
fetchAttendance(); // 주간 데이터 갱신
227+
fetchTodayAttendance(); // 오늘 상단 데이터 갱신
223228
} else {
224229
alert(res.data.message || "출석 실패");
225230
}
@@ -229,8 +234,6 @@ const Attendance = () => {
229234
}
230235
};
231236

232-
console.log("attendanceData: ", attendanceData);
233-
234237
return (
235238
<div className={styles.attendance_page}>
236239
<Header />
@@ -251,7 +254,6 @@ const Attendance = () => {
251254
)}
252255
<div className={styles.attend_img_container}>
253256
{todayStatuses.map((status, idx) => {
254-
console.log(`렌더링된 이미지 ${idx + 1}:`, getBoomImage(status));
255257
return (
256258
<div className={styles.boom_icon} key={idx}>
257259
<img src={getBoomImage(status)} alt={`attendance-${idx}`} />
@@ -268,4 +270,4 @@ const Attendance = () => {
268270
);
269271
};
270272

271-
export default Attendance;
273+
export default Attendance;

0 commit comments

Comments
 (0)