@@ -24,11 +25,10 @@ const SessionSelectBox = ({
diff --git a/frontend/src/utils/attendanceList.js b/frontend/src/utils/attendanceList.js
index 2cfe565d..f7f18d4c 100644
--- a/frontend/src/utils/attendanceList.js
+++ b/frontend/src/utils/attendanceList.js
@@ -1,10 +1,70 @@
import { api } from './axios.js';
+import { getAttendanceSessions, getRounds } from './attendanceManage';
+
+const getSessionId = (session) =>
+ session?.sessionId || session?.attendanceSessionId || session?.id || null;
+
+const getSessionTitle = (session) =>
+ session?.session?.title || session?.title || session?.sessionTitle || '';
+
+const buildRoundMetaMap = async () => {
+ const sessions = await getAttendanceSessions();
+ if (!Array.isArray(sessions) || sessions.length === 0) return new Map();
+
+ const perSessionRoundMeta = await Promise.all(
+ sessions.map(async (session) => {
+ const sessionId = getSessionId(session);
+ if (!sessionId) return [];
+
+ try {
+ const rounds = await getRounds(sessionId);
+ if (!Array.isArray(rounds)) return [];
+
+ const sessionTitle = getSessionTitle(session);
+ return rounds
+ .filter((round) => !!round?.roundId)
+ .map((round) => [
+ round.roundId,
+ {
+ sessionTitle,
+ roundDate: round.roundDate,
+ roundStartAt: round.startAt || round.roundStartAt,
+ },
+ ]);
+ } catch {
+ return [];
+ }
+ }),
+ );
+
+ return new Map(perSessionRoundMeta.flat());
+};
export const attendanceList = async () => {
try {
const res = await api.get('/api/attendance/me');
- // console.log('API BASE URL:', import.meta.env.VITE_API_URL);
- return res.data;
+
+ const records = Array.isArray(res.data) ? res.data : [];
+ if (records.length === 0) return records;
+
+ try {
+ const roundMetaMap = await buildRoundMetaMap();
+
+ return records.map((record) => {
+ const roundMeta = roundMetaMap.get(record?.roundId);
+ if (!roundMeta) return record;
+
+ return {
+ ...record,
+ sessionTitle: record?.sessionTitle || roundMeta.sessionTitle,
+ roundDate: record?.roundDate || roundMeta.roundDate,
+ roundStartAt: record?.roundStartAt || roundMeta.roundStartAt,
+ };
+ });
+ } catch {
+ // Keep attendance view available even if metadata enrichment fails.
+ return records;
+ }
} catch (err) {
console.error('출석 세션 불러오기 중 오류 발생: ', err);
throw err;
diff --git a/frontend/src/utils/normalizeSessionTitle.js b/frontend/src/utils/normalizeSessionTitle.js
new file mode 100644
index 00000000..7ccc64cc
--- /dev/null
+++ b/frontend/src/utils/normalizeSessionTitle.js
@@ -0,0 +1,10 @@
+const SESSION_TITLE_FALLBACK = '기타';
+
+export const normalizeSessionTitle = (sessionTitle) => {
+ if (typeof sessionTitle !== 'string') return SESSION_TITLE_FALLBACK;
+
+ const normalizedTitle = sessionTitle.trim();
+ return normalizedTitle !== '' ? normalizedTitle : SESSION_TITLE_FALLBACK;
+};
+
+export const getSessionTitleFallback = () => SESSION_TITLE_FALLBACK;