Conversation
- 약속 상세 페이지 API 연동 및 UI 컴포넌트 구현. - useMeetingDetail 훅으로 데이터 조회 및 상태 관리. - 약속 정보, 책 정보, 참가자, 버튼 상태를 표시하는 컴포넌트 분리. - 라우트 파라미터를 gatheringId/meetingId로 명확히 구분.
약속 상세 페이지에 참가신청/취소 기능 및 UI 개선 작업: - 약속 참가신청/취소 API 연동 (useJoinMeeting, useCancelJoinMeeting 훅 추가) - 액션 버튼에 참가/취소 로직 구현 (confirm 모달 및 에러 처리 포함) - 시간 기반 약속 상태 표시 (약속 전/중/후 Badge 자동 계산) - 지도 모달 컴포넌트 추가 (MapModal, 추후 지도 API 연동 예정) - 날짜/시간 표시 개선 (시작~종료 시간 분리 표시) - API 엔드포인트 상수화 (meetings.endpoints.ts) - 타입명 오타 수정 (MeddtingDetailActionStateType → MeetingDetailActionStateType)
|
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모임 상세 조회 및 상호작용을 추가합니다. 엔드포인트 중앙화(MEETINGS_ENDPOINTS), 상세 API·목데이터, React Query 훅(조회/참여/취소), 상세 페이지와 관련 UI(헤더/정보/버튼/지도 모달), 타입·유틸·라우트 및 컴포넌트 재수출 변화를 도입합니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Browser
participant MeetingDetailPage
participant useMeetingDetail
participant QueryClient
participant API
participant MeetingDetailInfo
Browser->>MeetingDetailPage: /gatherings/:gatheringId/meetings/:meetingId 접속
MeetingDetailPage->>useMeetingDetail: useMeetingDetail(meetingId)
useMeetingDetail->>QueryClient: 캐시 조회 (meetingQueryKeys.detail)
QueryClient->>API: getMeetingDetail(meetingId) 요청
API-->>QueryClient: GetMeetingDetailResponse 반환
QueryClient->>useMeetingDetail: 데이터 제공
useMeetingDetail-->>MeetingDetailPage: data/loading 상태 전달
MeetingDetailPage->>MeetingDetailInfo: 상세 데이터 전달
MeetingDetailInfo-->>Browser: UI 렌더링 (책/참여자/시간/장소)
sequenceDiagram
participant Browser
participant MeetingDetailButton
participant ConfirmModal
participant useJoinMeeting
participant QueryClient
participant API
Browser->>MeetingDetailButton: "참여" 버튼 클릭
MeetingDetailButton->>ConfirmModal: openConfirm 호출
Browser->>ConfirmModal: 사용자 확인
ConfirmModal->>useJoinMeeting: joinMutation.mutate(meetingId)
useJoinMeeting->>API: joinMeeting(meetingId) 호출
API-->>useJoinMeeting: 성공/실패 응답
alt 성공
useJoinMeeting->>QueryClient: invalidateQueries(meetingQueryKeys.detail(meetingId))
QueryClient->>API: 재조회(getMeetingDetail) -> 최신 참여자 반영
else 실패
useJoinMeeting-->>Browser: openError 호출
end
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: 8
🤖 Fix all issues with AI agents
In `@src/features/meetings/components/MeetingDetailButton.tsx`:
- Around line 77-81: The help text is currently only shown when isEnabled is
true, so users in the EDIT_TIME_EXPIRED (disabled) state don't see why the
button is disabled; update the render condition in MeetingDetailButton (the JSX
that outputs the <p> with className "text-grey-700 typo-body6 pt-tiny") to show
the message when either isEnabled is true or type === 'EDIT_TIME_EXPIRED' (e.g.,
change the conditional from {isEnabled && (...) } to something like {(isEnabled
|| type === 'EDIT_TIME_EXPIRED') && (...)}) so the explanatory text is visible
for the disabled EDIT_TIME_EXPIRED state while keeping the same message logic.
In `@src/features/meetings/components/MeetingDetailInfo.tsx`:
- Around line 33-35: The code assumes meeting.schedule.displayDate.split(' ~ ')
always yields two parts; update MeetingDetailInfo (where startDate and endDate
are assigned) to validate the split result length, assign startDate = parts[0]
and only set endDate if parts.length > 1, and in render logic (same component
usage around lines that currently use startDate/endDate) conditionally render
the end time or use a fallback/placeholder when endDate is undefined to avoid
printing "undefined".
- Around line 52-56: In MeetingDetailInfo, the class name typo "typo-cation2"
prevents the caption style from applying; update the class on the <span> that
renders participants maxCount from "typo-cation2" to the correct "typo-caption2"
so it matches the project's typography token and restores proper styling.
In `@src/features/meetings/hooks/useMeetingDetail.ts`:
- Around line 31-40: The queryKey currently uses
meetingQueryKeys.detail(meetingId) even when meetingId is invalid, which lets
NaN serialize to null and pollute the cache; update useMeetingDetail so it
computes isValidMeetingId and uses meetingQueryKeys.detail(meetingId) only when
valid, otherwise pass a fixed sentinel key (e.g.,
['meetings','detail','invalid'] or similar) to avoid NaN→null collisions, keep
enabled: isValidMeetingId and the existing queryFn/getMeetingDetail usage
intact; locate the logic in useMeetingDetail and change the queryKey selection
around meetingQueryKeys.detail to the conditional sentinel approach.
In `@src/features/meetings/meetings.endpoints.ts`:
- Around line 1-25: Prettier formatting warnings were raised for the
MEETINGS_ENDPOINTS file; run the formatter and commit the changes to resolve CI
failures—open the file containing the MEETINGS_ENDPOINTS constant and run
`prettier --write` (or your project's equivalent formatting command) to apply
consistent formatting, then stage and commit the updated file so the API
endpoint definitions (APPROVALS, DETAIL, REJECT, CONFIRM, DELETE, JOIN,
CANCEL_JOIN) comply with the project's Prettier rules.
In `@src/features/meetings/meetings.mock.ts`:
- Around line 358-362: The mock function getMockMeetingDetail currently throws a
plain Error when a meeting is missing; update it to throw an error shaped like
the UI expects (include a userMessage field) so the detail page can render a
friendly message, e.g., throw an object containing message and userMessage (or a
subclass/typed error) instead of a plain Error; modify getMockMeetingDetail to
construct and throw that shaped error so callers consuming
GetMeetingDetailResponse can rely on error.userMessage.
In `@src/routes/index.tsx`:
- Around line 94-100: The route path is inserting ROUTES.MEETING_SETTING (a
function) directly into a template, causing the function to be stringified;
update the path to call the function with the route parameter placeholder
instead—e.g. replace
`${ROUTES.GATHERINGS}/:gatheringId${ROUTES.MEETING_SETTING}` with a call like
`${ROUTES.GATHERINGS}${ROUTES.MEETING_SETTING(':gatheringId')}` (or
`${ROUTES.GATHERINGS}/:gatheringId${ROUTES.MEETING_SETTING(':gatheringId')}`
depending on how ROUTES.MEETING_SETTING concatenates) so MeetingSettingPage is
registered at the correct parametric URL.
In `@src/shared/constants/routes.ts`:
- Around line 24-30: ROUTES.MEETINGS, ROUTES.MEETING_CREATE and
ROUTES.MEETING_UPDATE are inconsistent with the router: either remove the unused
constants or add matching router entries; decide which by searching for usages
of MEETINGS, MEETING_CREATE and MEETING_UPDATE and then either (A) remove the
unused constants from src/shared/constants/routes.ts (and update any imports) or
(B) add corresponding routes to the router configuration that match the helpers
(e.g. a route for '/gatherings/:gatheringId/meetings' plus routes for
'/gatherings/:gatheringId/meetings/create' and
'/gatherings/:gatheringId/meetings/:meetingId/update') so the helper functions
(MEETING_CREATE, MEETING_UPDATE, MEETING_DETAIL, MEETING_SETTING) actually
correspond to real routes.
🧹 Nitpick comments (4)
src/features/meetings/lib/formatDateTime.ts (2)
1-2: TODO 코멘트 확인
timeUtils와 병합 예정이라고 되어 있는데, 이 작업을 추적하기 위한 이슈가 있나요?이슈 생성을 도와드릴까요?
17-29: 실시간 상태 업데이트 고려 필요
getMeetingStatusByTime이 호출 시점의new Date()를 사용합니다.
→ 사용자가 페이지에 머무르는 동안 상태 배지가 자동 갱신되지 않습니다.
→ 약속 시작/종료 시점에 상태가 즉시 반영되지 않을 수 있습니다.실시간 반영이 필요하다면
setInterval또는useEffect기반 폴링을 고려해주세요.src/features/meetings/components/MeetingDetailHeader.tsx (2)
14-21: 불필요한 Fragment 제거 가능단일 자식 요소만 반환하므로
<>...</>Fragment가 필요하지 않습니다.♻️ 리팩토링 제안
return ( - <> - <div className="flex items-start border-b gap-small border-b-grey-300 pb-[10px]"> - <h3 className="text-black typo-heading3">{children}</h3> - <Badge size="small" color={status.color}> - {status.text} - </Badge> - </div> - </> + <div className="flex items-start border-b gap-small border-b-grey-300 pb-[10px]"> + <h3 className="text-black typo-heading3">{children}</h3> + <Badge size="small" color={status.color}> + {status.text} + </Badge> + </div> )
5-8: Props 타입 개선 고려
children을string으로 제한하면ReactNode를 전달할 수 없습니다. 현재는 제목 텍스트만 필요하므로 문제없지만, 확장성을 고려하면ReactNode로 변경하거나title: stringprop으로 명시하는 것도 방법입니다.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@src/features/meetings/components/MeetingDetailInfo.tsx`:
- Line 56: The <dt> for the 참가인원 label in MeetingDetailInfo (the JSX element
with className={`text-grey-600 ${LABEL_WIDTH}`}) is missing the typo-caption1
class; update its className to include "typo-caption1" alongside "text-grey-600"
and LABEL_WIDTH so its font styling matches the other <dt> elements (those
around lines where other <dt>s use typo-caption1).
- 약속 생성 시 스케줄이 없는 경우를 처리하기 위해 schedule 타입을 nullable로 변경. - MeetingDetailInfo와 MeetingDetailHeader에서 스케줄 데이터 유무에 따라 조건부 렌더링 적용. - useMeetingDetail 훅에서 유효하지 않은 meetingId로 인한 쿼리 키 충돌 방지 로직 추가. - 약속 설정 페이지 라우팅 경로 수정.
mgYang53
left a comment
There was a problem hiding this comment.
추가한 코멘트는 사소한 것이니 확인하고 머지해주세요!
고생하셨습니다 👍
- 컴포넌트 export 방식을 named에서 default로 통일 - 약속장 role을 HOST에서 LEADER로 변경 - 날짜/시간 유틸리티 함수 파일 구조 재정리 (dateTimeFormatters, dateTimeUtils 분리) - 약속 진행 상태(progressStatus) 기반 배지 표시 로직 추가 - 불필요한 null 체크 제거 및 타입 안정성 향상 - 라우팅 경로 구조 개선 (하드코딩 제거)
🚀 풀 리퀘스트 제안
📋 작업 내용
약속(Meeting) 상세 화면의 UI/UX 및 기능을 완성했습니다.
사용자는 약속 정보를 확인하고, 참가 신청 및 취소가 가능하며, 약속 상태를 실시간으로 확인할 수 있습니다.
🔧 변경 사항
1. 약속 상세 UI 구현
2. 약속 상세 조회 기능 구현
3. 약속 참가/취소 기능
📸 스크린샷 (선택 사항)
Summary by CodeRabbit
모임 상세 페이지 추가
New Features
Chores