Skip to content

[Fix] WTH-329: 어드민 멤버 페이지 QA 수정사항#81

Merged
JIN921 merged 33 commits intodevelopfrom
feat/WTH-329-어드민-QA-멤버-페이지-수정사항
Apr 29, 2026

Hidden character warning

The head ref may contain hidden characters: "feat/WTH-329-\uc5b4\ub4dc\ubbfc-QA-\uba64\ubc84-\ud398\uc774\uc9c0-\uc218\uc815\uc0ac\ud56d"
Merged

[Fix] WTH-329: 어드민 멤버 페이지 QA 수정사항#81
JIN921 merged 33 commits intodevelopfrom
feat/WTH-329-어드민-QA-멤버-페이지-수정사항

Conversation

@JIN921
Copy link
Copy Markdown
Collaborator

@JIN921 JIN921 commented Apr 28, 2026

✅ PR 유형

어떤 변경 사항이 있었나요?

  • 새로운 기능 추가
  • 버그 수정
  • 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)
  • 코드 리팩토링
  • 주석 추가 및 수정
  • 문서 수정
  • 빌드 부분 혹은 패키지 매니저 수정
  • 파일 혹은 폴더명 수정
  • 파일 혹은 폴더 삭제

📌 관련 이슈번호

  • Closed #329

✅ Key Changes

🆕 새 기능

  • 리더 권한 이양 — 선택 1명 / 멤버 상세 모달에서 리더로 변경 가능 (LEAD만 노출, 이양 후 자기 자신은 ADMIN으로 즉시 반영)
  • 현재 진행 기수 변경 — 활성 기수 칩의 미트볼 메뉴에서 해당 기수를 진행 중인 기수로 설정

🐛 버그 / QA 수정

  • 어드민 직접 진입 시 권한 미인식 문제 해결 — 어드민 레이아웃에서도 dashboard API로 user store를 hydrate하도록 수정 (UserHydrator 추가)
  • 리더 이양 후 캐시 문제 해결useUserStore.setRole('ADMIN') 즉시 반영 + 서버 dashboard 태그 캐시 updateTag로 무효화
  • 멤버가 없을 때 전체선택 체크박스가 체크되는 문제 수정 (members.length > 0 가드 추가)
  • 멤버 테이블 컬럼 헤더 sticky + 내부 세로 스크롤 — 멤버 많아질 때 헤더 고정으로 가독성 개선
  • 테이블 미트볼 메뉴 버튼 복원 — 행 전체 클릭 + 미트볼 모두 모달 오픈 (이벤트 분리)
  • 어드민 멤버 페이지 가로 스크롤 동작 정상화min-w-3xlmin-w-0로 변경하여 일정관리 페이지와 동일한 스크롤 패턴 적용
  • 에러 코드별 토스트 메시지 노출
    • 21001 (이미 존재하는 기수) → 기수 추가 실패 시
    • 21113 (LEAD만 권한 이양 가능) → 리더 변경 실패 시
    • 21114 (LEAD는 이양을 통해서만 변경 가능) → 권한 변경 실패 시
  • 멤버 타입의 미사용 role 필드 제거 — 실제 역할 표시는 position만 사용 (헤더 '역할' 중복 라벨 해결)
  • 리더 이양 다이얼로그 라벨/설명 통일LEAD리더, description 일관성 유지
  • 관리자 → 어드민 용어 통일

♻️ 리팩토링

  • 컴포넌트 분리 — 기수 칩 그룹을 CardinalPillList로 추출
  • 공용 유틸 추출
    • getApiErrorCode(err) — axios 에러 코드 추출 패턴 통합
    • parseCardinals(raw) — 활동기수 문자열 파싱 통합
  • runBulkMutation에 에러별 메시지 오버라이드 콜백 추가 — 21114 같은 특정 에러 코드 감지 시 다른 토스트 노출 가능
  • MemberTopBar / MemberDetailModal의 리더 변경 액션을 액션 배열로 통합 — 인라인 JSX 제거, 일관된 렌더링 패턴
  • Table 컴포넌트에 wrapperClassName prop 추가 — sticky thead 지원
  • useUserStoresetRole 액션 추가 — 직접 setState 호출 제거 (store 디자인 컨벤션 준수)
  • 매직넘버 → 상수 추출MEMBER_ROLE_ERROR_CODE, CARDINAL_ERROR_CODE
  • 전체선택 체크박스 indeterminate 동기화를 useEffect로 변경 — 콜백 ref의 재호출 미보장 이슈 해결
  • Next.js 16 호환revalidateTag 시그니처 변경에 맞춰 updateTag로 교체

📸 스크린샷 or 실행영상


🎸 기타 사항 or 추가 코멘트

  • member.cardinal이 다중 기수 문자열일 때 멤버 상세 모달에서 첫 숫자만 표시되는 부분에 TODO 주석 추가 (응답 정렬 확인 후 수정 예정)

하 왜 기수 추가하고 추가한 기수로 유저 기수 변경하는 게 안 될까요,,?? 저만 이런 걸까요..?? ㅜㅜ
파일 체인지는 이제 네이밍 한 번에 바꾸기 하면서 다른 파일들도 건들게 돼 가지구,, 이름 때문에 체크된 부분 훅훅 넘기시면 생각보다 별 거 없을 겁니다,,, ㅎㅎ,,

Summary by CodeRabbit

  • 새로운 기능

    • 리더 권한 이양(transfer lead) 기능 추가
    • 기수 관리 개선: 전체 선택, 드래그 상호작용 및 현재 기수 지정 기능
    • 대시보드 초기 로드 시 사용자/동아리 정보 자동 수집과 오류별 리디렉션 처리
  • 개선사항

    • 앱 전반에서 "관리자" → "운영진" 용어 통일
    • 회원 관리 UX 간소화(대량 작업 유틸·카디널 파싱·상세 모달 개선)
    • 테이블 레이아웃/헤더 개선 및 외부 래퍼 클래스 지원
    • 공통 유틸(일괄 변이 처리, API 오류 코드 추출) 추가

JIN921 added 26 commits April 28, 2026 12:09
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

📝 Walkthrough

Walkthrough

관리자 영역을 운영진으로 재브랜딩하고, 기수 관리(UI/훅/API), 리더 권한 이양, 서버측 대시보드 조회 및 UserHydrator 기반 사용자·클럽 상태 하이드레이션을 추가했습니다. 회원 관리 UI/테이블/모달과 관련 유틸·상수도 리팩토링했습니다.

Changes

Cohort / File(s) Summary
레이블 재브랜딩
src/app/(public)/landing/page.tsx, src/components/admin/board/BoardCard.tsx, src/components/admin/board/modal/constants.ts, src/components/admin/layout/LNB.tsx, src/components/attendance/AttendanceTodayCard.tsx, src/components/home/HomeBoardContent.tsx, src/components/layout/Footer.tsx, src/components/layout/header/DefaultActions.tsx, src/components/layout/header/Header.tsx, src/components/layout/header/MobileNavSheet.tsx, src/constants/home/tutorial.tsx, src/constants/landing/landing.ts
UI 텍스트/aria-label 등에서 "관리자""운영진"으로 일괄 변경
기수(Cardinal) 기능 추가/개선
src/components/admin/member/CardinalPillList.tsx, src/components/admin/CardinalDropdown.tsx, src/components/admin/member/CardinalCard.tsx, src/hooks/mutations/admin/useAdminCardinalMutations.ts, src/lib/apis/cardinal.ts, src/utils/admin/parseCardinals.ts, src/constants/errorCode.ts
CardinalPillList 신규 컴포넌트, CardinalDropdown에 onSelectAll 추가, useSetCurrentCardinal 훅 및 cardinalApi.setCurrentCardinal, parseCardinals 유틸, 관련 에러 코드 추가
리더 권한 이양 (Transfer Lead)
src/components/admin/member/MemberTopBar.tsx, src/components/admin/member/modal/MemberDetailModal.tsx, src/hooks/mutations/admin/useAdminMemberMutations.ts, src/lib/apis/adminMember.ts, src/stores/useUserStore.ts, src/constants/admin/memberTopBar.constants.ts, src/constants/admin/memberDetailModal.constants.ts, src/constants/errorCode.ts
useTransferLead 훅·API 추가, UI 액션/모달/상수 타입 변경, MEMBER_ROLE_ERROR_CODE 추가, 사용자 스토어에 setRole 추가
관리자 레이아웃: 서버 대시보드 조회 및 Hydration
src/app/(private)/[clubId]/admin/layout.tsx, src/lib/actions/club.ts
서버에서 homeServerApi.getDashboard(clubId) 호출, 403일 경우 /${clubId}/home로 리다이렉트, 성공 시 UserHydrator로 사용자·클럽 정보 주입 및 revalidateDashboard 서버 액션 추가
회원 관리 페이지 및 테이블 리팩토링
src/components/admin/member/MemberPageContent.tsx, src/components/admin/member/MemberTable.tsx, src/components/admin/member/MemberTopBar.tsx
Cardinal 필터링 단순화(parseCardinals), CardinalPillList 도입, bulk mutation 헬퍼 통합, 테이블 선택/행 클릭 동작 재설계 및 레이아웃 변경
회원 상세 모달 및 상수 정리
src/components/admin/member/modal/MemberDetailModal.tsx, src/constants/admin/memberDetailModal.constants.ts, src/constants/admin/memberTable.constants.ts
onApprove/onResetPassword 제거, onTransferLead 추가, 활동정보 표시 변경, FooterAction/TopBarAction 타입 도입 및 컬럼명(직급→역할) 변경
테이블 컴포넌트 변경
src/components/ui/table.tsx
마우스 드래그 수평 스크롤 제거, wrapperClassName prop 추가로 컨테이너 스타일 유연화
유틸·공유 함수 추가 및 배럴 업데이트
src/utils/shared/getApiErrorCode.ts, src/utils/shared/runBulkMutation.ts, src/utils/shared/index.ts, src/hooks/mutations/admin/index.ts
getApiErrorCode, runBulkMutation 추가 및 재수출, useTransferLead/useSetCurrentCardinal 훅 배럴에 노출
데이터 매퍼·타입 변경
src/utils/admin/memberMapper.ts, src/types/admin/member.d.ts
ROLE_MAP 외부로 노출, Member 타입에서 role 필드 제거, toMember 매핑에서 role 제거
기타 UI/입력 개선
src/components/admin/member/modal/AddCardinalModal.tsx, src/components/admin/member/modal/ChangeCardinalsModal.tsx, src/components/admin/index.ts, src/components/admin/member/CardinalCard.tsx
기수 입력을 텍스트(numeric inputMode)로 변경·정규화, ChangeCardinalsModal이 ID 배열 제출, CardinalPillListCardinalPillListProps export 추가, CardinalCard에 endIcon prop 추가

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

🔨 Refactor

Suggested reviewers

  • nabbang6
  • dalzzy

Poem

🐰 운영진에게 바치는 축하 노래,
기수는 줄지어, 권한은 손에 쥐고,
레이아웃은 새 숨을 쉬고 데이터는 물들어,
클릭 한 번에 흐름이 바뀌네—
토끼가 뿅 하고 박수 쳐요! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.89% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목은 PR의 주요 변경사항인 어드민 멤버 페이지 QA 수정사항을 명확하게 요약하고 있습니다.
Description check ✅ Passed PR 설명은 템플릿의 모든 필수 섹션을 포함하고 있으며, 새로운 기능, 버그 수정, 리팩토링에 대해 구체적이고 상세하게 설명하고 있습니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/WTH-329-어드민-QA-멤버-페이지-수정사항

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
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

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

@github-actions
Copy link
Copy Markdown

PR 테스트 결과

Jest: 통과

🎉 모든 테스트를 통과했습니다!

@github-actions
Copy link
Copy Markdown

🤖 Claude 테스트 제안

모델: claude-sonnet-4-6 | 토큰: 0 입력 / 0 출력

변경된 컴포넌트에 대해 Claude가 생성한 테스트 코드입니다. 검토 후 적합한 부분만 사용하세요.

src/app/(private)/[clubId]/admin/layout.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/app/(public)/landing/page.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/components/admin/CardinalDropdown.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/components/admin/board/BoardCard.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/components/admin/board/modal/constants.ts

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


이 코멘트는 Claude API를 통해 자동 생성되었습니다. 반드시 검토 후 사용하세요.

@github-actions
Copy link
Copy Markdown

구현한 기능 Preview: https://weeth-6qz4a84mn-weethsite-4975s-projects.vercel.app

@github-actions
Copy link
Copy Markdown

PR 검증 결과

TypeScript: 통과
ESLint: 통과
Prettier: 통과
Build: 통과

🎉 모든 검증을 통과했습니다!

Copy link
Copy Markdown

@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: 4

🧹 Nitpick comments (2)
src/stores/useUserStore.ts (1)

20-20: useUserActions에도 setRole를 함께 노출하는 편이 일관적입니다.

새 액션이 생겼는데 selector 묶음에는 빠져 있어, 호출부 패턴이 분산될 수 있습니다.

♻️ 제안 수정안
 export const useUserActions = () =>
   useUserStore(
     useShallow((store) => ({
       setUser: store.setUser,
+      setRole: store.setRole,
       reset: store.reset,
     })),
   );

Also applies to: 31-36

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

In `@src/stores/useUserStore.ts` at line 20, The selector bundle/useUserActions
should include the new setRole action for consistency; add setRole (the function
defined as setRole: (role: Role) => set({ role }, false, 'setRole')) to the
useUserActions export alongside the other actions (the same group that includes
the actions mentioned around lines 31-36) so callers can import all user actions
from useUserActions rather than mixing call patterns.
src/components/admin/CardinalDropdown.tsx (1)

40-40: 간소화 제안: 불필요한 화살표 함수 래퍼 제거

onSelectAll이 이미 함수이므로 직접 전달할 수 있습니다.

♻️ 제안된 변경
-          {onSelectAll && <DropdownMenuItem onSelect={() => onSelectAll()}>전체</DropdownMenuItem>}
+          {onSelectAll && <DropdownMenuItem onSelect={onSelectAll}>전체</DropdownMenuItem>}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/admin/CardinalDropdown.tsx` at line 40, The JSX uses an
unnecessary arrow wrapper around the onSelectAll callback: in
CardinalDropdown.tsx change the DropdownMenuItem prop from onSelect={() =>
onSelectAll()} to passing the function directly as onSelect={onSelectAll} to
simplify and avoid creating an extra closure; locate the DropdownMenuItem usage
and update similarly if any other menu items wrap callbacks in no-op arrow
functions.
🤖 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/app/`(private)/[clubId]/admin/layout.tsx:
- Around line 18-20: The server-side call to homeServerApi.getDashboard(clubId)
in layout.tsx can throw and currently bubbles up; wrap the await call in a
try-catch inside the async component (or loader) that calls getDashboard and, on
catch, return/render a simple fallback UI (e.g., a minimal admin error
placeholder) or rethrow a controlled error after logging; alternatively add an
error boundary file named error.tsx under the same route (the [clubId]/admin
segment) to handle and display errors—target the getDashboard call and the
exported default async layout function when applying the change.

In `@src/constants/term.ts`:
- Line 61: Replace the Korean particle typos in the policy text constants:
change the occurrence of '“동아리 운영진”란' to '“동아리 운영진”이란' and change each '운영진는' to
'운영진은' wherever they appear in the term strings (the constants that contain
those sentences, e.g., the string entries shown with '“동아리 운영진”란' and the other
lines with '운영진는'); update all three occurrences so the user-facing terms are
grammatically correct before release.

In `@src/utils/shared/getApiErrorCode.ts`:
- Around line 3-4: getApiErrorCode currently returns err.response?.data?.code
without guaranteeing it's a number; update getApiErrorCode to validate/coerce
the value from isAxiosError(err) ? err.response?.data?.code so the function
truly returns number | undefined — e.g., extract the raw value from
err.response?.data?.code, check typeof === 'number' (or attempt Number(value)
and ensure !Number.isNaN), and return the numeric value or undefined; keep
references to getApiErrorCode and isAxiosError and the err.response?.data?.code
access to locate the change.

In `@src/utils/shared/runBulkMutation.ts`:
- Around line 14-23: The function currently shows toastSuccess even when args is
empty; add an initial guard in runBulkMutation (before calling
Promise.allSettled and using mutateAsync) that checks if args is falsy or
args.length === 0 and short-circuits (e.g., return early) instead of proceeding;
optionally call toastError or a specific "no items selected" message from
messages to inform the user, ensuring toastSuccess is only triggered after real
mutations complete and no errors are present (affects args, mutateAsync,
toastSuccess, toastError, resolveErrorMessage, messages).

---

Nitpick comments:
In `@src/components/admin/CardinalDropdown.tsx`:
- Line 40: The JSX uses an unnecessary arrow wrapper around the onSelectAll
callback: in CardinalDropdown.tsx change the DropdownMenuItem prop from
onSelect={() => onSelectAll()} to passing the function directly as
onSelect={onSelectAll} to simplify and avoid creating an extra closure; locate
the DropdownMenuItem usage and update similarly if any other menu items wrap
callbacks in no-op arrow functions.

In `@src/stores/useUserStore.ts`:
- Line 20: The selector bundle/useUserActions should include the new setRole
action for consistency; add setRole (the function defined as setRole: (role:
Role) => set({ role }, false, 'setRole')) to the useUserActions export alongside
the other actions (the same group that includes the actions mentioned around
lines 31-36) so callers can import all user actions from useUserActions rather
than mixing call patterns.
🪄 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: 66d39301-2d90-41b5-a4c9-ad42a2739cd1

📥 Commits

Reviewing files that changed from the base of the PR and between 8c7007b and d4e96ee.

📒 Files selected for processing (41)
  • src/app/(private)/[clubId]/admin/layout.tsx
  • src/app/(public)/landing/page.tsx
  • src/components/admin/CardinalDropdown.tsx
  • src/components/admin/board/BoardCard.tsx
  • src/components/admin/board/modal/constants.ts
  • src/components/admin/index.ts
  • src/components/admin/layout/LNB.tsx
  • src/components/admin/member/CardinalCard.tsx
  • src/components/admin/member/CardinalPillList.tsx
  • src/components/admin/member/MemberPageContent.tsx
  • src/components/admin/member/MemberTable.tsx
  • src/components/admin/member/MemberTopBar.tsx
  • src/components/admin/member/modal/MemberDetailModal.tsx
  • src/components/admin/schedule/general/SchedulePageContent.tsx
  • src/components/attendance/AttendanceTodayCard.tsx
  • src/components/home/HomeBoardContent.tsx
  • src/components/layout/Footer.tsx
  • src/components/layout/header/DefaultActions.tsx
  • src/components/layout/header/Header.tsx
  • src/components/layout/header/MobileNavSheet.tsx
  • src/components/ui/table.tsx
  • src/constants/admin/memberDetailModal.constants.ts
  • src/constants/admin/memberTable.constants.ts
  • src/constants/admin/memberTopBar.constants.ts
  • src/constants/errorCode.ts
  • src/constants/home/tutorial.tsx
  • src/constants/landing/landing.ts
  • src/constants/term.ts
  • src/hooks/mutations/admin/index.ts
  • src/hooks/mutations/admin/useAdminCardinalMutations.ts
  • src/hooks/mutations/admin/useAdminMemberMutations.ts
  • src/lib/actions/club.ts
  • src/lib/apis/adminMember.ts
  • src/lib/apis/cardinal.ts
  • src/stores/useUserStore.ts
  • src/types/admin/member.d.ts
  • src/utils/admin/memberMapper.ts
  • src/utils/admin/parseCardinals.ts
  • src/utils/shared/getApiErrorCode.ts
  • src/utils/shared/index.ts
  • src/utils/shared/runBulkMutation.ts
💤 Files with no reviewable changes (1)
  • src/types/admin/member.d.ts

Comment thread src/app/(private)/[clubId]/admin/layout.tsx Outdated
Comment thread src/constants/term.ts Outdated
Comment thread src/utils/shared/getApiErrorCode.ts Outdated
Comment thread src/utils/shared/runBulkMutation.ts
@JIN921 JIN921 changed the title fix: 어드민 멤버 페이지 QA 수정사항 (WTH-329) [Fix] WTH-329: 어드민 멤버 페이지 QA 수정사항 Apr 28, 2026
@JIN921 JIN921 self-assigned this Apr 28, 2026
@JIN921 JIN921 requested review from dalzzy, nabbang6 and woneeeee April 28, 2026 22:08
@JIN921 JIN921 added 🐞 BugFix Something isn't working 📬 API 서버 API 통신 labels Apr 28, 2026
Copy link
Copy Markdown
Member

@woneeeee woneeeee left a comment

Choose a reason for hiding this comment

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

Image

요거 타이포 설정이 피그마랑 다른 것 같아서 확인 부탁드립니당!!
추가적으로 api 응답이 오기 전까지 로딩이나 불러오는 중... 이런 메시지가 있으면 좋을 것 같아요 아무것도 안떠서 순간 오류인가 생각하긴 했슴니당... 이건 나중에 출시 후에 해도 되긴 할덧..... 🦦

그리고 전에 [어드민: 멤버 관리] 표에서 그 라인을 클릭했을때 모달이 뜨도록 수정 요 부분이 아직 반영이 안되어있는 것 같습니당!! <- 워메 잘 뜨네요... 제가 착각해서 다른 프리뷰 url로 확인했나봅니당... 죄송ㅎㅐ요 ㅠㅠㅠㅠ

Copy link
Copy Markdown
Member

@dalzzy dalzzy left a comment

Choose a reason for hiding this comment

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

확인했습니당~!!
저는 지원님이 말씀하신 라인 클릭 시 모달 뜨는 건 잘 되는 것 같아여 ..!! 머징

그은데 새로운 기수 추가 모달에서 input에 위아래 화살표 나오는거 제거하는 게 좋을 것 같습니당
input type 그냥 text로 하고 숫자만 입력 가능하도록 하고 text 정렬도 right로 해주면 좋을 것 같아요!!

Image

멤버 리스트 체크박스도 저희가 쓰는 svg 로 변경하는 게 좋을 듯 한데
일단 할 게 많으면,, 제껴두고 이건 나중에 수정해도 될 듯 합니당..

Image

Copy link
Copy Markdown
Collaborator

@nabbang6 nabbang6 left a comment

Choose a reason for hiding this comment

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

확인햇습니다~~!!! 짱짱
저도 방금 추가한 기수로 기수 변경이 안 돼서 확인해보니,, 기수 변경 patch 요청 자체에 404 에러가 뜨고 잇는 것 같습니다 ㅜ _ㅜ 스웨거에서도 요렇게 뜨고 잇어서 배겐드 분들께 여쭤보아야 할 것 같아용 ...

Image

@github-actions
Copy link
Copy Markdown

🤖 Claude 테스트 제안

모델: claude-sonnet-4-6 | 토큰: 0 입력 / 0 출력

변경된 컴포넌트에 대해 Claude가 생성한 테스트 코드입니다. 검토 후 적합한 부분만 사용하세요.

src/app/(private)/[clubId]/admin/layout.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/app/(private)/[clubId]/error.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/app/(public)/landing/page.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/app/api/proxy/auth/refresh/route.ts

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/components/admin/CardinalDropdown.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


이 코멘트는 Claude API를 통해 자동 생성되었습니다. 반드시 검토 후 사용하세요.

@github-actions
Copy link
Copy Markdown

PR 테스트 결과

Jest: 통과

🎉 모든 테스트를 통과했습니다!

@github-actions
Copy link
Copy Markdown

구현한 기능 Preview: https://weeth-3zd0hlzb8-weethsite-4975s-projects.vercel.app

@github-actions
Copy link
Copy Markdown

PR 검증 결과

TypeScript: 통과
ESLint: 통과
Prettier: 통과
Build: 통과

🎉 모든 검증을 통과했습니다!

Copy link
Copy Markdown

@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)
src/app/api/proxy/auth/refresh/route.ts (1)

56-96: ⚠️ Potential issue | 🟠 Major

auth 리다이렉트는 요청 origin 기준으로 URL을 구성해야 합니다.

NEXT_PUBLIC_APP_URL이 현재 요청 origin과 다르면, 이 응답에서 설정한 인증 쿠키가 다른 origin으로 리다이렉트되어 접근할 수 없게 됩니다. 라인 86-94에서 쿠키를 설정한 응답을 쿠키가 유효한 origin으로 리다이렉트해야 하므로 request.nextUrl.origin 기준으로 URL을 만드는 것이 맞습니다. src/proxy.ts:16-24도 동일하게 request.url 기반으로 login URL을 구성하고 있습니다.

수정안
-  const appUrl = process.env.NEXT_PUBLIC_APP_URL ?? request.nextUrl.origin;
+  const appUrl = request.nextUrl.origin;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/api/proxy/auth/refresh/route.ts` around lines 56 - 96, The redirect
and login responses use NEXT_PUBLIC_APP_URL via the local appUrl variable which
can differ from the current request origin; change constructions that use appUrl
(the appUrl assignment, the buildLoginResponse(...) calls and the
NextResponse.redirect(new URL(safeRedirect, appUrl)) call) to use
request.nextUrl.origin (or request.url's origin) as the base so cookies and
redirects are created for the current request origin instead of
NEXT_PUBLIC_APP_URL; ensure all places that call buildLoginResponse or create
the redirectResponse pass request.nextUrl.origin as the base URL.
🧹 Nitpick comments (1)
src/components/admin/member/MemberTable.tsx (1)

75-87: 토큰 외 값은 피해주세요.

gap-600max-h-[600px]는 이 저장소의 TSX 스타일 가이드에서 권장하는 토큰 범위를 벗어난 hardcoded 값입니다. 기존 spacing/size 토큰으로 맞추거나, 정말 필요하다면 디자인 토큰 추가 여부를 먼저 확인해 주세요.

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

In `@src/components/admin/member/MemberTable.tsx` around lines 75 - 87, The code
uses hardcoded utility classes gap-600 and max-h-[600px] in MemberTable (the
outer div using className and the Table wrapperClassName) which violate the TSX
style guide; replace those with existing design tokens (e.g., the repository's
spacing/size token classes used elsewhere such as gap-200/gap-300 or the
appropriate max-h token) or, if a new token is required, coordinate with design
to add it before committing; update the outer div's className and the Table
wrapperClassName to use the tokenized classes instead of gap-600 and
max-h-[600px].
🤖 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/member/MemberTable.tsx`:
- Around line 53-54: Compute selection state against the currently visible
members instead of using selectedIds.size directly: derive a
visibleSelectedCount by counting members whose id exists in selectedIds (e.g.,
members.filter(m => selectedIds.has(m.id)).length) and then set isAllSelected =
members.length > 0 && visibleSelectedCount === members.length and hasAnySelected
= visibleSelectedCount > 0; alternatively, when members changes clear or
intersect selectedIds to keep only visible IDs. Apply the same change to the
other similar selection calculations in this file (the block around the repeated
logic).
- Around line 116-120: The TableRow currently only handles mouse clicks via
onClick and is not keyboard-accessible; update the TableRow element (the one
with key={member.id} and onClick={() => onMemberAction?.(member)}) to be
focusable and respond to Enter/Space: add tabIndex={0}, role="button" (or
appropriate ARIA role), and implement an onKeyDown handler that calls
onMemberAction?.(member) when the user presses Enter or Space (for Space,
preventDefault to avoid scrolling). Keep the existing onClick behavior and
visual cursor style.

---

Outside diff comments:
In `@src/app/api/proxy/auth/refresh/route.ts`:
- Around line 56-96: The redirect and login responses use NEXT_PUBLIC_APP_URL
via the local appUrl variable which can differ from the current request origin;
change constructions that use appUrl (the appUrl assignment, the
buildLoginResponse(...) calls and the NextResponse.redirect(new
URL(safeRedirect, appUrl)) call) to use request.nextUrl.origin (or request.url's
origin) as the base so cookies and redirects are created for the current request
origin instead of NEXT_PUBLIC_APP_URL; ensure all places that call
buildLoginResponse or create the redirectResponse pass request.nextUrl.origin as
the base URL.

---

Nitpick comments:
In `@src/components/admin/member/MemberTable.tsx`:
- Around line 75-87: The code uses hardcoded utility classes gap-600 and
max-h-[600px] in MemberTable (the outer div using className and the Table
wrapperClassName) which violate the TSX style guide; replace those with existing
design tokens (e.g., the repository's spacing/size token classes used elsewhere
such as gap-200/gap-300 or the appropriate max-h token) or, if a new token is
required, coordinate with design to add it before committing; update the outer
div's className and the Table wrapperClassName to use the tokenized classes
instead of gap-600 and max-h-[600px].
🪄 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: db695a7c-f18a-44cb-a393-3aed0bd1349b

📥 Commits

Reviewing files that changed from the base of the PR and between d4e96ee and 52853fe.

📒 Files selected for processing (14)
  • src/app/(private)/[clubId]/admin/layout.tsx
  • src/app/(private)/[clubId]/error.tsx
  • src/app/api/proxy/auth/refresh/route.ts
  • src/components/admin/member/MemberTable.tsx
  • src/components/admin/member/MemberTopBar.tsx
  • src/components/admin/member/modal/AddCardinalModal.tsx
  • src/components/admin/member/modal/ChangeCardinalsModal.tsx
  • src/components/attendance/AttendanceTodayCard.tsx
  • src/components/home/HomeBoardContent.tsx
  • src/components/layout/header/DefaultActions.tsx
  • src/constants/home/tutorial.tsx
  • src/constants/term.ts
  • src/utils/shared/getApiErrorCode.ts
  • src/utils/shared/runBulkMutation.ts
✅ Files skipped from review due to trivial changes (4)
  • src/components/home/HomeBoardContent.tsx
  • src/components/attendance/AttendanceTodayCard.tsx
  • src/components/layout/header/DefaultActions.tsx
  • src/constants/home/tutorial.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/utils/shared/getApiErrorCode.ts
  • src/constants/term.ts
  • src/app/(private)/[clubId]/admin/layout.tsx
  • src/utils/shared/runBulkMutation.ts

Comment on lines +53 to +54
const isAllSelected = members.length > 0 && selectedIds.size === members.length;
const hasAnySelected = selectedIds.size > 0;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

현재 멤버 기준으로 선택 상태를 계산해 주세요.

selectedIds.size만 보면 필터/빈 목록에서 현재 보이지 않는 ID까지 체크 상태로 집계됩니다. 그 결과 헤더 아이콘과 aria-pressed가 서로 어긋날 수 있습니다. members와의 교집합 기준으로 hasAnySelected/isAllSelected를 계산하거나, 멤버 목록이 바뀔 때 선택 상태를 정리해 주세요.

🔧 제안 수정
-  const isAllSelected = members.length > 0 && selectedIds.size === members.length;
-  const hasAnySelected = selectedIds.size > 0;
+  const selectedMemberIds = members.filter((member) => selectedIds.has(member.id));
+  const isAllSelected = members.length > 0 && selectedMemberIds.length === members.length;
+  const hasAnySelected = selectedMemberIds.length > 0;

Also applies to: 99-104

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

In `@src/components/admin/member/MemberTable.tsx` around lines 53 - 54, Compute
selection state against the currently visible members instead of using
selectedIds.size directly: derive a visibleSelectedCount by counting members
whose id exists in selectedIds (e.g., members.filter(m =>
selectedIds.has(m.id)).length) and then set isAllSelected = members.length > 0
&& visibleSelectedCount === members.length and hasAnySelected =
visibleSelectedCount > 0; alternatively, when members changes clear or intersect
selectedIds to keep only visible IDs. Apply the same change to the other similar
selection calculations in this file (the block around the repeated logic).

Comment on lines +116 to +120
<TableRow
key={member.id}
className="hover:bg-container-neutral-interaction cursor-pointer border-0"
onClick={() => onMemberAction?.(member)}
>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

행 클릭에 키보드 접근성을 추가해 주세요.

TableRow는 클릭으로 모달을 열지만, <tr>onClick만 붙어 있어 키보드 사용자는 같은 동작을 수행할 수 없습니다. 이 변경은 행 전체를 상호작용 요소로 만들었으니 tabIndex/Enter/Space 처리 같은 대체 수단이 필요합니다.

⌨️ 제안 수정
             <TableRow
               key={member.id}
               className="hover:bg-container-neutral-interaction cursor-pointer border-0"
               onClick={() => onMemberAction?.(member)}
+              tabIndex={0}
+              onKeyDown={(e) => {
+                if (e.key === 'Enter' || e.key === ' ') {
+                  e.preventDefault();
+                  onMemberAction?.(member);
+                }
+              }}
             >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<TableRow
key={member.id}
className="hover:bg-container-neutral-interaction cursor-pointer border-0"
onClick={() => onMemberAction?.(member)}
>
<TableRow
key={member.id}
className="hover:bg-container-neutral-interaction cursor-pointer border-0"
onClick={() => onMemberAction?.(member)}
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
onMemberAction?.(member);
}
}}
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/admin/member/MemberTable.tsx` around lines 116 - 120, The
TableRow currently only handles mouse clicks via onClick and is not
keyboard-accessible; update the TableRow element (the one with key={member.id}
and onClick={() => onMemberAction?.(member)}) to be focusable and respond to
Enter/Space: add tabIndex={0}, role="button" (or appropriate ARIA role), and
implement an onKeyDown handler that calls onMemberAction?.(member) when the user
presses Enter or Space (for Space, preventDefault to avoid scrolling). Keep the
existing onClick behavior and visual cursor style.

@JIN921 JIN921 merged commit ccd36ba into develop Apr 29, 2026
5 checks passed
@JIN921 JIN921 deleted the feat/WTH-329-어드민-QA-멤버-페이지-수정사항 branch April 29, 2026 10:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📬 API 서버 API 통신 🐞 BugFix Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants