[FE] 출석조회 세션 선택 전 중복 발생 해결#286
Hidden character warning
Conversation
Walkthrough세션 제목 정규화 유틸을 추가하고 이를 SessionSelectBox, SessionManage, Attendance 등에서 사용하도록 통합했습니다. 출석 데이터는 라운드 메타를 조회해 기록에 sessionTitle·roundDate·roundStartAt를 보강하도록 변경되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as Frontend UI
participant Utils as attendanceList utils
participant API as attendanceManage.getRounds
participant Renderer as Renderer
UI->>Utils: 요청 (attendance 조회 후 enrichment)
Utils->>API: getRounds(sessionIds)
API-->>Utils: rounds list (roundId, sessionTitle, startAt)
Utils->>Utils: buildRoundMetaMap(rounds) -> map by roundId
Utils-->>UI: enriched attendance records (sessionTitle, roundDate, roundStartAt)
UI->>Renderer: 렌더링 (SessionManage/SessionSelectBox 사용)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
출석조회 화면에서 세션 선택 전(혹은 세션 데이터 중복/공백 처리로 인해) 발생하던 중복 표시 및 세션 선택 상태 꼬임을 줄이기 위해, 세션 타이틀 정규화/중복 제거 및 기본 선택값 동기화를 추가한 PR입니다.
Changes:
Attendance에서 세션 옵션을 메모이즈하고, 유효한 기본 세션이 선택되도록 상태를 동기화SessionSelectBox에서 세션 타이틀을 trim 기반으로 정규화하고 중복 옵션을 제거SessionManage에서 세션 타이틀 정규화 및attendanceId기반 중복 제거 로직 추가
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| frontend/src/pages/Attendance.jsx | 세션 옵션 계산/기본 선택 세션 동기화 및 옵션 없을 때 선택 비활성화 처리 |
| frontend/src/components/attendance/SessionSelectBox.jsx | 세션 타이틀 정규화/중복 제거 및 select value 안정화 |
| frontend/src/components/attendance/SessionManage.jsx | 세션 타이틀 정규화 및 목록 중복 제거(표시 중복 완화) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@frontend/src/components/attendance/SessionSelectBox.jsx`:
- Around line 4-5: normalizeSessionTitle currently returns '' for
non-string/empty titles which removes the "기타" option upstream; make it return
the same placeholder label used elsewhere (e.g. '기타') or use a shared
normalization util so SessionManage.jsx and Attendance.jsx see identical values.
Update normalizeSessionTitle (and the other occurrences at the 13-17 block) to
map empty or non-string sessionTitle values to the canonical "기타" token, or
refactor to import and use a shared function so the dropdown and auto-select
logic refer to the same normalized value.
In `@frontend/src/pages/Attendance.jsx`:
- Around line 20-29: sessionOptions is computed from attendanceSessions by
reading session.sessionTitle which doesn't exist in the real API shape (see
frontend/src/utils/attendanceList.js), so sessionOptions becomes empty and
disables <SessionSelectBox>; fix by deriving options from the actual field(s)
the API provides (or synthesize sessionTitle earlier) instead of
session.sessionTitle, update the useMemo that builds sessionOptions to use the
correct property (or map attendanceSessions to include a sessionTitle before
this component runs), and ensure the effect that clears selectedSession only
runs when there truly are no options so the SessionSelectBox isn't erroneously
disabled.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d8e65172-e888-4142-b2a6-e6f04c4e1abf
📒 Files selected for processing (3)
frontend/src/components/attendance/SessionManage.jsxfrontend/src/components/attendance/SessionSelectBox.jsxfrontend/src/pages/Attendance.jsx
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
frontend/src/components/attendance/SessionSelectBox.jsx (2)
25-37: 빈 세션 목록 시 select 값 불일치 가능성
sessionList가 빈 배열인 경우currentValue는 빈 문자열이 되지만, 렌더링되는<option>이 없어 React controlled component 경고가 발생할 수 있습니다.♻️ 제안: 빈 목록 처리 추가
<select id="session-select" className={styles.session} value={currentValue} onChange={(event) => onChange?.(event.target.value)} - disabled={disabled} + disabled={disabled || sessionList.length === 0} > + {sessionList.length === 0 && ( + <option value="">세션 없음</option> + )} {sessionList.map((item) => ( <option key={item} value={item}> {item} </option> ))} </select>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/components/attendance/SessionSelectBox.jsx` around lines 25 - 37, The select can become a controlled component with no options when sessionList is empty, causing React warnings; update the SessionSelectBox rendering to handle empty sessionList by ensuring an option always exists (e.g., render a placeholder "<option value=\"\">No sessions</option>" when sessionList.length === 0) and/or normalize currentValue before passing to the select (use "" if currentValue is undefined/null or not in sessionList). Modify the JSX that maps sessionList (and the value prop usage of currentValue) so the select always has at least one option and the value is kept in sync.
17-18: 부모 컴포넌트와의 자동 선택 로직 중복
currentValue가sessionList[0]으로 폴백하는 로직이Attendance.jsx의useEffect(Line 31-42)에서도 동일하게 수행됩니다. 두 곳에서 자동 선택을 처리하면 초기 렌더링 시 불필요한 상태 업데이트가 발생할 수 있습니다.현재 구조에서는
SessionSelectBox가currentValue를 내부적으로 계산하지만onChange를 통해 부모에게 알리지 않으므로, 부모의selectedSession과 실제 표시되는 값이 일시적으로 불일치할 수 있습니다.♻️ 제안: 자동 선택 로직을 한 곳에서만 관리
부모 컴포넌트(
Attendance.jsx)에서 자동 선택을 담당하고 있으므로, 여기서는 단순히selectedSession을 그대로 사용하거나, 폴백 시onChange를 호출하여 부모 상태를 동기화하는 것이 좋습니다:- const currentValue = sessionList.includes(selectedSession) ? selectedSession : sessionList[0] || ''; + // 부모에서 자동 선택을 처리하므로 여기서는 selectedSession 직접 사용 + // sessionList에 없는 경우 빈 문자열로 처리 (부모 useEffect가 동기화) + const currentValue = sessionList.includes(selectedSession) ? selectedSession : '';또는
useEffect를 추가하여 폴백 시 부모에게 알림:useEffect(() => { if (sessionList.length > 0 && !sessionList.includes(selectedSession)) { onChange?.(sessionList[0]); } }, [sessionList, selectedSession, onChange]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/components/attendance/SessionSelectBox.jsx` around lines 17 - 18, SessionSelectBox computes currentValue = sessionList.includes(selectedSession) ? selectedSession : sessionList[0] || '' causing duplicate auto-selection with Attendance.jsx; remove internal fallback logic and either use selectedSession directly or, if you must fallback in the child, notify the parent by calling onChange(sessionList[0]) so parent state stays in sync. Update SessionSelectBox to stop mutating displayed value independently (remove the fallback assignment to currentValue) and instead rely on the parent's selectedSession or trigger onChange inside a useEffect when sessionList changes and selectedSession is not present; reference the symbols SessionSelectBox, currentValue, selectedSession, sessionList, onChange and the parent's useEffect in Attendance.jsx when making the change.frontend/src/utils/attendanceList.js (1)
10-41: 세션별 회차 조회 실패 시 로깅 부재
Promise.all내부의catch블록에서 에러를 완전히 무시하고 있습니다. 특정 세션의 회차 조회가 실패해도 전체 기능은 동작하지만, 디버깅이 어려워질 수 있습니다.♻️ 제안: 최소한의 에러 로깅 추가
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 { + } catch (err) { + console.warn(`세션 ${sessionId} 회차 조회 실패:`, err); return []; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/utils/attendanceList.js` around lines 10 - 41, In buildRoundMetaMap, do not silently swallow errors in the sessions.map catch for getRounds; update that catch inside the async callback (the function passed to sessions.map) to log the error along with identifying info (e.g., sessionId and/or sessionTitle from getSessionId/getSessionTitle) before returning []; use the existing logging mechanism (console.error or the app logger) so failures in getRounds are recorded while preserving the current behavior of returning [] on error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@frontend/src/components/attendance/SessionManage.jsx`:
- Around line 78-105: The deduplication logic in visibleSessions skips sessions
missing attendanceId, causing duplicates and undefined React keys; update the
filter to compute a stable dedupe key for each session (e.g., const dedupeKey =
session.attendanceId ?? `${session.roundId ?? ""}-${session.userId ??
""}-${session.roundDate ?? ""}`) and use that key with seenAttendanceIds to
decide whether to push into deduplicated; ensure you add the original session
object (or attach the dedupeKey as a new property) to the deduplicated array so
the UI can use a stable key instead of undefined, keeping the rest of the
visibleSessions logic (normalizeSessionTitle, getTimestamp sorting) intact.
---
Nitpick comments:
In `@frontend/src/components/attendance/SessionSelectBox.jsx`:
- Around line 25-37: The select can become a controlled component with no
options when sessionList is empty, causing React warnings; update the
SessionSelectBox rendering to handle empty sessionList by ensuring an option
always exists (e.g., render a placeholder "<option value=\"\">No
sessions</option>" when sessionList.length === 0) and/or normalize currentValue
before passing to the select (use "" if currentValue is undefined/null or not in
sessionList). Modify the JSX that maps sessionList (and the value prop usage of
currentValue) so the select always has at least one option and the value is kept
in sync.
- Around line 17-18: SessionSelectBox computes currentValue =
sessionList.includes(selectedSession) ? selectedSession : sessionList[0] || ''
causing duplicate auto-selection with Attendance.jsx; remove internal fallback
logic and either use selectedSession directly or, if you must fallback in the
child, notify the parent by calling onChange(sessionList[0]) so parent state
stays in sync. Update SessionSelectBox to stop mutating displayed value
independently (remove the fallback assignment to currentValue) and instead rely
on the parent's selectedSession or trigger onChange inside a useEffect when
sessionList changes and selectedSession is not present; reference the symbols
SessionSelectBox, currentValue, selectedSession, sessionList, onChange and the
parent's useEffect in Attendance.jsx when making the change.
In `@frontend/src/utils/attendanceList.js`:
- Around line 10-41: In buildRoundMetaMap, do not silently swallow errors in the
sessions.map catch for getRounds; update that catch inside the async callback
(the function passed to sessions.map) to log the error along with identifying
info (e.g., sessionId and/or sessionTitle from getSessionId/getSessionTitle)
before returning []; use the existing logging mechanism (console.error or the
app logger) so failures in getRounds are recorded while preserving the current
behavior of returning [] on error.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0e4b2ffd-706b-4df0-9a3a-6cd3187fa1db
📒 Files selected for processing (5)
frontend/src/components/attendance/SessionManage.jsxfrontend/src/components/attendance/SessionSelectBox.jsxfrontend/src/pages/Attendance.jsxfrontend/src/utils/attendanceList.jsfrontend/src/utils/normalizeSessionTitle.js
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/src/pages/Attendance.jsx
Summary by CodeRabbit
릴리스 노트
새 기능
버그 수정