Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | Summary |
|---|---|
Routingfrontend/src/App.tsx |
ClubUnionPage 임포트 및 /club-union 라우트 추가; 일부 주석(가드 관련) 제거. |
Header & Navigationfrontend/src/components/common/Header/Header.tsx, frontend/src/services/header/useHeaderService.ts, frontend/src/constants/eventName.ts |
Header 컴포넌트들을 memo로 분리하고 공통 navLinks 모델로 재구성. useHeaderService에 handleClubUnionClick(navigate + 트래킹) 추가 및 기존 핸들러들에 useCallback 적용. 이벤트 상수에 CLUB_UNION_BUTTON_CLICKED 추가. |
Club Union Page & Datafrontend/src/pages/ClubUnionPage/ClubUnionPage.tsx, frontend/src/pages/ClubUnionPage/ClubUnionPage.styles.ts, frontend/src/constants/CLUB_UNION_INFO.ts |
ClubUnionPage 컴포넌트와 반응형 스타일 컴포넌트 추가, 멤버 인터페이스 및 정적 멤버 데이터(아바타 매핑 포함) 추가. |
Sequence Diagram(s)
sequenceDiagram
actor User
participant Header as Header (UI)
participant Hook as useHeaderService
participant Router as Router
participant Page as ClubUnionPage
User->>Header: "총동아리연합회 소개" 클릭
Header->>Hook: handleClubUnionClick()
Hook->>Router: navigate('/club-union') + trackEvent(EVENT_NAME.CLUB_UNION_BUTTON_CLICKED)
Router-->>Page: ClubUnionPage 렌더
User->>Page: 프로필 카드 호버
Page-->>User: 오버레이 표시 (CSS 트랜지션)
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~25 minutes
Assessment against linked issues
| Objective | Addressed | Explanation |
|---|---|---|
| 총동아리연합회 페이지 및 구성원 소개 UI 구현 (MOA-164) | ✅ |
Possibly related PRs
- [refactor] Header 컴포넌트 리팩터링 - View와 service 로직 분리 및 선언 순서 개선 #340: Header 리팩터링 및 네비게이션 훅 변경과 직접적 코드 중첩 가능성 있음.
- [feature] 소개페이지 임시 이미지로 대체 및 메뉴바 구현 #366: Header, App.tsx, useHeaderService 관련 변경과 라우팅/네비게이션 관점에서 연관.
- [release] v1.0.2 #388: 네비게이션/라우팅 훅과 경로 추가의 코드적 유사성 존재.
Suggested labels
🔨 Refactor, 🎨 Design
Suggested reviewers
- PororoAndFriends
- seongwon030
- lepitaaar
Tip
🔌 Remote MCP (Model Context Protocol) integration is now available!
Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.
📜 Recent review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
frontend/src/constants/CLUB_UNION_INFO.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/src/constants/CLUB_UNION_INFO.ts
✨ Finishing Touches
- 📝 Generate Docstrings
🧪 Generate unit tests
- Create PR with unit tests
- Post copyable unit tests in a comment
- Commit unit tests in branch
feature/#661-introduce-association-members-MOA-164
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.
🪧 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.Open a follow-up GitHub issue for this discussion.
- Files and specific lines of code (under the "Files changed" tab): Tag
@coderabbitaiin a new review comment at the desired location with your query. - PR comments: Tag
@coderabbitaiin 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 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/Issue comments)
Type @coderabbitai help to get the list of available commands.
Other keywords and placeholders
- Add
@coderabbitai ignoreanywhere in the PR description to prevent this PR from being reviewed. - Add
@coderabbitai summaryto generate the high-level summary at a specific location in the PR description. - Add
@coderabbitaianywhere in the PR title to generate the title automatically.
Status, Documentation and Community
- Visit our Status Page to check the current availability of CodeRabbit.
- 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.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (15)
frontend/src/constants/eventName.ts (1)
17-18: 이벤트 네이밍 컨벤션 정비 제안EVENT_NAME 값들이 한/영 혼재(예: ‘공유하기 버튼 클릭’, ‘Club Union Button Clicked’)입니다. 분석/대시보드 필터링 편의성을 위해 언어/형식을 통일하는 것을 권장합니다. 예: 전부 영어 문장형 또는 전부 한글 문장형.
frontend/src/pages/ClubUnionPage/ClubUnionPage.tsx (3)
19-19: 키보드 접근성 확보: 카드 포커스 가능하도록 tabIndex/라벨 추가호버 기반 오버레이는 마우스 의존적입니다. 키보드 사용자도 동일한 정보를 얻을 수 있도록 카드 컨테이너를 포커스 가능하게 하고 적절한 aria-label을 부여해 주세요.
아래처럼 속성을 추가하면 :focus-within CSS로 오버레이를 노출할 수 있습니다(스타일에서 대응 필요).
- <Styled.ProfileCardContainer key={member.id}> + <Styled.ProfileCardContainer + key={member.id} + tabIndex={0} + aria-label={`${member.role} ${member.name} 프로필 카드`} + >추가 확인: styles에서 ProfileCardContainer에 :focus 또는 :focus-within 상태에 InfoOverlay가 보이도록 되어 있는지 검증 부탁드립니다.
33-35: 연락처를 클릭 가능한 tel 링크로 제공모바일 사용성을 위해 전화번호를 tel 링크로 노출하는 것을 권장합니다. 시각적으로는 동일하고 접근성도 향상됩니다.
- {member.contact && ( - <Styled.Contact>{member.contact}</Styled.Contact> - )} + {member.contact && ( + <Styled.Contact> + <a + href={`tel:${member.contact.replace(/[^0-9]/g, '')}`} + aria-label={`${member.name} 연락처로 전화 걸기`} + > + {member.contact} + </a> + </Styled.Contact> + )}
12-16: SEO 개선: 페이지 타이틀/메타 추가 제안검색/공유 최적화를 위해 페이지 타이틀(meta) 설정을 권장합니다. react-helmet-async를 사용 중이라면 아래와 같이 간단히 적용 가능합니다.
추가 코드 예시(파일 상단 및 JSX 내부에 적용):
// 상단 import import { Helmet } from 'react-helmet-async'; // JSX 내 PageContainer 위쪽 <Helmet> <title>총동아리연합회 소개 | 모아동</title> <meta name="description" content="부경대학교 제16대 총동아리연합회 '온' 구성원 및 소개" /> </Helmet>frontend/src/constants/CLUB_UNION_INFO.ts (1)
31-39: 연락처(전화번호) 공개 범위 확인 필요하드코딩된 연락처가 실제 개인 전화번호인지 확인 부탁드립니다. 실제 번호라면 공개/보관 동의 확보 또는 대체(대표번호/이메일/폼 링크) 권장합니다.
원하시면 개인정보 노출 최소화를 위한 대체 필드/표준 포맷 가이드(예: 대표 연락채널 우선, 개인 연락처는 opt-in) 초안을 드리겠습니다.
frontend/src/components/common/Header/Header.tsx (5)
125-129: navLinks 재생성으로 메모이제이션 이점 상쇄 — useMemo 권장Header가 리렌더될 때마다 navLinks 배열이 새로 생성되어 DesktopHeader/MobileMenuDrawer의 memo 이점이 줄어듭니다. useMemo로 참조 안정성을 확보하세요.
- const navLinks: NavLinkData[] = [ - { label: '모아동 소개', handler: handleIntroduceClick }, - { label: '총동아리연합회 소개', handler: handleClubUnionClick }, - ]; + const navLinks = useMemo<NavLinkData[]>( + () => [ + { label: '모아동 소개', handler: handleIntroduceClick }, + { label: '총동아리연합회 소개', handler: handleClubUnionClick }, + ], + [handleIntroduceClick, handleClubUnionClick], + );파일 상단 import 보강(선택 적용):
// 기존 import { memo } from 'react'; // 변경 import { memo, useMemo } from 'react';
95-107: 모바일 헤더의 검색창: /admin에서는 숨김 처리 일관성 제안데스크톱 헤더는 isAdminPage에서 SearchBox를 숨기지만, 모바일 헤더는 항상 노출됩니다. 관리 페이지에서의 UX 일관성을 위해 prop로 제어하는 것을 권장합니다.
-const MobileHeader = memo(({ onHomeClick, onMenuClick }: MobileHeaderProps) => ( +const MobileHeader = memo(({ onHomeClick, onMenuClick, isAdminPage }: MobileHeaderProps) => ( <Styled.MobileHeaderContainer> <Styled.MobileHeaderWrapper> <Styled.MobileMainIcon onClick={onHomeClick} aria-label='홈으로 이동'> <img src={MobileMainIcon} alt='모아동 로고' /> </Styled.MobileMainIcon> - <SearchBox /> + {!isAdminPage && <SearchBox />} <Styled.MobileMenu onClick={onMenuClick} aria-label='메뉴 열기'> <img src={MenuBarIcon} alt='' /> </Styled.MobileMenu> </Styled.MobileHeaderWrapper> </Styled.MobileHeaderContainer> ));MobileHeaderProps에도 isAdminPage 추가 필요:
interface MobileHeaderProps { onHomeClick: () => void; onMenuClick: () => void; + isAdminPage: boolean; }사용부(라인 133-136) 업데이트:
- <MobileHeader - onHomeClick={() => handleHomeClick('mobile')} - onMenuClick={openMenu} - /> + <MobileHeader + onHomeClick={() => handleHomeClick('mobile')} + onMenuClick={openMenu} + isAdminPage={isAdminPage} + />
69-73: 클릭 가능한 로고의 키보드 접근성 보강img에 onClick만 부여하면 키보드 조작이 어렵습니다. role, tabIndex, onKeyDown을 추가해 접근성을 개선하세요.
<Styled.DrawerMainIcon src={DesktopMainIcon} alt='모아동 로고' - onClick={onHomeClick} + onClick={onHomeClick} + role='button' + tabIndex={0} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') onHomeClick(); + }} />보다 근본적으로는 버튼 요소를 사용하는 것이 이상적입니다만, 현재 스타일 구조를 고려해 최소 변경안을 제안드립니다.
147-151: 관리 페이지에서 모바일 드로어 링크 숨김 제안데스크톱과 동일하게 /admin 경로에서는 네비 링크를 숨기는 편이 일관적입니다.
- navLinks={navLinks} + navLinks={isAdminPage ? [] : navLinks}
130-143: inline 콜백이 memo 이점을 감소 — useCallback으로 바인딩 권장JSX 내 즉석 화살표 함수는 매 렌더마다 새 참조를 만들어 memoized 자식 컴포넌트를 불필요하게 리렌더링할 수 있습니다. device 인자를 바인딩한 핸들러를 useCallback으로 만들어 전달하세요.
적용 예시(컴포넌트 내부, return 위):
import { memo, useMemo, useCallback } from 'react'; const onHomeClickMobile = useCallback(() => handleHomeClick('mobile'), [handleHomeClick]); const onHomeClickDesktop = useCallback(() => handleHomeClick('desktop'), [handleHomeClick]);사용부 변경:
- <MobileHeader - onHomeClick={() => handleHomeClick('mobile')} + <MobileHeader + onHomeClick={onHomeClickMobile} onMenuClick={openMenu} - /> + isAdminPage={isAdminPage} + /> ... - <DesktopHeader + <DesktopHeader isAdminPage={isAdminPage} navLinks={navLinks} - onHomeClick={() => handleHomeClick('desktop')} + onHomeClick={onHomeClickDesktop} />frontend/src/services/header/useHeaderService.ts (1)
27-35: 라우트 경로 하드코딩 제거(상수화) 제안라우트 문자열('/introduce', '/club-union')을 상수로 분리하면 오타 방지와 전역 변경 용이성이 커집니다. 아래처럼 파일 상단에 ROUTES 상수를 두고 사용하도록 리팩터링을 제안합니다.
적용 diff (이 범위 내 대체):
- navigate('/introduce'); + navigate(ROUTES.INTRODUCE); @@ - navigate('/club-union'); + navigate(ROUTES.CLUB_UNION);추가: 파일 상단(라인 6과 7 사이 등 적절한 위치)에 ROUTES 상수 선언
const ROUTES = { HOME: '/', INTRODUCE: '/introduce', CLUB_UNION: '/club-union', } as const;frontend/src/pages/ClubUnionPage/ClubUnionPage.styles.ts (4)
49-67: 오버레이가 숨김 상태에서도 포인터 이벤트를 가로채지 않도록 처리현재 opacity만 0이라 마우스 이벤트를 여전히 캡처할 가능성이 있습니다. 일반적으로 숨김 상태에선 pointer-events: none을 주고, hover/focus 시에만 auto로 바꾸는 패턴을 권장합니다. 오버레이 내 링크/버튼을 도입할 계획이 있다면 특히 중요합니다.
적용 diff(InfoOverlay에 기본값 추가):
export const InfoOverlay = styled.div` @@ opacity: 0; transition: opacity 0.3s ease; border-radius: 50%; box-sizing: border-box; + pointer-events: none; `;적용 diff(컨테이너의 hover/focus-within 시 포인터 이벤트 활성화):
- &:hover, - &:focus-within { + &:hover, + &:focus-within { @@ ${InfoOverlay} { opacity: 1; + pointer-events: auto; }Also applies to: 101-113
49-67: Reduce Motion 환경 지원 권장모션 민감 사용자를 위해 prefers-reduced-motion 설정 시 전환을 비활성화하는 것이 좋습니다.
적용 diff:
export const InfoOverlay = styled.div` @@ transition: opacity 0.3s ease; @@ box-sizing: border-box; + @media (prefers-reduced-motion: reduce) { + transition: none; + } `;
69-76: 이미지 트랜지션에도 Reduce Motion 대응이미지 스케일/필터 변환은 멋지지만 모션 최소화를 원하는 사용자도 고려해 주세요.
적용 diff:
export const ProfileImage = styled.img` @@ transition: transform 0.3s ease, filter 0.3s ease; + @media (prefers-reduced-motion: reduce) { + transition: none; + } `;
4-17: 색상/여백 상수화(디자인 토큰) 고려여기와 본 파일 전반의 색상(#222, #555, #333, #ff5414) 및 여백 값(예: 100px, 40px 등)은 테마/토큰으로 관리하면 유지보수성이 좋아집니다. 프로젝트에 theme 또는 색상 상수가 있다면 그쪽으로 통일하는 것을 추천합니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (7)
frontend/src/App.tsx(3 hunks)frontend/src/components/common/Header/Header.tsx(1 hunks)frontend/src/constants/CLUB_UNION_INFO.ts(1 hunks)frontend/src/constants/eventName.ts(1 hunks)frontend/src/pages/ClubUnionPage/ClubUnionPage.styles.ts(1 hunks)frontend/src/pages/ClubUnionPage/ClubUnionPage.tsx(1 hunks)frontend/src/services/header/useHeaderService.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
frontend/**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx}: Replace magic numbers with named constants for clarity.
Replace complex or nested ternary operators with if/else statements or IIFEs for readability.
Assign complex boolean conditions to named variables.
Use consistent return types for similar functions and hooks.
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle).
Use unique, descriptive names for custom wrappers and functions to avoid ambiguity.
Define constants near related logic or ensure names link them clearly.
Files:
frontend/src/pages/ClubUnionPage/ClubUnionPage.tsxfrontend/src/constants/eventName.tsfrontend/src/constants/CLUB_UNION_INFO.tsfrontend/src/pages/ClubUnionPage/ClubUnionPage.styles.tsfrontend/src/services/header/useHeaderService.tsfrontend/src/components/common/Header/Header.tsxfrontend/src/App.tsx
frontend/**/*.tsx
📄 CodeRabbit Inference Engine (frontend/.cursorrules)
frontend/**/*.tsx: Abstract complex logic/interactions into dedicated components or higher-order 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.
Break down broad state management into smaller, focused hooks or contexts.
Use component composition instead of props drilling.
Files:
frontend/src/pages/ClubUnionPage/ClubUnionPage.tsxfrontend/src/components/common/Header/Header.tsxfrontend/src/App.tsx
🧠 Learnings (2)
📓 Common learnings
Learnt from: seongwon030
PR: Moadong/moadong#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
PR: Moadong/moadong#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/pages/ClubUnionPage/ClubUnionPage.tsxfrontend/src/App.tsx
🧬 Code Graph Analysis (4)
frontend/src/pages/ClubUnionPage/ClubUnionPage.tsx (1)
frontend/src/constants/CLUB_UNION_INFO.ts (1)
CLUB_UNION_MEMBERS(31-122)
frontend/src/pages/ClubUnionPage/ClubUnionPage.styles.ts (1)
frontend/src/styles/mediaQuery.ts (1)
media(6-9)
frontend/src/services/header/useHeaderService.ts (1)
frontend/src/constants/eventName.ts (1)
EVENT_NAME(1-18)
frontend/src/components/common/Header/Header.tsx (1)
frontend/src/components/common/Header/Header.styles.ts (1)
MobileMainIcon(112-124)
🔇 Additional comments (9)
frontend/src/constants/eventName.ts (2)
17-18: 이벤트 상수 추가 LGTM새 이벤트 키(CLUB_UNION_BUTTON_CLICKED)와 리터럴 값 정의 모두 일관적이며 사용에 문제 없습니다.
17-18: Mixpanel 초기화 및 handleClubUnionClick 트래킹 호출 정상 확인
useHeaderService.ts의handleClubUnionClick에서
trackEvent(EVENT_NAME.CLUB_UNION_BUTTON_CLICKED)호출이 정상적으로 이루어지고 있습니다.
(경로: frontend/src/services/header/useHeaderService.ts:33-35)initSDK.ts의initializeMixpanel()함수에서 Mixpanel이 초기화(mixpanel.init)되며,
index.tsx에서 해당 함수가 호출되어 앱 시작 시 전역 초기화가 확인되었습니다.
(경로: frontend/src/utils/initSDK.ts:5-9, frontend/src/index.tsx:11)위 사항 모두 정상 동작함을 확인했으므로 추가 조치 없이 해당 변경을 승인합니다.
frontend/src/App.tsx (2)
22-22: /club-union 라우트 추가 LGTM새 페이지 임포트 및 라우트 등록이 정상이며 404 캐치올 전에 배치되어 동작에 문제 없습니다.
Also applies to: 98-99
80-87: 형식 변경(개행/정렬)에 대한 코멘트 생략의미적 변경이 없어 별도 피드백은 없습니다.
frontend/src/constants/CLUB_UNION_INFO.ts (1)
18-29: 아바타 매핑 구성 깔끔합니다역할별 아이콘 매핑이 명확하고 재사용에도 용이합니다. 임시 자산 사용임을 고려하면 충분히 합리적인 트레이드오프입니다.
frontend/src/components/common/Header/Header.tsx (1)
114-120: handleClubUnionClick 네비게이션 및 이벤트 트래킹 검증 완료스크립트 확인 결과 handleClubUnionClick 내부에서
navigate('/club-union')호출 후trackEvent(EVENT_NAME.CLUB_UNION_BUTTON_CLICKED)를 한 번만 실행
하며, 중복 트래킹이나 기타 사이드이펙트는 발생하지 않음을 확인했습니다. 문제 없습니다.frontend/src/services/header/useHeaderService.ts (3)
17-25: useCallback으로 홈 이동 핸들러 안정화(LGTM)의존성 배열 구성도 정확하고, 홈 이동 시 검색어 초기화 + 이벤트 트래킹 흐름이 명확합니다.
37-39: 모바일 메뉴 버튼 트래킹(LGTM)핸들러 메모이제이션과 이벤트 트래킹만 수행하는 단일 책임이 잘 지켜졌습니다.
32-35: Mixpanel 동작 확인 완료아래 항목을 모두 점검하여 정상 동작이 확인되었습니다:
- useMixpanelTrack 훅이 주요 컴포넌트 및 서비스에서 제대로 임포트·사용되고 있음
- mixpanel.init 호출이
frontend/src/utils/initSDK.ts내에 존재- PR 관련 이벤트 상수(
CLUB_UNION_BUTTON_CLICKED등)가useHeaderService.ts및eventName.ts에서 올바르게 참조/club-union경로가frontend/src/App.tsx에<Route path='/club-union'…>형태로 등록handleHomeClick('desktop' | 'mobile')호출부가Header.tsx에서 각각 올바르게 전달더 이상 추가 조치가 필요 없습니다.
suhyun113
left a comment
There was a problem hiding this comment.
수고하셨습니다!!!
모르는 코드가 많았는데, 덕분에 구조를 보면서 많이 배울 수 있었습니다.
|
이거 어차피 분기마다 바뀔 데이터인것 같은데 서버에서 데이터 내려주는게 낫지안나여 ?? |
빠른개발을 위해 ㅎㅎ |
빠른 개발+ 총동연멤바가 1년마다 바뀌더라고용 |
…ttps://github.com/Moadong/moadong into feature/#661-introduce-association-members-MOA-164
#️⃣연관된 이슈
📝작업 내용
총동아리연합회 소개 페이지 신규 구현
총동아리연합회(/club-union) 소개 페이지를 신규 제작했습니다.
주요 기능 및 UI
프로필 그리드: 총동연담당자 프로필을 반응형 원형 그리드 레이아웃으로 구현했습니다.
인터랙티브 프로필 카드: 프로필에 마우스 호버 또는 키보드 포커스 시 상세 정보(역할, 소개)가 나타나는 인터랙션을 추가했습니다.
코드 구조 및 리팩토링
데이터 상수화: 페이지에 사용되는 모든 데이터(집행부 정보, 공약 등)를 constants 파일로 분리하여 유지보수 용이성을 높였습니다.
Header 컴포넌트 개선: Header에 '총동아리연합회 소개' 메뉴를 추가하고, 데이터 기반(NAV_LINKS 배열)으로 렌더링하도록 리팩토링하여 중복 코드를 제거하고 확장성을 개선했습니다.
이에 맞춰 useHeaderService에 네비게이션 핸들러와 Mixpanel 이벤트 추적 로직을 추가했습니다.
중점적으로 리뷰받고 싶은 부분(선택)
믹스패널 잘 작동하는지 확인 한번 부탁드립니다.
🫡 참고사항
총동연 소개 페이지에 사용된 프로필 이미지는 카테고리 버튼 이미지를 이용해 임시로 사용하였습니다
Summary by CodeRabbit
신규 기능
리팩터링