Conversation
모임장 전용 설정 페이지 추가 (정보 수정, 멤버 관리, 모임 삭제). - 모임 이름/설명 수정 및 저장 기능 - 멤버 관리 탭 (승인 대기/승인 완료) 및 승인·거절·강퇴 기능 - 모임 삭제 확인 모달 연동 - 멤버 목록 커서 기반 페이지네이션 지원 - 관련 API, 타입, 엔드포인트, 쿼리 훅 추가
|
Warning Rate limit exceeded
⌛ 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. Walkthrough모임 멤버 관리 기능 추가: 멤버 카드 컴포넌트, 멤버 조회/승인/거절/제거 API, 관련 훅 및 쿼리 키 정의, 멤버 관리 페이지 신규 구성. Changes
Sequence DiagramsequenceDiagram
actor User
participant GatheringSettingPage
participant useGatheringMembers as useGatheringMembers<br/>(Infinite Query)
participant gatheringQueryKeys
participant API as API Client
participant QueryClient
User->>GatheringSettingPage: 모임 설정 페이지 진입
GatheringSettingPage->>useGatheringMembers: 멤버 목록 조회 (status, gatheringId)
useGatheringMembers->>gatheringQueryKeys: membersByStatus(gatheringId, status) 쿼리 키 생성
useGatheringMembers->>API: getGatheringMembers(params) 요청
API-->>useGatheringMembers: GatheringMemberListResponse 반환
useGatheringMembers-->>GatheringSettingPage: 무한 쿼리 데이터 제공
User->>GatheringSettingPage: 멤버 승인/거절/제거 액션
GatheringSettingPage->>API: handleJoinRequest 또는 removeMember 뮤테이션 호출
API-->>GatheringSettingPage: 성공 응답
GatheringSettingPage->>QueryClient: gatheringQueryKeys.detail(id) 무효화
QueryClient-->>GatheringSettingPage: 관련 쿼리 재조회
GatheringSettingPage-->>User: 변경사항 UI 반영
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 검토 포인트:
Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 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.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@src/features/gatherings/gatherings.types.ts`:
- Around line 228-234: The two request types use inconsistent field
names—CreateGatheringRequest uses gatheringDescription while
GatheringUpdateRequest uses description—so either unify the types or add
explicit mapping: confirm the backend API field (description vs
gatheringDescription), then update GatheringUpdateRequest to use the same field
name as CreateGatheringRequest (or vice versa) so both types use a single symbol
(e.g., gatheringDescription) and update all places that reference
GatheringUpdateRequest/GatheringCreateRequest accordingly; alternatively, if you
must keep both client-side names, add a single conversion helper (e.g., a
mapRequest or normalizeGatheringRequest function used before sending) that maps
description <-> gatheringDescription and update callers to use that helper to
ensure consistent payloads.
In `@src/pages/Gatherings/GatheringSettingPage.tsx`:
- Around line 33-36: Add an explicit early return when the route param id is
missing or invalid: after extracting id via useParams and computing gatheringId,
check if id is undefined or if Number(id) is NaN and return early (e.g., null or
a <Navigate/> to a safe route) so you never pass NaN into useGatheringMembers;
update or add the enabled guard for useGatheringMembers to use the validated
gatheringId instead of assuming the later gathering check will protect you.
🧹 Nitpick comments (6)
src/features/gatherings/hooks/useUpdateGathering.ts (1)
22-23: 모임 이름 변경 후 목록 캐시 정합성 고려모임 이름/설명 수정 후 목록(
lists) 캐시에 이전 값이 남을 수 있습니다.useCreateGathering은gatheringQueryKeys.all을 무효화하는 반면 여기서는detail만 무효화합니다.사용자가 저장 후 목록으로 돌아갈 때 잠시 이전 이름이 보일 수 있으나, 목록 재방문 시 리페치되므로 심각하지는 않습니다. 필요 시
lists()도 함께 무효화하는 것을 고려해 보세요.♻️ 선택적 수정안
onSuccess: (_, { gatheringId }) => { queryClient.invalidateQueries({ queryKey: gatheringQueryKeys.detail(gatheringId) }) + queryClient.invalidateQueries({ queryKey: gatheringQueryKeys.lists() }) },src/features/gatherings/hooks/useGatheringSettingForm.ts (1)
28-28:isValid에서name.length와name.trim().length혼용
name.trim().length > 0으로 공백만 입력을 차단하지만,name.length <= MAX_NAME_LENGTH는 앞뒤 공백 포함 길이를 기준으로 합니다.Input에maxLength가 걸려 있어 실질적 문제는 없지만, 의도를 명확히 하려면 둘 다trim()기준으로 통일하는 게 낫습니다.제안
- const isValid = name.trim().length > 0 && name.length <= MAX_NAME_LENGTH + const isValid = name.trim().length > 0 && name.trim().length <= MAX_NAME_LENGTHsrc/pages/Gatherings/GatheringSettingPage.tsx (1)
33-188: LEADER 역할 검증 누락이 페이지는 모임장 전용 설정 페이지이지만,
gathering.currentUserRole === 'LEADER'검증이 없습니다. API 호출은 서버에서 거부되겠지만, 비 리더 사용자에게 설정 UI가 노출됩니다.
gathering로드 후 역할 확인 및 리다이렉트를 추가하는 것을 권장합니다.src/features/gatherings/components/MemberCard.tsx (1)
5-5:MemberCardAction타입이 export되지 않음
GatheringSettingPage의handleMemberAction(Line 166)에서'approve' | 'reject' | 'remove'를 인라인으로 중복 정의하고 있습니다.MemberCardAction을 export하면 타입 동기화가 보장됩니다.제안
-type MemberCardAction = 'approve' | 'reject' | 'remove' +export type MemberCardAction = 'approve' | 'reject' | 'remove'src/features/gatherings/hooks/useGatheringMembers.ts (2)
22-45:enabled조건 누락 — 유효하지 않은gatheringId로 요청이 발생할 수 있음
gatheringId가0이나 비정상 값일 때도 쿼리가 실행됩니다. 호출부에서 가드하더라도 훅 자체에enabled조건을 두는 것이 안전합니다.제안
return useInfiniteQuery< GatheringMemberListResponse, Error, InfiniteData<GatheringMemberListResponse, PageParam>, readonly (string | number)[], PageParam >({ queryKey: gatheringQueryKeys.membersByStatus(gatheringId, status), queryFn: async ({ pageParam }: { pageParam: PageParam }) => { const response = await getGatheringMembers({ gatheringId, status, pageSize: PAGE_SIZES.GATHERING_MEMBERS, cursorId: pageParam, }) return response.data }, initialPageParam: undefined as PageParam, getNextPageParam: (lastPage: GatheringMemberListResponse): PageParam => { if (!lastPage.hasNext || !lastPage.nextCursor) return undefined return (lastPage.nextCursor as GatheringMemberListCursor).gatheringMemberId }, + enabled: gatheringId > 0, })코딩 가이드라인에서
enabled 조건을 중점적으로 보도록 안내하고 있습니다.
41-44:nextCursor의 타입 단언(as) 불필요Line 42에서
!lastPage.nextCursornull 체크 후 TS가GatheringMemberListCursor로 자동 내로잉합니다.as GatheringMemberListCursor캐스트 없이도.gatheringMemberId접근이 가능합니다.제안
getNextPageParam: (lastPage: GatheringMemberListResponse): PageParam => { if (!lastPage.hasNext || !lastPage.nextCursor) return undefined - return (lastPage.nextCursor as GatheringMemberListCursor).gatheringMemberId + return lastPage.nextCursor.gatheringMemberId },
- gatheringId NaN 가드 추가 (GatheringDetailPage 패턴 통일) - LEADER 역할 검증 추가 (비리더 접근 시 null 반환) - useGatheringMembers에 enabled 조건 추가 - useUpdateGathering에서 lists 캐시도 invalidate - isValid에서 name.trim().length 기준 통일 - MemberCardAction 타입 export 및 페이지에서 재사용 - nextCursor 불필요한 타입 단언(as) 제거
🚀 풀 리퀘스트 제안
📋 작업 내용
모임장(LEADER) 전용 설정 페이지를 구현했습니다. 모임 정보 수정, 멤버 관리(승인/거절/강퇴), 모임 삭제 기능을 제공합니다.
🔧 변경 사항
PATCH /join-requests/{memberId})DELETE /members/{userId})MemberStatusFilter,ApproveType에Extract유틸리티 타입 적용📸 스크린샷
Summary by CodeRabbit
릴리스 노트