Skip to content

[Feature/#64] 모임방 상세 페이지 UI#70

Merged
holdn2 merged 9 commits into
mainfrom
feature/#64/group-detail-page-ui
May 9, 2026
Merged

[Feature/#64] 모임방 상세 페이지 UI#70
holdn2 merged 9 commits into
mainfrom
feature/#64/group-detail-page-ui

Conversation

@holdn2
Copy link
Copy Markdown
Contributor

@holdn2 holdn2 commented May 8, 2026

📌 Related Issues

📄 Tasks

  • 모임방 상세 페이지 구현
  • 모임방 상단 정보 GroupInfo 공통 컴포넌트로 분리
  • 모임방 투표 관련 캐러셀 구현 (엠티뷰 포함)
  • 더보기 클릭 시 바텀시트 및 모달 구현 (방 삭제, 나가기, 신고)

📷 Screenshot

image image image image image image image image

Summary by CodeRabbit

  • 새로운 기능
    • 그룹 상세 페이지 추가: 헤더, 도서 정보, 투표 캐러셀, 읽기 기록 개요, 일일 한마디 버튼, 하단 시트(삭제/나가기/신고) 및 확인 모달 포함
  • 개선 사항
    • 그룹 정보 컴포넌트 통합·재설계(모집/비모집 대응, 읽기메이트 핸들링)
    • 네비게이션 파라미터 전달 방식 일관화 및 터치/네비게이션 반응성 개선

@holdn2 holdn2 self-assigned this May 8, 2026
@holdn2 holdn2 added the feature Add new features label May 8, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

Review Change Stack

Warning

Rate limit exceeded

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

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ 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.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7928dadd-764a-4e5c-b5a0-ab2706f4db8c

📥 Commits

Reviewing files that changed from the base of the PR and between 14cc59e and cf76025.

📒 Files selected for processing (2)
  • screens/group-detail/components/votes-carousel/index.tsx
  • src/shared/ui/group-info/index.tsx
📝 Walkthrough

Walkthrough

이 PR은 진행 중이거나 완료된 모임방의 상세 페이지 기능을 구현합니다. GroupDetailScreen과 Expo Router 레이아웃 및 동적 [roomId] 라우트를 추가하고, 타입 정의(DTO)와 DUMMY_GROUP_DETAIL을 포함합니다. 헤더, 바텀시트, 확인 모달, 책 정보 컴포넌트, 기록장 요약, 투표 카루셀, 일일 인사말 컴포넌트 등을 새로 추가했으며, RecruitingGroupInfo를 범용 GroupInfo로 리팩토링하고 여러 화면의 네비게이션과 ISBN 파라미터 전달을 정규화했습니다.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🏠 모임방 문이 열리면,
책이 놓이고 투표가 속삭이며,
헤더 빛은 길을 비추고,
탭 하나가 다음 화면으로 이어지네,
새 페이지에 축하를 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.26% 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 제목은 feature/#64와 관련된 '모임방 상세 페이지 UI' 구현을 명확히 나타내고 있으며, 변경 사항의 핵심을 잘 요약하고 있습니다.
Description check ✅ Passed PR 설명에서 관련 이슈, 작업 내용, 스크린샷이 모두 포함되어 있으나 'PR Point'와 'ETC' 섹션이 누락되었습니다.
Linked Issues check ✅ Passed 변경 사항이 issue #64의 모임방 상세 페이지 UI, 독서메이트 페이지, 오늘의 한마디 페이지 구현 요구사항을 충족합니다.
Out of Scope Changes check ✅ Passed 몇몇 주변 파일들(my-group-carousel-item, join-group, saved-book, search components, book-info-bar, group-info, my-group-card)의 변경사항이 포함되어 있으나, 이들은 group-detail 라우팅 또는 GroupInfo 공통화 작업 지원으로 볼 수 있습니다.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/#64/group-detail-page-ui

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.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/shared/ui/book-info-bar/index.tsx (1)

20-20: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

P4 - 완료된 TODO는 제거/갱신해주세요

클릭 시 상세 이동은 이미 구현되어 있어서 현재 TODO 문구가 오해를 만들 수 있습니다. TODO를 제거하거나 실제 남은 작업으로 갱신해 주세요.

As per coding guidelines 가독성, 예외처리, 테스트/확장/유지보수성을 기반으로 리뷰해야 하며 팀 스타일 통일성도 확인해야 합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/ui/book-info-bar/index.tsx` at line 20, Remove or update the
misleading TODO comment "// TODO: 클릭 시 책 상세 정보 페이지로 이동되도록" in
src/shared/ui/book-info-bar/index.tsx (component BookInfoBar) because the
click-to-detail navigation is already implemented; either delete the TODO or
replace it with an accurate note about any remaining work (or a short FIXME with
exact next steps) so the source and BookInfoBar's click handler no longer imply
incomplete functionality.
🧹 Nitpick comments (3)
src/shared/ui/group-info/index.tsx (1)

90-128: ⚡ Quick win

[P4] 분기 UI 회귀 방지용 단위 테스트 2~3개를 같이 추가하면 안정성이 크게 올라갑니다

변경 분기가 많아서 테스트 한 번만 깔아두면 이후 리팩터링이 훨씬 편합니다. 추천 케이스:

  1. isRecruiting=true일 때 독서메이트 영역 disabled + 화살표 미노출
  2. isRecruiting=false + onPressReadingMate 전달 시 클릭 콜백 호출
  3. recruitEndDate 유무에 따른 모집 칩 노출/미노출

As per coding guidelines src/**: "미작성한 테스트 코드 케이스가 있다면, 어떤 테스트가 필요한지 제안해주세요."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/ui/group-info/index.tsx` around lines 90 - 128, Add unit tests for
the GroupInfo UI to prevent regression around the recruiting/display branches:
write tests for the component exported in src/shared/ui/group-info/index.tsx
(the Pressable block/reading mate area and the recruit end-date chip).
Specifically: (1) render with isRecruiting=true and assert the Pressable is
disabled and the right-arrow icon (IcRightRight) is not present; (2) render with
isRecruiting=false, pass a mock onPressReadingMate handler (or simulate
handleToReadingMateList via the component prop) and assert pressing the
Pressable invokes the callback; (3) render twice for recruitEndDate present vs
absent and assert the recruit chip (the View with styles.endDateCategoryItem and
the text containing recruitEndDate) is shown when provided and not rendered when
undefined. Use the component name from the file and test-library utilities to
query by text/role and simulate press.
screens/group/components/my-group-carousel/my-group-carousel-item.tsx (1)

137-137: P4: TODO — 이미지 영역 포함 탭 UX 이슈

이미지 영역까지 눌렀을 때 네비게이션이 동작하지 않는 문제가 남아있습니다. 별도 이슈로 트래킹하면 좋을 것 같습니다.

새 이슈로 등록하거나 원인 분석이 필요하시면 말씀해 주세요! (PressablehitSlop 또는 Animated.View의 레이아웃 충돌이 원인일 가능성이 있습니다.)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@screens/group/components/my-group-carousel/my-group-carousel-item.tsx` at
line 137, The carousel item’s image isn’t triggering navigation because the
touchable area likely doesn’t cover the image or an Animated.View is
intercepting touches; update MyGroupCarouselItem so the Pressable fully wraps
the image view (or move the Animated.View inside the Pressable) and add a
conservative hitSlop on the Pressable to expand its tappable area, remove/adjust
any pointerEvents or touch handling on the Animated.View that could block
touches, then verify navigation works when tapping the image; check the
Pressable usage and Animated.View containment in the component to locate the
exact spot to change.
screens/group-detail/group-detail-screen.tsx (1)

67-79: ⚡ Quick win

P4: 네비게이션 폴백 로직은 헬퍼로 추출하면 유지보수성이 더 좋아집니다

Line 7478과 Line 101105가 동일해서 이후 경로 정책 변경 시 누락 위험이 있습니다. 작은 헬퍼로 묶어두면 액션 추가 시에도 안전합니다. 디테일 잘 만드셨고, 여기까지만 정리하면 더 탄탄해집니다 🙂

♻️ 제안 리팩터링
+  const navigateBackOrGroup = () => {
+    if (router.canGoBack()) {
+      router.back();
+    } else {
+      router.push("/group");
+    }
+  };

   const handleReportGroup = () => {
     setIsBottomSheetVisible(false);
     Toast.show({
       type: "default",
       text1: "모임방 신고를 완료했어요.",
     });
-    if (router.canGoBack()) {
-      router.back();
-    } else {
-      router.push("/group");
-    }
+    navigateBackOrGroup();
   };
...
-    if (router.canGoBack()) {
-      router.back();
-    } else {
-      router.push("/group");
-    }
+    navigateBackOrGroup();
   };

Also applies to: 87-106

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@screens/group-detail/group-detail-screen.tsx` around lines 67 - 79, Extract
the repeated navigation fallback into a small helper (e.g.,
navigateBackOrPushHome or goBackOrToGroup) and replace the duplicated logic in
handleReportGroup and the other identical locations (the blocks using
router.canGoBack(), router.back(), router.push("/group")) with a single call to
that helper; the helper should accept the router instance (and optionally a
fallback path like "/group") and perform the canGoBack/back or push(fallback)
decision so future path-policy changes are made in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@screens/group-detail/components/daily-greeting-button/index.tsx`:
- Around line 14-16: handleToDailyGreeting currently only console.logs and
leaves the button non-functional; remove the console.log and implement the
intended behavior or a safe interim: either call the actual navigation helper
(e.g., invoke the app router/navigation function with roomId — references:
handleToDailyGreeting and roomId) to navigate to the daily-greeting page, or
disable the button and show a "준비 중" toast/modal until navigation is
implemented. Ensure you update the button's disabled state and remove any
console.log from handleToDailyGreeting so production code has no stray logs.

In `@screens/group-detail/components/group-detail-modal/index.tsx`:
- Around line 24-28: The modal currently shows the deletion warning
unconditionally because the AppText blocks use a fixed string; update the
conditional rendering in the group-detail-modal component so the descriptive
text and button label vary by the prop type (the existing type variable) — when
type === "delete" keep the current deletion warning and confirm copy, but when
type === "leave" show a leave-specific message (e.g., explain leaving the room
or losing access) and change the negative button text to "아니요" (also adjust the
confirm button copy appropriately for each action). Locate and update the two
AppText instances that render the secondary message and the buttons around the
same area (the AppText blocks and the button labels referenced near the existing
type === "delete" conditional) so they branch on type === "delete" vs "leave".

In `@screens/group-detail/components/record-book-overview/index.tsx`:
- Around line 45-59: Clamp the progress value before rendering so the progress
bar and displayed percentage never break layout; compute a clampedPercentage =
Math.min(100, Math.max(0, userPercentage)) and use clampedPercentage for both
the displayed text and the style width (i.e., in the View with
styles.currentProgress and the AppText showing userPercentage) so the bar width
is always between 0% and 100% and the shown number matches the bar.

In `@src/shared/ui/group-info/index.tsx`:
- Around line 40-42: The CTA currently uses a no-op console.log in
handleToReadingMateList which breaks the user flow; change the component to
accept a callback prop (e.g., onOpenReadingMateList?: (roomId: string) => void)
and replace the body of handleToReadingMateList to call that prop with roomId
(and optionally fall back to existing navigation behavior only if the prop is
not provided). Update the component props/type signature to include
onOpenReadingMateList, call it from handleToReadingMateList, and ensure callers
(parent components) pass the real navigation handler so the CTA performs the
intended navigation instead of logging.

---

Outside diff comments:
In `@src/shared/ui/book-info-bar/index.tsx`:
- Line 20: Remove or update the misleading TODO comment "// TODO: 클릭 시 책 상세 정보
페이지로 이동되도록" in src/shared/ui/book-info-bar/index.tsx (component BookInfoBar)
because the click-to-detail navigation is already implemented; either delete the
TODO or replace it with an accurate note about any remaining work (or a short
FIXME with exact next steps) so the source and BookInfoBar's click handler no
longer imply incomplete functionality.

---

Nitpick comments:
In `@screens/group-detail/group-detail-screen.tsx`:
- Around line 67-79: Extract the repeated navigation fallback into a small
helper (e.g., navigateBackOrPushHome or goBackOrToGroup) and replace the
duplicated logic in handleReportGroup and the other identical locations (the
blocks using router.canGoBack(), router.back(), router.push("/group")) with a
single call to that helper; the helper should accept the router instance (and
optionally a fallback path like "/group") and perform the canGoBack/back or
push(fallback) decision so future path-policy changes are made in one place.

In `@screens/group/components/my-group-carousel/my-group-carousel-item.tsx`:
- Line 137: The carousel item’s image isn’t triggering navigation because the
touchable area likely doesn’t cover the image or an Animated.View is
intercepting touches; update MyGroupCarouselItem so the Pressable fully wraps
the image view (or move the Animated.View inside the Pressable) and add a
conservative hitSlop on the Pressable to expand its tappable area, remove/adjust
any pointerEvents or touch handling on the Animated.View that could block
touches, then verify navigation works when tapping the image; check the
Pressable usage and Animated.View containment in the component to locate the
exact spot to change.

In `@src/shared/ui/group-info/index.tsx`:
- Around line 90-128: Add unit tests for the GroupInfo UI to prevent regression
around the recruiting/display branches: write tests for the component exported
in src/shared/ui/group-info/index.tsx (the Pressable block/reading mate area and
the recruit end-date chip). Specifically: (1) render with isRecruiting=true and
assert the Pressable is disabled and the right-arrow icon (IcRightRight) is not
present; (2) render with isRecruiting=false, pass a mock onPressReadingMate
handler (or simulate handleToReadingMateList via the component prop) and assert
pressing the Pressable invokes the callback; (3) render twice for recruitEndDate
present vs absent and assert the recruit chip (the View with
styles.endDateCategoryItem and the text containing recruitEndDate) is shown when
provided and not rendered when undefined. Use the component name from the file
and test-library utilities to query by text/role and simulate press.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: edf06c48-01bb-47cb-8060-576932832b35

📥 Commits

Reviewing files that changed from the base of the PR and between 12412aa and 125f54e.

📒 Files selected for processing (26)
  • app/_layout.tsx
  • app/group-detail/[roomId].tsx
  • app/group-detail/_layout.tsx
  • screens/group-detail/components/daily-greeting-button/index.tsx
  • screens/group-detail/components/group-book/index.tsx
  • screens/group-detail/components/group-detail-bottom-sheet/index.tsx
  • screens/group-detail/components/group-detail-header/index.tsx
  • screens/group-detail/components/group-detail-modal/index.tsx
  • screens/group-detail/components/index.ts
  • screens/group-detail/components/record-book-overview/index.tsx
  • screens/group-detail/components/votes-carousel/index.tsx
  • screens/group-detail/constants/index.ts
  • screens/group-detail/group-detail-screen.tsx
  • screens/group-detail/index.ts
  • screens/group-detail/types/index.ts
  • screens/group/components/my-group-carousel/my-group-carousel-item.tsx
  • screens/join-group/components/index.ts
  • screens/join-group/components/join-group-book/index.tsx
  • screens/join-group/join-group-screen.tsx
  • screens/saved/components/saved-book/index.tsx
  • screens/search/components/most-searched-book-item/index.tsx
  • screens/search/components/searched-book-item/index.tsx
  • src/shared/ui/book-info-bar/index.tsx
  • src/shared/ui/group-info/index.tsx
  • src/shared/ui/index.ts
  • src/shared/ui/my-group-card/index.tsx
💤 Files with no reviewable changes (1)
  • screens/join-group/components/index.ts

Comment thread screens/group-detail/components/daily-greeting-button/index.tsx
Comment thread screens/group-detail/components/group-detail-modal/index.tsx
Comment thread screens/group-detail/components/record-book-overview/index.tsx Outdated
Comment thread src/shared/ui/group-info/index.tsx Outdated
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: 1

♻️ Duplicate comments (1)
screens/group-detail/components/daily-greeting-button/index.tsx (1)

14-18: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

[P2] 오늘의 한마디 버튼이 실제 상세 플로우를 열지 않습니다

지금은 alert 플레이스홀더만 실행되어, PR 목표(오늘의 한마디 페이지 흐름 구현) 기준으로 사용자 액션이 기능으로 이어지지 않습니다. 실제 라우트로 연결하거나, 미구현 상태라면 버튼 비활성화+명시적 안내로 동작을 고정해 주세요.

빠른 수정 예시
+import { router } from "expo-router";
...
   const handleToDailyGreeting = () => {
-    alert(`${roomId}번 오늘의 한마디 페이지 준비 중`);
+    router.push({
+      pathname: "/daily-greeting/[roomId]",
+      params: { roomId: String(roomId) },
+    });
   };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@screens/group-detail/components/daily-greeting-button/index.tsx` around lines
14 - 18, The button's onPress handler handleToDailyGreeting currently only shows
an alert placeholder and doesn't navigate to the daily-greeting flow; replace
the placeholder with the real routing call (e.g., use the app navigation to
navigate to the DailyGreeting screen with roomId) or, if the flow isn't
implemented yet, disable the Pressable (set disabled prop and apply visual
disabled style in styles.container) and change handleToDailyGreeting to show a
clear message like "오늘의 한마디는 준비 중입니다" so the UX is explicit; update references
in this file to use the app's navigation helper (e.g., useNavigation()/navigate)
or adjust Pressable disabled behavior and styles accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/shared/ui/group-info/index.tsx`:
- Around line 89-102: The right-arrow affordance (IcRightRight) is shown even
when the Pressable is disabled, which misleads users; update the rendering logic
in the GroupInfo component so IcRightRight is only rendered when the Pressable
is active (i.e., when onPressReadingMate exists and isRecruiting is false).
Locate the Pressable block using the Pressable, onPressReadingMate and
isRecruiting symbols and change the conditional around IcRightRight so the arrow
is omitted when the control is disabled.

---

Duplicate comments:
In `@screens/group-detail/components/daily-greeting-button/index.tsx`:
- Around line 14-18: The button's onPress handler handleToDailyGreeting
currently only shows an alert placeholder and doesn't navigate to the
daily-greeting flow; replace the placeholder with the real routing call (e.g.,
use the app navigation to navigate to the DailyGreeting screen with roomId) or,
if the flow isn't implemented yet, disable the Pressable (set disabled prop and
apply visual disabled style in styles.container) and change
handleToDailyGreeting to show a clear message like "오늘의 한마디는 준비 중입니다" so the UX
is explicit; update references in this file to use the app's navigation helper
(e.g., useNavigation()/navigate) or adjust Pressable disabled behavior and
styles accordingly.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e932533c-354f-4577-af10-cc9a90bbf6e6

📥 Commits

Reviewing files that changed from the base of the PR and between 125f54e and 14cc59e.

📒 Files selected for processing (5)
  • screens/group-detail/components/daily-greeting-button/index.tsx
  • screens/group-detail/components/group-detail-modal/index.tsx
  • screens/group-detail/components/record-book-overview/index.tsx
  • screens/group-detail/group-detail-screen.tsx
  • src/shared/ui/group-info/index.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • screens/group-detail/components/record-book-overview/index.tsx
  • screens/group-detail/components/group-detail-modal/index.tsx
  • screens/group-detail/group-detail-screen.tsx

Comment thread src/shared/ui/group-info/index.tsx
@holdn2 holdn2 merged commit 1397580 into main May 9, 2026
1 check passed
@holdn2 holdn2 deleted the feature/#64/group-detail-page-ui branch May 9, 2026 01:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Add new features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] 모임방(진행중 또는 완료된) 상세 페이지 UI

1 participant