Skip to content

[feat] 주제 확정 UI 및 기능 구현 #65

Merged
haruyam15 merged 5 commits intodevelopfrom
feat/topics-confirm-47
Feb 11, 2026
Merged

[feat] 주제 확정 UI 및 기능 구현 #65
haruyam15 merged 5 commits intodevelopfrom
feat/topics-confirm-47

Conversation

@haruyam15
Copy link
Contributor

@haruyam15 haruyam15 commented Feb 8, 2026

🚀 풀 리퀘스트 제안

📋 작업 내용

주제 확정 모달 UI 및 기능 구현
확정할 주제를 순서대로 선택하고 한 번에 확정하는 플로우
TopicHeader에서 주제가 1개 이상일 때만 "주제 확정하기" 버튼 노출

🔧 변경 사항

신규 컴포넌트

ConfirmTopicModal — 주제 확정 모달 (주제 목록 조회 + 순서 선택 + 확정 요청)
ConfirmModalTopicCard — 확정 모달 내 주제 카드 (NumberedCheckbox 포함)

신규 훅

useConfirmTopics — 주제 확정 mutation, 성공 시 제안/확정 주제 쿼리 캐시 무효화

API 레이어

topics.types.ts — ConfirmTopicsParams, ConfirmTopicsResponse 타입 추가
topics.endpoints.ts — CONFIRM 엔드포인트 추가
topics.api.ts — confirmTopics 함수 추가 (목데이터 포함)
topics.mock.ts — getMockConfirmTopics 추가, canConfirm 목데이터 true로 변경

기존 컴포넌트 변경 사항

TopicHeader — proposedTopicsCount, onOpenChange props 추가, 주제 없을 시 버튼 비활성화
MeetingDetailPage — ConfirmTopicModal 연결, isConfirmTopicOpen 상태 관리

📸 스크린샷 (선택 사항)

스크린샷 2026-02-08 오후 11 12 27

Summary by CodeRabbit

  • 새로운 기능
    • 주제 확정 모달 추가: 제안된 주제를 선택해 한 번에 확정 가능
    • 주제 카드 UI 추가: 카드 클릭으로 선택 토글, 선택 시 시각적 강조
    • 선택 관리 개선: 번호형 체크박스 그룹, 전체해제, 선택 개수 표시 및 로딩 스켈레톤
    • 회의 상세에서 모달 열기 버튼 제공으로 빠른 접근 가능
    • 서버 연동 및 확인 흐름 강화: 확정 요청 전송, 성공 시 목록 갱신 및 오류 처리

주제 확정 모달 및 관련 로직을 추가.
사용자가 제안된 주제를 순서대로 선택해 확정할 수 있도록 구현.
- ConfirmTopicModal, ConfirmModalTopicCard 컴포넌트 추가
- useConfirmTopics mutation 훅 및 confirmTopics API 추가
- ConfirmTopicsParams, ConfirmTopicsResponse 타입 정의
- TopicHeader에 확정 버튼 활성화 조건 및 클릭 핸들러 연결
@haruyam15 haruyam15 linked an issue Feb 8, 2026 that may be closed by this pull request
@haruyam15 haruyam15 self-assigned this Feb 8, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 8, 2026

Walkthrough

제안된 주제들을 선택해 확정하는 모달 기반 기능(카드·모달 컴포넌트, API 엔드포인트·타입, 뮤테이션 훅, 모의 데이터, NumberedCheckbox ref 지원)이 추가되어 클라이언트에서 주제 확정 흐름을 처리합니다. (50단어 이내)

Changes

Cohort / File(s) Summary
확정 모달 UI
src/features/topics/components/ConfirmModalTopicCard.tsx, src/features/topics/components/ConfirmTopicModal.tsx
모달용 선택 카드와 주제 확정 모달 추가. 카드 전체 클릭으로 체크박스 토글, 선택 목록 관리, 확인 시 전역 확인 모달 후 뮤테이션 호출 및 로딩/에러 처리 포함.
토픽 헤더·컴포넌트 인덱스
src/features/topics/components/TopicHeader.tsx, src/features/topics/components/index.ts
TopicHeaderproposedTopicsCount, onOpenChange props 추가 및 확정 버튼 표시 조건/클릭 동작 연결. 새 컴포넌트 둘을 재수출함.
API 엔드포인트·타입
src/features/topics/topics.endpoints.ts, src/features/topics/topics.types.ts, src/features/topics/topics.api.ts
/topics/confirm 엔드포인트 추가, ConfirmTopicsParams/ConfirmTopicsResponse 타입 도입 및 confirmTopics 구현(모의/실제 분기 포함).
뮤테이션 훅·훅 바렐
src/features/topics/hooks/useConfirmTopics.ts, src/features/topics/hooks/index.ts
주제 확정 뮤테이션 훅 추가: confirmTopics 호출 및 성공 시 proposedList·confirmedList 캐시 무효화. 훅 인덱스에 재수출 추가.
모의 데이터·페이지 통합
src/features/topics/topics.mock.ts, src/pages/Meetings/MeetingDetailPage.tsx
getMockConfirmTopics 추가 및 getMockProposedTopics에서 canConfirm 활성화. MeetingDetailPage에 ConfirmTopicModal 통합(모달 상태, 레이아웃 패딩, 헤더 prop 전달).
공유 UI 변경
src/shared/ui/NumberedCheckbox.tsx
NumberedCheckbox를 forwardRef로 래핑해 외부에서 버튼 ref를 전달할 수 있도록 변경(기존 동작 유지).

Sequence Diagram

sequenceDiagram
    participant User as User
    participant Modal as ConfirmTopicModal
    participant CheckboxGroup as NumberedCheckboxGroup
    participant Hook as useConfirmTopics
    participant API as Topics API
    participant QC as QueryClient

    User->>Modal: 모달 열기
    User->>CheckboxGroup: 카드 클릭 -> 체크/선택 토글
    Modal->>Hook: 확정 요청 (gatheringId, meetingId, topicIds)
    Hook->>API: confirmTopics 호출
    API-->>Hook: ConfirmTopicsResponse
    Hook->>QC: proposedList 캐시 무효화
    Hook->>QC: confirmedList 캐시 무효화
    QC-->>Modal: UI 갱신 반영
    Modal-->>User: 모달 닫기 및 선택 초기화
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • choiyoungae
  • mgYang53
🚥 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 제목은 변경사항의 핵심을 정확히 반영하고 있습니다. 주제 확정 UI와 기능 구현이라는 주된 목표를 명확하게 전달하며, 간결하고 구체적입니다.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/topics-confirm-47

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
src/features/topics/topics.api.ts (1)

230-247: 새 함수 구조는 기존 패턴과 일관성 있게 잘 작성되었습니다.

한 가지 참고: PR 리뷰 코멘트에서 USE_MOCK_DATA를 환경변수 기반(VITE_USE_MOCK)으로 전환하자는 합의가 진행 중입니다. 이 파일의 모든 함수에 적용되는 사항이므로, 별도 후속 PR에서 일괄 전환하면 좋겠습니다.

// 예시
const USE_MOCK_DATA = import.meta.env.VITE_USE_MOCK === 'true'
src/features/topics/topics.types.ts (1)

38-39: description 타입이 string인데, CreateTopicRequest/CreateTopicResponse에서는 string | null로 선언되어 있습니다.

→ API 응답에서 null이 내려올 경우 런타임 불일치가 발생할 수 있습니다.
→ TODO 코멘트가 이미 이 불확실성을 언급하고 있으므로, 백엔드 확정 후 ProposedTopicItem.descriptionConfirmedTopicItem.descriptionstring | null로 통일하는 것을 권장합니다.

제안
 // ProposedTopicItem (line 39)
-  description: string
+  description: string | null

 // ConfirmedTopicItem (line 68)
-  description: string
+  description: string | null

Also applies to: 67-68

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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.

@haruyam15 haruyam15 added the feat 새로운 기능 추가 label Feb 8, 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: 3

🤖 Fix all issues with AI agents
In `@src/features/topics/components/ConfirmTopicModal.tsx`:
- Around line 47-51: 선택 배열의 순서 불일치를 막기 위해 상태 갱신 로직을 하나로 통일하세요:
NumberedCheckboxGroup.onChange에서 사용하는 배열 생성 로직을 단일 소스(예: 새로운
updateSelectedTopics 함수)로 추출하고 setSelectedTopicIds 호출을 그 함수로만 수행하도록 하며, Card의
onClick(handleToggle)에서는 직접 setSelectedTopicIds를 호출하지 말고 이 공통
함수(updateSelectedTopics 또는 NumberedCheckboxGroup의 onChange 핸들러)를 호출해 토글 동작을
위임하세요; 즉 handleToggle은 내부에서 prev 기반의 수동 토글을 하지 말고
NumberedCheckboxGroup.onChange와 동일한 경로(공통 함수)를 호출하도록 변경해 선택 순서가 항상 동일하게 유지되도록 하고
같은 변경을 파일 내 다른 유사 위치(예: 107-109)에도 적용하세요.
- Around line 39-43: The modal always runs the useProposedTopics query even when
closed; update the ConfirmTopicModal to avoid fetching when open is false by
passing an enabled flag or changing rendering: either add an enabled option to
the hook call (e.g., useProposedTopics({ gatheringId, meetingId, pageSize: 100,
enabled: open })) after extending useProposedTopics to accept and forward an
enabled param to its internal react-query call, or alternatively stop mounting
the component when closed by changing the parent (MeetingDetailPage) to render
ConfirmTopicModal only when open (open && <ConfirmTopicModal .../>). Ensure you
reference useProposedTopics, ConfirmTopicModal, and the open prop when
implementing the change.

In `@src/pages/Meetings/MeetingDetailPage.tsx`:
- Around line 198-203: ConfirmTopicModal retains selectedTopicIds across reopen
because Radix Dialog only hides DOM; add a useEffect inside ConfirmTopicModal
that watches the open prop (the open passed into ConfirmTopicModal) and calls
setSelectedTopicIds([]) when open becomes false to reset selection; reference
the selectedTopicIds state and its setter setSelectedTopicIds and the open prop
in your effect to ensure the modal clears selections on close.
🧹 Nitpick comments (1)
src/features/topics/hooks/useConfirmTopics.ts (1)

43-57: 캐시 무효화가 정상 동작하지만, 더 넓은 범위의 무효화를 고려해볼 수 있습니다.

현재 proposedList({ gatheringId, meetingId })로 무효화하면 TanStack Query v5의 partial matching 덕분에 pageSize가 포함된 실제 쿼리 키도 매칭됩니다. 동작에는 문제 없습니다.

다만, 향후 다른 파라미터가 추가될 경우를 대비해 topicQueryKeys.proposedLists() / topicQueryKeys.confirmedLists() 수준으로 무효화하면 유지보수가 더 편할 수 있습니다.

♻️ 선택적 리팩터링 제안
     onSuccess: (_, variables) => {
-      // 제안된 주제 무효화
       queryClient.invalidateQueries({
-        queryKey: topicQueryKeys.proposedList({
-          gatheringId: variables.gatheringId,
-          meetingId: variables.meetingId,
-        }),
+        queryKey: topicQueryKeys.proposedLists(),
       })
-      // 확정된 주제 무효화
       queryClient.invalidateQueries({
-        queryKey: topicQueryKeys.confirmedList({
-          gatheringId: variables.gatheringId,
-          meetingId: variables.meetingId,
-        }),
+        queryKey: topicQueryKeys.confirmedLists(),
       })
     },

- NumberedCheckbox에 forwardRef 적용하여 외부 ref 접근 가능하도록 수정
- ConfirmModalTopicCard에서 onClick prop 제거 후 ref 클릭 방식으로 변경
- ConfirmTopicModal 닫기 시 선택 초기화 통합(handleClose), 외부 클릭 방지 추가
- ConfirmTopicModal 조건부 렌더링 적용하여 상태 초기화 보장
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: 1

🤖 Fix all issues with AI agents
In `@src/features/topics/topics.types.ts`:
- Line 38: Fix the typo in the JSDoc TODO comments by changing "없을떄" to "없을때" in
the comment string /** 주제 설명 (Todo : 없을떄 null인지 빈값인지 체크해야함)*/ and the identical
comment at the other occurrence (around line with the same text), updating both
instances to read "없을때".

Copy link
Contributor

@mgYang53 mgYang53 left a comment

Choose a reason for hiding this comment

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

전체적으로 목데이터를 쓰고 계신 것 같은데, 실제 api로 언제 전환하실 예정이신가요??

const { data: topicsInfiniteData, isLoading } = useProposedTopics({
gatheringId,
meetingId,
pageSize: 100,
Copy link
Contributor

Choose a reason for hiding this comment

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

한 번에 전체 로드하게 하신 이유가 있나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

여기는 초기로딩 길더라도 한번에 보여줘야 UX가 좋을 것 같아서 한번에 로드했습니다
찔끔찔끔 보이면 순서 정할때 답답할것 같아서요! 다른 아이디어나 의견있으면 말씀주십셔~

Copy link
Contributor Author

Choose a reason for hiding this comment

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

목데이터는 전체 개발 마무리되면 모두 제거하고
실제 api연동하고 테스트 해 볼 예정이었는데
아래 영애님 말대로 목데이터를 어떻게 관리할지 정해봐야겠어요~!

Copy link
Contributor

Choose a reason for hiding this comment

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

무한스크롤 훅을 사용하는게 좋을까 했는데 무한 스크롤 훅이 모달에 대응하고 있지 않은 상태네요.
아직 주제는 그렇게 많이 등록되지 않는다는 가정 하에 현재는 이렇게만 하고,
추후 리팩토링 시 적용할 수 있으면 하시죠!

/** 주제 제목 */
title: string
/** 주제 설명 */
/** 주제 설명 (Todo : 없을떄 null인지 빈값인지 체크해야함)*/
Copy link
Contributor

Choose a reason for hiding this comment

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

description이 없을 때가 있으면 null 타입은 아직 고려 안하시는 이유가 있을까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

아 discription이 없으면 null로오는지 ''이렇게 빈값으로 오는지 아직 몰라서
목데이터제거하고 api테스트하면서 수정하려고 적어뒀습니다~

@choiyoungae
Copy link
Contributor

choiyoungae commented Feb 9, 2026

목데이터 관련해서는 추후 백엔드 서버가 운영되지 않는 상황도 고려해,
완전히 제거하기보다는 env 기반 toggle로 관리하는 방향이 적절하지 않을까 생각합니다.

저는 현는 USE_MOCK 값을 기준으로 분기해두었고,
.env.production에서는 false, .env.development에서는 true로 설정해두고 아래와 같이 사용 중입니다.

/** 목데이터 사용 여부 플래그 */
const USE_MOCK = import.meta.env.VITE_USE_MOCK === 'true'

이 부분은 한 번 다 같이 방향을 맞춰보면 좋을 것 같고,
정해지는 기준이 있다면 저도 그에 맞게 설정을 조정하겠습니다.
개발 중 실제 API 확인이 필요한 경우에는
개인적으로 development 환경에서만 값을 변경해 확인하는 것도 가능해,
공통 기준을 가져가더라도 유연하게 대응할 수 있을 것 같아요.

@mgYang53
Copy link
Contributor

mgYang53 commented Feb 9, 2026

목데이터 관련해서는 추후 백엔드 서버가 운영되지 않는 상황도 고려해, 완전히 제거하기보다는 env 기반 toggle로 관리하는 방향이 적절하지 않을까 생각합니다.

저는 현는 USE_MOCK 값을 기준으로 분기해두었고, .env.production에서는 false, .env.development에서는 true로 설정해두고 아래와 같이 사용 중입니다.

/** 목데이터 사용 여부 플래그 */
const USE_MOCK = import.meta.env.VITE_USE_MOCK === 'true'

이 부분은 한 번 다 같이 방향을 맞춰보면 좋을 것 같고, 정해지는 기준이 있다면 저도 그에 맞게 설정을 조정하겠습니다. 개발 중 실제 API 확인이 필요한 경우에는 개인적으로 development 환경에서만 값을 변경해 확인하는 것도 가능해, 공통 기준을 가져가더라도 유연하게 대응할 수 있을 것 같아요.

목데이터 관련해서는 추후 백엔드 서버가 운영되지 않는 상황도 고려해, 완전히 제거하기보다는 env 기반 toggle로 관리하는 방향이 적절하지 않을까 생각합니다.

저는 현는 USE_MOCK 값을 기준으로 분기해두었고, .env.production에서는 false, .env.development에서는 true로 설정해두고 아래와 같이 사용 중입니다.

/** 목데이터 사용 여부 플래그 */
const USE_MOCK = import.meta.env.VITE_USE_MOCK === 'true'

이 부분은 한 번 다 같이 방향을 맞춰보면 좋을 것 같고, 정해지는 기준이 있다면 저도 그에 맞게 설정을 조정하겠습니다. 개발 중 실제 API 확인이 필요한 경우에는 개인적으로 development 환경에서만 값을 변경해 확인하는 것도 가능해, 공통 기준을 가져가더라도 유연하게 대응할 수 있을 것 같아요.

이 부분은 각자 생각해보고 추후 정하는걸로 하시죠!

@haruyam15 대신 현재 파일별로 목데이터 사용 여부 변수가 선언되어 있어 env 파일을 이용해서 공통 관리할 수 있으면 좋겠네요

@haruyam15 haruyam15 merged commit 788f1fc into develop Feb 11, 2026
2 of 3 checks passed
@haruyam15 haruyam15 deleted the feat/topics-confirm-47 branch February 11, 2026 10:44
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] 주제 확정 UI 및 기능 구현

3 participants