-
Notifications
You must be signed in to change notification settings - Fork 2
[feature] 동아리 상세페이지 > 공통 레이아웃(UI 틀) 구현 #964
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Instagram, YouTube 아이콘 교체
- ClubProfileCard 컴포넌트 추가 (커버, 로고, 클럽명, SNS 링크, 소개) - 반응형 레이아웃 지원 (모바일/태블릿/데스크탑)
- 새 라우트 및 페이지 구조 추가 - 프로필 카드 컴포넌트 사용 - 탭 기반 콘텐츠 전환 구현
- CLUB_INTRO_TAB_CLICKED 이벤트 추가 - CLUB_FEED_TAB_CLICKED 이벤트 추가
- 동아리 기본 정보 (이름, 로고, 커버 이미지) - 상세 설명 (소개, 활동 내용, 수상 내역, FAQ 등) - 모집 정보 및 SNS 링크 데이터
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | 변경 사항 요약 |
|---|---|
라우팅 및 상수 frontend/src/App.tsx, frontend/src/constants/eventName.ts |
새로운 /club2/:clubId 라우트 추가, ClubDetailPage2를 Suspense로 감싸기; 탭 클릭 이벤트 추가 (CLUB_INTRO_TAB_CLICKED, CLUB_FEED_TAB_CLICKED) |
ClubDetailPage2 주요 컴포넌트 frontend/src/pages/clubDetailPage2/ClubDetailPage2.tsx, frontend/src/pages/clubDetailPage2/ClubDetailPage2.styles.ts |
클럽 데이터 조회 후 렌더링하는 페이지 컴포넌트 구현; 탭 관리, Mixpanel 추적, 반응형 레이아웃 포함 |
ClubProfileCard 서브컴포넌트 frontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.tsx, frontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.styles.ts |
커버 이미지, 로고, 클럽명, 채용 배지, SNS 링크, 소개 섹션을 렌더링하는 프로필 카드 컴포넌트; 플랫폼별 아이콘 매핑 포함 |
타입 및 모의 데이터 frontend/src/types/club.ts, frontend/src/pages/clubDetailPage2/mockData.ts |
새로운 타입 정의 (Award, IdealCandidate, FAQ, DetailedDescription, ClubApiResponse); 클럽 상세 정보용 모의 데이터 추가 |
Sequence Diagram(s)
sequenceDiagram
actor User
participant Router as App Router
participant Page as ClubDetailPage2
participant Hook as useGetClubDetail
participant API as API
participant Analytics as Mixpanel
participant Card as ClubProfileCard
User->>Router: Navigate to /club2/:clubId
Router->>Page: Render with clubId
Page->>Hook: Fetch club data
Hook->>API: GET /club/:clubId
API-->>Hook: Club data response
Hook-->>Page: Data loaded
Page->>Analytics: Track page view
Page->>Card: Pass club data
Card-->>Page: Render profile card
Page-->>User: Display page with tabs
rect rgb(200, 220, 255)
Note over User,Analytics: Tab Interaction Flow
User->>Page: Click intro/feed tab
Page->>Page: Update active tab state
Page->>Analytics: Track tab click event
Analytics-->>Page: Event recorded
Page-->>User: Render tab content
end
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
- [feature] 상세페이지 동아리 SNS 링크 노출 기능 추가 #409: SNS 링크 처리 및 플랫폼별 아이콘 매핑 로직 중복 (소셜 링크 렌더링 방식)
- [fix] 지원서 미등록 시 alert 반복 버그 수정 및 외부 링크/지원서 분기 처리 #605: ClubApiResponse의 externalApplicationUrl 필드 및 클럽 상세 타입 정의 확장 관련
- [feature] 동아리 지원서 답변 화면 구현 및 관련 컴포넌트 개발 #490: App.tsx 라우트 및 컴포넌트 임포트 변경
Suggested labels
✨ Feature, 💻 FE
Suggested reviewers
- lepitaaar
- Zepelown
- seongwon030
Pre-merge checks and finishing touches
❌ Failed checks (1 inconclusive)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Title check | ❓ Inconclusive | PR 제목 'Feature/#951 club detail layout moa 445'는 변경 사항의 주요 내용(ClubDetailPage2 구현, 반응형 레이아웃, 탭 네비게이션)을 충분히 반영하지 못하고 있으며, 이슈 번호와 약자(moa, 445)를 포함하여 명확성과 가독성이 낮습니다. | 제목을 더 명확하게 수정하세요. 예: 'Add ClubDetailPage2 with responsive layout and tab navigation' 또는 'Implement club detail page layout with profile card and tabs'로 변경하면 변경 사항이 더 명확해집니다. |
✅ Passed checks (4 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Linked Issues check | ✅ Passed | PR의 모든 주요 목표가 MOA-445 요구사항을 충족합니다: 상세페이지 기본 레이아웃 구성, 모바일/데스크탑 반응형 스타일 적용, 하위 섹션 삽입 가능한 구조, 레이아웃 안정성 확보. |
| Out of Scope Changes check | ✅ Passed | 모든 변경사항이 MOA-445의 클럽 상세페이지 공통 레이아웃 구현 범위 내에 있으며, 범위를 벗어난 변경은 없습니다. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
✨ 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
feature/#951-club-detail-layout-MOA-445
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 @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this 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
🧹 Nitpick comments (9)
frontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.styles.ts (5)
5-16: 매직 넘버를 명명된 상수로 교체하세요.
max-width: 375px: 모바일 너비는 명명된 상수로 정의해야 합니다.border-radius: 20px: 이 값은 파일 전체에서 반복되므로 상수로 추출하면 일관성과 유지보수성이 향상됩니다.background-color: #ffffff: 테마의colors.base.white를 사용해야 합니다.코딩 가이드라인에 따라 매직 넘버를 명명된 상수로 교체하여 명확성을 높여야 합니다.
🔎 제안하는 개선 방안
상수 파일이나 파일 상단에 정의:
const MOBILE_MAX_WIDTH = 375; const CARD_BORDER_RADIUS = 20;그런 다음 스타일에서 사용:
export const Container = styled.div` position: relative; width: 100%; - max-width: 375px; - background-color: #ffffff; - border-radius: 20px; + max-width: ${MOBILE_MAX_WIDTH}px; + background-color: ${colors.base.white}; + border-radius: ${CARD_BORDER_RADIUS}px; overflow: hidden;
18-24: 매직 넘버를 명명된 상수로 교체하세요.
height: 213px는 디자인 사양에서 온 값으로 보입니다. 명명된 상수로 추출하면 디자인 변경 시 유지보수가 용이합니다.🔎 제안하는 개선 방안
const COVER_IMAGE_HEIGHT = 213;export const CoverImage = styled.img` width: 100%; - height: 213px; + height: ${COVER_IMAGE_HEIGHT}px; position: relative; z-index: 1; object-fit: cover;
26-44: 매직 넘버와 하드코딩된 색상을 상수로 교체하세요.LogoWrapper와 Logo 컴포넌트에 여러 매직 넘버와 하드코딩된 색상이 있습니다:
- 위치 값:
top: 165px,left: 16px- 크기 값:
width: 64px,height: 64px- 테두리 반경:
border-radius: 16px,14px- 패딩:
padding: 2px- 색상:
background-color: #ffffff→colors.base.white사용 필요🔎 제안하는 개선 방안
const LOGO_SIZE = 64; const LOGO_TOP_OFFSET = 165; const LOGO_LEFT_OFFSET = 16; const LOGO_BORDER_RADIUS = 16; const LOGO_INNER_BORDER_RADIUS = 14; const LOGO_PADDING = 2;export const LogoWrapper = styled.div` position: absolute; - top: 165px; - left: 16px; - width: 64px; - height: 64px; - border-radius: 16px; - background-color: #ffffff; - padding: 2px; + top: ${LOGO_TOP_OFFSET}px; + left: ${LOGO_LEFT_OFFSET}px; + width: ${LOGO_SIZE}px; + height: ${LOGO_SIZE}px; + border-radius: ${LOGO_BORDER_RADIUS}px; + background-color: ${colors.base.white}; + padding: ${LOGO_PADDING}px; z-index: 3; `; export const Logo = styled.img` width: 100%; height: 100%; - border-radius: 14px; + border-radius: ${LOGO_INNER_BORDER_RADIUS}px; object-fit: cover; border: 0.5px solid var(--Gray-400, #dcdcdc);
46-61: 하드코딩된 색상을 테마 색상으로 교체하세요.
- Line 51:
background-color: #f5f5f5→colors.gray[100]사용- Line 55:
background-color: #ffffff→colors.base.white사용- 여러 패딩 값(
42px,20px,40px,16px)과 마진 값(-20px)은 명명된 상수로 추출하는 것을 고려하세요.
132-144: 하드코딩된 색상을 테마에 추가하거나 기존 테마 색상을 사용하세요.
- Line 133:
color: #0066cc는 URL 링크 색상으로 보이지만 테마에 정의되어 있지 않습니다. 이 색상을 테마에 추가하거나 기존 accent 색상(예:colors.accent[1][900])을 사용하는 것을 고려하세요.- Lines 139, 142: 하드코딩된 배경색 대신
colors.base.white및colors.gray[100]을 사용하세요.frontend/src/pages/clubDetailPage2/ClubDetailPage2.tsx (2)
27-29: 로딩 상태에서 사용자 피드백을 제공하세요.현재
clubDetail이 없으면null을 반환하여 빈 화면이 표시됩니다. 사용자에게 로딩 중임을 알리는 인디케이터를 표시하는 것이 좋습니다.🔎 제안하는 개선 방안
if (!clubDetail) { - return null; + return <div>로딩 중...</div>; // 또는 적절한 로딩 스피너 컴포넌트 }
31-33: 에러 처리를 개선하여 더 나은 사용자 경험을 제공하세요.현재 에러 메시지가 너무 단순합니다. 에러 유형에 따른 구체적인 안내와 재시도 옵션을 제공하는 것을 고려하세요.
🔎 제안하는 개선 방안
if (error) { - return <div>에러가 발생했습니다.</div>; + return ( + <ErrorFallback + message="클럽 정보를 불러오는 중 문제가 발생했습니다." + onRetry={() => window.location.reload()} + /> + ); }frontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.tsx (1)
25-32: 플랫폼 이름 매핑을 상수로 추출하세요.하드코딩된 플랫폼 이름 매핑은 여러 곳에서 사용될 수 있으므로 공유 상수 파일로 추출하는 것이 좋습니다. 이렇게 하면 플랫폼 이름 변경 시 한 곳에서만 수정하면 됩니다.
🔎 제안하는 개선 방안
상수 파일(예:
@/constants/snsConfig.ts)에 추가:export const SNS_PLATFORM_NAMES: Record<string, string> = { instagram: '인스타그램', youtube: '유튜브', x: 'X', } as const;그런 다음 컴포넌트에서 사용:
+ import { SNS_PLATFORM_NAMES } from '@/constants/snsConfig'; const getSocialPlatformName = (platform: string) => { - const names: Record<string, string> = { - instagram: '인스타그램', - youtube: '유튜브', - x: 'X', - }; - return names[platform] || platform; + return SNS_PLATFORM_NAMES[platform] || platform; };frontend/src/pages/clubDetailPage2/ClubDetailPage2.styles.ts (1)
10-28: 레이아웃 관련 매직 넘버를 명명된 상수로 교체하는 것을 고려하세요.여러 레이아웃 값들이 하드코딩되어 있습니다:
max-width: 1180px: 콘텐츠 최대 너비margin-top: 100px: 헤더 오프셋으로 보임gap: 24px: 그리드 간격이러한 값들을 명명된 상수로 추출하면 디자인 시스템 변경 시 유지보수가 용이합니다.
🔎 제안하는 개선 방안
const CONTENT_MAX_WIDTH = 1180; const HEADER_HEIGHT_OFFSET = 100; const CONTENT_GAP = 24;export const ContentWrapper = styled.div` - max-width: 1180px; + max-width: ${CONTENT_MAX_WIDTH}px; width: 100%; margin: 0 auto; display: flex; - gap: 24px; - margin-top: 100px; + gap: ${CONTENT_GAP}px; + margin-top: ${HEADER_HEIGHT_OFFSET}px;
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (2)
frontend/src/assets/images/icons/sns/instagram_icon.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/sns/youtube_icon.svgis excluded by!**/*.svg
📒 Files selected for processing (8)
frontend/src/App.tsxfrontend/src/constants/eventName.tsfrontend/src/pages/clubDetailPage2/ClubDetailPage2.styles.tsfrontend/src/pages/clubDetailPage2/ClubDetailPage2.tsxfrontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.styles.tsfrontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.tsxfrontend/src/pages/clubDetailPage2/mockData.tsfrontend/src/types/club.ts
🧰 Additional context used
📓 Path-based instructions (3)
frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx,js,jsx}: Replace magic numbers with named constants for clarity
Replace complex/nested ternaries withif/elseor IIFEs for readability
Assign complex boolean conditions to named variables for explicit meaning
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle)
Use unique and descriptive names for custom wrappers/functions to avoid ambiguity
Define constants near related logic or ensure names link them clearly to avoid silent failures
Break down broad state management into smaller, focused hooks/contexts to reduce coupling
Files:
frontend/src/types/club.tsfrontend/src/constants/eventName.tsfrontend/src/App.tsxfrontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.tsxfrontend/src/pages/clubDetailPage2/ClubDetailPage2.styles.tsfrontend/src/pages/clubDetailPage2/mockData.tsfrontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.styles.tsfrontend/src/pages/clubDetailPage2/ClubDetailPage2.tsx
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/types/club.tsfrontend/src/constants/eventName.tsfrontend/src/App.tsxfrontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.tsxfrontend/src/pages/clubDetailPage2/ClubDetailPage2.styles.tsfrontend/src/pages/clubDetailPage2/mockData.tsfrontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.styles.tsfrontend/src/pages/clubDetailPage2/ClubDetailPage2.tsx
frontend/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{tsx,jsx}: Abstract complex logic/interactions into dedicated components/HOCs
Separate significantly different conditional UI/logic into distinct components
Colocate simple, localized logic or use inline definitions to reduce context switching
Choose field-level or form-level cohesion based on form requirements when using form libraries like react-hook-form
Use Component Composition instead of Props Drilling to reduce coupling
Files:
frontend/src/App.tsxfrontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.tsxfrontend/src/pages/clubDetailPage2/ClubDetailPage2.tsx
🧠 Learnings (7)
📓 Common learnings
Learnt from: seongwon030
Repo: Moadong/moadong PR: 195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
📚 Learning: 2025-03-19T05:18:07.818Z
Learnt from: seongwon030
Repo: Moadong/moadong PR: 195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
Applied to files:
frontend/src/App.tsxfrontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.tsxfrontend/src/pages/clubDetailPage2/ClubDetailPage2.tsx
📚 Learning: 2025-11-25T14:08:23.253Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.253Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Abstract complex logic/interactions into dedicated components/HOCs
Applied to files:
frontend/src/App.tsxfrontend/src/pages/clubDetailPage2/ClubDetailPage2.styles.ts
📚 Learning: 2025-11-25T14:08:23.253Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.253Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Separate significantly different conditional UI/logic into distinct components
Applied to files:
frontend/src/App.tsxfrontend/src/pages/clubDetailPage2/ClubDetailPage2.styles.tsfrontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.styles.ts
📚 Learning: 2025-05-16T06:25:11.193Z
Learnt from: seongwon030
Repo: Moadong/moadong PR: 418
File: frontend/src/mocks/api/clubHandlers.test.ts:0-0
Timestamp: 2025-05-16T06:25:11.193Z
Learning: API 관련 상수(예: API_BASE)는 frontend/src/mocks/constants/api.ts에 정의되어 있으며, 다른 파일에서 재정의하지 말고 이 파일에서 import하여 사용해야 합니다.
Applied to files:
frontend/src/pages/clubDetailPage2/mockData.ts
📚 Learning: 2025-11-25T14:08:23.253Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.253Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Replace magic numbers with named constants for clarity
Applied to files:
frontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.styles.ts
📚 Learning: 2025-07-19T05:05:10.196Z
Learnt from: seongwon030
Repo: Moadong/moadong PR: 548
File: frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx:17-57
Timestamp: 2025-07-19T05:05:10.196Z
Learning: ClubDetailPage.tsx에서 notJoinedClubNames 배열의 하드코딩은 의도적인 설계 결정입니다. 개발자가 명시적으로 하드코딩을 선택했으므로 이에 대한 리팩토링 제안을 하지 않아야 합니다.
Applied to files:
frontend/src/pages/clubDetailPage2/ClubDetailPage2.tsx
🧬 Code graph analysis (5)
frontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.tsx (1)
frontend/src/types/club.ts (1)
SNSPlatform(14-14)
frontend/src/pages/clubDetailPage2/ClubDetailPage2.styles.ts (2)
frontend/src/styles/mediaQuery.ts (1)
media(8-14)frontend/src/styles/theme/colors.ts (1)
colors(1-81)
frontend/src/pages/clubDetailPage2/mockData.ts (1)
frontend/src/types/club.ts (1)
ClubApiResponse(60-75)
frontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.styles.ts (2)
frontend/src/styles/mediaQuery.ts (1)
media(8-14)frontend/src/styles/theme/colors.ts (1)
colors(1-81)
frontend/src/pages/clubDetailPage2/ClubDetailPage2.tsx (3)
frontend/src/pages/clubDetailPage2/mockData.ts (1)
mockClubApi(3-43)frontend/src/hooks/queries/club/useGetClubDetail.ts (1)
useGetClubDetail(6-20)frontend/src/constants/eventName.ts (2)
PAGE_VIEW(81-95)USER_EVENT(1-37)
🔇 Additional comments (6)
frontend/src/constants/eventName.ts (1)
21-22: LGTM!새로운 탭 클릭 이벤트 상수가 올바르게 추가되었으며 기존 네이밍 패턴을 따릅니다.
frontend/src/App.tsx (1)
10-10: LGTM!새로운 라우트가 기존 패턴을 따라 올바르게 추가되었습니다. Suspense 경계 내에서 lazy-loading이 적절히 구현되어 있습니다.
Also applies to: 47-54
frontend/src/pages/clubDetailPage2/mockData.ts (1)
6-7: 에셋 경로가 프로덕션 환경에서 작동하지 않을 수 있습니다.
/src/assets/...로 시작하는 경로는 개발 환경에서만 작동할 수 있습니다. 빌드된 앱에서는 적절한 public 경로나 import된 에셋을 사용해야 합니다.모크 데이터이므로 테스트 목적으로는 괜찮지만, 실제 API 통합 시 이 경로들이 올바른 에셋 URL로 교체되어야 합니다.
frontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.tsx (1)
51-51: 기본 이미지 경로를 확인하세요.
'/default-cover.jpg'및'/default-logo.jpg'경로가 실제로 존재하는지 확인이 필요합니다. 존재하지 않으면 이미지 로딩 오류가 발생합니다.프로젝트의 다른 부분에서 사용하는 기본 이미지 패턴(예:
/src/assets/images/logos/default_profile_image.svg)을 따르는 것을 권장합니다.🔎 제안하는 수정 방안
+ import defaultLogo from '@/assets/images/logos/default_profile_image.svg'; + import defaultCover from '@/assets/images/banners/default_banner.png'; - <Styled.CoverImage src={cover || '/default-cover.jpg'} alt="클럽 커버" /> + <Styled.CoverImage src={cover || defaultCover} alt="클럽 커버" /> - <Styled.Logo src={logo || '/default-logo.jpg'} alt={`${name} 로고`} /> + <Styled.Logo src={logo || defaultLogo} alt={`${name} 로고`} />Also applies to: 55-55
frontend/src/types/club.ts (1)
36-75: LGTM!새로운 타입 정의가 잘 구조화되어 있고 TypeScript 모범 사례를 따릅니다.
DetailedDescription의 중첩 구조(Award,IdealCandidate,FAQ)가 명확하며,ClubApiResponse인터페이스가 모든 필요한 필드를 포함하고 있습니다.frontend/src/pages/clubDetailPage2/ClubDetailPage2.styles.ts (1)
41-56: TabButton의 전이 속성(transient prop) 사용이 올바릅니다.
$activeprop에$접두사를 사용하여 DOM에 전달되지 않도록 한 것은 styled-components v5.1+ 모범 사례를 잘 따르고 있습니다. 이는 React의 알 수 없는 prop 경고를 방지합니다.
| const getSocialIcon = (platform: string) => { | ||
| const icons: Record<string, string> = { | ||
| instagram: InstagramIcon, | ||
| youtube: YoutubeIcon, | ||
| }; | ||
| return icons[platform]; | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'x' 플랫폼 아이콘이 누락되었습니다.
getSocialIcon 함수에 'x' 플랫폼에 대한 아이콘 매핑이 없습니다. Line 71-72에서 아이콘이 없으면 null을 반환하므로 x 링크는 렌더링되지 않습니다.
SNSPlatform 타입에 'x'가 포함되어 있다면 해당 아이콘을 추가하거나, 지원하지 않는 플랫폼이라면 타입에서 제거해야 합니다.
🔎 제안하는 수정 방안
Option 1: X 아이콘 추가
+ import XIcon from '@/assets/images/icons/sns/x_icon.svg';
const getSocialIcon = (platform: string) => {
const icons: Record<string, string> = {
instagram: InstagramIcon,
youtube: YoutubeIcon,
+ x: XIcon,
};
return icons[platform];
};Option 2: 기본 아이콘 제공
+ import DefaultSnsIcon from '@/assets/images/icons/sns/default_icon.svg';
const getSocialIcon = (platform: string) => {
const icons: Record<string, string> = {
instagram: InstagramIcon,
youtube: YoutubeIcon,
+ x: DefaultSnsIcon,
};
- return icons[platform];
+ return icons[platform] || DefaultSnsIcon;
};Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In
frontend/src/pages/clubDetailPage2/components/ClubProfileCard/ClubProfileCard.tsx
around lines 34 to 40, the getSocialIcon function lacks a mapping for the 'x'
platform so X links render as null; add an entry for 'x' in the icons record
pointing to the X icon asset (or, if X should not be supported, remove 'x' from
the SNSPlatform type) and ensure the function returns that icon (or supply a
sensible default icon) so X links render correctly.
seongwon030
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고생하셨습니다
#️⃣연관된 이슈
📝작업 내용
✨ 새로운 동아리 상세 페이지 (ClubDetailPage2) 구현
1. 반응형 2단 레이아웃
default.mp4
2. ClubProfileCard 컴포넌트
3. 탭 네비게이션 & 이벤트 추적
CLUB_INTRO_TAB_CLICKED: 소개 탭 클릭 추적CLUB_FEED_TAB_CLICKED: 피드 탭 클릭 추적임시 변경사항 (추후 수정 예정)
ClubDetailPage2사용 중 (기존 페이지와 구분을 위한 임시 네이밍)/club2/:clubId사용 중mockData.ts)ClubDetailPage대체 또는 병합 예정🫡 참고사항
/club/:clubId)는 그대로 유지/club2/67ee2b97b35e3c267e3c2485Summary by CodeRabbit
릴리스 노트
✏️ Tip: You can customize this high-level summary in your review settings.