Skip to content

20260220 fe #214 about attendace page#243

Merged
discipline24 merged 3 commits intomainfrom
20260220-FE-#214-About-Attendace-Page
Feb 24, 2026
Merged

20260220 fe #214 about attendace page#243
discipline24 merged 3 commits intomainfrom
20260220-FE-#214-About-Attendace-Page

Conversation

@yyunee
Copy link
Contributor

@yyunee yyunee commented Feb 24, 2026

1) #214

2) 변경 요약 (What & Why)

출석 관리 페이지

  • 세션 관련 코드 수정
  • 라운드 관련 코드 수정

QR 렌더링 페이지 추가

  • QR 생성 버튼 클릭 시 QR을 보여주는 페이지 오픈

기타

  • 만일의 상황을 위해 check-in page 코드 추가 (현재 사용되지 않음)

3) 스크린샷 / 동영상 (UI 변경 시)

image1

image2


4) 상세 변경사항

1. 세션 관련 코드 수정

  • 세션/라운드 API 응답 스펙 변경에 맞게 프론트 로직 수정
  • roundId, startAt, closeAt 기준으로 데이터 매핑 변경
  • 기존 startTime, allowedMinutes 제거
  • 회차 렌더링 시 고유 key 값을 roundId로 수정
  • 회차 생성/수정 시 새로운 DTO 구조 반영

2. 라운드 관련 코드 수정

  • 회차 생성 폼 필드 변경
    (roundName, roundDate, startAt, closeAt, locationName)
  • allowedMinutes 제거 → closeAt - startAt 계산 방식으로 변경
  • 회차 테이블 렌더링 구조 수정
  • 상태값(roundStatus) 확장 가능하도록 구조 정리

3. QR 렌더링 페이지 신규 구현

  • 각 라운드 행 우측에 QR 생성 버튼 추가
  • 버튼 클릭 시 새 탭에서 QR 렌더링 페이지 오픈
  • SSE API /api/attendance/rounds/{roundId}/qr-stream 연결
  • event: qrToken 커스텀 이벤트 수신 처리
  • 실시간 전달되는 qrTokenQRCodeSVG로 렌더링
  • 3분 주기 토큰 갱신 시 자동 QR 업데이트

5) 참고사항

  • 출석관리 UI는 추후 수정 예정
  • 조회 시 라운드/세션 데이터 로딩에 다소 시간이 소요됨

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능
    • QR 코드 기반 출석 체크인 시스템 추가
    • 라운드별 QR 코드 생성 및 표시 기능 구현
    • 라운드 생성 시 라운드명, 시작/종료 시간, 위치 정보 입력 가능
    • 세션 생성 시 설명, 허용 시간, 상태 정보 추가 설정 가능
    • 라운드 관리 화면에서 QR 코드 생성 버튼 추가

@yyunee yyunee self-assigned this Feb 24, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 24, 2026

Walkthrough

출석 QR 관리 기능을 추가하기 위해 새로운 라우트, 컴포넌트, 유틸리티를 도입했습니다. 기존 출석 관리 UI를 리팩토링하고 QR 코드 생성 및 체크인 인프라를 구축했으며, AttendanceContext를 개선하고 API 엔드포인트를 업데이트했습니다.

Changes

Cohort / File(s) Summary
라우팅 및 의존성
frontend/src/App.jsx, package.json
QR 관리 페이지(CheckInPage, QrRenderPage) 라우트 추가 및 qrcode.react 라이브러리 의존성 추가
라운드 및 세션 관리 UI 리팩토링
frontend/src/components/attendancemanage/RoundDayPicker.jsx, frontend/src/components/attendancemanage/SessionManagementCard.jsx, frontend/src/components/attendancemanage/SessionSettingCard.jsx
라운드 추가/관리 폼 필드 재구성(단일 날짜, roundName, startTime, endTime, locationName), 세션 상태 관리를 컨텍스트 기반으로 변경, 세션 생성 필드 단순화(description, allowedMinutes, status)
컨텍스트 및 유틸리티 API 개선
frontend/src/contexts/AttendanceContext.jsx, frontend/src/utils/attendanceManage.js
AttendanceContext를 명시적으로 내보내기, handleAddSession 시그니처 변경(객체 기반), API 페이로드 수정(startAt, closeAt, roundName, locationName), API 엔드포인트 경로 업데이트
QR 관리 새 기능
frontend/src/components/attendancemanage/qrmanagement/QrRenderPage.jsx, frontend/src/components/attendancemanage/qrmanagement/CheckInPage.jsx, frontend/src/utils/qrManage.js
QR 렌더링 페이지(SSE 스트림 구독, QR 코드 표시), QR 체크인 유틸리티(checkInWithQr), 체크인 페이지 기본 구조(현재 주석 처리)

Sequence Diagram

sequenceDiagram
    participant User as 사용자
    participant QRP as QrRenderPage
    participant API as 백엔드 QR Stream<br/>(EventSource)
    participant UI as QR Code Display

    User->>QRP: 라운드 QR 페이지 접속<br/>(roundId 포함)
    QRP->>API: connectRoundQrStream(roundId)<br/>SSE 연결
    activate API
    Note over API: QR 토큰 생성 및 스트림
    API->>QRP: qrToken 이벤트 수신
    deactivate API
    QRP->>QRP: qrData 상태 업데이트
    QRP->>UI: QRCodeSVG 렌더링<br/>(qrToken 값)
    UI->>User: QR 코드 표시
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45분

Possibly related issues

Possibly related PRs

Suggested reviewers

  • DongEun02
  • Kosw6
  • gxuoo

Poem

🐰 QR 코드가 반짝반짝, 라운드마다 토큰 생성!
체크인 준비는 다음 단계로, 스트림이 흘러흘러 데이터 운반,
출석 관리는 이제 더 똑똑해졌네! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive 제목이 매우 모호하고 구체적인 정보를 제공하지 않습니다. '20260220'는 날짜이고 '#214'는 이슈 번호이며 'attendace page'는 철자 오류('attendance'의 오타)를 포함합니다. 제목을 명확하게 변경하세요. 예: 'Add QR code generation and attendance round management' 또는 '출석 관리 페이지에 QR 코드 생성 기능 추가'
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 20260220-FE-#214-About-Attendace-Page

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (1)
frontend/src/App.jsx (1)

68-69: <Layout /> 외부로 분리 고려

/attendance/admin/qr는 새 탭에서 QR을 전시하는 화면이므로, <Layout />의 내비게이션 헤더가 함께 렌더링됩니다. 출석 확인용 QR 전시 화면에는 불필요한 UI이며, /attendance/check-in 역시 단순 처리 화면임을 감안하면 두 라우트 모두 Layout 밖에 두는 것이 적합합니다.

♻️ 라우트 분리 제안
         <Route element={<ProtectedRoute />}>
           <Route element={<Layout />}>
             ...
-            <Route path="/attendance/admin/qr" element={<QrRenderPage />} />
-            <Route path="/attendance/check-in" element={<CheckInPage />} />
           </Route>
+          <Route path="/attendance/admin/qr" element={<QrRenderPage />} />
+          <Route path="/attendance/check-in" element={<CheckInPage />} />
         </Route>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/App.jsx` around lines 68 - 69, 두 라우트는 내비게이션 헤더가 필요하지 않은 간단한
화면이므로 <Layout /> 안에 렌더링되지 않도록 분리해야 합니다; App.jsx에서 현재 <Route
path="/attendance/admin/qr" element={<QrRenderPage />} /> 및 <Route
path="/attendance/check-in" element={<CheckInPage />} /> 를 찾아서 기존
<Layout>...</Layout> 라우트 그룹 바깥으로 옮기고, 필요하다면 각각 별도의 최상위 Route로 등록해 레이아웃이 적용되지 않도록
변경하세요 (참고 컴포넌트: QrRenderPage, CheckInPage, Layout).
🤖 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/attendancemanage/qrmanagement/CheckInPage.jsx`:
- Around line 1-3: CheckInPage.jsx currently calls api.post but the api import
is commented out, causing a ReferenceError; restore or add the correct import
for the shared axios helper (e.g., import api from '../../../utils/axios' or the
named export used in your project) so that api.post is defined, or replace the
api.post call with the project QR utility function (the existing QR helper
method used elsewhere) and update references in the CheckInPage component
accordingly; ensure you update the top-level imports and keep the function name
api and the api.post usage in the component consistent.
- Around line 11-17: The CheckInPage useEffect currently checks
localStorage.getItem('accessToken') which is incompatible with the cookie-based
auth used elsewhere (see axios.js withCredentials); update the logic in the
CheckInPage component (the useEffect block) to perform an authenticated API call
(e.g., call your current-user or /me endpoint via the existing axios instance)
to verify the session and only navigate to /login if that call fails or returns
401/unauthenticated, rather than reading localStorage; ensure you use the same
axios instance that sends cookies (withCredentials) and handle async state and
cleanup in the useEffect.

In `@frontend/src/components/attendancemanage/qrmanagement/QrRenderPage.jsx`:
- Around line 25-26: QrRenderPage.jsx currently passes qrData.qrToken directly
into <QRCodeSVG value={...}> which can be null/undefined/empty and will crash;
update the render logic in the QrRenderPage component to validate and normalize
qrData.qrToken (e.g., check qrData && typeof qrData.qrToken === 'string' &&
qrData.qrToken.trim() !== '') and only render <QRCodeSVG value={qrData.qrToken}>
when that check passes, otherwise render a safe fallback (placeholder UI or a
default non-null string) so the value prop always receives a valid string.
- Around line 11-19: The component's useEffect calls
connectRoundQrStream(roundId, (data) => setQrData(data)) but omits the onError
handler so SSE errors leave qrData null and UI stuck; update the effect to pass
a third argument to connectRoundQrStream (an onError callback) that sets
component error state or sets qrData to an error sentinel and triggers any
loading flags to false (use the existing setQrData or a new setError/setLoading
state), and ensure the returned cleanup still calls es.close() so streams are
closed on unmount; reference connectRoundQrStream, setQrData, qrData, and
useEffect when making the change.

In `@frontend/src/components/attendancemanage/RoundDayPicker.jsx`:
- Around line 32-69: handleComplete allows end times before start times and
won't catch errors if AttendanceContext.handleAddRounds swallows them; add a
pre-submit validation in handleComplete after building startAt/closeAt that
compares Date(startAt) and Date(closeAt) and alerts/returns if closeAt <=
startAt, and ensure you don't submit when invalid. Also update
AttendanceContext.handleAddRounds to propagate errors (remove swallowing
try/catch or rethrow the caught error) so the try/catch in handleComplete can
handle failures; keep existing console.log/closeAddRoundsModal behavior inside
the try block.

In `@frontend/src/components/attendancemanage/SessionManagementCard.jsx`:
- Around line 125-155: The table body in SessionManagementCard.jsx renders five
<td> cells (date, start time, duration, round number, and a QR button) via
currentDisplayedRounds.map, but the table header still has only four columns,
causing misalignment; update the table header JSX in the SessionManagementCard
component to include a fifth <th> (e.g., "QR" or the localized label) aligned
with the QR button column so the header count matches the body cells and table
columns stay aligned.

In `@frontend/src/utils/axios.js`:
- Around line 3-5: api 인스턴스가 baseURL을 빈 문자열로 고정해 환경 설정을 무시하므로, export된 const
api의 설정에서 baseURL을 빈 문자열('') 대신 프로젝트에서 정의한 BASE_URL (예:
import.meta.env.VITE_API_URL || '')로 바꿔 일관된 오리진을 사용하도록 수정하세요; 즉 axios.create 호출의
baseURL 옵션을 BASE_URL로 교체하고, BASE_URL이 파일에 정의되어 있지 않다면 같은 파일 상단에 const BASE_URL =
import.meta.env.VITE_API_URL || ''를 추가해 참조 오류가 없도록 해주세요.

In `@frontend/src/utils/qrManage.js`:
- Around line 18-21: The SSE listener for 'qrToken' should guard against invalid
or empty JSON to avoid crashing the stream: in the event handler attached via
eventSource.addEventListener('qrToken', ...) wrap JSON.parse(event.data) in a
try/catch, check for falsy/empty event.data before parsing, call
onError?.(error) when parsing fails (or when event.data is empty) and return
early so the stream continues, otherwise call onMessage?.(parsed) with the
parsed payload.

---

Nitpick comments:
In `@frontend/src/App.jsx`:
- Around line 68-69: 두 라우트는 내비게이션 헤더가 필요하지 않은 간단한 화면이므로 <Layout /> 안에 렌더링되지 않도록
분리해야 합니다; App.jsx에서 현재 <Route path="/attendance/admin/qr" element={<QrRenderPage
/>} /> 및 <Route path="/attendance/check-in" element={<CheckInPage />} /> 를 찾아서
기존 <Layout>...</Layout> 라우트 그룹 바깥으로 옮기고, 필요하다면 각각 별도의 최상위 Route로 등록해 레이아웃이 적용되지
않도록 변경하세요 (참고 컴포넌트: QrRenderPage, CheckInPage, Layout).

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 864fcdc and 75e172c.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (11)
  • frontend/src/App.jsx
  • frontend/src/components/attendancemanage/RoundDayPicker.jsx
  • frontend/src/components/attendancemanage/SessionManagementCard.jsx
  • frontend/src/components/attendancemanage/SessionSettingCard.jsx
  • frontend/src/components/attendancemanage/qrmanagement/CheckInPage.jsx
  • frontend/src/components/attendancemanage/qrmanagement/QrRenderPage.jsx
  • frontend/src/contexts/AttendanceContext.jsx
  • frontend/src/utils/attendanceManage.js
  • frontend/src/utils/axios.js
  • frontend/src/utils/qrManage.js
  • package.json

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/components/attendancemanage/SessionManagementCard.jsx (1)

11-17: ⚠️ Potential issue | 🟡 Minor

formatDate 함수에서 날짜 전용 ISO 문자열 파싱 시 타임존 오프셋 문제

roundDate는 백엔드에서 LocalDate 타입으로 직렬화되어 프론트엔드에 "2026-02-21" 형식의 날짜 전용 문자열로 전달됩니다. JavaScript의 new Date() 스펙에 따르면 시간 정보가 없는 ISO 문자열은 UTC 자정으로 파싱되므로, UTC 음수 오프셋 지역(예: EST, PST)에서는 표시되는 날짜가 하루 전으로 어긋날 수 있습니다.

현재 KST(UTC+9) 환경에서는 문제가 없으나, 국제 배포 시 대응하기 위해 아래와 같이 수정하는 것이 안전합니다.

제안 수정안
 const formatDate = (dateStr) => {
   if (!dateStr) return '';
-  const date = new Date(dateStr);
-  const month = String(date.getMonth() + 1).padStart(2, '0');
-  const day = String(date.getDate()).padStart(2, '0');
+  const [year, month, day] = dateStr.split('T')[0].split('-');
   return `${month}/${day}`;
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/attendancemanage/SessionManagementCard.jsx` around
lines 11 - 17, formatDate currently calls new Date(dateStr) which treats
date-only ISO strings as UTC midnight and can shift the day in negative-offset
timezones; update formatDate to parse the "YYYY-MM-DD" roundDate string manually
(split the string into year, month, day and construct a local Date via new
Date(year, monthIndex, day) or format directly from the parts) so the date is
interpreted in local calendar terms and always returns the same MM/DD string;
ensure you still handle falsy input and non-matching formats as a fallback.
♻️ Duplicate comments (1)
frontend/src/components/attendancemanage/SessionManagementCard.jsx (1)

115-122: 이전 리뷰 지적 사항 반영 확인

Line 121에 <th>QR 코드</th> 컬럼 헤더가 추가되어 테이블 바디(5열)와 헤더(5열)가 정렬됩니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/attendancemanage/SessionManagementCard.jsx` around
lines 115 - 122, The table header in SessionManagementCard.jsx was missing the
QR code column which caused column misalignment with the table body; update the
<thead> in SessionManagementCard.jsx to include the missing <th>QR 코드</th> so
the header columns (일자, 시간, 가능(분), 회차, QR 코드) match the five columns rendered in
the tbody (date, time, availableMinutes, sessionNumber, qrCode) and verify the
column order aligns with the data rendering logic.
🧹 Nitpick comments (1)
frontend/src/components/attendancemanage/SessionManagementCard.jsx (1)

4-8: 사용되지 않는 import 3개 제거 필요

useContext(line 4), addRound(line 7), RoundDayPicker(line 8)가 모두 컴포넌트 내에서 참조되지 않습니다.

🧹 제안 수정안
-import { useContext, useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
 import { toast } from 'react-toastify';
 import { useAttendance } from '../../contexts/AttendanceContext';
-import { getRounds, addRound } from '../../utils/attendanceManage';
-import RoundDayPicker from './RoundDayPicker';
+import { getRounds } from '../../utils/attendanceManage';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/attendancemanage/SessionManagementCard.jsx` around
lines 4 - 8, Remove the three unused imports to clean up the module: delete
useContext from the React import, remove addRound from the import of
'../../utils/attendanceManage', and remove the RoundDayPicker import; leave the
remaining used imports (e.g., useEffect, useState, toast, useAttendance,
getRounds) intact so SessionManagementCard.jsx only imports symbols that are
actually referenced.
🤖 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/attendancemanage/SessionManagementCard.jsx`:
- Around line 55-68: The function handleAddRound is dead code—it's defined but
never used; either wire it into the intended consumer (pass handleAddRound as
the callback prop to RoundDayPicker or to whatever component opened by
openAddRoundsModal) so the RoundDayPicker or modal calls handleAddRound
(ensuring it uses selectedSessionId and handleAddRounds), or remove
handleAddRound entirely to clean up unused code; update any parent call-sites
that should receive the callback (e.g., where openAddRoundsModal is invoked) to
accept and forward handleAddRound if you choose to keep it.
- Around line 127-141: The rendering uses new Date(round.startAt) and new
Date(round.closeAt) without validation, which can produce "Invalid Date" or NaN;
update the SessionManagementCard.jsx row rendering to validate dates before
formatting: create Date objects for round.startAt/round.closeAt, test validity
with isFinite(date.getTime()) or !isNaN(date.getTime()), only call
toLocaleTimeString and compute minutes when both dates are valid, and otherwise
render a safe fallback (e.g., '-' or 'N/A') in the time and minutes cells;
ensure you reference the existing variables startTime, closeTime and the minutes
calculation so the change is localized to that table row.

---

Outside diff comments:
In `@frontend/src/components/attendancemanage/SessionManagementCard.jsx`:
- Around line 11-17: formatDate currently calls new Date(dateStr) which treats
date-only ISO strings as UTC midnight and can shift the day in negative-offset
timezones; update formatDate to parse the "YYYY-MM-DD" roundDate string manually
(split the string into year, month, day and construct a local Date via new
Date(year, monthIndex, day) or format directly from the parts) so the date is
interpreted in local calendar terms and always returns the same MM/DD string;
ensure you still handle falsy input and non-matching formats as a fallback.

---

Duplicate comments:
In `@frontend/src/components/attendancemanage/SessionManagementCard.jsx`:
- Around line 115-122: The table header in SessionManagementCard.jsx was missing
the QR code column which caused column misalignment with the table body; update
the <thead> in SessionManagementCard.jsx to include the missing <th>QR 코드</th>
so the header columns (일자, 시간, 가능(분), 회차, QR 코드) match the five columns rendered
in the tbody (date, time, availableMinutes, sessionNumber, qrCode) and verify
the column order aligns with the data rendering logic.

---

Nitpick comments:
In `@frontend/src/components/attendancemanage/SessionManagementCard.jsx`:
- Around line 4-8: Remove the three unused imports to clean up the module:
delete useContext from the React import, remove addRound from the import of
'../../utils/attendanceManage', and remove the RoundDayPicker import; leave the
remaining used imports (e.g., useEffect, useState, toast, useAttendance,
getRounds) intact so SessionManagementCard.jsx only imports symbols that are
actually referenced.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 75e172c and b459ccd.

📒 Files selected for processing (3)
  • frontend/src/components/attendancemanage/SessionManagementCard.jsx
  • frontend/src/components/attendancemanage/qrmanagement/CheckInPage.jsx
  • frontend/src/components/attendancemanage/qrmanagement/QrRenderPage.jsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/src/components/attendancemanage/qrmanagement/QrRenderPage.jsx
  • frontend/src/components/attendancemanage/qrmanagement/CheckInPage.jsx

Copy link
Contributor

@discipline24 discipline24 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다~

@discipline24 discipline24 merged commit e650a20 into main Feb 24, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

⚙️ [기능추가][출석] 출석체크 QR코드 체크인 페이지 구현

2 participants