[feature] 모집 상태 보기 기능을 제거하고 중앙동아리 태그를 이동한다#759
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. Warning
|
| Cohort / File(s) | Change Summary |
|---|---|
MainPage 스타일 변경frontend/src/pages/MainPage/MainPage.styles.ts |
SectionTabs(styled.nav) 및 Tab(styled.button, $active 상태, 언더라인 인디케이터) 추가. 기존 반응형 규칙을 media 헬퍼로 대체, 간격/폰트 크기/트랜지션 조정. FilterWrapper 익스포트 제거. |
MainPage 컴포넌트 변경frontend/src/pages/MainPage/MainPage.tsx |
StatusRadioButton 의존성 제거 및 관련 상태 제거. tabs = ['중앙동아리']와 로컬 활성 탭 상태 도입하여 SectionTabs/Styled.Tab로 렌더링. 데이터 쿼리는 유지(recruitmentStatus='all'). |
반응형 유틸 추가/수정frontend/src/styles/mediaQuery.ts |
BREAKPOINT에 mini_mobile:375, laptop:1280 추가, tablet을 900→700으로 수정. media 객체에 mini_mobile·laptop 미디어쿼리 추가 및 기존 쿼리 조정. |
Sequence Diagram(s)
sequenceDiagram
participant U as 사용자
participant MP as MainPage.tsx
participant MQ as mediaQuery (스타일)
participant CL as CardList
U->>MP: 페이지 진입
MP->>CL: 데이터 요청 (recruitmentStatus='all')
CL-->>MP: 데이터 반환
MP-->>U: 리스트 렌더링 + 탭 UI 노출
U->>MP: 탭 클릭(중앙동아리)
MP->>MP: active 탭 상태 업데이트
MP->>MQ: 탭 스타일(SectionTabs/Tab) 적용
MP-->>U: 재렌더링 (데이터 쿼리 변경 없음)
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related issues
- [feature] MOA-259 모집 상태 보기 기능을 제거하고 중앙동아리 태그를 이동한다 #756: 모집 상태 UI 제거 및 "중앙동아리" 탭 이동 관련 변경과 목적이 동일함 — 본 PR의 UI/로직 변경과 직접 연관됨.
Possibly related PRs
- [refactor] 모바일 활동사진 UI 그리드 형태로 수정 및 반응형 개선 작업 #554: mediaQuery 유틸리티 표준화 및 하드코딩된 미디어쿼리 교체와 연관됨 —
frontend/src/styles/mediaQuery.ts변경과 코드 레벨로 관련됨.
Suggested reviewers
- Zepelown
- seongwon030
- alsdddk
Pre-merge checks and finishing touches
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Out of Scope Changes Check | 대부분 변경은 이슈 목표와 일치하지만 frontend/src/pages/MainPage/MainPage.styles.ts에서 CardList의 상단 마진 제거 및 transition timing 조정과 같은 레이아웃·스타일 변경은 연결 이슈의 명시적 요구사항에 포함되어 있지 않아 범위를 벗어난 것으로 보입니다. | 해당 스타일 변경은 별도의 디자인 확인 또는 시각 회귀 테스트를 거치거나 가능하면 별도 PR로 분리하여 의도와 영향 범위를 명확히 기록하도록 요청합니다. |
✅ 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] 모집 상태 보기 기능을 제거하고 중앙동아리 태그를 이동한다"은 변경된 주요 내용인 모집 상태 필터 제거와 중앙동아리 탭 이동을 명확히 요약하고 있어 변경사항과 직접 연관되며 간결합니다. |
| Linked Issues Check | ✅ Passed | 제출된 변경사항은 연결된 이슈 MOA-259의 핵심 목표인 '모집 상태 보기 기능 제거'와 '중앙동아리 태그(탭) 이동'을 코드 수준에서 충족합니다; StatusRadioButton 및 관련 로컬 상태(isFilterActive)와 FilterWrapper 제거, recruitmentStatus를 'all'로 유지한 점, 그리고 SectionTabs·Tab 컴포넌트와 tabs 배열에 '중앙동아리' 추가로 탭 UI가 상단으로 이동·클릭 가능하게 구현된 것이 그 증거입니다. |
| Docstring Coverage | ✅ Passed | No functions found in the changes. Docstring coverage check skipped. |
📜 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 (3)
frontend/src/pages/MainPage/MainPage.styles.ts(3 hunks)frontend/src/pages/MainPage/MainPage.tsx(2 hunks)frontend/src/styles/mediaQuery.ts(1 hunks)
Tip
👮 Agentic pre-merge checks are now available in preview!
Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
- Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
- Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.
Please see the documentation for more information.
Example:
reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post.
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: 1
🧹 Nitpick comments (4)
frontend/src/pages/MainPage/MainPage.styles.ts (2)
21-30: 탭 컨테이너에 ARIA 속성 부여로 접근성 강화탭 패턴을 명시적으로 표현하면 스크린 리더 탐색성이 좋아집니다.
attrs로role/aria-label을 고정하세요. 또한 간격/마진 값은 테마 토큰으로 점진적 이관을 고려해 주세요.-export const SectionTabs = styled.nav` +export const SectionTabs = styled.nav.attrs({ + role: 'tablist', + 'aria-label': '동아리 구분', +})` display: flex; gap: 18px; margin: 60px 8px 24px; @media (max-width: 500px) { gap: 16px; margin: 32px 4px 16px; } `;
32-59: Tab 버튼에 type/role/aria-selected 부여 + 세미콜론 누락
- 기본
type이submit인 상황을 예방하기 위해type="button"을 지정하세요.- 탭 역할/선택 상태를 ARIA로 노출하면 접근성이 좋아집니다.
- Line 57의 세미콜론이 빠져 있습니다.
- 색상/굵기/두께 등 매직 넘버는 테마 토큰으로 추출 권장.
-export const Tab = styled.button<{$active?: boolean}>` +export const Tab = styled.button.attrs<{$active?: boolean}>(props => ({ + type: 'button', + role: 'tab', + 'aria-selected': !!props.$active, +}))<{$active?: boolean}>` display: flex; position: relative; font-size: 24px; font-weight: bold; color: ${({$active}) => $active ? '#787878' : '#DCDCDC'}; border: none; background: none; cursor: pointer; &::after { content: ''; position: absolute; left: 0; bottom: -4px; width: 100%; height: 1.5px; background: #787878; border-radius: 1.5px; transform: ${({$active}) => $active ? 'scaleX(1)' : 'scaleX(0)'}; transform-origin: center; transition: transform 0.2s ease; } @media (max-width: 500px) { - font-size: 14px + font-size: 14px; } + + &:focus-visible { + outline: 2px solid currentColor; + outline-offset: 2px; + } `;frontend/src/pages/MainPage/MainPage.tsx (2)
27-29: 단일 탭 구현은 OK. 확장 대비 타입/상수 구조만 정리 권장현재 1개 탭이라 단순 상태만으로 충분합니다. 향후 확장 시를 대비해 탭 키를 유니온 타입/상수로 분리해 재사용 가능하게 해두면 좋습니다.
56-63: 키보드 화살표 내비게이션 추가 제안 (접근성 탭 패턴)좌/우 화살표로 탭 이동을 지원하면 키보드 접근성이 향상됩니다. 아래처럼 간단히 처리 가능합니다.
- {tabs - .map((tab) =>( - <Styled.Tab key={tab} $active={active===tab} onClick={() => setActive(tab)}> + {tabs.map((tab) => ( + <Styled.Tab + key={tab} + $active={active===tab} + onClick={() => setActive(tab)} + onKeyDown={(e) => { + if (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') return; + const i = tabs.indexOf(tab); + const next = e.key === 'ArrowRight' ? (i + 1) % tabs.length : (i - 1 + tabs.length) % tabs.length; + setActive(tabs[next]); + }} + > {tab} - </Styled.Tab> - ))} + </Styled.Tab> + ))}
📜 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 (2)
frontend/src/pages/MainPage/MainPage.styles.ts(2 hunks)frontend/src/pages/MainPage/MainPage.tsx(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/MainPage/MainPage.tsxfrontend/src/pages/MainPage/MainPage.styles.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/MainPage/MainPage.tsx
| const { keyword } = useSearchKeyword(); | ||
| const { isSearching } = useSearchIsSearching(); | ||
| const recruitmentStatus = isFilterActive ? 'OPEN' : 'all'; | ||
| const recruitmentStatus = 'all'; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
🧩 Analysis chain
recruitmentStatus 상수화에 따른 훅 시그니처/쿼리키 영향 점검
UI에서 모집 상태 필터를 제거했으므로 훅 인자 유지가 불필요할 수 있습니다. useGetCardList의 쿼리 키/파라미터에서 recruitmentStatus를 완전히 제거 가능 여부를 확인해주세요(중복 캐시 방지 차원).
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "잔존 컴포넌트/스타일 사용 여부 확인 (StatusRadioButton/FilterWrapper)"
rg -n -C2 --type=ts --type=tsx "\bStatusRadioButton\b|FilterWrapper\b" frontend || true
echo "recruitmentStatus 사용처 확인"
rg -n -C2 --type=ts --type=tsx "\brecruitmentStatus\b" frontend || true
echo "useGetCardList 정의/파라미터 확인"
rg -n -C3 --type=ts --type=tsx "(export\s+(const|function)\s+useGetCardList\b|function\s+useGetCardList\s*\()" frontend || trueLength of output: 189
rg의 --type=tsx 옵션 때문에 검색이 실패했습니다. 아래 스크립트로 타입 필터 없이 재검색해 주세요:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "잔존 컴포넌트/스타일 사용 여부 확인 (StatusRadioButton / FilterWrapper)"
rg -n -C2 "\bStatusRadioButton\b|\bFilterWrapper\b" frontend || true
echo "recruitmentStatus 사용처 확인"
rg -n -C2 "\brecruitmentStatus\b" frontend || true
echo "useGetCardList 정의/파라미터(함수/const export) 및 호출 확인"
rg -n -C3 "export\s+(const|function)\s+useGetCardList\b|function\s+useGetCardList\s*\(|\buseGetCardList\s*\(" frontend || trueLength of output: 8889
recruitmentStatus 제거 및 useGetCardList 시그니처·쿼리키 정리 필요
검증: useGetCardList 정의는 frontend/src/hooks/queries/club/useGetCardList.ts이고 호출지는 frontend/src/pages/MainPage/MainPage.tsx(현재 recruitmentStatus = 'all' 상수 전달) 한 곳뿐입니다. 조치(요약):
- useGetCardList에서 recruitmentStatus 파라미터 제거 및 queryKey에서 삭제(또는 훅 내부에서 고정값 'all' 사용). 파일: frontend/src/hooks/queries/club/useGetCardList.ts.
- 훅 내부의 파라미터 명/순서(category ↔ division)가 혼동을 유발하므로 queryKey와 getClubList 호출 인자 순서를 명확히 일치시키고 시그니처를 정리할 것.
- 호출부(MainPage.tsx)를 훅 시그니처에 맞춰 수정(인자 재정렬/제거). 파일: frontend/src/pages/MainPage/MainPage.tsx.
- 참고: getClubList(frontend/src/apis/getClubList.ts)는 recruitmentStatus를 URL 파라미터로 사용하므로, 훅에서 제거할 경우 getClubList에 기본값('all')이 전달되도록 호출하도록 변경할 것.
| <Styled.SectionTabs> | ||
| {tabs | ||
| .map((tab) =>( | ||
| <Styled.Tab key={tab} $active={active===tab} onClick={() => setActive(tab)}> | ||
| {tab} | ||
| </Styled.Tab> | ||
| ))} | ||
| </Styled.SectionTabs> |
| const division = 'all'; | ||
| const searchCategory = isSearching ? 'all' : selectedCategory; | ||
|
|
||
| const tabs = ['중앙동아리'] as const; |
There was a problem hiding this comment.
as const를 사용하지 않아도 큰 문제는 없지만, "중앙동아리"처럼 탭은 값이 정해져 있는 집합이기 때문에 읽기 전용으로 두는게 좋을 것 같다고 생각했습니다ㅏ
const tabs = ['중앙동아리', '가동아리', '과동아리'] as const;
const [active, setActive] = useState<typeof tabs[number]>('중앙동아리');위의 코드처럼 tabs의 값들로부터 타입을 바로 추론해 active를 관리하면, 항상 tabs 안의 값만 선택할 수 있게 됩니당
이렇게 해주면 "중동아리"처럼 오타나 잘못된 값이 들어가도 컴파일 단계에서 바로 막아줄 수 있고, tabs의 배열이 타입을 바로 추론해주기 때문에 별도의 타입 선언도 필요없습니다
간결하게 작성할 수도 있고, 타입 안정성을 확보할 수 있어서 as const를 사용했어요~
There was a problem hiding this comment.
tab에 들어갈 동아리 타입을 types/club.ts에서 관리하는 방식도 좋아 보입니다!
조금 멀리 보면 API 응답에서 division 값으로 중동/과동 등이 분류될 것 같아서
아래처럼 관리하면 기존 API 타입을 확장하면서, 앞으로 필터링이나 카테고리 기반 기능을 추가할 때도 유용할 것 같아요.
// 예시
// types/club.ts
export type DivisionKey = '중동' | '가동' | '과동';
export interface Club {
id: string;
name: string;
logo: string;
tags: string[];
recruitmentStatus: string;
division: DivisionKey; // ← 문자열 대신 타입으로 관리
category: string;
introduction: string;
}
export const DivisionLabel: Record<DivisionKey, string> = {
중동: '중앙동아리',
가동: '가동아리',
과동: '과동아리',
};
// 사용할 때
const tabs: DivisionKey[] = ['중동', '과동'];다만 현재 API가 "중동"처럼 태그 형태로 내려주다 보니 매핑 로직이 꼭 필요하겠네요.
수현님이 사용하신 as const 방식도 타입 안정성을 챙기려는 의도가 잘 드러나서 좋았습니다~ 🙂
There was a problem hiding this comment.
오 좋은 조언 감사합니다ㅏ
그런데 당장은 중동을 제외하고는 어떻게 될지 몰라서 지금 타입을 정의하는 것보다는 나중에 확정되었을 때, 추가하면 좋을 것 같아요!
추후 확장성을 고려해서 준서님께서 제시해주신 부분을 참고할 수 있도록 //TODO 주석으로 남겨뒀습니다ㅏ 감사합니당
| export const SectionTabs = styled.nav` | ||
| display: flex; |
There was a problem hiding this comment.
nav semantic 태그 사용해주신거 좋네요~
접근성까지 잘 챙기신 것 같아요 👏
| @media (max-width: 500px) { | ||
| font-size: 14px |
There was a problem hiding this comment.
반응형 처리 잘 해주셨네요
다만 @media (max-width: 500px)는 직접 쓰기보다 frontend/src/styles/mediaQuery.ts의 media 유틸을 사용해주세요!
| @media (max-width: 500px) { | |
| font-size: 14px | |
| import { media } from '@/styles/mediaQuery'; | |
| ${media.mobile} { | |
| font-size: 14px; | |
| } | |
| `; |
현재 파일의 다른 부분에도 동일한 코드가 남아있으니 함께 수정 부탁드립니다
추후 다른 작업 시에도 동일한 @media (max-width: 500px)패턴이 보이면 변경 해주세요~
| margin: 32px 4px 16px; | ||
| } |
#️⃣연관된 이슈
📝작업 내용
중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
New Features
Refactor
Style