Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | 변경 사항 |
|---|---|
라우팅 업데이트 frontend/src/App.tsx, frontend/src/pages/AdminPage/components/SideBar/SideBar.tsx |
App.tsx에서 /admin/application-list로 ApplicationListTab을 렌더링하고 /admin/application-list/edit에서 ApplicationEditTab을 중첩 라우트로 추가. SideBar.tsx에서 네비게이션 링크를 /admin/application-edit에서 /admin/application-list로 변경. |
ApplicationListTab 컴포넌트 frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx, frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts |
학기별로 그룹화된 지원서 목록을 렌더링하는 새로운 React 탭 컴포넌트 추가. 드롭다운 메뉴 상태 관리, 문서 레벨 마우스다운 리스너를 통한 메뉴 닫기 기능 포함. 레이아웃, 타이포그래피, 호버 상태, 동적 활성 상태 스타일링을 정의하는 20개 이상의 스타일 컴포넌트 추가. |
ApplicationMenu 컴포넌트 frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx |
기본지원서로 설정, 제목 수정하기, 삭제 세 가지 옵션이 있는 드롭다운 메뉴 컴포넌트 추가. 활성 상태 토글 기능 및 각 항목에 대한 onClick 핸들러 포함. |
Sequence Diagram
sequenceDiagram
actor User
participant UI as ApplicationListTab UI
participant State as Component State
participant Menu as ApplicationMenu
participant Document as Document Listener
User->>UI: 페이지 로드
UI->>State: openMenuId = null로 초기화
UI->>UI: 학기별 지원서 목록 렌더링
User->>UI: More 버튼 클릭 (Row 1)
UI->>State: openMenuId = Row1ID 설정
State->>Document: 문서 mousedown 리스너 추가
State->>Menu: ApplicationMenu 렌더링 (isActive 전달)
rect rgba(200, 220, 255, 0.3)
Note over User,Document: 메뉴 열린 상태
User->>Menu: 메뉴 항목 클릭 또는
User->>Document: 메뉴 외부 클릭
end
Document->>State: mousedown 감지 (메뉴 외부)
State->>State: openMenuId = null 설정
State->>Document: 문서 리스너 제거
State->>UI: 메뉴 닫기
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 minutes
- 라우팅 변경: 간단한 경로 매핑 및 중첩 라우트 추가
- 스타일 컴포넌트: 다수이나 단순한 프리젠테이션 스타일 정의
- 컴포넌트 로직: 상태 관리, 이벤트 리스너, 메뉴 열기/닫기 기능 검토 필요
특별히 검토해야 할 사항:
- ApplicationListTab.tsx의 useEffect 훅과 문서 리스너 정리 로직이 올바르게 구현되었는지 확인
- 메뉴 외부 클릭 시 메뉴 닫기 동작이 정상 작동하는지 확인
- 초기 애플리케이션 데이터가 파일 내 하드코딩되어 있으며, 실제 API 연동은 추후 필요한지 확인
- SideBar.tsx의 네비게이션 링크 변경이 전체 어드민 페이지 네비게이션 흐름에 영향을 주지 않는지 확인
Possibly related issues
- MOA-261 (학기별로 지원서 목록을 보여주는 페이지 추가한다): 이 PR의 변경사항이 해당 이슈의 목표를 직접 구현합니다. ApplicationListTab 컴포넌트 추가를 통해 학기별 지원서 목록 표시 기능을 제공합니다.
Possibly related PRs
- [feature] 관리자페이지 사이드바에 지원서 제작 탭 추가 #489: 어드민 라우팅 및 사이드바 진입점 수정(App.tsx, SideBar.tsx) — 지원서 관리 경로의 중첩 구조 변경과 관련
- [feature] 사이드바 내용을 계층 구조로 변경한다 #711: 어드민 사이드바 구현 수정(SideBar.tsx) — 네비게이션 대상 경로 변경과 관련하여 동시 영향 영역
- [release] FE v1.1.1 #733: 어드민 라우팅 및 사이드바 수정(App.tsx, SideBar.tsx) — 지원서 관리 라우트 변경 및 네비게이션 항목 업데이트
Suggested labels
🎨 Design, ✨ New Feature
Suggested reviewers
- Zepelown
- seongwon030
- oesnuj
Pre-merge checks and finishing touches
✅ Passed checks (4 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title Check | ✅ Passed | PR 제목인 "[feature] 지원서 목록 페이지 생성"은 changeset의 주요 변경사항을 명확하게 요약하고 있습니다. 실제로 ApplicationListTab 컴포넌트가 새로 생성되었으며, 관련 라우팅 및 네비게이션이 업데이트되었으며, 제목은 구체적이고 개발자의 관점에서 가장 중요한 변경사항을 강조하고 있습니다. 제목은 간결하면서도 명확하여 팀원들이 변경 이력을 스캔할 때 주요 변경사항을 쉽게 파악할 수 있습니다. |
| Linked Issues Check | ✅ Passed | PR의 변경사항들이 연관 이슈 MOA-261의 요구사항을 충분히 충족하고 있습니다. 학기별 지원서 목록을 보여주는 페이지가 ApplicationListTab 컴포넌트로 구현되었으며 MOA-261, 사이드바의 '지원서 관리' 버튼이 application-list 경로로 연결되도록 변경되었고 MOA-261, '새 양식 만들기' 버튼이 폼 작성 페이지로 연결되는 기능이 포함되었으며 MOA-261, 더보기 버튼에 대한 dropdown 메뉴가 ApplicationMenu 컴포넌트로 구현되었습니다 MOA-261. 모든 핵심 코딩 요구사항이 이행되었습니다. |
| Out of Scope Changes Check | ✅ Passed | PR에 포함된 모든 변경사항이 MOA-261 이슈의 범위 내에 있습니다. App.tsx의 라우팅 변경은 새로운 지원서 목록 페이지 추가를 위한 것이며, SideBar.tsx의 네비게이션 업데이트는 요구사항 중 '사이드바 연결 변경'에 해당하며, ApplicationListTab 관련 파일들의 추가는 목록 페이지 구현의 핵심이고, ApplicationMenu 컴포넌트는 더보기 버튼 모달 구현입니다. 지정된 이슈 범위를 벗어나는 변경사항이 없습니다. |
✨ 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/#760-add-application-list-page-MOA-261
📜 Recent review details
Configuration used: CodeRabbit 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 selected for processing (5)
frontend/src/App.tsx(2 hunks)frontend/src/pages/AdminPage/components/SideBar/SideBar.tsx(3 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts(1 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx(1 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx
- frontend/src/App.tsx
- frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx
- frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
🧰 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/AdminPage/components/SideBar/SideBar.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/AdminPage/components/SideBar/SideBar.tsx
🔇 Additional comments (1)
frontend/src/pages/AdminPage/components/SideBar/SideBar.tsx (1)
38-38: 경로 변경이 정상적으로 구현되었습니다.라우팅 설정 검증 결과:
App.tsx66-68줄:path='application-list'로ApplicationListTab컴포넌트가 올바르게 연결됨App.tsx70-71줄: 중첩 라우트path='application-list/edit'으로ApplicationEditTab연결- SideBar.tsx 38줄:
/admin/application-list경로가 App.tsx 라우팅과 일치ApplicationListTab.tsx56줄: 새 지원서 생성 시/admin/application-list/edit로 올바르게 네비게이션라우팅 구조가 일관성 있게 구성되어 있으며, 기존
startsWith활성화 로직이 두 경로 모두에서 정상 작동합니다.
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.
Actionable comments posted: 6
🧹 Nitpick comments (14)
frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.styles.ts (2)
60-70: 중복 브레이크포인트 정리 권장Lines 60-64와 66-70에서
font-size: 10px가 중복 정의되어 있습니다. 500px와 375px 브레이크포인트 모두 동일한 폰트 크기를 설정하므로, 하나로 통합하거나 차별점이 있다면 명확히 하는 것이 유지보수에 유리합니다.
47-53:span기본·미디어 브레이크포인트 line-height 비율 통일 필요
- 기본 스타일(font-size:14px)에 line-height:30px(비율 2.14), 768px 이하(font-size:12px)에도 30px(비율 2.5)로 과도하게 설정돼 있습니다.
- 500px·375px 이하에서만
line-height: normal을 적용하는 대신, 모든 브레이크포인트에 unitless(line-height:1.4~1.6) 또는 적정 px 값을 명시해 통일하세요.frontend/src/pages/AdminPage/AdminPage.tsx (1)
8-8: 컴포넌트 간 스타일 결합도 검토 권장부모 컴포넌트(AdminPage)가 자식 컴포넌트(SideBar)의 스타일 파일에서
Divider를 직접 import하고 있습니다. 이는 컴포넌트 간 결합도를 높이며,Divider가 AdminPage 레이아웃의 일부라면AdminPage.styles.ts에 정의하는 것이 더 적절할 수 있습니다.코딩 가이드라인에 따라 컴포넌트 컴포지션을 활용하고 props drilling을 피해야 합니다.
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx (1)
110-110: catch 블록의 에러 매개변수 활용 권장Line 110에서
error매개변수를 받고 있지만 활용하지 않습니다. 에러 로깅, 모니터링, 또는 사용자에게 더 구체적인 에러 메시지 제공을 위해 이 매개변수를 활용하는 것을 권장합니다.- } catch (error) { + } catch (error) { + console.error('Application submission failed:', error); alert(frontend/src/constants/eventName.ts (1)
1-20: 이벤트 이름 네이밍 일관성 개선 권장
EVENT_NAME객체 내에서 이벤트 이름이 영어와 한글로 혼재되어 있습니다:
- Lines 2-8, 11-18: 영어 사용
- Lines 9-10: 한글 사용 ('공유하기 버튼 클릭', 'sns링크 버튼 클릭')
- Line 19: 영어 사용 (새로 추가됨)
이벤트 이름의 언어를 통일하면 유지보수성과 가독성이 향상됩니다. 영어 또는 한글 중 하나로 통일하는 것을 권장합니다.
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx (1)
14-16: 핸들러 구현 필요 여부를 확인하세요.현재 메뉴 아이템 클릭 핸들러는 콘솔 로그만 출력하는 플레이스홀더입니다. 실제 동작(기본 지원서 설정, 제목 수정, 삭제)을 구현할 계획이 있는지 확인하고, 향후 이슈로 추적하거나 이번 PR에서 완성할지 검토하세요.
실제 핸들러 구현이 필요하다면 상태 관리 및 API 연동 코드를 생성해드릴 수 있습니다. 필요하신가요?
frontend/src/pages/AdminPage/AdminPage.styles.ts (1)
9-17: 매직 넘버를 명명된 상수로 추출하는 것을 고려하세요.
top: 98px와height: calc(100vh - 98px)에서98px는 헤더 높이를 가정하는 매직 넘버입니다. 이 값을 별도의 상수로 추출하면 유지보수성이 향상되고, 헤더 높이가 변경될 때 일관성을 유지하기 쉬워집니다.예시:
const HEADER_HEIGHT = '98px'; export const Divider = styled.div` position: sticky; top: ${HEADER_HEIGHT}; height: calc(100vh - ${HEADER_HEIGHT}); /* ... */ `;frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx (1)
9-20: 하드코딩된 데이터를 API 호출로 대체할 계획을 확인하세요.
initialdata는 현재 하드코딩된 더미 데이터입니다. 실제 지원서 목록을 불러오는 API 연동 작업이 계획되어 있는지 확인하고, 향후 이슈로 추적하거나 이번 PR에서 완성할지 검토하세요.API 연동 코드를 생성해드릴 수 있습니다. 필요하신가요?
frontend/src/assets/images/icons/category_button/index.ts (1)
16-34: 카테고리 키의 타입 안전성을 개선하는 것을 고려하세요.현재
Record<string, string>타입은 카테고리 키에 대한 타입 체크를 제공하지 않아, 소비 코드에서 오타가 발생해도 컴파일 타임에 감지되지 않습니다. 유니온 타입이나 enum을 사용하면 타입 안전성을 높일 수 있습니다.예시:
type CategoryKey = 'all' | 'volunteer' | 'religion' | 'hobby' | 'study' | 'sport' | 'performance'; export const inactiveCategoryIcons: Record<CategoryKey, string> = { all: iconAll, volunteer: iconVolunteer, religion: iconReligion, hobby: iconHobby, study: iconStudy, sport: iconSport, performance: iconPerformance, }; export const activeCategoryIcons: Record<CategoryKey, string> = { all: iconAllActive, volunteer: iconVolunteerActive, religion: iconReligionActive, hobby: iconHobbyActive, study: iconStudyActive, sport: iconSportActive, performance: iconPerformanceActive, };frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsx (1)
47-50: 아이콘 조회 시 폴백 처리를 추가하는 것을 고려하세요.
activeCategoryIcons[category.type]과inactiveCategoryIcons[category.type]는category.type이 매핑에 없을 경우undefined를 반환하여 렌더링 오류를 일으킬 수 있습니다. 기본 아이콘을 제공하거나 에러 처리를 추가하면 안정성이 향상됩니다.예시:
const iconSrc = selectedCategory === category.id ? (activeCategoryIcons[category.type] || defaultActiveIcon) : (inactiveCategoryIcons[category.type] || defaultInactiveIcon);frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts (1)
74-84: 매직 넘버를 명명된 상수로 추출하는 것을 고려하세요.
margin-right: 35px(line 77)와margin-right: 25px(line 83)는 매직 넘버입니다. 이러한 값을 상수로 추출하면 향후 디자인 변경 시 일관성을 유지하기 쉬워집니다.예시:
const DATE_HEADER_MARGIN = '35px'; const SEPARATOR_MARGIN = '25px'; export const DateHeader = styled.span` /* ... */ margin-right: ${DATE_HEADER_MARGIN}; `; export const Separation_Bar = styled.img` /* ... */ margin-right: ${SEPARATOR_MARGIN}; `;frontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.styles.ts (2)
8-8: z-index 값을 상수로 관리하는 것을 고려하세요.
z-index: 100은 높은 값입니다. 애플리케이션 전체에서 z-index 값을 일관되게 관리하기 위해 테마나 상수 파일에서 관리하는 것이 좋습니다. 다른 오버레이 컴포넌트(모달, 드롭다운 등)와의 충돌을 방지할 수 있습니다.예시:
// theme/zIndex.ts export const Z_INDEX = { FOOTER: 100, MODAL: 200, DROPDOWN: 150, } as const;그런 다음 스타일에서 사용:
+import { Z_INDEX } from '@/theme/zIndex'; + export const ClubDetailFooterContainer = styled.div` position: sticky; bottom: 0; width: 100%; height: 65px; - z-index: 100; + z-index: ${Z_INDEX.FOOTER}; padding: 10px 40px; ...
9-9: 매우 작은 화면에서의 padding 조정을 고려하세요.
padding: 10px 40px는 작은 모바일 화면(< 400px)에서 컨텐츠 영역을 과도하게 줄일 수 있습니다.미디어 쿼리를 추가하여 작은 화면에서 padding을 줄이는 것을 고려하세요:
export const ClubDetailFooterContainer = styled.div` position: sticky; bottom: 0; width: 100%; height: 65px; z-index: 100; padding: 10px 40px; display: flex; align-items: center; justify-content: space-between; gap: 16px; background-color: white; border-top: 1px solid #cdcdcd; + + @media (max-width: 400px) { + padding: 10px 20px; + } `;frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx (1)
35-46: 외부 링크 오픈에 대한 추적 이벤트 추가를 고려하세요.사용자가 외부 지원 폼을 열 때 추적 이벤트가 발생하지 않습니다. 사용자 행동 분석을 위해 이 액션을 추적하는 것이 좋습니다.
다음 diff를 적용하여 추적 이벤트를 추가하세요:
} catch (err: unknown) { const externalFormLink = clubDetail.externalApplicationUrl?.trim(); if (!externalFormLink) { alert('동아리 모집 정보를 확인해주세요.'); return; } + trackEvent(EVENT_NAME.CLUB_APPLY_BUTTON_CLICKED, { + isExternal: true, + clubName: clubDetail.name + }); window.open(externalFormLink, '_blank', 'noopener,noreferrer'); }참고:
EVENT_NAME에 새로운 이벤트를 추가하거나 기존 이벤트에isExternal플래그를 추가하는 방식 중 선택할 수 있습니다.
📜 Review details
Configuration used: CodeRabbit 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 (25)
frontend/src/assets/images/banners/banner_desktop1.pngis excluded by!**/*.pngfrontend/src/assets/images/banners/banner_desktop2.pngis excluded by!**/*.pngfrontend/src/assets/images/banners/banner_mobile1.pngis excluded by!**/*.pngfrontend/src/assets/images/banners/banner_mobile2.pngis excluded by!**/*.pngfrontend/src/assets/images/icons/Delete_applicant.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/Morebutton.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/Plus.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_all_button_icon.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_all_button_icon_active.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_hobby_button_icon.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_hobby_button_icon_active.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_performance_button_icon.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_performance_button_icon_active.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_religion_button_icon.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_religion_button_icon_active.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_sport_button_icon.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_sport_button_icon_active.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_study_button_icon.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_study_button_icon_active.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_volunteer_button_icon.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/category_button/category_volunteer_button_icon_active.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/check_inactive.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/pencil_icon_3.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/separation_bar.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/share_filled_icon.svgis excluded by!**/*.svg
📒 Files selected for processing (25)
frontend/src/App.tsx(2 hunks)frontend/src/apis/application/getApplication.ts(2 hunks)frontend/src/assets/images/icons/category_button/index.ts(1 hunks)frontend/src/constants/CLUB_UNION_INFO.ts(2 hunks)frontend/src/constants/eventName.ts(1 hunks)frontend/src/pages/AdminPage/AdminPage.styles.ts(1 hunks)frontend/src/pages/AdminPage/AdminPage.tsx(2 hunks)frontend/src/pages/AdminPage/components/SideBar/SideBar.styles.ts(1 hunks)frontend/src/pages/AdminPage/components/SideBar/SideBar.tsx(1 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts(1 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx(1 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx(1 hunks)frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx(3 hunks)frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx(1 hunks)frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.styles.ts(1 hunks)frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx(1 hunks)frontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.styles.ts(1 hunks)frontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.tsx(2 hunks)frontend/src/pages/ClubDetailPage/components/ClubDetailHeader/ClubDetailHeader.tsx(0 hunks)frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.styles.ts(0 hunks)frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx(3 hunks)frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.styles.ts(2 hunks)frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsx(2 hunks)frontend/src/store/useCategoryStore.ts(1 hunks)frontend/src/utils/getDeadLineText.ts(1 hunks)
💤 Files with no reviewable changes (2)
- frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.styles.ts
- frontend/src/pages/ClubDetailPage/components/ClubDetailHeader/ClubDetailHeader.tsx
🧰 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/ApplicationFormPage/ApplicationFormPage.tsxfrontend/src/pages/AdminPage/components/SideBar/SideBar.tsxfrontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.styles.tsfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsxfrontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.styles.tsfrontend/src/assets/images/icons/category_button/index.tsfrontend/src/store/useCategoryStore.tsfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.tsfrontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsxfrontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.tsxfrontend/src/App.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsxfrontend/src/utils/getDeadLineText.tsfrontend/src/constants/eventName.tsfrontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsxfrontend/src/pages/AdminPage/components/SideBar/SideBar.styles.tsfrontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsxfrontend/src/pages/AdminPage/AdminPage.tsxfrontend/src/apis/application/getApplication.tsfrontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.styles.tsfrontend/src/pages/ClubDetailPage/ClubDetailPage.tsxfrontend/src/pages/AdminPage/AdminPage.styles.tsfrontend/src/constants/CLUB_UNION_INFO.ts
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/ApplicationFormPage/ApplicationFormPage.tsxfrontend/src/pages/AdminPage/components/SideBar/SideBar.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsxfrontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsxfrontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.tsxfrontend/src/App.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsxfrontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsxfrontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsxfrontend/src/pages/AdminPage/AdminPage.tsxfrontend/src/pages/ClubDetailPage/ClubDetailPage.tsx
🧠 Learnings (1)
📚 Learning: 2025-09-21T02:23:27.796Z
Learnt from: seongwon030
PR: Moadong/moadong#744
File: frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx:47-48
Timestamp: 2025-09-21T02:23:27.796Z
Learning: ClubApplyButton 컴포넌트에서 ShareButton은 항상 렌더링되어야 하므로 정적 import를 사용하는 것이 적절함. 동적 import는 불필요함.
Applied to files:
frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx
🧬 Code graph analysis (6)
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx (1)
frontend/src/constants/eventName.ts (1)
EVENT_NAME(1-20)
frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsx (2)
frontend/src/store/useCategoryStore.ts (1)
useSelectedCategory(28-32)frontend/src/assets/images/icons/category_button/index.ts (2)
activeCategoryIcons(26-34)inactiveCategoryIcons(16-24)
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx (1)
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts (1)
MoreButton(155-163)
frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx (2)
frontend/src/hooks/queries/club/useGetClubDetail.ts (1)
useGetClubDetail(6-20)frontend/src/constants/eventName.ts (1)
EVENT_NAME(1-20)
frontend/src/pages/AdminPage/AdminPage.styles.ts (1)
frontend/src/pages/AdminPage/components/SideBar/SideBar.styles.ts (1)
Divider(40-46)
frontend/src/constants/CLUB_UNION_INFO.ts (1)
frontend/src/assets/images/icons/category_button/index.ts (1)
inactiveCategoryIcons(16-24)
🔇 Additional comments (14)
frontend/src/store/useCategoryStore.ts (1)
28-31: LGTM!코드 스타일을 일관되게 개선한 변경사항입니다. 기능에는 영향이 없습니다.
frontend/src/pages/AdminPage/components/SideBar/SideBar.tsx (1)
38-38: LGTM!지원서 관리 경로를 새로운 목록 페이지로 변경한 것이 PR의 의도와 일치합니다. 라우팅 구조 변경이 올바르게 반영되었습니다.
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx (1)
92-94: 이벤트 트래킹 시점 검토 필요
trackEvent가 폼 검증 이전(Line 96)에 호출되어, 검증 실패한 제출 시도도 모두 기록됩니다. 이것이 의도한 동작인지 확인이 필요합니다.만약 성공적인 제출만 추적하려면, Line 104 (
await applyToClub성공 후)로 이동을 고려하세요. 반대로 모든 제출 시도(유효성 검증 실패 포함)를 추적하려는 것이라면 현재 위치가 적절합니다.frontend/src/pages/AdminPage/components/SideBar/SideBar.styles.ts (1)
11-13: Header 높이에 맞는 명명된 상수 사용 권장
SideBar의top: 98px이 실제 헤더 높이와 일치하는지 확인하고, 헤더 높이를 나타내는 명명된 상수(예: THEME.HEADER_HEIGHT)로 추출해 재사용해주세요.frontend/src/constants/CLUB_UNION_INFO.ts (1)
1-21: 카테고리 아이콘을 멤버 아바타로 재사용한 의도 확인 요청
MEMBER_AVATARS에inactiveCategoryIcons를 사용해 멤버 역할별 아이콘을 설정하고 있습니다.- 임원진(PRESIDENT, VICE_PRESIDENT, SECRETARY, PROMOTION)은 모두
inactiveCategoryIcons.all을, 분과장(RELIGION, HOBBY, STUDY, VOLUNTEER, PERFORMANCE, SPORT)은 각 분과의 카테고리 아이콘을 사용합니다.- 카테고리 버튼용 아이콘 변경 시 멤버 아바타에도 영향이 있으므로, 멤버 아바타 전용 아이콘 세트 도입 여부를 검토해 주세요.
frontend/src/App.tsx (1)
65-69: 라우팅 구조 변경이 올바르게 적용되었습니다.지원서 목록 페이지(
application-list)를 메인 경로로 설정하고 편집 페이지를 하위 경로(application-list/edit)로 중첩한 구조가 명확하며, PR 목표와 일치합니다.frontend/src/apis/application/getApplication.ts (1)
7-7: 로깅 메시지 한글화가 적절합니다.콘솔 에러 메시지를 한글로 변경하여 UI 텍스트와 일관성을 유지했습니다. 세미콜론 추가는 코드 스타일 개선입니다.
Also applies to: 16-16
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx (1)
37-55: 외부 클릭 감지 로직이 올바르게 구현되었습니다.
useEffect를 사용하여 메뉴가 열려 있을 때만mousedown이벤트 리스너를 등록하고, 메뉴 외부 클릭 시 닫히도록 구현한 로직이 명확하고 안전합니다. 클린업 함수로 리스너를 제거하여 메모리 누수를 방지했습니다.frontend/src/pages/MainPage/components/CategoryButtonList/CategoryButtonList.tsx (1)
25-25:selectedCategory구조 분해가 올바르게 적용되었습니다.이제
useSelectedCategory훅에서selectedCategory값을 가져와 아이콘 조건부 렌더링에 사용하고 있으며, 이는 리팩토링된 타입 기반 아이콘 로직과 일치합니다.frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts (2)
112-138: 활성 상태 스타일링이 명확하게 구현되었습니다.
$activeprop을 사용한 조건부 스타일링과::before가상 요소를 통한 장식용 점 표시가 깔끔하게 구현되어 있습니다. 스타일 로직이 명확하고 유지보수하기 좋습니다.
176-189: 드롭다운 메뉴 포지셔닝이 올바르게 구현되었습니다.
MenuContainer의 절대 포지셔닝과 z-index 설정이 적절하며, 버튼 아래에 메뉴가 표시되도록 구현되어 있습니다. 그림자 효과도 UI 층위를 명확히 표현합니다.frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx (3)
13-16: LGTM! RECRUITMENT_STATUS 상수 추가모집 상태 문자열을 상수로 추출한 것은 좋은 관행입니다. 코드의 유지보수성과 타입 안전성이 향상됩니다.
49-65: renderButtonContent 헬퍼 함수는 잘 구조화되어 있습니다.버튼 컨텐츠 렌더링 로직을 별도 함수로 분리한 것은 좋은 관행입니다. 코드의 가독성과 테스트 가능성이 향상됩니다.
25-25: 반환값 undefined는 React에서 null로 처리됨
JSX 내 컴포넌트의 early return 반환값 undefined는 React가 null로 간주하므로 별도 처리가 필요 없습니다.Likely an incorrect or invalid review comment.
| <ClubDetailFooter | ||
| recruitmentPeriod={clubDetail.recruitmentPeriod} | ||
| recruitmentForm={clubDetail.recruitmentForm} | ||
| presidentPhoneNumber={clubDetail.presidentPhoneNumber} | ||
| /> |
There was a problem hiding this comment.
사용하지 않는 prop을 전달하고 있습니다.
ClubDetailFooter 컴포넌트에 recruitmentForm prop을 전달하고 있지만, 업데이트된 ClubDetailFooter 컴포넌트는 recruitmentPeriod만 destructure하고 recruitmentForm은 사용하지 않습니다.
다음 diff를 적용하여 사용하지 않는 prop을 제거하세요:
<ClubDetailFooter
recruitmentPeriod={clubDetail.recruitmentPeriod}
- recruitmentForm={clubDetail.recruitmentForm}
/>📝 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.
| <ClubDetailFooter | |
| recruitmentPeriod={clubDetail.recruitmentPeriod} | |
| recruitmentForm={clubDetail.recruitmentForm} | |
| presidentPhoneNumber={clubDetail.presidentPhoneNumber} | |
| /> | |
| <ClubDetailFooter | |
| recruitmentPeriod={clubDetail.recruitmentPeriod} | |
| /> |
🤖 Prompt for AI Agents
In frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx around lines 73-76, the
ClubDetailFooter is being passed an unused prop recruitmentForm — remove
recruitmentForm from the JSX so only recruitmentPeriod is passed; also update
any local variables or prop type usages in this file if they were only present
to supply recruitmentForm (remove or simplify them) and run type-checks to
ensure no remaining references to recruitmentForm remain.
frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.styles.ts
Show resolved
Hide resolved
frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx
Show resolved
Hide resolved
| interface ClubDetailFooterProps { | ||
| recruitmentPeriod: string; | ||
| recruitmentForm: string; | ||
| presidentPhoneNumber: string; | ||
| } |
There was a problem hiding this comment.
인터페이스에 사용하지 않는 prop이 정의되어 있습니다.
ClubDetailFooterProps 인터페이스에 recruitmentForm이 정의되어 있지만, 컴포넌트에서 destructure하지 않고 사용하지도 않습니다.
다음 diff를 적용하여 사용하지 않는 prop을 인터페이스에서 제거하세요:
interface ClubDetailFooterProps {
recruitmentPeriod: string;
- recruitmentForm: string;
}📝 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.
| interface ClubDetailFooterProps { | |
| recruitmentPeriod: string; | |
| recruitmentForm: string; | |
| presidentPhoneNumber: string; | |
| } | |
| interface ClubDetailFooterProps { | |
| recruitmentPeriod: string; | |
| } |
🤖 Prompt for AI Agents
In
frontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.tsx
around lines 6 to 9, the ClubDetailFooterProps interface declares an unused prop
recruitmentForm; remove recruitmentForm from the interface so the props only
include recruitmentPeriod, and ensure any related imports or references to
recruitmentForm in this file are removed or updated accordingly.
frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx
Show resolved
Hide resolved
suhyun113
left a comment
There was a problem hiding this comment.
첫 PR 수고하셨습니다!
UI 정말 똑같이 잘 만드신 것 같아요!👍
이제 추가된 디자인 작업과 연동이 남았네요..! 화이팅입니다아
| import * as Styled from './ApplicationListTab.styles'; | ||
| import Plus from '@/assets/images/icons/Plus.svg'; | ||
| import Separation_bar from '@/assets/images/icons/Separation_bar.svg'; | ||
| import MoreButton from '@/assets/images/icons/MoreButton.svg'; |
There was a problem hiding this comment.
svg 파일 이름이 Morebutton.svg인데, import 된 파일 이름은 MoreButton.svg네요.
separation_bar.svg도 import 경로에는 대문자로 되어있어서...
파일 이름으로 통일하는 것이 보기 좋을 것 같아요!
#️⃣연관된 이슈
📝작업 내용
중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
New Features
UI/UX Improvements