Skip to content

[feat] 모임 설정 페이지 구현#69

Merged
mgYang53 merged 3 commits intodevelopfrom
feat/gatherings-setting-57
Feb 11, 2026
Merged

[feat] 모임 설정 페이지 구현#69
mgYang53 merged 3 commits intodevelopfrom
feat/gatherings-setting-57

Conversation

@mgYang53
Copy link
Contributor

@mgYang53 mgYang53 commented Feb 9, 2026

🚀 풀 리퀘스트 제안

📋 작업 내용

모임장(LEADER) 전용 설정 페이지를 구현했습니다. 모임 정보 수정, 멤버 관리(승인/거절/강퇴), 모임 삭제 기능을 제공합니다.

🔧 변경 사항

  • 모임 정보 수정 (이름 최대 12자, 설명 최대 150자) 및 저장 기능
  • 멤버 관리 탭 UI (승인 대기 / 승인 완료, 카운트 배지)
  • 가입 요청 승인/거절 기능 (PATCH /join-requests/{memberId})
  • 멤버 강퇴 기능 (DELETE /members/{userId})
  • 모임 삭제 확인 모달 연동
  • 멤버 목록 커서 기반 페이지네이션 (더보기 버튼)
  • MemberCard 컴포넌트 추가
  • 관련 API 함수, 엔드포인트, 타입, 쿼리 훅 추가
  • MemberStatusFilter, ApproveTypeExtract 유틸리티 타입 적용

📸 스크린샷

image image 스크린샷 2026-02-09 오후 11 47 54

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능
    • 모임 설정 페이지에서 모임 정보(이름, 설명) 수정 가능
    • 가입 신청 멤버 승인/거절 기능 추가
    • 모임 멤버 관리 및 제거 기능 추가
    • 멤버 목록을 대기 중/활성 상태로 필터링하여 조회 가능

모임장 전용 설정 페이지 추가 (정보 수정, 멤버 관리, 모임 삭제).
- 모임 이름/설명 수정 및 저장 기능
- 멤버 관리 탭 (승인 대기/승인 완료) 및 승인·거절·강퇴 기능
- 모임 삭제 확인 모달 연동
- 멤버 목록 커서 기반 페이지네이션 지원
- 관련 API, 타입, 엔드포인트, 쿼리 훅 추가
@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Warning

Rate limit exceeded

@mgYang53 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 3 minutes and 32 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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

Cohort / File(s) Summary
컴포넌트 및 페이지
src/features/gatherings/components/MemberCard.tsx, src/features/gatherings/components/index.ts, src/pages/Gatherings/GatheringSettingPage.tsx, src/pages/Gatherings/index.ts
멤버 카드 컴포넌트 신규 추가(승인/거절/제거 액션 지원), 모임 설정 페이지 신규 구성(멤버 관리, 폼 유효성 검증 포함).
API 및 엔드포인트
src/features/gatherings/gatherings.api.ts, src/features/gatherings/gatherings.endpoints.ts
멤버 조회, 승인/거절, 제거, 모임 수정/삭제 API 함수 추가. 관련 엔드포인트 경로 정의(MEMBERS, HANDLE_JOIN_REQUEST, REMOVE_MEMBER, DETAIL 등).
타입 및 쿼리 키
src/features/gatherings/gatherings.types.ts, src/features/gatherings/hooks/gatheringQueryKeys.ts, src/features/gatherings/index.ts
GatheringMember에 memberStatus, joinedAt 필드 추가. 멤버 목록 조회 타입(GetGatheringMembersParams, GatheringMemberListResponse), 승인 타입(ApproveType, MemberStatusFilter) 신규 정의. 쿼리 키 팩토리 확장(members, membersByStatus).
커스텀 훅
src/features/gatherings/hooks/useGatheringMembers.ts, src/features/gatherings/hooks/useUpdateGathering.ts, src/features/gatherings/hooks/useDeleteGathering.ts, src/features/gatherings/hooks/useHandleJoinRequest.ts, src/features/gatherings/hooks/useRemoveMember.ts, src/features/gatherings/hooks/useGatheringSettingForm.ts, src/features/gatherings/hooks/index.ts
멤버 무한 페이지네이션(useGatheringMembers), 모임 수정/삭제, 요청 처리, 멤버 제거 뮤테이션 훅 추가. 모임 설정 폼 상태 관리 훅(MAX_NAME_LENGTH: 50, MAX_DESCRIPTION_LENGTH: 500) 신규.
라우팅 및 상수
src/routes/index.tsx, src/shared/constants/pagination.ts
/gatherings/:id/settings 경로 신규 추가. 페이지네이션 상수 추가(GATHERING_MEMBERS: 9).

Sequence Diagram

sequenceDiagram
    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 반영
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

검토 포인트:

  • 새로운 무한 페이지네이션 로직(useGatheringMembers)의 cursor 처리 정확성 확인
  • GatheringSettingPage의 327줄 코드에서 멤버 액션 핸들러 흐름 및 상태 관리 검증
  • API 레이어의 5개 신규 함수(getGatheringMembers, updateGathering, deleteGathering, handleJoinRequest, removeMember) 정상 연동 확인
  • React 18에서 의존성 배열, useCallback/useMemo 사용 적절성 검토
  • 폼 유효성 검증(MAX_NAME_LENGTH: 50, MAX_DESCRIPTION_LENGTH: 500) 반영 여부 확인

Possibly related PRs

Suggested reviewers

  • haruyam15
  • choiyoungae
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
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.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 변경 사항의 핵심을 명확히 반영합니다. 모임 설정 페이지 구현이라는 주요 변경 사항을 간결하게 설명하고 있습니다.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/gatherings-setting-57

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.

@mgYang53 mgYang53 changed the base branch from main to develop February 9, 2026 14:46
@mgYang53 mgYang53 changed the title feat: 모임 설정 페이지 구현 (#57) [feat] 모임 설정 페이지 구현 Feb 9, 2026
@mgYang53 mgYang53 linked an issue Feb 9, 2026 that may be closed by this pull request
34 tasks
@mgYang53 mgYang53 self-assigned this Feb 9, 2026
@mgYang53 mgYang53 added the feat 새로운 기능 추가 label Feb 9, 2026
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

🤖 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) 캐시에 이전 값이 남을 수 있습니다. useCreateGatheringgatheringQueryKeys.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.lengthname.trim().length 혼용

name.trim().length > 0으로 공백만 입력을 차단하지만, name.length <= MAX_NAME_LENGTH는 앞뒤 공백 포함 길이를 기준으로 합니다. InputmaxLength가 걸려 있어 실질적 문제는 없지만, 의도를 명확히 하려면 둘 다 trim() 기준으로 통일하는 게 낫습니다.

제안
- const isValid = name.trim().length > 0 && name.length <= MAX_NAME_LENGTH
+ const isValid = name.trim().length > 0 && name.trim().length <= MAX_NAME_LENGTH
src/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되지 않음

GatheringSettingPagehandleMemberAction(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로 요청이 발생할 수 있음

gatheringId0이나 비정상 값일 때도 쿼리가 실행됩니다. 호출부에서 가드하더라도 훅 자체에 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.nextCursor null 체크 후 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) 제거
Copy link
Contributor

@haruyam15 haruyam15 left a comment

Choose a reason for hiding this comment

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

고생하셨슴다

@mgYang53 mgYang53 merged commit ef9d570 into develop Feb 11, 2026
2 checks passed
@mgYang53 mgYang53 deleted the feat/gatherings-setting-57 branch February 11, 2026 10:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 새로운 기능 추가

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] 모임 설정 페이지 구현

2 participants