[Refactor] WTH-358 : 출석 어드민 기수 조회 시 전체 기수 부터 표시되게 수정#89
Conversation
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 Walkthrough개요출석 페이지의 cardinal 선택 처리를 개선하여, 변경사항
예상 코드 리뷰 난이도🎯 3 (중간 난이도) | ⏱️ ~25분 관련 가능성 있는 PR
제안 라벨
제안 검토자
시 🐰
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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. Review rate limit: 0/1 reviews remaining, refill in 41 minutes and 35 seconds.Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/components/admin/attendance/AttendancePageContent.tsx (2)
46-49:⚠️ Potential issue | 🔴 Critical더티 상태에서 “전체 기수(null)” 변경이 적용되지 않습니다.
Line 46 조건(
pendingCardinalId !== null) 때문에, “전체 기수”를 선택하고 확인해도setSelectedCardinalId가 호출되지 않습니다. 변경 목적을 직접 깨는 로직 버그입니다.🔧 제안 수정안
- const [pendingCardinalId, setPendingCardinalId] = useState<number | null>(null); + const [pendingCardinalId, setPendingCardinalId] = useState<number | null | undefined>( + undefined, + ); const confirmCardinalChange = () => { setDirtyCardIds(new Set()); setCardinalDialogOpen(false); - if (pendingCardinalId !== null) { + if (pendingCardinalId !== undefined) { setSelectedCardinalId(pendingCardinalId); - setPendingCardinalId(null); + setPendingCardinalId(undefined); } };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/admin/attendance/AttendancePageContent.tsx` around lines 46 - 49, The condition currently prevents applying a "null" selection because it only runs when pendingCardinalId !== null; change the guard to allow null values (e.g., check for undefined instead) or simply always apply the pending value: replace the if (pendingCardinalId !== null) { setSelectedCardinalId(pendingCardinalId); setPendingCardinalId(null); } with a check like if (pendingCardinalId !== undefined) { setSelectedCardinalId(pendingCardinalId); setPendingCardinalId(null); } (referencing pendingCardinalId, setSelectedCardinalId, setPendingCardinalId).
22-41:⚠️ Potential issue | 🟡 Minor
useCallback제거를 권장합니다.React Compiler가 활성화된 환경에서
AttendanceSessionCard와CardinalDropdown모두React.memo를 사용하지 않으므로, 이 콜백들의 참조 안정성은 성능 최적화에 영향을 주지 않습니다. React Compiler가 자동으로 함수 최적화를 처리하므로 일반 함수로 구현하는 것이 더 단순합니다. 프로젝트 가이드라인(useMemo,useCallback,React.memo는 실제 필요한 경우를 제외하고 불필요)에 따라 두useCallback을 제거하고 일반 함수로 변경하세요.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/admin/attendance/AttendancePageContent.tsx` around lines 22 - 41, The two callbacks handleDirtyChange and handleCardinalSelect should be converted from useCallback hooks to plain functions because their memoization provides no benefit (AttendanceSessionCard and CardinalDropdown are not memoized); replace the const handleDirtyChange = useCallback(...) and const handleCardinalSelect = useCallback(...) with regular function declarations/const arrow functions that call setDirtyCardIds, setPendingCardinalId, setCardinalDialogOpen, and setSelectedCardinalId directly, and remove the empty/dependency arrays—keep the same parameter names and behavior so closures (isDirty, setDirtyCardIds, etc.) still work.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/admin/attendance/AttendancePageContent.tsx`:
- Around line 56-90: The code uses hardcoded Tailwind utilities (pb-[64px],
h-[72px], min-w-172.5) inside AttendancePageContent JSX (affecting the Card,
Skeleton and empty-state div and the container wrapping AttendanceSessionCard),
which violates the design-token rule; replace those ad-hoc classes with the
appropriate design-token classes (e.g., spacing, height, min-width tokens) or
the component CVA token variants used elsewhere (follow patterns in Card,
Skeleton, AttendanceSessionCard props) and if a required token doesn't exist,
stop and propose adding a new token to the design system for review before
introducing it; ensure all replacements use the token names rather than
bracketed values and update the components (Skeleton, Card,
AttendanceSessionCard usage) to accept token-based classnames/props if needed.
---
Outside diff comments:
In `@src/components/admin/attendance/AttendancePageContent.tsx`:
- Around line 46-49: The condition currently prevents applying a "null"
selection because it only runs when pendingCardinalId !== null; change the guard
to allow null values (e.g., check for undefined instead) or simply always apply
the pending value: replace the if (pendingCardinalId !== null) {
setSelectedCardinalId(pendingCardinalId); setPendingCardinalId(null); } with a
check like if (pendingCardinalId !== undefined) {
setSelectedCardinalId(pendingCardinalId); setPendingCardinalId(null); }
(referencing pendingCardinalId, setSelectedCardinalId, setPendingCardinalId).
- Around line 22-41: The two callbacks handleDirtyChange and
handleCardinalSelect should be converted from useCallback hooks to plain
functions because their memoization provides no benefit (AttendanceSessionCard
and CardinalDropdown are not memoized); replace the const handleDirtyChange =
useCallback(...) and const handleCardinalSelect = useCallback(...) with regular
function declarations/const arrow functions that call setDirtyCardIds,
setPendingCardinalId, setCardinalDialogOpen, and setSelectedCardinalId directly,
and remove the empty/dependency arrays—keep the same parameter names and
behavior so closures (isDirty, setDirtyCardIds, etc.) still work.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a12135ad-ea8f-4829-b923-8fff3f07c319
📒 Files selected for processing (3)
src/components/admin/attendance/AttendancePageContent.tsxsrc/hooks/queries/admin/useAdminAttendanceQueries.tssrc/lib/apis/adminAttendance.ts
| <div className="flex min-w-0 flex-col gap-400 p-700"> | ||
| <CardinalDropdown | ||
| cardinals={cardinals} | ||
| activeCardinal={activeCardinal} | ||
| onSelect={handleCardinalSelect} | ||
| onSelectAll={() => handleCardinalSelect(null)} | ||
| /> | ||
|
|
||
| {sessions.length > 0 ? ( | ||
| <Card className="mt-400 gap-400 px-600 pt-600 pb-[64px]"> | ||
| {sessions.map((session) => ( | ||
| <AttendanceSessionCard | ||
| key={session.id} | ||
| sessionId={session.id} | ||
| date={formatKoreanDate(new Date(session.start))} | ||
| title={session.title} | ||
| isCurrentWeek={session.isCurrentWeek} | ||
| onDirtyChange={handleDirtyChange} | ||
| /> | ||
| ))} | ||
| {isLoading ? ( | ||
| <Card className="mt-400 gap-400 overflow-x-auto px-600 pt-600 pb-[64px]"> | ||
| <div className="min-w-172.5"> | ||
| {Array.from({ length: 4 }, (_, i) => ( | ||
| <Skeleton key={i} className="mt-400 h-[72px] w-full first:mt-0 rounded-md" /> | ||
| ))} | ||
| </div> | ||
| </Card> | ||
| ) : sessions.length > 0 ? ( | ||
| <Card className="mt-400 gap-400 overflow-x-auto px-600 pt-600 pb-[64px]"> | ||
| <div className="flex min-w-172.5 flex-col gap-400"> | ||
| {sessions.map((session) => ( | ||
| <AttendanceSessionCard | ||
| key={session.id} | ||
| sessionId={session.id} | ||
| date={formatKoreanDate(new Date(session.start))} | ||
| title={session.title} | ||
| isCurrentWeek={session.isCurrentWeek} | ||
| onDirtyChange={handleDirtyChange} | ||
| /> | ||
| ))} | ||
| </div> | ||
| </Card> | ||
| ) : ( | ||
| <Card className="mt-400 flex items-center justify-center px-600 py-800"> | ||
| <span className="typo-body1 text-text-alternative"> | ||
| {activeCardinal ? '등록된 정기모임이 없습니다.' : '기수를 선택해 주세요.'} | ||
| </span> | ||
| <Card className="mt-400 flex items-center justify-center overflow-x-auto px-600 py-800"> | ||
| <div className="min-w-172.5 text-center"> | ||
| <span className="typo-body1 text-text-alternative">등록된 정기모임이 없습니다.</span> |
There was a problem hiding this comment.
하드코딩된 Tailwind 값 사용(pb-[64px], h-[72px], min-w-172.5)은 토큰 규칙 위반입니다.
Line 65, Line 66, Line 68, Line 73, Line 74, Line 88, Line 89의 임의값 클래스는 디자인 토큰 우선 원칙과 충돌합니다. 토큰 클래스로 치환하고, 필요한 토큰이 없다면 먼저 토큰 추가 여부를 합의해 주세요.
As per coding guidelines Use Tailwind CSS v4 with class-variance-authority (cva) for styling and Always use design token classes first; no hardcoded values. Ask user before adding new tokens.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/admin/attendance/AttendancePageContent.tsx` around lines 56 -
90, The code uses hardcoded Tailwind utilities (pb-[64px], h-[72px],
min-w-172.5) inside AttendancePageContent JSX (affecting the Card, Skeleton and
empty-state div and the container wrapping AttendanceSessionCard), which
violates the design-token rule; replace those ad-hoc classes with the
appropriate design-token classes (e.g., spacing, height, min-width tokens) or
the component CVA token variants used elsewhere (follow patterns in Card,
Skeleton, AttendanceSessionCard props) and if a required token doesn't exist,
stop and propose adding a new token to the design system for review before
introducing it; ensure all replacements use the token names rather than
bracketed values and update the components (Skeleton, Card,
AttendanceSessionCard usage) to accept token-based classnames/props if needed.
…into WTH-358/출석-어드민-기수-조회-시-전체-기수-부터-표시되게-수정
🤖 Claude 테스트 제안
변경된 컴포넌트에 대해 Claude가 생성한 테스트 코드입니다. 검토 후 적합한 부분만 사용하세요.
|
PR 테스트 결과✅ Jest: 통과 🎉 모든 테스트를 통과했습니다! |
PR 검증 결과✅ TypeScript: 통과 🎉 모든 검증을 통과했습니다! |
|
구현한 기능 Preview: https://weeth-cqaa86t5r-weethsite-4975s-projects.vercel.app |
🤖 Claude 테스트 제안
변경된 컴포넌트에 대해 Claude가 생성한 테스트 코드입니다. 검토 후 적합한 부분만 사용하세요.
|
PR 테스트 결과✅ Jest: 통과 🎉 모든 테스트를 통과했습니다! |
PR 검증 결과✅ TypeScript: 통과 🎉 모든 검증을 통과했습니다! |
|
구현한 기능 Preview: https://weeth-m91p18cjg-weethsite-4975s-projects.vercel.app |
✅ PR 유형
어떤 변경 사항이 있었나요?
📌 관련 이슈번호
✅ Key Changes
📸 스크린샷 or 실행영상
2026-04-29.225521.mp4
🎸 기타 사항 or 추가 코멘트
스켈레톤도 빠져 잇길래...
급하게 추가햇습니다...
Summary by CodeRabbit
출시 노트
새 기능
개선 사항