Skip to content

feat: 참여 후 모임방 상세 화면 구현#79

Merged
ljh130334 merged 16 commits into
developfrom
feat/yesgroupdetail
Aug 7, 2025
Merged

feat: 참여 후 모임방 상세 화면 구현#79
ljh130334 merged 16 commits into
developfrom
feat/yesgroupdetail

Conversation

@ljh130334
Copy link
Copy Markdown
Member

@ljh130334 ljh130334 commented Aug 7, 2025

#️⃣연관된 이슈

따로 등록하지 않았습니다.

📝작업 내용

참여 후 모임방 상세 화면을 새로 구현하였습니다. 사용자가 모임에 참여한 후 활용할 수 있는 다양한 섹션들을 포함하고 있습니다.

주요 구현 내용

1. 라우팅 구조 추가

  • 참여 전: /group/detail
  • 참여 후: /group/detail/joined 경로로 분리하여 명확한 화면 구분을 구현했습니다.

2. 컴포넌트 기반 아키텍처 설계

  • GroupBookSection: 모임방의 책 제목 및 저자 표시
  • RecordSection: 현재 독서 진행률과 페이지 정보를 프로그레스바와 함께 제공
  • CommentSection: 오늘의 한마디 기능 연결 섹션
  • HotTopicSection: 모임방의 뜨거운 감자(투표) 기능을 포함한 인터랙티브 섹션

3. 투표 시스템 구현

  • 투표 결과가 아닌 질문과 선택지만 미리보기로 제공
  • 자연스러운 터치/마우스 드래그 스크롤로 다중 투표 탐색 가능
  • 투표 클릭 시 해당 투표가 위치한 페이지의 기록장으로 이동하는 딥링크 기능
  • 투표가 없는 경우의 빈 상태 화면 구현

스크린샷 (선택)

2025-08-07.4.27.08.mov

💬리뷰 요구사항(선택)

드래그 이벤트 처리에서 useCallbackuseEffect를 적절히 활용했는지, 그리고 불필요한 리렌더링이 발생하지 않는지 성능 관점에서 검토 부탁드립니다.

Summary by CodeRabbit

  • New Features

    • 그룹 상세 페이지에 참여한 그룹 전용 상세 화면이 추가되었습니다.
    • 참여한 그룹 상세 화면에서 기록장, 오늘의 한마디, 핫토픽 투표, 그룹 도서 정보 등 다양한 섹션이 제공됩니다.
    • 핫토픽 투표 섹션에서 슬라이드 방식의 투표 목록과 투표 기능이 제공됩니다.
    • 그룹 액션을 위한 하단 시트가 추가되어 그룹 삭제, 탈퇴, 신고 기능을 제공합니다.
  • Style

    • 그룹 상세 및 각 섹션에 대한 스타일이 개선되어 더욱 깔끔한 UI를 제공합니다.
    • 소개글의 줄 간격(line-height)이 조정되어 가독성이 향상되었습니다.
  • Bug Fixes

    • 없음
  • Chores

    • 라우팅에 참여한 그룹 상세 경로가 추가되었습니다.

@vercel
Copy link
Copy Markdown

vercel Bot commented Aug 7, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
thip ✅ Ready (Inspect) Visit Preview 💬 Add feedback Aug 7, 2025 1:33pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 7, 2025

Walkthrough

새로운 그룹 상세 페이지(참여 그룹용)와 관련된 주요 UI 섹션(기록, 코멘트, 핫토픽, 책 등) 컴포넌트 및 스타일 파일이 추가되었습니다. 그룹 상세 페이지의 라우팅이 확장되었고, 일부 기존 스타일에 미세 조정이 이루어졌습니다. 또한 그룹 액션용 바텀 시트 UI와 컴포넌트가 새로 도입되었습니다.

Changes

Cohort / File(s) Change Summary
참여 그룹 상세 페이지 및 라우팅
src/pages/groupDetail/ParticipatedGroupDetail.tsx, src/pages/groupDetail/ParticipatedGroupDetail.styled.ts, src/pages/index.tsx
참여 그룹 상세 페이지 컴포넌트 및 스타일 추가, 해당 경로 라우팅 추가
핵심 섹션 UI 컴포넌트
src/components/group/CommentSection.tsx, src/components/group/GroupBookSection.tsx, src/components/group/HotTopicSection.tsx, src/components/group/RecordSection.tsx
각종 그룹 상세 섹션(코멘트, 책, 핫토픽, 기록) React 컴포넌트 신규 추가
핵심 섹션 스타일
src/components/group/CommentSection.styled.ts, src/components/group/GroupBookSection.styled.ts, src/components/group/HotTopicSection.styled.ts, src/components/group/RecordSection.styled.ts
각종 그룹 상세 섹션용 styled-components 신규 추가
그룹 액션 바텀 시트 UI 컴포넌트 및 스타일
src/components/group/GroupActionBottomSheet.tsx, src/components/group/GroupActionBottomSheet.styled.ts
그룹 액션을 위한 바텀 시트 컴포넌트 및 스타일 추가, 소유자 여부에 따른 액션 분기 포함
기존 상세 페이지 스타일 조정
src/pages/groupDetail/GroupDetail.styled.ts
기존 Intro 스타일에 line-height 속성 추가

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Router
    participant ParticipatedGroupDetail
    participant SectionComponents
    participant GroupActionBottomSheet

    User->>Router: "group/detail/joined" 경로로 이동
    Router->>ParticipatedGroupDetail: 컴포넌트 렌더링
    ParticipatedGroupDetail->>SectionComponents: (RecordSection, CommentSection, HotTopicSection, GroupBookSection) 렌더링
    SectionComponents-->>ParticipatedGroupDetail: UI 및 상호작용 제공
    ParticipatedGroupDetail->>GroupActionBottomSheet: 그룹 액션 바텀 시트 오픈/클로즈 제어
    GroupActionBottomSheet-->>ParticipatedGroupDetail: 액션 콜백 실행 및 상태 변경
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

✨ Feature, 🎨 Html&css

Suggested reviewers

  • heeeeyong

Poem

🐇
새로운 그룹 페이지, 섹션이 반짝!
기록도, 코멘트도, 핫토픽도 척척
토끼는 뛰며 코드를 살펴
스타일도 예쁘게, 라우팅도 착착
바텀 시트 액션도 한몫 톡톡
오늘도 즐거운 리뷰의 시간
깡총깡총, 멋진 변화에 박수!

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between afe25b0 and a87e2f6.

📒 Files selected for processing (1)
  • src/components/group/HotTopicSection.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/group/HotTopicSection.tsx
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/yesgroupdetail

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 3

♻️ Duplicate comments (1)
src/components/group/HotTopicSection.styled.ts (1)

4-13: 다른 섹션들과 동일한 코드 중복 이슈

앞서 언급했듯이 HotTopicSection의 기본 스타일들도 다른 섹션들과 중복되는 패턴을 보입니다. 공통 베이스 컴포넌트 사용을 고려해보세요.

🧹 Nitpick comments (9)
src/components/group/CommentSection.tsx (1)

16-28: 컴포넌트 구현 품질 개선 제안

전반적인 구현은 깔끔하고 접근성 고려사항(alt 텍스트)도 잘 적용되었습니다. 하지만 컴포넌트명과 styled 컴포넌트명이 동일하여 혼란을 야기할 수 있습니다.

 import {
-  CommentSection as StyledCommentSection,
+  CommentSectionWrapper,
   CommentSectionHeader,
   CommentSectionTitle,
   CommentSectionChevron,
   CommentContent,
   CommentText,
 } from './CommentSection.styled';

 const CommentSection = ({ message, onClick }: CommentSectionProps) => {
   return (
-    <StyledCommentSection>
+    <CommentSectionWrapper>
       <CommentSectionHeader onClick={onClick}>
         <CommentSectionTitle>오늘의 한마디</CommentSectionTitle>
         <CommentSectionChevron src={rightChevron} alt="한마디 이동 버튼" />
       </CommentSectionHeader>
       <CommentContent>
         <CommentText>{message}</CommentText>
       </CommentContent>
-    </StyledCommentSection>
+    </CommentSectionWrapper>
   );
 };
src/components/group/GroupBookSection.tsx (1)

16-26: 컴포넌트 구현 품질 개선 제안

컴포넌트 구현이 깔끔하고 접근성도 잘 고려되었습니다. CommentSection과 동일한 네이밍 개선을 적용하여 일관성을 유지하는 것이 좋겠습니다.

 import {
-  GroupBookSection as StyledGroupBookSection,
+  GroupBookSectionWrapper,
   BookTitle,
   BookAuthor,
   ChevronIcon,
   RightSection,
 } from './GroupBookSection.styled';

 const GroupBookSection = ({ title, author, onClick }: GroupBookSectionProps) => {
   return (
-    <StyledGroupBookSection onClick={onClick}>
+    <GroupBookSectionWrapper onClick={onClick}>
       <BookTitle>{title}</BookTitle>
       <RightSection>
         <BookAuthor>{author}</BookAuthor>
         <ChevronIcon src={rightChevron} alt="책 이동 버튼" />
       </RightSection>
-    </StyledGroupBookSection>
+    </GroupBookSectionWrapper>
   );
 };
src/components/group/RecordSection.tsx (1)

31-34: 인라인 스타일을 styled component로 리팩토링

진행도 텍스트와 퍼센트 기호를 감싸는 컨테이너에 인라인 스타일이 사용되고 있습니다. 일관성을 위해 styled component를 사용하는 것을 권장합니다.

RecordSection.styled.ts 파일에 새로운 styled component를 추가하세요:

export const ProgressTextContainer = styled.div`
  display: flex;
  align-items: baseline;
`;

그리고 컴포넌트에서 사용하세요:

-        <div style={{ display: 'flex', alignItems: 'baseline' }}>
+        <ProgressTextContainer>
          <ProgressText>{progress}</ProgressText>
          <PercentText>%</PercentText>
-        </div>
+        </ProgressTextContainer>
src/pages/groupDetail/ParticipatedGroupDetail.tsx (2)

42-42: 빈 핸들러 함수 구현 필요

handleMoreButton 함수가 비어있습니다. 더보기 버튼의 기능을 구현하거나 TODO 주석을 추가하세요.

const handleMoreButton = () => {
+  // TODO: 더보기 메뉴 기능 구현
+  console.log('More button clicked');
};

67-113: 모킹 데이터를 별도 파일로 분리

컴포넌트 내부에 모킹 데이터가 정의되어 있습니다. 코드의 가독성과 재사용성을 위해 별도의 모킹 파일로 분리하는 것을 권장합니다.

src/mocks/participatedGroupDetail.mock.ts 파일을 생성하여 데이터를 분리하세요:

export const mockRecordData = {
  bookAuthor: '최정화 저',
  currentPage: 1,
  progress: 30,
};

export const mockCommentData = {
  message: '모임방 멤버들과 간단한 인사를 나눠보세요!',
};

export const mockPolls: Poll[] = [
  // 현재 데이터들...
];
src/components/group/CommentSection.styled.ts (1)

4-13: 다른 섹션들과의 코드 중복 개선 고려

CommentSection, RecordSection, HotTopicSection의 스타일드 컴포넌트들 사이에 상당한 중복이 있습니다. 공통 스타일들을 기본 섹션 컴포넌트로 추출하는 것을 고려해보세요.

공통 스타일을 위한 베이스 컴포넌트를 생성할 수 있습니다:

// src/components/group/shared/BaseSection.styled.ts
export const BaseSection = styled.section`
  display: flex;
  flex-direction: column;
  width: 90%;
  gap: 12px;
  background: ${colors.darkgrey.dark};
  margin: 20px 20px 0 20px;
  padding: 16px 12px;
  border-radius: 12px;
`;

export const BaseSectionHeader = styled.div`
  display: flex;
  justify-content: space-between;
  align-items: center;
  cursor: pointer;
`;

export const BaseSectionTitle = styled.h3`
  color: ${colors.white};
  font-size: ${typography.fontSize.base};
  font-weight: ${typography.fontWeight.semibold};
  margin: 0;
`;

Also applies to: 15-20, 22-27, 29-33

src/components/group/HotTopicSection.tsx (3)

108-121: 터치 이벤트에서 preventDefault 사용 주의

모든 터치 이벤트에서 preventDefault()를 호출하면 스크롤과 같은 기본 브라우저 동작을 차단할 수 있습니다.

더 정교한 처리를 위해 다음과 같이 개선하는 것을 고려하세요:

 const handleTouchStart = (e: React.TouchEvent) => {
-  e.preventDefault();
   handleDragStart(e.touches[0].clientX);
 };

 const handleTouchMove = (e: React.TouchEvent) => {
-  e.preventDefault();
+  if (isDragging) {
+    e.preventDefault();
+  }
   handleDragMove(e.touches[0].clientX);
 };

이렇게 하면 드래그가 시작된 후에만 기본 동작을 차단합니다.


130-148: 전역 이벤트 리스너의 메모리 누수 방지 개선

현재 구현은 올바르지만, 컴포넌트가 언마운트될 때도 이벤트 리스너가 제거되도록 보장해야 합니다.

다음과 같이 개선할 수 있습니다:

 useEffect(() => {
   const handleMouseMove = (e: MouseEvent) => {
     handleDragMove(e.clientX);
   };

   const handleMouseUp = () => {
     handleDragEnd();
   };

   if (isDragging) {
     document.addEventListener('mousemove', handleMouseMove);
     document.addEventListener('mouseup', handleMouseUp);
+  } else {
+    // 드래그가 끝났을 때도 리스너 제거 보장
+    document.removeEventListener('mousemove', handleMouseMove);
+    document.removeEventListener('mouseup', handleMouseUp);
   }

   return () => {
     document.removeEventListener('mousemove', handleMouseMove);
     document.removeEventListener('mouseup', handleMouseUp);
   };
 }, [isDragging, handleDragMove]);

191-195: 인라인 스타일 객체 최적화 고려

매 렌더링마다 새로운 스타일 객체가 생성되어 불필요한 리렌더링을 유발할 수 있습니다.

성능 최적화를 위해 스타일 객체를 useMemo로 메모이제이션하세요:

+const slideContainerStyle = useMemo(
+  () => ({
+    transform: `translateX(${translateX}%)`,
+    transition: isDragging ? 'none' : 'transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94)',
+    cursor: isDragging ? 'grabbing' : 'grab',
+  }),
+  [translateX, isDragging],
+);

 <SlideContainer
   ref={slideRef}
   onTouchStart={handleTouchStart}
   onTouchMove={handleTouchMove}
   onTouchEnd={handleTouchEnd}
   onMouseDown={handleMouseDown}
-  style={{
-    transform: `translateX(${translateX}%)`,
-    transition: isDragging ? 'none' : 'transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94)',
-    cursor: isDragging ? 'grabbing' : 'grab',
-  }}
+  style={slideContainerStyle}
 >
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c7242cc and b4efd6a.

⛔ Files ignored due to path filters (1)
  • src/assets/group/right-chevron.svg is excluded by !**/*.svg
📒 Files selected for processing (12)
  • src/components/group/CommentSection.styled.ts (1 hunks)
  • src/components/group/CommentSection.tsx (1 hunks)
  • src/components/group/GroupBookSection.styled.ts (1 hunks)
  • src/components/group/GroupBookSection.tsx (1 hunks)
  • src/components/group/HotTopicSection.styled.ts (1 hunks)
  • src/components/group/HotTopicSection.tsx (1 hunks)
  • src/components/group/RecordSection.styled.ts (1 hunks)
  • src/components/group/RecordSection.tsx (1 hunks)
  • src/pages/groupDetail/GroupDetail.styled.ts (1 hunks)
  • src/pages/groupDetail/ParticipatedGroupDetail.styled.ts (1 hunks)
  • src/pages/groupDetail/ParticipatedGroupDetail.tsx (1 hunks)
  • src/pages/index.tsx (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (10)
src/components/group/GroupBookSection.styled.ts (1)
src/styles/global/global.ts (3)
  • colors (4-53)
  • typography (56-77)
  • semanticColors (80-153)
src/pages/groupDetail/ParticipatedGroupDetail.styled.ts (1)
src/styles/global/global.ts (1)
  • colors (4-53)
src/components/group/CommentSection.tsx (1)
src/components/group/CommentSection.styled.ts (6)
  • CommentSection (4-13)
  • CommentSectionHeader (15-20)
  • CommentSectionTitle (22-27)
  • CommentSectionChevron (29-33)
  • CommentContent (35-38)
  • CommentText (40-45)
src/components/group/GroupBookSection.tsx (1)
src/components/group/GroupBookSection.styled.ts (5)
  • GroupBookSection (4-14)
  • BookTitle (16-22)
  • RightSection (36-40)
  • BookAuthor (24-28)
  • ChevronIcon (30-34)
src/components/group/HotTopicSection.styled.ts (2)
src/styles/global/global.ts (2)
  • colors (4-53)
  • typography (56-77)
src/components/group/HotTopicSection.tsx (1)
  • VoteOption (20-23)
src/pages/groupDetail/ParticipatedGroupDetail.tsx (8)
src/mocks/groupDetail.mock.ts (1)
  • mockGroupDetail (1-53)
src/components/group/HotTopicSection.tsx (1)
  • Poll (25-30)
src/pages/groupDetail/ParticipatedGroupDetail.styled.ts (1)
  • ParticipatedWrapper (4-16)
src/pages/groupDetail/GroupDetail.styled.ts (14)
  • TopBackground (19-28)
  • Header (30-49)
  • BannerSection (51-59)
  • GroupTitle (61-66)
  • SubTitle (68-73)
  • Intro (75-80)
  • MetaInfo (82-86)
  • Meta (88-100)
  • MetaDate (102-106)
  • MetaMember (108-112)
  • MetaTotalMember (114-118)
  • TagRow (120-123)
  • Tag (125-135)
  • TagGenre (137-139)
src/components/group/GroupBookSection.styled.ts (1)
  • GroupBookSection (4-14)
src/components/group/RecordSection.styled.ts (1)
  • RecordSection (4-13)
src/components/group/CommentSection.styled.ts (1)
  • CommentSection (4-13)
src/components/group/HotTopicSection.styled.ts (1)
  • HotTopicSection (4-13)
src/components/group/RecordSection.tsx (1)
src/components/group/RecordSection.styled.ts (10)
  • RecordSection (4-13)
  • RecordSectionHeader (15-20)
  • RecordSectionTitle (22-27)
  • RecordSectionChevron (29-33)
  • RecordSectionContent (35-39)
  • CurrentPage (41-45)
  • ProgressText (71-75)
  • PercentText (65-69)
  • ProgressBar (47-55)
  • ProgressBarFill (57-63)
src/components/group/HotTopicSection.tsx (1)
src/components/group/HotTopicSection.styled.ts (15)
  • VoteOption (64-77)
  • HotTopicSection (4-13)
  • VoteOptionNumber (79-83)
  • VoteOptionText (85-89)
  • HotTopicContent (29-34)
  • EmptyVoteContainer (111-118)
  • EmptyVoteTitle (120-125)
  • SlideContainer (36-43)
  • SlideItem (45-49)
  • HotTopicText (51-56)
  • VoteOptionsList (58-62)
  • Pagination (91-96)
  • PaginationDot (98-109)
  • HotTopicSectionHeader (15-20)
  • HotTopicSectionTitle (22-27)
src/components/group/RecordSection.styled.ts (1)
src/styles/global/global.ts (3)
  • colors (4-53)
  • typography (56-77)
  • semanticColors (80-153)
src/components/group/CommentSection.styled.ts (1)
src/styles/global/global.ts (2)
  • colors (4-53)
  • typography (56-77)
🪛 Biome (2.1.2)
src/components/group/HotTopicSection.tsx

[error] 20-20: Shouldn't redeclare 'VoteOption'. Consider to delete it or rename it.

'VoteOption' is defined here:

(lint/suspicious/noRedeclare)

🔇 Additional comments (22)
src/pages/groupDetail/GroupDetail.styled.ts (1)

79-79: 텍스트 가독성 개선 승인

line-height: 20px 추가로 텍스트의 줄 간격이 개선되어 가독성이 향상되었습니다.

src/pages/index.tsx (2)

38-38: 컴포넌트 import 승인

ParticipatedGroupDetail 컴포넌트가 올바르게 import되었습니다.


55-55: 라우팅 구조 개선 승인

참여 후 그룹 상세 화면을 위한 /group/detail/joined 라우트 추가가 적절합니다. PR 목표에 따라 참여 전과 후 화면을 명확히 분리하는 좋은 구조입니다.

src/pages/groupDetail/ParticipatedGroupDetail.styled.ts (1)

1-16: 일관된 스타일 컴포넌트 구현 승인

ParticipatedWrapper 스타일 컴포넌트가 기존 패턴과 일관되게 구현되었습니다. 반응형 디자인을 위한 min/max width 제약과 적절한 레이아웃 속성들이 잘 적용되었습니다.

src/components/group/CommentSection.tsx (1)

11-14: Props 인터페이스 정의 승인

타입 안전성을 위한 적절한 Props 인터페이스가 정의되었습니다.

src/components/group/GroupBookSection.tsx (1)

10-14: Props 인터페이스 정의 승인

명확하고 타입 안전한 Props 인터페이스가 잘 정의되었습니다.

src/components/group/RecordSection.tsx (1)

22-41: 컴포넌트 구현 승인

컴포넌트의 전체적인 구조와 기능이 잘 구현되어 있습니다. 클릭 이벤트 처리, 진행도 표시, 그리고 일관된 스타일링이 적용되어 있습니다.

src/components/group/GroupBookSection.styled.ts (1)

1-40: styled components 구현 승인

GroupBookSection을 위한 styled components가 일관성 있게 잘 구현되어 있습니다. 전역 색상 및 타이포그래피 시스템을 적절히 활용하고 있으며, 다른 그룹 섹션들과 일관된 디자인 패턴을 따르고 있습니다.

src/pages/groupDetail/ParticipatedGroupDetail.tsx (2)

33-66: PR 목표와 불일치하는 구현

PR 설명에서 useCallbackuseEffect 훅의 사용에 대한 리뷰를 요청했지만, 실제 코드에서는 이러한 훅들이 사용되지 않고 있습니다. 드래그 이벤트 처리와 성능 최적화가 필요한 부분이 있다면 해당 훅들의 사용을 고려해보세요.

Likely an incorrect or invalid review comment.


115-176: 컴포넌트 구조 및 JSX 구현 승인

전체적인 컴포넌트 구조와 JSX 구현이 잘 되어 있습니다. 각 섹션 컴포넌트들이 적절히 배치되어 있고, props 전달과 이벤트 핸들링이 올바르게 구현되어 있습니다.

src/components/group/CommentSection.styled.ts (1)

1-45: 전반적인 styled components 구현 승인

CommentSection을 위한 styled components가 일관성 있게 잘 구현되어 있습니다. 전역 스타일 시스템을 적절히 활용하고 있습니다.

src/components/group/HotTopicSection.styled.ts (3)

36-43: 터치 및 드래그 최적화 구현 승인

SlideContainer에서 touch-action: pan-xuser-select: none 속성들이 적절히 설정되어 있어 수평 스와이프 기능이 최적화되어 있습니다. 이는 PR 목표에서 언급된 터치 및 마우스 드래그 스크롤 기능을 지원합니다.


98-109: 동적 스타일링과 상호작용 효과 구현 승인

PaginationDot 컴포넌트에서 active prop을 기반으로 한 조건부 스타일링과 호버 효과가 잘 구현되어 있습니다. 사용자 경험을 향상시키는 부드러운 트랜지션도 포함되어 있습니다.


1-125: 복잡한 UI 컴포넌트 스타일링 승인

HotTopicSection을 위한 종합적인 스타일드 컴포넌트들이 잘 구현되어 있습니다. 슬라이드 기능, 투표 옵션, 페이지네이션, 빈 상태 등 모든 요소가 일관성 있게 스타일링되어 있고, 사용자 상호작용을 위한 적절한 효과들이 포함되어 있습니다.

src/components/group/HotTopicSection.tsx (3)

62-72: snapToClosest 함수의 useCallback 사용 우수

snapToClosest 함수를 useCallback으로 메모이제이션한 것은 성능 최적화에 좋은 접근입니다. dependency array도 적절하게 설정되어 있습니다.


39-54: 전반적인 구현 품질 우수

컴포넌트의 전반적인 구조와 로직이 잘 설계되어 있습니다. 드래그 상태에 따른 클릭 방지 로직(!isDragging 체크)과 투표 옵션 렌더링이 적절히 구현되어 있습니다.

Also applies to: 157-168


82-97: handleDragMove의 dependency array 최적화 필요

useCallback의 dependency array에 불필요한 의존성들이 포함되어 성능 저하를 일으킬 수 있습니다.

다음과 같이 최적화하세요:

 const handleDragMove = useCallback(
   (clientX: number) => {
     if (!isDragging) return;

     const deltaX = clientX - startX;
     const newTranslateX = startTranslateX + (deltaX / window.innerWidth) * 100;

     // 드래그 범위 제한 (약간의 오버스크롤 허용)
     const minTranslate = getTargetTranslateX(polls.length - 1) - 20;
     const maxTranslate = getTargetTranslateX(0) + 20;

     const limitedTranslateX = Math.max(minTranslate, Math.min(maxTranslateX, newTranslateX));
     setTranslateX(limitedTranslateX);
   },
-  [isDragging, startX, startTranslateX, polls.length],
+  [isDragging, startX, startTranslateX, polls.length],
 );

실제로는 dependency array가 적절합니다. 하지만 polls.length가 자주 변경되지 않는다면, 이를 별도 ref로 관리하여 불필요한 재생성을 방지할 수 있습니다.

Likely an incorrect or invalid review comment.

src/components/group/RecordSection.styled.ts (5)

1-3: Import 구조 적절함

필요한 스타일 토큰들을 명확하게 import하고 있으며, 전역 스타일 시스템을 적절히 활용하고 있습니다.


4-13: 일관된 레이아웃 패턴 사용

다른 섹션 컴포넌트들(HotTopicSection 등)과 동일한 레이아웃 패턴(width: 90%, margin, padding, border-radius)을 사용하여 UI 일관성을 유지하고 있습니다.


57-63: ProgressBarFill 애니메이션 구현 우수

progress prop을 받아서 동적으로 width를 설정하고, smooth transition을 적용한 것이 좋습니다. 사용자 경험을 향상시키는 적절한 애니메이션입니다.


29-33: Chevron 아이콘 마진 검토 필요

음수 마진(margin-right: -8px)을 사용한 이유가 명확하지 않습니다. 의도된 디자인인지 확인이 필요합니다.

다음이 의도된 디자인인지 확인해 주세요:

  • 아이콘이 컨테이너 경계를 넘어서는 것이 의도된 것인지
  • 다른 섹션들과의 일관성을 위해 마진 조정이 필요한지

65-75: 색상 사용의 일관성 우수

텍스트 요소들이 purple.main 색상을 일관되게 사용하여 브랜드 아이덴티티를 잘 반영하고 있습니다. 타이포그래피 설정도 전역 스타일 시스템을 적절히 활용하고 있습니다.

Comment thread src/components/group/HotTopicSection.tsx Outdated
Comment on lines +15 to +20
interface RecordSectionProps {
bookAuthor: string;
currentPage: number;
progress: number;
onClick: () => void;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

사용되지 않는 props 제거 필요

bookAuthor prop이 인터페이스에 정의되어 있지만 컴포넌트 내에서 실제로 사용되지 않고 있습니다.

사용되지 않는 prop을 제거하여 인터페이스를 정리하세요:

interface RecordSectionProps {
-  bookAuthor: string;
  currentPage: number;
  progress: number;
  onClick: () => void;
}

또한 함수 시그니처에서도 제거하세요:

-const RecordSection = ({ currentPage, progress, onClick }: RecordSectionProps) => {
+const RecordSection = ({ currentPage, progress, onClick }: RecordSectionProps) => {

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/components/group/RecordSection.tsx between lines 15 and 20, the
bookAuthor prop is defined in the RecordSectionProps interface but is not used
anywhere in the component. Remove bookAuthor from the interface definition and
also remove it from any function signatures or component props where it is
declared to keep the interface clean and accurate.

};

const handleBookSectionClick = () => {
navigate(`/book/123`);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

하드코딩된 값들을 상수로 분리

책 ID(/book/123)와 쿼리 매개변수(filter=poll)가 하드코딩되어 있습니다. 이러한 값들을 상수로 분리하거나 props/context에서 받아오는 것을 권장합니다.

+const BOOK_ID = '123'; // 실제로는 props나 context에서 가져와야 함
+const POLL_FILTER = 'poll';

const handleBookSectionClick = () => {
-  navigate(`/book/123`);
+  navigate(`/book/${BOOK_ID}`);
};

const handlePollClick = (pageNumber: number) => {
-  navigate(`/memory?page=${pageNumber}&filter=poll`);
+  navigate(`/memory?page=${pageNumber}&filter=${POLL_FILTER}`);
};

Also applies to: 64-64

🤖 Prompt for AI Agents
In src/pages/groupDetail/ParticipatedGroupDetail.tsx at lines 58 and 64, the
book ID and query parameter values are hardcoded in the navigate calls. Refactor
these lines to replace the hardcoded strings with constants defined at the top
of the file or passed in via props or context. This will improve maintainability
and flexibility by centralizing these values.

Copy link
Copy Markdown
Collaborator

@heeeeyong heeeeyong left a comment

Choose a reason for hiding this comment

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

고생하셨습니다~ 반응형 요구사항이 있는데 피그마에서 해당부분 페이지 늘려서 확인한번 해주시면 감사하겠습니다!

Comment on lines +82 to +97
const handleDragMove = useCallback(
(clientX: number) => {
if (!isDragging) return;

const deltaX = clientX - startX;
const newTranslateX = startTranslateX + (deltaX / window.innerWidth) * 100;

// 드래그 범위 제한 (약간의 오버스크롤 허용)
const minTranslate = getTargetTranslateX(polls.length - 1) - 20;
const maxTranslate = getTargetTranslateX(0) + 20;

const limitedTranslateX = Math.max(minTranslate, Math.min(maxTranslate, newTranslateX));
setTranslateX(limitedTranslateX);
},
[isDragging, startX, startTranslateX, polls.length],
);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

startX와 startTranslateX 를 useCallback의 의존성관리에서 빼서 useRef로 관리하는건 어떨까요?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

오! 좋은 지적 감사합니다!
useCallback 의존성 배열에서 빼고 dragStateRef로 관리하도록 수정하겠습니다! 👏🏻

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

🧹 Nitpick comments (1)
src/pages/groupDetail/ParticipatedGroupDetail.styled.ts (1)

18-27: 터치 디바이스를 고려한 인터랙션 개선을 권장합니다.

현재 hover 효과는 데스크톱에서는 좋은 UX를 제공하지만, 터치 디바이스에서는 hover 상태가 제대로 동작하지 않습니다. 모바일 우선 디자인을 고려할 때 active 상태도 추가하는 것이 좋겠습니다.

다음과 같이 터치 친화적인 상태를 추가해보세요:

export const ClickableMeta = styled.div`
  display: flex;
  flex-direction: column;
  width: 100%;
  cursor: pointer;

  &:hover {
    opacity: 0.8;
  }
+
+  &:active {
+    opacity: 0.7;
+    transform: scale(0.98);
+  }
`;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9efe7e8 and 86a8664.

📒 Files selected for processing (2)
  • src/pages/groupDetail/ParticipatedGroupDetail.styled.ts (1 hunks)
  • src/pages/groupDetail/ParticipatedGroupDetail.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/pages/groupDetail/ParticipatedGroupDetail.tsx
🔇 Additional comments (2)
src/pages/groupDetail/ParticipatedGroupDetail.styled.ts (2)

29-32: 깔끔하고 명확한 아이콘 컴포넌트입니다.

24px의 고정 크기는 UI 아이콘으로 적절하며, 구현이 간결하고 명확합니다.


34-39: 헤더 레이아웃을 위한 적절한 구조입니다.

justify-content: space-betweenalign-items: center의 조합이 메타 정보를 양쪽 끝에 배치하는 일반적인 헤더 패턴에 잘 맞습니다. 구현이 표준적이고 효과적입니다.

Comment on lines +4 to +16
export const ParticipatedWrapper = styled.div`
display: flex;
position: relative;
flex-direction: column;
align-items: center;
justify-content: center;
min-width: 320px;
max-width: 767px;
height: 100%;
margin: 0 auto;
background-color: ${colors.black.main};
overflow: hidden;
`;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

메인 컨테이너의 수직 정렬 방식을 재검토해주세요.

justify-content: center로 인해 콘텐츠가 화면 중앙에 위치하게 되는데, 일반적으로 그룹 상세 페이지의 콘텐츠는 상단부터 자연스럽게 흘러야 합니다. 콘텐츠가 많을 때 레이아웃 문제가 발생할 수 있습니다.

다음과 같이 수정을 권장합니다:

export const ParticipatedWrapper = styled.div`
  display: flex;
  position: relative;
  flex-direction: column;
  align-items: center;
-  justify-content: center;
+  justify-content: flex-start;
  min-width: 320px;
  max-width: 767px;
  height: 100%;
  margin: 0 auto;
  background-color: ${colors.black.main};
  overflow: hidden;
`;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const ParticipatedWrapper = styled.div`
display: flex;
position: relative;
flex-direction: column;
align-items: center;
justify-content: center;
min-width: 320px;
max-width: 767px;
height: 100%;
margin: 0 auto;
background-color: ${colors.black.main};
overflow: hidden;
`;
export const ParticipatedWrapper = styled.div`
display: flex;
position: relative;
flex-direction: column;
align-items: center;
justify-content: flex-start;
min-width: 320px;
max-width: 767px;
height: 100%;
margin: 0 auto;
background-color: ${colors.black.main};
overflow: hidden;
`;
🤖 Prompt for AI Agents
In src/pages/groupDetail/ParticipatedGroupDetail.styled.ts between lines 4 and
16, the main container uses justify-content: center which vertically centers the
content, causing layout issues when there is a lot of content. Change
justify-content from center to flex-start to align the content naturally from
the top and prevent overflow or layout problems.

@ljh130334 ljh130334 merged commit fb7ed7e into develop Aug 7, 2025
3 checks passed
@ljh130334 ljh130334 deleted the feat/yesgroupdetail branch August 10, 2025 06:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants