Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React from 'react';
import { createPortal } from 'react-dom';
import styles from './AbsenceSummaryModal.module.css';

const AbsenceSummaryModal = ({ isOpen, onClose, userRows }) => {
if (!isOpen) return null;

// 결석한 기록이 있는 유저들만 필터링하고 결석 횟수 계산
const absenceData = userRows
const absenceData = (userRows || [])
.map(user => {
const totalAbsences = user.attendances.filter(att => att.status === 'ABSENT').length;
const totalLates = user.attendances.filter(att => att.status === 'LATE').length;
const totalAbsences = (user.attendances || []).filter(att => att.status === 'ABSENT').length;
const totalLates = (user.attendances || []).filter(att => att.status === 'LATE').length;
return {
...user,
totalAbsences,
Expand All @@ -18,7 +18,7 @@ const AbsenceSummaryModal = ({ isOpen, onClose, userRows }) => {
.filter(user => user.totalAbsences > 0 || user.totalLates > 0)
.sort((a, b) => b.totalAbsences - a.totalAbsences || b.totalLates - a.totalLates);

return (
const modalContent = (
<div className={styles.modalOverlay} onClick={onClose}>
<div
className={styles.modalContent}
Expand Down Expand Up @@ -80,6 +80,8 @@ const AbsenceSummaryModal = ({ isOpen, onClose, userRows }) => {
</div>
</div>
);

return createPortal(modalContent, document.body);
};

export default AbsenceSummaryModal;
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
padding: 24px 28px;
overflow-y: auto;
flex: 1;
max-height: 100%;
}

.summaryTable {
Expand All @@ -75,13 +76,16 @@
}

.summaryTable th {
position: sticky;
top: -24px; /* modalBody padding-top 보정 */
text-align: left;
padding: 12px 14px;
font-size: 14px;
font-weight: 600;
color: #64748b;
background: #f8fafc;
border-bottom: 2px solid #e2e8f0;
z-index: 10;
}

.summaryTable td {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,8 @@ const AttendanceManagementCard = ({ styles: commonStyles }) => {
const fetchRequestIdRef = useRef(0);

const sortedUserRows = useMemo(() => {
if (!attendanceData.rounds.length) {
return attendanceData.userRows
if (!(attendanceData?.rounds || []).length) {
return (attendanceData?.userRows || [])
.map((user, index) => ({ user, index }))
.sort((a, b) => {
const priorityDiff =
Expand All @@ -170,9 +170,9 @@ const AttendanceManagementCard = ({ styles: commonStyles }) => {
}

// 로컬 시간대 기준으로 오늘 날짜(YYYY-MM-DD)와 정렬된 회차 목록 생성
const sortedRounds = [...attendanceData.rounds].sort(
const sortedRounds = [...(attendanceData?.rounds || [])].sort(
(a, b) =>
a.roundDate.localeCompare(b.roundDate) || a.roundNumber - b.roundNumber
(a.roundDate || '').localeCompare(b.roundDate || '') || (a.roundNumber || 0) - (b.roundNumber || 0)
);
const todayStr = new Date().toLocaleDateString('sv-SE');

Expand All @@ -181,10 +181,9 @@ const AttendanceManagementCard = ({ styles: commonStyles }) => {
sortedRounds[sortedRounds.length - 1];

const targetRoundId = targetRound?.roundId;

return [...attendanceData.userRows].sort((a, b) => {
const aAtt = a.attendances.find((att) => att.roundId === targetRoundId);
const bAtt = b.attendances.find((att) => att.roundId === targetRoundId);
return [...(attendanceData?.userRows || [])].sort((a, b) => {
const aAtt = (a?.attendances || []).find((att) => att.roundId === targetRoundId);
const bAtt = (b?.attendances || []).find((att) => att.roundId === targetRoundId);

const aStatus = aAtt?.status || 'PENDING';
const bStatus = bAtt?.status || 'PENDING';
Expand Down Expand Up @@ -513,7 +512,7 @@ const AttendanceManagementCard = ({ styles: commonStyles }) => {
<th className={styles.nameHeader}>이름</th>
<th className={styles.roleHeader}>역할</th>
<th className={styles.studentIdHeader}>학번</th>
{attendanceData.rounds.map((round) => (
{(attendanceData?.rounds || []).map((round) => (
<th key={round.roundId} className={styles.roundHeader}>
{round.roundNumber}회차
</th>
Expand All @@ -540,7 +539,7 @@ const AttendanceManagementCard = ({ styles: commonStyles }) => {
<td>{user.userName}</td>
<td>{getRoleDisplayLabel(user.role)}</td>
<td>{user.studentId}</td>
{user.attendances.map((att) => {
{(user.attendances || []).map((att) => {
const statusClass =
styles[
ATTENDANCE_CONFIG[att.status]?.className ||
Expand Down Expand Up @@ -585,7 +584,7 @@ const AttendanceManagementCard = ({ styles: commonStyles }) => {
) : (
<tr>
<td
colSpan={4 + attendanceData.rounds.length}
colSpan={4 + (attendanceData?.rounds || []).length}
className={styles.noData}
>
데이터가 존재하지 않습니다.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,12 @@ const SessionManagementCard = ({ styles: commonStyles }) => {
const rounds = await getRounds(selectedSessionId);
setCurrentDisplayedRounds(rounds || []);
} catch (e) {
toast.error('라운드를 불러오지 못했습니다.');
const status = e?.response?.status ?? e?.status;
if (status === 403) {
toast.error('세션 멤버가 아니거나 조회 권한이 없습니다.');
} else {
toast.error('라운드를 불러오지 못했습니다.');
}
setCurrentDisplayedRounds([]);
}
};
Expand Down Expand Up @@ -214,8 +219,8 @@ const SessionManagementCard = ({ styles: commonStyles }) => {
</tr>
</thead>
<tbody>
{currentDisplayedRounds.length > 0 ? (
currentDisplayedRounds.map((round, index) => {
{(currentDisplayedRounds || []).length > 0 ? (
(currentDisplayedRounds || []).map((round, index) => {
const startTime = new Date(round.startAt);
const closeTime = new Date(round.closeAt);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,6 @@
width: 100%;
min-width: 0;
overflow-x: auto;
overflow-y: hidden;
padding-bottom: 2px;
margin-left: 0;
}
Expand Down