Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | Summary |
|---|---|
ApplicantsListTab 스타일 제거 frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.styles.ts |
전체 스타일 모듈 삭제: Container, Title, Header, AddButton, ApplicationRow, MenuContainer 등 21개 styled-component 정의 제거 |
ApplicantsListTab 컴포넌트 리팩토링 frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx |
중앙 집중식 스타일 경로로 import 업데이트; ApplicationRowItem 기반 렌더링으로 전환; isExpanded 상태 추가; ActiveList UI 섹션 도입; useDeleteApplication 및 updateApplicationStatus 훅 통합; 그룹별 고유 메뉴 키 생성 |
ApplicationListTab 스타일 확장 frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts |
MenuItemProps, ExpandButtonProps 인터페이스 추가; ActiveListContainer, ActiveListTitle, ExpandButton, ExpandArrow, MessageContainer, NoActiveFormsMessage 컴포넌트 추가; Header 하단 margin 16px → 24px, AddButton 폰트 조정, ApplicationList 너비 857px → auto, MenuContainer 위치 조정; 레거시 row/title/date 레이아웃 컴포넌트 제거 |
ApplicationListTab 컴포넌트 리팩토링 frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx |
ApplicationRowItem 기반 렌더링으로 전환; handleToggleClick으로 상태 전환 로직 추가; isExpanded, MAX_INITIAL_ITEMS 상태 도입; ActiveList UI 블록(ActiveListBody, ActiveApplicationRow) 렌더링; 그룹별 고유 키 접두사 구성; onEdit, onMenuToggle, onToggleStatus, onDelete 핸들러 통합 |
ApplicationMenu 컴포넌트 업데이트 frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx |
ApplicationMenuProps에 onDelete (필수), onToggleStatus (선택) 추가; 메뉴 항목에서 onToggleStatus 직접 호출; 활성 상태에 따라 동적 토글 버튼 텍스트('지원서 활성화' / '지원서 비활성화') 렌더링 |
Delete API 활성화 frontend/src/apis/application/deleteApplication.ts |
주석 처리된 구현 활성화; DELETE 요청을 /club/application/{id} 엔드포인트에 수행; 기본 export 추가 |
Delete Hook 활성화 frontend/src/hooks/queries/application/useDeleteApplication.ts |
useDeleteApplication 훅 주석 해제 및 활성화; useMutation으로 deleteApplication 호출; 성공 시 ['applicationForm'] 쿼리 무효화; 에러 로깅 |
ApplicationRowItem 컴포넌트 추가 frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsx frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.style.ts |
새 컴포넌트 및 스타일 모듈 추가; ApplicationRow, ApplicationTitle($active), ApplicationDatetable, ApplicationDate, MoreButton, MoreButtonIcon, MoreButtonContainer 스타일 정의; 지원서별 unique 메뉴 키 생성; ApplicationMenu 통합; onEdit, onMenuToggle, onToggleStatus, onDelete 콜백 처리 |
추정 코드 리뷰 노력
🎯 4 (복잡함) | ⏱️ ~45분
- 주의 필요 영역:
- ApplicationRowItem 통합: 새로운 컴포넌트가 여러 핸들러를 연결하고 고유 메뉴 키 생성 로직 포함 — 메뉴 상태 관리 및 콜백 전달 검증 필요
- 상태 전환 로직: updateApplicationStatus 호출, 쿼리 무효화, 에러 핸들링이 ApplicantsListTab과 ApplicationListTab에서 유사하게 구현됨 — 일관성 확인 필요
- ActiveList 렌더링 로직: isExpanded 상태, MAX_INITIAL_ITEMS 계산, 빈 상태 메시지 — UI 동작 및 경계값 테스트 필요
- 스타일 마이그레이션: ApplicantsListTab.styles.ts 삭제 후 ApplicationListTab.styles.ts에서 스타일 제공 — 모든 의존성 마이그레이션 확인 필요
- API 활성화: deleteApplication, useDeleteApplication 주석 해제 — 에러 처리 및 응답 파싱 검증 필요
Possibly related issues
- [feature] MOA-366 대표 지원서 보기 추가 #867: 활성/대표 지원서 UI 구현 — 본 PR에서 ActiveList 컴포넌트, ApplicationRowItem, 상태 전환, 관련 스타일이 해당 이슈에 정확히 대응
Possibly related PRs
- [Release] v1.0.9 #627: ApplicantsTab, ApplicantDetailPage, 지원자 API/컨텍스트/라우트 수정 — 같은 지원자 관리 영역의 컴포넌트/스타일 변경
- [feature] 다중 지원서 API 연결 #783: ApplicantsListTab.styles.ts 추가 — 본 PR이 동일 파일 삭제와 직접 관련
- [feature] 지원서 활성화 버튼 기능 구현 #866: Admin 지원서 목록 UI 및 상태 전환/활성화 플로우 구현 — ApplicationMenu props, updateApplicationStatus 사용, 지원서 목록 컴포넌트 공통 수정
Suggested reviewers
- seongwon030
- lepitaaar
- oesnuj
- Zepelown
Pre-merge checks and finishing touches
✅ Passed checks (5 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 | PR은 MOA-366의 주요 요구사항인 '대표 지원서를 모아보는 디자인 구현'을 충실히 구현했습니다. ActiveList 컴포넌트 추가, 게시된 지원서 섹션 구현, 4개 이상 시 펼쳐보기 기능 추가, 미존재 시 메시지 표시 등 모든 요구사항이 충족되었습니다. |
| Out of Scope Changes check | ✅ Passed | PR의 모든 변경사항은 대표 지원서 모아보기 기능 구현과 직접적으로 관련되어 있습니다. 삭제된 ApplicantsListTab.styles 파일, ApplicationRowItem 컴포넌트 분리, 상태 토글 기능 추가 등은 모두 이 기능을 지원하는 리팩토링입니다. |
| 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/#867-add-active-application-section-MOA-366
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: 4
♻️ Duplicate comments (1)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (1)
18-19: 상태 토글 + 쿼리 무효화 흐름은 깔끔하게 연결되어 있습니다
handleToggleClick에서
updateApplicationStatus호출- 성공 시
queryClient.invalidateQueries({ queryKey: ['applicationForm'] });로 리스트 재조회- 메뉴 닫기(
setOpenMenuId(null)) 및 실패 시console.error+alert까지 한 흐름으로 잘 정리되어 있어, 비동기 상태 토글 UX 측면에서 큰 문제는 없어 보입니다.
추가로, API 레벨의 토글 로직/타입 정리는
updateApplicationStatus파일 코멘트에서 제안드린 정도만 반영되면 충분해 보입니다.Also applies to: 47-59, 101-102
🧹 Nitpick comments (9)
frontend/src/types/application.ts (1)
49-56: status 대문자 변경에 맞춰 타입/필드 정합성 점검이 필요해 보입니다
ApplicationFormItem.status는'ACTIVE' | 'PUBLISHED' | 'UNPUBLISHED'로 잘 정규화되었는데,ApplicationFormData.active는 여전히'active' | 'published' | 'unpublished'로 남아 있습니다.
- 서버에서 내려오는 필드가
status(대문자) /active(소문자 문자열) /active(boolean) 중 어떤 의미로 쓰이는지 한 번 더 정리해 두는 게 좋겠습니다.- 가능하다면 동일 개념은 한 필드명/케이스로 통일(
status+ 대문자 리터럴 oractive+ boolean)하고, 타입도ApplicationFormItem['status']식으로 재사용하면 실수를 줄일 수 있습니다.이 부분은 다른 API/컴포넌트와의 인터페이스까지 영향을 주는 지점이라, 전체적으로 사용하는 곳에서
'active'비교가 남아 있지 않은지도 한 번 더 확인 부탁드립니다.Also applies to: 68-73
frontend/src/apis/application/updateApplication.ts (1)
33-58:updateApplicationStatus의 타입 및 토글 로직을 좀 더 명시적으로 만드는 것이 좋겠습니다현재 구현은 기능적으로 동작은 하겠지만, 의도가 살짝 불분명하게 보입니다.
currentStatus: string보다는currentStatus: ApplicationFormItem['status']처럼 구체 타입(또는 union 타입)을 쓰면 오타/잘못된 값 전달을 컴파일 타임에 막을 수 있습니다.const newStatus = currentStatus === 'ACTIVE' ? false : true;는 결국currentStatus !== 'ACTIVE'와 같아서,
'ACTIVE'→active: false,'PUBLISHED' | 'UNPUBLISHED'→active: true
로 동작합니다. “한 번에 하나만 대표지원서(활성)로 둔다” 같은 도메인 룰이라면 의도에 맞는지 백엔드와 함께 정의를 맞춰 두는 게 좋겠습니다.- 변수명이
newStatus이지만 실제로는 booleanactive를 의미하므로,newActive같이 더 직관적인 이름으로 바꾸면 코드 읽기가 훨씬 수월합니다.이 함수는 여러 곳에서 재사용될 가능성이 높아서, 지금 시점에 타입/이름을 조금만 더 정리해 두면 이후 유지보수 비용을 줄일 수 있을 것 같습니다.
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts (1)
103-112:ApplicationList카드 간 간격 스타일에서 불필요한 세미콜론 제거 제안
ApplicationList에서 아래 부분이 있습니다.&:not(:last-child) { margin-bottom: 20px; };마지막
};중;는 불필요한 토큰이라 브라우저가 무시하긴 하지만, 스타일 문자열을 읽기 어렵게 만들고 오타처럼 보입니다.아래처럼 정리해 두면 더 깔끔할 것 같습니다.
- &:not(:last-child) { - margin-bottom: 20px; - }; + &:not(:last-child) { + margin-bottom: 20px; + }frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (1)
124-139: 대표지원서 모아보기 리스트 파생 로직과 styled 정의 위치를 조금 정리하면 좋겠습니다
activeForms→formsToDisplay파생 로직은 직관적입니다만,
showExpandButton = activeForms.length >= MAX_INITIAL_ITEMS;조건 때문에
딱 3개일 때도 “펼쳐보기/접기” 버튼이 보이지만 실제로는 표시 개수가 변하지 않습니다.
UX 측면에선>비교가 더 자연스러워 보입니다.- const showExpandButton = activeForms.length >= MAX_INITIAL_ITEMS; + const showExpandButton = activeForms.length > MAX_INITIAL_ITEMS;
ActiveListBody,ActiveApplicationRow를 컴포넌트 내부에서styled(...)로 매 렌더마다 생성하고 있는데,
styled-components 관점에서는 컴포넌트 바깥(파일 상단 or.styles.ts)에서 정의하는 패턴이 더 일반적이고 성능/디버깅에도 유리합니다.가능하다면 두 styled 컴포넌트를
ApplicantsListTab.styles.ts로 옮기거나, 최소한 함수 바깥으로 분리해 두는 것을 추천드립니다.frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx (4)
47-59: 상태 토글 파라미터 의미를 더 명확하게 만들면 타입 안전성이 올라갈 것 같습니다.현재
handleToggleClick에서currentStatus를 문자열로 받아 그대로updateApplicationStatus에 넘기고, API 쪽에서'ACTIVE'여부만으로 boolean을 뒤집는 구조라 상태 값이 늘어났을 때 의미가 모호해질 수 있습니다.
ApplicationFormItem['status']타입을 그대로 사용하거나, 아예isActive: boolean으로 추상화해서 API 레벨에서active토글만 책임지도록 바꾸는 방향을 고려해 보셔도 좋겠습니다.Also applies to: 174-176, 234-235
68-72: 메뉴 key 분리 방식은 좋지만, 상태 갱신 시 콜백 패턴 사용을 추천합니다.
contextPrefix를 받아activelist-,group_...형태로uniqueKey를 만드는 방식은 대표 리스트/학기별 리스트 간 메뉴 ID 충돌을 잘 방지해 줍니다. 다만setOpenMenuId(openMenuId === uniqueKey ? null : uniqueKey)는 기존 state에 의존하는 패턴이라, 향후 동시 이벤트 처리에서 안전하게 가려면 아래처럼 콜백 형태로 쓰는 게 더 좋습니다.setOpenMenuId(prev => (prev === uniqueKey ? null : uniqueKey));Also applies to: 223-227
124-128: 대표지원서 모아보기 UX 세부 동작 및 코드 정리에 대한 제안입니다.
showExpandButton = activeForms.length >= MAX_INITIAL_ITEMS;라서 정확히 3개일 때도 펼치기 버튼이 노출되는데, UX상 “3개 이하일 땐 버튼 숨김”이 자연스러우면>로 바꾸는 편이 낫습니다.- 대표 리스트 map 내부에서
const isActive = true;로 고정하기보다는, 아래처럼 실제 상태에 기반해 두는 편이 향후 상태 체계 변경 시 더 안전합니다.const isActive = application.status === 'ACTIVE';기능적으로는 현재 구현으로도 문제는 없지만, 유지보수 관점에서 위 정리가 도움이 될 것 같습니다.
Also applies to: 141-191
129-139: 컴포넌트 내부에서 styled-components 정의는 밖으로 빼는 것이 좋습니다.
ActiveListBody,ActiveApplicationRow를 함수 컴포넌트 내부에서 정의하면 렌더마다 새로운 styled 컴포넌트가 생성되어, 불필요한 스타일 인젝션과 React 최적화 포인트 손실(메모이제이션 등)로 이어질 수 있습니다.
가능하면ApplicationListTab.styles.ts혹은 파일 상단(컴포넌트 바깥)으로 옮겨서 정의하고, 여기서는 그대로 import해서 사용하는 구조를 추천드립니다.frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.styles.ts (1)
46-68: ExpandButton 주석과 구현이 어긋나 있어, isExpanded에 따른 아이콘 회전이 동작하지 않습니다.현재
&::after { content: 'v'; }만 있고isExpanded같은 props를 받지 않아서, 주석에 적힌 “회전 로직은 ApplicationListTab.tsx에서 isExpanded 상태에 따라 스타일을 넘겨야 함”이 구현되어 있지 않습니다.
텍스트(‘접기’/‘펼쳐보기’)만으로도 상태 전달은 되지만, 디자인 요구사항이 아이콘 회전까지 포함한다면$expanded같은 boolean prop을 추가해서 아래처럼 처리하는 걸 고려해 보셔도 좋겠습니다.export const ExpandButton = styled.div<{ $expanded: boolean }>` /* ...기존 스타일... */ &::after { content: '⌄'; font-size: 18px; margin-left: 4px; transform: ${({ $expanded }) => ($expanded ? 'rotate(180deg)' : 'none')}; transition: transform 0.2s ease; } }그리고
ApplicationListTab.tsx쪽에서<Styled.ExpandButton $expanded={isExpanded} />로 넘기면 됩니다.
📜 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 (7)
frontend/src/apis/application/updateApplication.ts(2 hunks)frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.styles.ts(5 hunks)frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx(7 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts(5 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx(6 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx(1 hunks)frontend/src/types/application.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx (3)
frontend/src/hooks/queries/application/useGetApplicationlist.ts (1)
useGetApplicationlist(4-10)frontend/src/apis/application/updateApplication.ts (1)
updateApplicationStatus(33-58)frontend/src/types/application.ts (1)
ApplicationFormItem(68-73)
frontend/src/apis/application/updateApplication.ts (1)
frontend/src/apis/auth/secureFetch.ts (1)
secureFetch(3-41)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (3)
frontend/src/hooks/queries/application/useGetApplicationlist.ts (1)
useGetApplicationlist(4-10)frontend/src/apis/application/updateApplication.ts (1)
updateApplicationStatus(33-58)frontend/src/types/application.ts (2)
SemesterGroup(75-79)ApplicationFormItem(68-73)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.styles.ts (1)
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts (6)
Title(12-16)ActiveLIstContainer(18-24)ActiveListTitleBox(26-35)ActiveListTitle(37-44)ExpandButton(46-68)Header(71-75)
🔇 Additional comments (6)
frontend/src/apis/application/updateApplication.ts (1)
5-19:updateApplication의 PATCH 변경 및 export 형태 영향 범위 확인 필요
updateApplication가PUT→PATCH로 바뀌고, 현재는 named export만 존재합니다.
- 백엔드가 동일 엔드포인트에서
PATCH를 허용하도록 이미 맞춰져 있는지 한 번 더 확인해 주세요.- 예전 코드에서
default export로updateApplication을 import 하던 곳이 있었다면 지금 PR 기준으로는 컴파일 타임에 바로 깨지므로, 전부import { updateApplication }형태로 정리되었는지도 함께 점검하는 게 안전합니다.빌드가 이미 통과했다면 대부분은 정리된 상태일 가능성이 높지만, 중요 API라서 한 번 더 확인해 두는 걸 추천드립니다.
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts (1)
251-258: MenuItem 타이포그래피/클래스 조정은 의도에 맞고 일관성 있어 보입니다
MenuItem에서
- 기본
font-weight: 400,font-size: 14px,color: #4b4b4b.default클래스에font-weight: 500로 정리한 부분은 메뉴 내 우선순위(대표지원서 토글)를 살리면서도 전체적으로 가독성이 좋게 정리된 것 같습니다.
높이
28px에 패딩8px 12px조합도 클릭 타깃으로 크게 문제 없어 보여서 그대로 유지하셔도 될 것 같습니다.Also applies to: 269-271
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (1)
68-72: 메뉴 오픈 상태를 contextPrefix + id로 분리한 방식은 잘 설계되었습니다
handleMoreButtonClick에서contextPrefix(activelist,group_...)와id를 조합해 유니크 키를 만들고,
- Active 리스트:
activelist-{id}- 학기별 리스트:
group_{year}_{term}-{id}형태로
openMenuId를 관리하는 구조는:
- 동일한 지원서가 위/아래 두 섹션에 동시에 보이는 상황에서도
어느 섹션의 메뉴가 열려 있는지 명확히 구분할 수 있고,- 하나의
menuRef를 재사용하면서도 outside click 핸들링을 단일화할 수 있어구조적으로 잘 짜여 있다고 느껴집니다. 추가적인 수정 없이 이 방향 그대로 유지하셔도 될 것 같습니다.
Also applies to: 164-178, 223-227, 230-235
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx (2)
12-23: React Query 연동 및 대표 지원서 상태/확장 상태 관리 흐름 괜찮습니다.
updateApplicationStatus+useQueryClient로 상태 토글 후invalidateQueries(['applicationForm'])하는 구조, 그리고isExpanded/MAX_INITIAL_ITEMS로 대표 지원서 섹션의 펼침 상태를 관리하는 방식이 명확하고 기존 데이터 흐름과도 잘 어울립니다.
200-201: 학기별 리스트에서의 groupUniqueKeyPrefix 사용 방식도 잘 정리되어 있습니다.
groupUniqueKeyPrefix로 학기별 섹션을 구분하고,currentMenuKey에 prefix를 섞어openMenuId와 비교하는 패턴 덕분에 동일한application.id가 대표 리스트와 학기별 리스트 양쪽에 존재해도 메뉴 open 상태가 섞이지 않는 점이 좋습니다.onToggleStatus도handleToggleClick으로 일관되게 연결돼 있어 유지보수하기 수월해 보입니다.Also applies to: 211-212, 223-227, 230-235
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.styles.ts (1)
104-112: 리스트 카드/행 및 메뉴 스타일 변경은 전반적으로 일관되고 무난해 보입니다.
ApplicationList의 width를 auto로 두고, border-radius를 20px로 키운 것, 그리고&:not(:last-child)에 margin-bottom을 준 것은 여러 카드가 쌓일 때 간격과 모서리 표현을 자연스럽게 만들어 줍니다.ApplicationRowhover 시 배경색과 하단 모서리 radius를 20px로 맞춘 것도 카드 radius와 일관성이 좋아 보입니다.MenuItem의 폰트 weight/size, 색,.default클래스 추가로 기본 액션과 보조 액션을 구분하는 것도 명확합니다.이 부분은 그대로 가져가셔도 괜찮아 보입니다.
Also applies to: 157-161, 251-258, 269-271
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.styles.ts
Outdated
Show resolved
Hide resolved
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
Outdated
Show resolved
Hide resolved
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
Outdated
Show resolved
Hide resolved
| onToggleStatus?: () => void; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
onToggleStatus를 optional로 두면 일부 메뉴에서 동작이 없어질 수 있습니다
onToggleStatus가 optional인데, Styled.MenuItem의 onClick에 그대로 연결되어 있어 prop을 넘기지 않은 경우(예: ApplicantsListTab.tsx 하단 리스트 쪽 ApplicationMenu 호출부)는 “기본지원서로 설정/해제”를 눌러도 아무 동작이 없습니다.
둘 중 하나로 정리하는 걸 추천드립니다.
onToggleStatus를 필수 prop으로 바꾸고, 모든ApplicationMenu사용처에서 콜백을 넘기도록 통일- 혹은,
onToggleStatus가 없는 경우에는 기본지원서 관련 메뉴 아이템 자체를 숨기거나 disabled 처리
현재 상태 그대로 배포되면 동일한 UI인데 어떤 곳은 동작하고 어떤 곳은 안 되는 혼란이 생길 수 있습니다.
Also applies to: 14-15, 18-29
🏁 Script executed:
#!/bin/bash
# Find ApplicationMenu component definition and surrounding code
fd -t f "ApplicationMenu.tsx" --exec cat {}Length of output: 1343
🏁 Script executed:
#!/bin/bash
# Find all usages of ApplicationMenu component
rg -n "ApplicationMenu" --type=tsx --type=ts -C 3Length of output: 27
🏁 Script executed:
#!/bin/bash
# Specifically check ApplicantsListTab.tsx for ApplicationMenu usage
fd -t f "ApplicantsListTab.tsx" --exec cat {}Length of output: 9580
onToggleStatus optional prop로 인한 일관성 없는 동작 확인됨 - 수정 필요
검증 결과, 지적 사항이 정확합니다:
- ApplicationMenu.tsx 라인 20:
onClick={onToggleStatus}가 직접 연결되어 있고 undefined 처리가 없음 - ApplicantsListTab.tsx 라인 149 (활성 지원서 섹션):
onToggleStatus={() => handleToggleClick(...)}전달됨 - ApplicantsListTab.tsx 라인 196 (일반 지원서 목록):
onToggleStatus미전달 → 클릭 시 아무 동작 없음
동일한 UI 메뉴가 위치에 따라 기능하거나 기능하지 않으므로 사용자 혼란이 발생합니다.
권장 해결 방안:
onToggleStatus를 필수 prop으로 변경 후 모든 호출부에서 콜백 전달- 또는
onToggleStatus미제공 시 해당 메뉴 아이템을 disabled/hidden 처리
🤖 Prompt for AI Agents
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx lines
11-12: the optional onToggleStatus prop leads to inconsistent UI behavior
because the component attaches onClick={onToggleStatus} without guarding for
undefined; fix by either (A) making onToggleStatus a required prop and updating
every caller (e.g., ApplicantsListTab around the active list at line ~149 and
the general list at line ~196) to pass the appropriate handleToggleClick
callback, or (B) keep it optional but change ApplicationMenu to defensively
handle missing callback by rendering the toggle menu item as disabled/hidden and
not binding onClick when onToggleStatus is undefined; apply one of these fixes
and ensure all call sites are updated or the menu item state reflects the
absence of the handler.
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.styles.ts
Outdated
Show resolved
Hide resolved
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.styles.ts
Outdated
Show resolved
Hide resolved
| width: auto; | ||
| height: auto; |
There was a problem hiding this comment.
원래 width는 fix 였던거 같은데 피그마 보니깐 fill 로 바뀌어 있어서 auto로 했습니다
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.styles.ts
Outdated
Show resolved
Hide resolved
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.styles.ts
Outdated
Show resolved
Hide resolved
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.styles.ts
Outdated
Show resolved
Hide resolved
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.styles.ts
Outdated
Show resolved
Hide resolved
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
Outdated
Show resolved
Hide resolved
| const ActiveListBody = styled(Styled.ApplicationList)` | ||
| border-top-left-radius: 0; | ||
| `; | ||
| const ActiveApplicationRow = styled(Styled.ApplicationRow)` | ||
| &:hover { | ||
| background-color: #f8f9fa; | ||
| &:first-child { | ||
| border-top-right-radius: 20px; | ||
| } | ||
| } | ||
| `; |
There was a problem hiding this comment.
내부에 스타일 컴포넌트를 추가하신 이유가 있나요?
There was a problem hiding this comment.
모아보기 창 스타일을 새로 만드려다가 기존에 지원서 리스트 스타일 그대로 쓰면 좋을 것 같아서 AI 한테 방법을 물어 봤더니 저 방식을 추천해줘서 저렇게 했습니다.
There was a problem hiding this comment.
그럼 스타일 파일에 추가하는 것이 관심사 분리에 더 좋을 것 같다는 생각이 드는데 어떻게 생각하시나요 ??
| return ( | ||
| <ActiveApplicationRow key={application.id}> |
There was a problem hiding this comment.
return안에 오는 컴포넌트를 따로 분리하는 건 어떤가요?
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (1)
230-234: 학기별 리스트의ApplicationMenu에도onToggleStatus전달이 필요합니다이 문제는 이전 리뷰에서 이미 지적되었습니다. 상단 "대표지원서 모아보기" 섹션에서는 토글이 동작하지만, 하단 학기별 리스트에서는 동일한 메뉴가 작동하지 않아 UX 일관성 문제가 발생합니다.
다음과 같이 수정하세요:
{openMenuId === currentMenuKey && ( <ApplicationMenu isActive={isActive} + onToggleStatus={() => handleToggleClick(application.id, application.status)} // onDelete={() => handleDeleteApplication(application.id)} /> )}frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx (1)
11-22:onToggleStatus가 optional이지만 undefined 체크 없이 사용되고 있습니다이 문제는 이전 리뷰에서 이미 지적되었습니다.
onToggleStatus가 전달되지 않은 경우(예: 하단 학기별 리스트) 메뉴 아이템을 클릭해도 아무 동작이 일어나지 않습니다.다음 중 하나로 해결해주세요:
onToggleStatus를 필수 prop으로 변경하고 모든 사용처에서 콜백 전달- optional로 유지하되, undefined인 경우 해당 메뉴 아이템을 숨기거나 disabled 처리
🧹 Nitpick comments (2)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (2)
129-139: 인라인 스타일 컴포넌트를 별도 스타일 파일로 분리하세요
ActiveListBody와ActiveApplicationRow를 컴포넌트 내부에서 정의하는 것은 권장되지 않는 패턴입니다. 렌더링마다 새로운 컴포넌트가 생성되어 성능 문제를 일으킬 수 있습니다.
ApplicantsListTab.styles.ts파일로 이동시켜주세요.
ApplicantsListTab.styles.ts에 추가:export const ActiveListBody = styled(ApplicationList)` border-top-left-radius: 0; `; export const ActiveApplicationRow = styled(ApplicationRow)` &:hover { background-color: #f8f9fa; &:first-child { border-top-right-radius: 20px; } } `;그리고 이 파일에서 import:
-import styled from 'styled-components';- const ActiveListBody = styled(Styled.ApplicationList)` - border-top-left-radius: 0; - `; - const ActiveApplicationRow = styled(Styled.ApplicationRow)` - &:hover { - background-color: #f8f9fa; - &:first-child { - border-top-right-radius: 20px; - } - } - `;
47-59: 에러 피드백 개선을 고려해보세요현재
alert()를 사용한 에러 피드백은 사용자 경험을 저해할 수 있습니다. 토스트 메시지나 인라인 에러 표시 등 더 나은 UX 패턴을 고려해보세요.
📜 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/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx(7 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts(7 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (4)
frontend/src/hooks/queries/application/useGetApplicationlist.ts (1)
useGetApplicationlist(4-10)frontend/src/context/AdminClubContext.tsx (1)
useAdminClubContext(40-47)frontend/src/apis/application/updateApplication.ts (1)
updateApplicationStatus(33-58)frontend/src/types/application.ts (2)
SemesterGroup(75-79)ApplicationFormItem(68-73)
🔇 Additional comments (1)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (1)
68-72: LGTM! 메뉴 키 충돌 방지 로직이 잘 구현되었습니다
contextPrefix를 사용하여 활성 지원서 섹션과 학기별 리스트의 메뉴를 구분하는 방식이 적절합니다. 이를 통해 서로 다른 섹션의 동일한 ID를 가진 지원서가 메뉴 상태를 공유하지 않게 됩니다.
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (2)
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx (1)
10-11:onToggleStatus가 optional이지만 undefined 처리가 없습니다
onToggleStatus가 선택적 prop으로 선언되어 있지만, Line 22에서onClick={onToggleStatus}로 직접 연결되어 있어 prop이 전달되지 않은 경우 클릭 시 아무 동작도 하지 않습니다.동일한 메뉴 UI가 일부 컨텍스트에서는 작동하고 다른 곳에서는 작동하지 않아 사용자 혼란을 야기할 수 있습니다.
다음 중 하나로 수정하세요:
onToggleStatus를 필수 prop으로 변경하고 모든 사용처에서 콜백 전달- 또는
onToggleStatus가 없을 때 해당 메뉴 아이템을 비활성화/숨김 처리- <Styled.MenuItem onClick={onToggleStatus} $ActiveMenu={true}> + <Styled.MenuItem + onClick={onToggleStatus} + $ActiveMenu={true} + style={{ opacity: onToggleStatus ? 1 : 0.5, cursor: onToggleStatus ? 'pointer' : 'not-allowed' }} + >Also applies to: 22-22
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts (1)
26-31: ActiveListContainer에 display 속성 누락
flex-direction: column이 설정되어 있지만display: flex가 명시되어 있지 않습니다. 일부 브라우저에서는flex-direction이 무시될 수 있습니다.export const ActiveListContainer = styled.div` + display: flex; flex-direction: column; width: auto;
🧹 Nitpick comments (5)
frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsx (1)
36-49: 날짜 포맷팅 로직을 공통 유틸리티로 추출 권장
formatDateTime함수가 이 컴포넌트 내부에 정의되어 있습니다. 동일한 날짜 포맷팅 로직이 여러 곳에서 필요할 가능성이 높으므로,src/utils/dateFormat.ts같은 공통 유틸리티 파일로 추출하는 것을 권장합니다.예시:
// src/utils/dateFormat.ts export const formatDateTime = (dateTimeString: string): string => { const now = new Date(); const date = new Date(dateTimeString); const isToday = now.getFullYear() === date.getFullYear() && now.getMonth() === date.getMonth() && now.getDate() === date.getDate(); const options: Intl.DateTimeFormatOptions = isToday ? { hour: 'numeric', minute: '2-digit', hour12: true } : { year: 'numeric', month: '2-digit', day: '2-digit' }; return date.toLocaleString('ko-KR', options); };사용 시:
+ import { formatDateTime } from '@/utils/dateFormat'; - const formatDateTime = (dateTimeString: string) => { - // ... - };frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (2)
36-47:window.confirm과alert사용보다 모달 컴포넌트 권장현재 브라우저 네이티브 confirm/alert를 사용하고 있습니다. 더 나은 사용자 경험을 위해 프로젝트의 디자인 시스템에 맞는 커스텀 모달 컴포넌트 사용을 권장합니다.
커스텀 모달 컴포넌트를 구현하거나 라이브러리(예: react-modal)를 사용하는 것을 고려해보세요.
56-56: 에러 로깅 일관성 개선 권장Based on learnings, 코드베이스 전체에서 에러 로깅 패턴이 일관되지 않습니다. 통일된 로깅 형식을 사용하는 것을 권장합니다.
예시:
} catch (error) { - console.error('지원서 상태 변경 실패:', error); + console.error('[ApplicationListTab] 지원서 상태 변경 실패:', error); alert("상태 변경에 실패했습니다."); }Also applies to: 59-59
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx (2)
34-45:window.confirm과alert사용보다 모달 컴포넌트 권장브라우저 네이티브 confirm/alert를 사용하고 있습니다. ApplicantsListTab과 동일한 패턴이므로 통일된 모달 컴포넌트로 전환하는 것을 권장합니다.
47-59: ApplicationListTab과 ApplicantsListTab 간 로직 중복Based on learnings,
handleToggleClick,handleDeleteApplication,handleToggleExpand등의 로직이 두 파일에서 거의 동일하게 구현되어 있습니다. 상태 관리를 더 작고 집중된 hooks/contexts로 분리하여 결합도를 줄이는 것을 권장합니다.공통 로직을 커스텀 훅으로 추출하는 것을 고려해보세요:
// hooks/useApplicationActions.ts export const useApplicationActions = () => { const queryClient = useQueryClient(); const { mutate: deleteApplication } = useDeleteApplication(); const [openMenuId, setOpenMenuId] = useState<string | null>(null); const handleToggleClick = async (applicationFormId: string, currentStatus: string) => { // ... 구현 }; const handleDeleteApplication = (applicationFormId: string) => { // ... 구현 }; return { openMenuId, setOpenMenuId, handleToggleClick, handleDeleteApplication, }; };Also applies to: 34-45, 61-63
📜 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 (1)
frontend/src/assets/images/icons/ExpandArrow.svgis excluded by!**/*.svg
📒 Files selected for processing (9)
frontend/src/apis/application/deleteApplication.ts(1 hunks)frontend/src/hooks/queries/application/useDeleteApplication.ts(1 hunks)frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.style.ts(1 hunks)frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsx(1 hunks)frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.styles.ts(0 hunks)frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx(6 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts(7 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx(5 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.styles.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/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsxfrontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.style.tsfrontend/src/apis/application/deleteApplication.tsfrontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsxfrontend/src/hooks/queries/application/useDeleteApplication.tsfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.tsfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.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/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsxfrontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsxfrontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.style.tsfrontend/src/apis/application/deleteApplication.tsfrontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsxfrontend/src/hooks/queries/application/useDeleteApplication.tsfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.tsfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx
🧠 Learnings (3)
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Break down broad state management into smaller, focused hooks/contexts to reduce coupling
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Abstract complex logic/interactions into dedicated components/HOCs
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx
📚 Learning: 2025-08-24T17:33:23.092Z
Learnt from: suhyun113
Repo: Moadong/moadong PR: 698
File: frontend/src/hooks/queries/applicants/useDeleteApplicants.ts:10-16
Timestamp: 2025-08-24T17:33:23.092Z
Learning: The codebase has inconsistent console logging patterns across files - mixing console.log/console.error for errors, using both Korean and English messages, and various formatting styles (template literals vs separate arguments, with/without emojis). A unified logging format like `console.error('[ModuleName] Operation failed:', error)` should be established for better debugging consistency.
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
🧬 Code graph analysis (3)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (5)
frontend/src/hooks/queries/application/useGetApplicationlist.ts (1)
useGetApplicationlist(4-10)frontend/src/context/AdminClubContext.tsx (1)
useAdminClubContext(40-47)frontend/src/hooks/queries/application/useDeleteApplication.ts (1)
useDeleteApplication(4-19)frontend/src/apis/application/updateApplication.ts (1)
updateApplicationStatus(33-58)frontend/src/types/application.ts (2)
SemesterGroup(75-79)ApplicationFormItem(68-73)
frontend/src/apis/application/deleteApplication.ts (2)
frontend/public/mockServiceWorker.js (1)
response(125-125)frontend/src/apis/auth/secureFetch.ts (1)
secureFetch(3-41)
frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsx (1)
frontend/src/types/application.ts (1)
ApplicationFormItem(68-73)
🔇 Additional comments (7)
frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.style.ts (1)
1-95: 스타일 컴포넌트 구현이 잘 되었습니다새로운 ApplicationRow 관련 스타일 컴포넌트들이 깔끔하게 정의되어 있습니다.
$activeprop을 활용한 조건부 스타일링과 hover 상태 처리가 적절합니다.frontend/src/hooks/queries/application/useDeleteApplication.ts (1)
4-19: React Query mutation 구현이 적절합니다
useMutation을 통한 삭제 API 연동과 성공 시 쿼리 무효화 처리가 올바르게 구현되어 있습니다.frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsx (1)
51-82: 컴포넌트 구조가 깔끔하게 구현되었습니다ApplicationRowItem이 재사용 가능한 구조로 잘 설계되어 있으며, props를 통한 이벤트 핸들링과 메뉴 상태 관리가 적절합니다.
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts (1)
33-42: ActiveListTitleBox의 display 속성 확인Line 36에
display: flex가 있어 적절하게 설정되어 있습니다.frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (1)
132-195: ApplicationRowItem 통합이 일관되게 구현되었습니다Active 리스트와 학기별 리스트 모두에서
ApplicationRowItem을 사용하여 일관된 렌더링과 이벤트 처리를 제공하고 있습니다.onToggleStatus,onDelete등의 콜백이 모두 적절히 연결되어 있습니다.frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx (2)
109-119: ActiveApplicationRow 스타일 컴포넌트 구현 확인이 파일에서는
ActiveApplicationRow가 실제로 사용되고 있어 적절합니다. ApplicantsListTab과 달리 주석 처리되지 않았습니다.
124-195: Active 리스트 기능이 잘 구현되었습니다게시된 지원서 섹션의 확장/축소 기능, 빈 상태 처리, ApplicationRowItem 통합이 모두 올바르게 구현되어 있습니다.
| if (!response.ok) { | ||
| console.error(`Failed to delete: ${response.statusText}`); | ||
| throw new Error((await response.json()).message); | ||
| } |
There was a problem hiding this comment.
에러 처리 시 response.json() 실패 가능성 대비 필요
response.ok가 false일 때 await response.json()을 호출하는데, 응답 본문이 비어있거나 JSON 형식이 아닐 경우 예외가 발생할 수 있습니다. 이 경우 catch 블록에서 처리되지만, 에러 메시지가 불명확해집니다.
다음과 같이 개선을 권장합니다:
if (!response.ok) {
console.error(`Failed to delete: ${response.statusText}`);
- throw new Error((await response.json()).message);
+ const errorData = await response.json().catch(() => ({ message: response.statusText }));
+ throw new Error(errorData.message);
}📝 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.
| if (!response.ok) { | |
| console.error(`Failed to delete: ${response.statusText}`); | |
| throw new Error((await response.json()).message); | |
| } | |
| if (!response.ok) { | |
| console.error(`Failed to delete: ${response.statusText}`); | |
| const errorData = await response.json().catch(() => ({ message: response.statusText })); | |
| throw new Error(errorData.message); | |
| } |
🤖 Prompt for AI Agents
In frontend/src/apis/application/deleteApplication.ts around lines 12 to 15, the
code calls await response.json() when response.ok is false which can throw if
the body is empty or not JSON; wrap the response parsing in a try/catch (or
first await response.text() then attempt JSON.parse) and fall back to a safe
message such as response.statusText or the raw text if parsing fails, then
include that fallback value in the thrown Error and console.error to ensure a
clear, non-crashing error message.
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
Outdated
Show resolved
Hide resolved
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts (2)
52-68:ExpandButton블록의 중복 중괄호 및 시맨틱/접근성 개선 제안
- Line 67의
} }로 인해 CSS 블록이 한 번 더 닫히는 형태가 되어, styled-components가 생성하는 CSS에서 문법 오류나 예기치 않은 스타일 깨짐이 발생할 수 있습니다. (이전에 남겨졌던 동일 리뷰 코멘트가 아직 반영되지 않은 것으로 보입니다.)&:hover { // background-color: #F2F2F2; /* 호버 시 배경색 변경 물어보기.. */ border-bottom-left-radius: 20px; border-bottom-right-radius: 20px; - } } + } `;
- 이름이
ExpandButton인데 실제 요소는styled.div라, 클릭 이벤트를 달아 버튼처럼 사용할 경우 키보드 포커스/엔터/스페이스 키 처리 등 접근성 측면에서 불리합니다. 가능하다면 아래처럼button으로 바꾸고, TSX 쪽에서type="button"까지 지정해 주는 것을 추천합니다.-export const ExpandButton = styled.div` +export const ExpandButton = styled.button` display: flex; justify-content: center; align-items: center; gap: 6px; padding: 10px; cursor: pointer; font-size: 14px; color: #787878; border-top: 1px solid #DCDCDC; /* 리스트와 구분하는 선 */(스타일 상 필요하다면
border: none; background: transparent;등을 추가)
25-31:ActiveListContainer에display: flex누락
ActiveListContainer에flex-direction: column;만 있고display: flex;가 빠져 있어서, 실제로는 flex 레이아웃이 적용되지 않습니다.export const ActiveListContainer = styled.div` - flex-direction: column; + display: flex; + flex-direction: column; width: auto; height: auto; margin-bottom: 46px; `;그냥 세로 스택 컨테이너로 쓰려던 의도라면 위처럼 수정하는 것이 맞을 것 같습니다.
🧹 Nitpick comments (3)
frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.style.ts (2)
3-9: 사용되지 않는 인터페이스 정리 제안
MenuItemProps,ExpandButtonProps가 이 파일 내에서는 전혀 사용되지 않습니다. 같은 이름의 인터페이스가ApplicationListTab.styles.ts에도 다시 정의되어 있어서, 여기 정의는 dead code로 보입니다.
- 이 파일에서 쓰지 않는다면 과감히 제거하거나,
- 공용으로 사용할 의도라면 별도 타입 파일로 분리해서 두 곳에서 import 하는 쪽이 더 명확합니다.
불필요한 타입 정의는 린트 경고(no-unused-vars 계열)를 유발할 수 있으니 한 번 정리하는 것을 추천드립니다.
63-67: 컴포넌트 이름 오타(ApplicationDatetable) 정리 권장
ApplicationDatetable이름이 오타처럼 보여서 검색/자동완성 시 혼동이 생길 수 있습니다.ApplicationDateTable또는ApplicationDateContainer등 의미가 더 명확한 이름으로 맞춰두면 이후 유지보수 시 이점이 클 것 같습니다.이미 사용 중인 곳이 있다면 함께 리네임이 필요하니, 영향 범위만 한 번 확인해 주세요.
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts (1)
118-135:AddButton주석 처리된 hover 스타일은 나중에 정리 권장
// &:hover { ... }형태로 호버 스타일이 주석 처리돼 있는데, 실제로 쓰지 않을 것이라면 제거하거나, 디자인이 확정되면 바로 적용해 두는 편이 좋습니다. 주석이 많아지면 실제 사용 중인 스타일과 실험/보류 상태를 구분하기 어려워집니다.큰 문제는 아니라서 후순위로 정리하셔도 됩니다.
📜 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/AdminPage/components/ApplicationRow/ApplicationRowItem.style.ts(1 hunks)frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsx(1 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts(5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsx
🧰 Additional context used
📓 Path-based instructions (2)
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/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.style.tsfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.style.tsfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
🧠 Learnings (1)
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Separate significantly different conditional UI/logic into distinct components
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
🔇 Additional comments (3)
frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.style.ts (1)
11-61: Row/Title/More 버튼 스타일 구조는 전반적으로 깔끔합니다Row, Title의 active 상태 강조(색상 + before 원형 포인트)와 More 버튼/아이콘 컨테이너 구조가 명확하게 분리되어 있어서, 이후 상태/동작을 추가하기에도 좋아 보입니다. 현재 스타일 정의 자체로는 특별한 문제는 없어 보입니다.
Also applies to: 69-101
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts (2)
70-76:ExpandArrow의 회전 스타일은 적절해 보입니다
$isExpanded플래그로 180도 회전만 토글하는 방식은 단순하고 명확해서, 추후 애니메이션(transition) 추가 등도 쉽게 확장 가능해 보입니다. 현재 구현 자체에는 특별한 문제는 없어 보입니다.
143-152: 리스트 카드 및 메뉴/아이템/구분선 스타일은 구조적으로 잘 잡혀 있습니다
ApplicationList의 카드 형태(흰 배경, radius 20px, 비마지막 카드 margin-bottom)와MenuContainer의 absolute 포지셔닝 + box-shadow,MenuItem의 hover 배경,$ActiveMenu에 따른 weight 변경,Separator의 1px 라인 처리등이 서로 잘 어울려서, 메뉴/리스트 UI 구조 자체는 명확하고 확장하기 좋아 보입니다. 현재 스타일 정의 관점에서는 별다른 이슈는 없어 보입니다.
Also applies to: 182-193, 195-221, 227-231
| // 활성화된 지원서가 없을경우 보여주는 메시지 컨테이너 | ||
| export const MessageContainer = styled.div` | ||
| display: flex; | ||
| flex-direction: column; | ||
| align-items: center; | ||
| justify-content: center; | ||
| width: auto; | ||
| height: auto; | ||
| margin-top: 25px; | ||
| margin-bottom: 25px; | ||
| `; | ||
|
|
||
| export const NoActiveFormsMessage = styled.div` | ||
| display: flex; | ||
| flex-direction: column; | ||
| align-items: center; | ||
| justify-content: center; | ||
| width: auto; | ||
| height: auto; | ||
| padding-top: 2px; | ||
| margin-bottom: 6px; | ||
| font-size: 16px; | ||
| font-weight: 600; | ||
| color: #FF5414; | ||
| `; | ||
|
|
||
| export const suggestionText = styled.div` | ||
| font-size: 14px; | ||
| font-weight: 500; | ||
| color: #787878; | ||
| `; |
There was a problem hiding this comment.
suggestionText 컴포넌트 이름을 PascalCase로 통일 권장
export const suggestionText = styled.div처럼 소문자로 시작하는 이름으로 export 하면, TSX에서 <suggestionText>로 사용할 때 React가 DOM 태그로 해석해 버려 스타일 컴포넌트가 의도대로 동작하지 않을 수 있습니다.
다른 styled 컴포넌트들과 동일하게 PascalCase로 맞추는 편이 안전합니다.
-export const suggestionText = styled.div`
+export const SuggestionText = styled.div`
font-size: 14px;
font-weight: 500;
color: #787878;
`;TSX 사용처에서도 SuggestionText로 이름을 맞춰주는지 함께 확인해 주세요.
🤖 Prompt for AI Agents
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
around lines 78 to 108: the styled component is exported as suggestionText
(camelCase) which can be interpreted as a DOM tag in JSX; rename the export to
PascalCase (SuggestionText) to match other styled components and prevent React
treating it as a native element, update the export identifier and any internal
references accordingly, and then update all TSX imports/usages to use
SuggestionText instead of suggestionText.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts (2)
104-108: 컴포넌트 이름을 PascalCase로 변경해야 합니다.이전 리뷰에서 지적되었으나 아직 수정되지 않았습니다.
suggestionText는 camelCase로 export되어 있어 JSX에서 DOM 태그로 해석될 수 있습니다. 다른 styled 컴포넌트들과 일관되게SuggestionText로 변경하세요.-export const suggestionText = styled.div` +export const SuggestionText = styled.div` font-size: 14px; font-weight: 500; color: #787878; `;사용하는 곳에서도
SuggestionText로 변경해야 합니다.
26-31:display: flex속성이 누락되었습니다.
flex-direction: column을 사용하려면display: flex가 필요합니다. 현재는 flex-direction이 무시되어 레이아웃이 의도대로 동작하지 않습니다.다음과 같이 수정하세요:
export const ActiveListContainer = styled.div` + display: flex; flex-direction: column; width: auto; height: auto; margin-bottom: 46px; `;
🧹 Nitpick comments (1)
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts (1)
20-231: 반복되는 수치를 명명된 상수로 추출하는 것을 고려하세요.코딩 가이드라인에 따르면 매직 넘버를 명명된 상수로 대체해야 합니다. 파일 전반에 걸쳐 반복되는 spacing 값(8px, 12px, 16px, 24px), font-size(12px, 14px, 16px, 24px), border-radius(8px, 20px) 등을 design token으로 추출하면 유지보수성과 일관성이 향상됩니다.
As per coding guidelines, replace magic numbers with named constants.
예시:
const SPACING = { xs: '8px', sm: '12px', md: '16px', lg: '24px', xl: '46px', }; const FONT_SIZE = { xs: '12px', sm: '14px', md: '16px', lg: '24px', }; const BORDER_RADIUS = { sm: '8px', lg: '20px', };그런 다음 컴포넌트에서 사용:
export const Title = styled.div` font-size: ${FONT_SIZE.lg}; font-weight: 700; margin-bottom: ${SPACING.lg}; `;
📜 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 (1)
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts(5 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
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/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
🧠 Learnings (5)
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Replace magic numbers with named constants for clarity
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Define constants near related logic or ensure names link them clearly to avoid silent failures
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Use unique and descriptive names for custom wrappers/functions to avoid ambiguity
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{ts,tsx} : Use consistent return types for similar functions/hooks
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Separate significantly different conditional UI/logic into distinct components
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
🔇 Additional comments (1)
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts (1)
3-9: 인터페이스 정의가 올바릅니다.Transient prop 접두사($)를 사용하여 styled-components에서 DOM 속성으로 전달되지 않도록 적절히 처리되었습니다.
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
Outdated
Show resolved
Hide resolved
| export const Separation_Bar = styled.div` | ||
| width: 1px; /* 아이콘 너비 */ | ||
| height: 12px; /* 아이콘 높이 */ | ||
| width: 1px; | ||
| height: 12px; | ||
| margin-right: 25px; | ||
| background-color: #DCDCDC; | ||
| `; |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
컴포넌트 이름을 PascalCase로 통일하세요.
Separation_Bar는 snake_case를 사용하고 있어 다른 컴포넌트들의 명명 규칙과 일관되지 않습니다. JavaScript/React 관례에 따라 SeparationBar로 변경하세요.
As per coding guidelines, use unique and descriptive names.
-export const Separation_Bar = styled.div`
+export const SeparationBar = styled.div`
width: 1px;
height: 12px;
margin-right: 25px;
background-color: #DCDCDC;
`;사용하는 곳에서도 SeparationBar로 변경해야 합니다.
📝 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.
| export const Separation_Bar = styled.div` | |
| width: 1px; /* 아이콘 너비 */ | |
| height: 12px; /* 아이콘 높이 */ | |
| width: 1px; | |
| height: 12px; | |
| margin-right: 25px; | |
| background-color: #DCDCDC; | |
| `; | |
| export const SeparationBar = styled.div` | |
| width: 1px; | |
| height: 12px; | |
| margin-right: 25px; | |
| background-color: #DCDCDC; | |
| `; |
🤖 Prompt for AI Agents
In
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
around lines 175 to 180, the styled component is named Separation_Bar using
snake_case; rename it to SeparationBar (PascalCase) and update all
imports/usages across the codebase to use SeparationBar instead, ensuring the
export name matches and run a project-wide search/replace to update references
and tests.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx (1)
16-198: 두 파일 간 심각한 코드 중복이 있습니다.이 파일과
ApplicantsListTab.tsx가 약 95% 유사합니다. 상태 관리, 핸들러 로직, 렌더링 구조가 거의 동일하며, 주요 차이점은handleGoToEditFormvshandleGoToDetailForm와 라우팅 경로뿐입니다.이러한 중복은 유지보수성을 저하시키고 버그 발생 가능성을 높입니다. 공통 로직을 추출하는 것을 강력히 권장합니다.
제안하는 리팩토링 방안:
- 공통 hook 추출: 상태 관리와 핸들러 로직을
useApplicationListLogic같은 custom hook으로 분리- 공유 컴포넌트: Active List 섹션과 Semester List 렌더링 로직을 별도 컴포넌트로 추출
- 설정 기반 차이: 편집/상세 보기 같은 차이점은 props나 context로 주입
As per coding guidelines, break down broad state management into smaller, focused hooks/contexts to reduce coupling.
예시 구조:
// hooks/useApplicationListLogic.ts export const useApplicationListLogic = (config: { onItemClick: (id: string) => void }) => { const queryClient = useQueryClient(); const [openMenuId, setOpenMenuId] = useState<string | null>(null); const [isExpanded, setIsExpanded] = useState(false); // ... 공통 로직 return { openMenuId, isExpanded, handleToggleClick, handleDeleteApplication, handleMenuToggle, handleToggleExpand, // ... }; }; // components/ApplicationListView.tsx export const ApplicationListView = ({ onItemClick, itemClickLabel }: Props) => { const logic = useApplicationListLogic({ onItemClick }); // ... 렌더링 로직 };
♻️ Duplicate comments (2)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (1)
111-121: 주석 처리된 코드를 제거하고 인라인 스타일 컴포넌트를 스타일 파일로 이동하세요.Lines 114-121의 주석 처리된
ActiveApplicationRow는 이전 리뷰에서 제거가 요청되었습니다.또한 Line 111-113의
ActiveListBody를 컴포넌트 내부에 정의하는 것보다 ApplicationListTab.styles.ts 파일로 이동하는 것이 관심사 분리 측면에서 더 적절합니다.- const ActiveListBody = styled(Styled.ApplicationList)` - border-top-left-radius: 0; - `; - // const ActiveApplicationRow = styled(Styled.ApplicationRow)` - // &:hover { - // background-color: #f8f9fa; - // &:first-child { - // border-top-right-radius: 20px; - // } - // } - // `;스타일 파일에서 export하여 사용하세요:
// ApplicationListTab.styles.ts에 추가 export const ActiveListBody = styled(ApplicationList)` border-top-left-radius: 0; `;frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts (1)
172-177: 컴포넌트 이름을 PascalCase로 변경하세요.
Separation_Bar는 snake_case를 사용하고 있어 다른 스타일 컴포넌트의 명명 규칙과 일치하지 않습니다.SeparationBar로 변경하고 사용처도 함께 업데이트해야 합니다.As per coding guidelines, use unique and descriptive names.
-export const Separation_Bar = styled.div` +export const SeparationBar = styled.div` width: 1px; height: 12px; margin-right: 25px; background-color: #DCDCDC; `;
🧹 Nitpick comments (1)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (1)
36-61: 사용자 인터랙션에 window.confirm/alert 사용을 개선할 수 있습니다.현재 삭제 확인과 오류 알림에 브라우저 네이티브
window.confirm과alert를 사용하고 있습니다. 이는 동작하지만 현대적인 UI 라이브러리의 모달이나 토스트 컴포넌트를 사용하면 더 나은 사용자 경험을 제공할 수 있습니다.상태 토글 로직(
handleToggleClick)은 올바르게 쿼리 무효화를 수행하고 있으며 에러 처리도 포함되어 있습니다.
📜 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/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx(6 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts(5 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx(5 hunks)
🧰 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/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.tsfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.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/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.tsfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx
🧠 Learnings (10)
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Break down broad state management into smaller, focused hooks/contexts to reduce coupling
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.tsfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Separate significantly different conditional UI/logic into distinct components
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Abstract complex logic/interactions into dedicated components/HOCs
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Colocate simple, localized logic or use inline definitions to reduce context switching
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Use Component Composition instead of Props Drilling to reduce coupling
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Choose field-level or form-level cohesion based on form requirements when using form libraries like react-hook-form
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Replace magic numbers with named constants for clarity
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Define constants near related logic or ensure names link them clearly to avoid silent failures
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Use unique and descriptive names for custom wrappers/functions to avoid ambiguity
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{ts,tsx} : Use consistent return types for similar functions/hooks
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts
🧬 Code graph analysis (1)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (5)
frontend/src/hooks/queries/application/useGetApplicationlist.ts (1)
useGetApplicationlist(4-10)frontend/src/context/AdminClubContext.tsx (1)
useAdminClubContext(40-47)frontend/src/hooks/queries/application/useDeleteApplication.ts (1)
useDeleteApplication(4-19)frontend/src/apis/application/updateApplication.ts (1)
updateApplicationStatus(33-58)frontend/src/types/application.ts (2)
SemesterGroup(75-79)ApplicationFormItem(68-73)
🔇 Additional comments (9)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (4)
1-26: 초기 설정 및 임포트가 적절합니다.공유 스타일 파일과 새로운 ApplicationRowItem 컴포넌트를 올바르게 임포트하고 있으며, 필요한 hook들이 적절히 구성되어 있습니다. MAX_INITIAL_ITEMS 상수도 명확한 이름으로 정의되어 있습니다.
67-94: 메뉴 상태 관리가 적절하게 구현되었습니다.
contextPrefix를 활용한 고유 키 생성 방식은 활성 리스트와 학기별 그룹 간 메뉴 충돌을 방지합니다. 외부 클릭 감지 로직도 표준적이고 올바르게 구현되어 있습니다.
126-163: 활성 리스트 섹션이 잘 구현되었습니다.게시된 지원서 섹션이 확장/축소 기능과 빈 상태 메시지를 포함하여 올바르게 구현되었습니다. 사용자 경험을 고려한 구현입니다.
169-197: 학기별 리스트의 ApplicationMenu 일관성 문제가 해결되었습니다.이전 리뷰에서 지적된 학기별 리스트의
onToggleStatus누락 문제가 Line 192에서 올바르게 해결되었습니다. 이제 두 섹션 모두 일관된 동작을 제공합니다.frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.styles.ts (5)
3-10: 인터페이스 정의가 적절합니다.Styled-components의 transient props 패턴($prefix)을 올바르게 사용하고 있으며, 타입 정의가 명확합니다.
25-108: Active List 스타일 컴포넌트가 잘 정의되었습니다.게시된 지원서 섹션의 모든 스타일 컴포넌트가 올바르게 구현되었습니다. 특히
ExpandButton의 hover 효과와ExpandArrow의 조건부 회전 애니메이션이 사용자 경험을 향상시킵니다.이전 리뷰에서 지적된
suggestionText의 PascalCase 변환도 Line 104에서SuggestionText로 적용되어 있습니다.
110-137: 헤더 및 버튼 스타일이 적절합니다.간격과 타이포그래피 조정이 일관성 있게 적용되었습니다. AddButton에 hover 효과가 없는 것은 의도된 디자인 결정으로 보입니다.
139-149: ApplicationList 스타일 업데이트가 적절합니다.
width: auto로 반응형 동작을 허용하고, 증가된border-radius로 현대적인 외관을 제공합니다. 마진 처리 패턴도 깔끔합니다.
179-228: 메뉴 스타일링이 올바르게 업데이트되었습니다.메뉴 위치 조정과 box-shadow 개선이 적절하며,
MenuItem의 조건부 스타일링($ActiveMenu)이 올바르게 구현되었습니다. 모든 CSS 값이 유효합니다.
| const ActiveListBody = styled(Styled.ApplicationList)` | ||
| border-top-left-radius: 0; | ||
| `; | ||
| const ActiveApplicationRow = styled(ApplicationRowItem)` | ||
| &:hover { | ||
| background-color: #F2F2F2; | ||
| &:first-child { | ||
| border-top-right-radius: 20px; | ||
| } | ||
| } | ||
| }; | ||
| `; |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
인라인 스타일 컴포넌트를 스타일 파일로 이동하세요.
ActiveListBody와 ActiveApplicationRow를 컴포넌트 내부에 정의하는 것보다 ApplicationListTab.styles.ts로 이동하여 관심사를 분리하는 것이 좋습니다.
- const ActiveListBody = styled(Styled.ApplicationList)`
- border-top-left-radius: 0;
- `;
- const ActiveApplicationRow = styled(ApplicationRowItem)`
- &:hover {
- background-color: #F2F2F2;
- &:first-child {
- border-top-right-radius: 20px;
- }
- }
- `;스타일 파일로 이동:
// ApplicationListTab.styles.ts에 추가
export const ActiveListBody = styled(ApplicationList)`
border-top-left-radius: 0;
`;
export const ActiveApplicationRow = styled.div`
&:hover {
background-color: #F2F2F2;
&:first-child {
border-top-right-radius: 20px;
}
}
`;There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (1)
111-121: 컴포넌트 함수 내부에 styled-components 정의 - 성능 및 정확성 문제
ActiveListBody와ActiveApplicationRow가 컴포넌트 함수 내부에 정의되어 있어 매 렌더링마다 새로운 컴포넌트가 생성됩니다. 이로 인해:
- React가 매번 컴포넌트를 리마운트하여 내부 상태 손실
- styled-components 처리 반복으로 성능 저하
- 불필요한 DOM 조작 발생
이전 리뷰어(seongwon030)도 스타일 파일로 분리하는 것이 관심사 분리에 더 좋다고 피드백했습니다.
스타일 파일로 이동하세요:
// ApplicationListTab.styles.ts에 추가 export const ActiveListBody = styled(ApplicationList)` border-top-left-radius: 0; `; export const ActiveApplicationRow = styled(ApplicationRowItem)` &:hover { background-color: ${({ theme }) => theme.colors.gray100 ?? '#f8f9fa'}; &:first-child { border-top-right-radius: 20px; } } `;그 후 import하여 사용:
-import styled from 'styled-components'; ... - const ActiveListBody = styled(Styled.ApplicationList)` - border-top-left-radius: 0; - `; - const ActiveApplicationRow = styled(ApplicationRowItem)` - &:hover { - background-color: #f8f9fa; - &:first-child { - border-top-right-radius: 20px; - } - } - `;
🧹 Nitpick comments (2)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (2)
36-47: 삭제 실패 시 에러 처리 누락
deleteApplicationmutation에onError콜백이 없어서 삭제 실패 시 사용자에게 피드백이 제공되지 않습니다.if (window.confirm('지원서 양식을 정말 삭제하시겠습니까?\n삭제된 양식은 복구할 수 없습니다.')) { deleteApplication(applicationFormId, { onSuccess: () => { setOpenMenuId(null); // 성공 알림 alert('삭제되었습니다.'); }, + onError: (error) => { + console.error('지원서 삭제 실패:', error); + alert('삭제에 실패했습니다.'); + }, }); }
126-163: LGTM! 게시된 지원서 섹션 구현조건부 렌더링, 펼쳐보기/접어두기 버튼, 빈 상태 메시지가 잘 구현되어 있습니다. 빈 상태에서 사용자에게 활성화 방법을 안내하는 UX가 좋습니다.
미미한 포맷팅 수정:
- {activeForms.length >0 ? ( + {activeForms.length > 0 ? (
📜 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 (1)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx(6 hunks)
🧰 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/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.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/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
🧠 Learnings (7)
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Break down broad state management into smaller, focused hooks/contexts to reduce coupling
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Separate significantly different conditional UI/logic into distinct components
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Abstract complex logic/interactions into dedicated components/HOCs
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Colocate simple, localized logic or use inline definitions to reduce context switching
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Use Component Composition instead of Props Drilling to reduce coupling
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Choose field-level or form-level cohesion based on form requirements when using form libraries like react-hook-form
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Replace magic numbers with named constants for clarity
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
🔇 Additional comments (5)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (5)
24-25: LGTM! 매직 넘버 대신 명명된 상수 사용
MAX_INITIAL_ITEMS상수를 사용하여 코드의 가독성과 유지보수성을 높였습니다. 코딩 가이드라인에 따른 좋은 구현입니다.
49-61: LGTM! 상태 토글 핸들러 구현try-catch로 에러 처리, 성공 시 쿼리 무효화, 메뉴 닫기 로직이 적절하게 구현되어 있습니다.
70-74: LGTM! 컨텍스트 프리픽스를 활용한 메뉴 키 관리
uniqueKey = ${contextPrefix}-${id}패턴으로 활성 지원서 목록과 학기별 목록 간의 메뉴 ID 충돌을 효과적으로 방지합니다.
103-109: LGTM! 데이터 파생 로직
activeForms필터링과formsToDisplay조건부 슬라이싱 로직이 명확하게 구현되어 있습니다.
182-195: LGTM! 학기별 목록에 토글 콜백 연결됨이전 리뷰에서 지적된
onToggleStatus누락 문제가 해결되었습니다. 이제 학기별 목록과 게시된 지원서 섹션 모두에서 일관된 메뉴 동작이 제공됩니다.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (1)
109-119: 컴포넌트 내부에 정의된 Styled Component는 심각한 성능 문제를 야기합니다.
ActiveListBody와ActiveApplicationRow를 컴포넌트 함수 내부에 정의하면 다음 문제가 발생합니다:
- 매 렌더링마다 재생성: 렌더링할 때마다 새로운 컴포넌트 타입이 생성됩니다
- React reconciliation 실패: React가 이전과 "다른" 컴포넌트로 인식하여 DOM을 불필요하게 재생성합니다
- 상태 손실 위험: 컴포넌트가 unmount/remount되어 내부 상태가 초기화될 수 있습니다
- 관심사 분리: 이전 리뷰에서도 언급되었듯이 스타일은 별도 파일로 분리하는 것이 좋습니다
해결 방법: 이 styled component들을 컴포넌트 외부 또는
ApplicationListTab.styles.ts파일로 이동시켜야 합니다.파일 상단(컴포넌트 외부)으로 이동:
+const ActiveListBody = styled(Styled.ApplicationList)` + border-top-left-radius: 0; +`; + +const ActiveApplicationRow = styled(ApplicationRowItem)` + &:hover { + background-color: #f8f9fa; + &:first-child { + border-top-right-radius: 20px; + } + } +`; + const ApplicationListTab = () => { const {data: allforms, isLoading, isError, error} = useGetApplicationlist(); // ... - const ActiveListBody = styled(Styled.ApplicationList)` - border-top-left-radius: 0; - `; - const ActiveApplicationRow = styled(ApplicationRowItem)` - &:hover { - background-color: #f8f9fa; - &:first-child { - border-top-right-radius: 20px; - } - } - `;또는
ApplicationListTab.styles.ts로 export하여 import하는 방법도 있습니다.As per coding guidelines, 코드 가이드라인에서 명시한 "관심사 분리"와 React 성능 모범 사례를 따라야 합니다.
🧹 Nitpick comments (2)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (2)
47-59: 에러 발생 시에도 메뉴 닫기를 고려하세요.현재 성공 시에만
setOpenMenuId(null)로 메뉴를 닫고 있는데(line 54), 에러 발생 시에도 메뉴를 닫는 것이 일관된 UX를 제공할 수 있습니다. 또한 line 57의alert사용도 앞서 언급한 것처럼 적절한 toast/snackbar 컴포넌트로 대체하는 것이 좋습니다.const handleToggleClick = async (applicationFormId: string, currentStatus: string) => { try { await updateApplicationStatus( applicationFormId, currentStatus ); queryClient.invalidateQueries({ queryKey: ['applicationForm'] }); - setOpenMenuId(null); } catch (error) { console.error('지원서 상태 변경 실패:', error); alert("상태 변경에 실패했습니다."); + } finally { + setOpenMenuId(null); } };
103-103: 문자열 리터럴 'ACTIVE' 대신 상수를 사용하세요.
form.status === 'ACTIVE'비교에서 문자열 리터럴을 직접 사용하면 오타 위험이 있고 유지보수가 어렵습니다. 타입 정의 파일(예:@/types/application.ts)에 상수나 enum을 정의하여 사용하는 것을 권장합니다.타입 파일에 다음과 같이 정의:
export const APPLICATION_STATUS = { ACTIVE: 'ACTIVE', INACTIVE: 'INACTIVE', // ... 기타 상태 } as const;그리고 사용:
-const activeForms = semesterGroups.flatMap(group => group.forms).filter(form => form.status === 'ACTIVE'); +const activeForms = semesterGroups.flatMap(group => group.forms).filter(form => form.status === APPLICATION_STATUS.ACTIVE);
📜 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 (1)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx(5 hunks)
🧰 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/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.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/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
🧠 Learnings (5)
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Break down broad state management into smaller, focused hooks/contexts to reduce coupling
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Separate significantly different conditional UI/logic into distinct components
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Abstract complex logic/interactions into dedicated components/HOCs
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Use Component Composition instead of Props Drilling to reduce coupling
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Colocate simple, localized logic or use inline definitions to reduce context switching
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
🔇 Additional comments (3)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (3)
22-23: 매직 넘버를 상수로 잘 정의했습니다.
MAX_INITIAL_ITEMS상수를 사용하여 초기 표시 개수를 명확하게 표현했습니다. 코드의 의도가 명확하고 유지보수가 용이합니다.
124-161: 게시된 지원서 섹션이 잘 구현되었습니다.
- 빈 상태(empty state) 처리가 명확하고 사용자 친화적입니다 (lines 151-160)
- 확장/축소 기능이 직관적이며, 남은 개수를 표시하여 UX가 좋습니다 (line 146)
ApplicationRowItem컴포넌트에 필요한 모든 핸들러와 props가 올바르게 전달되었습니다다만 앞서 지적한
ActiveApplicationRowstyled component의 정의 위치 문제만 해결하면 완벽합니다.
180-193: ApplicationRowItem 사용으로 일관성 있는 구현을 달성했습니다.이전 리뷰에서 지적되었던 상단 "게시된 지원서" 섹션과 하단 학기별 리스트의
ApplicationMenu동작 불일치 문제가 해결되었습니다. 이제 두 섹션 모두ApplicationRowItem을 사용하고onToggleStatus핸들러를 전달하여 일관된 동작을 제공합니다.다만 line 184의
application.status === 'ACTIVE'역시 앞서 언급한 것처럼 문자열 리터럴 대신 상수를 사용하는 것이 좋습니다.
| const handleDeleteApplication = (applicationFormId: string) => { | ||
| // 사용자에게 재확인 | ||
| if (window.confirm('지원서 양식을 정말 삭제하시겠습니까?\n삭제된 양식은 복구할 수 없습니다.')) { | ||
| deleteApplication(applicationFormId, { | ||
| onSuccess: () => { | ||
| setOpenMenuId(null); | ||
| // 성공 알림 | ||
| alert('삭제되었습니다.'); | ||
| }, | ||
| }); | ||
| } | ||
| }; |
There was a problem hiding this comment.
window.confirm과 alert 사용은 UX를 저해합니다.
window.confirm과 alert는 브라우저의 기본 다이얼로그로, 다음과 같은 문제가 있습니다:
- UI를 완전히 차단하여 사용자 경험을 해칩니다
- 스타일링이 불가능하여 애플리케이션 디자인과 일관성이 없습니다
- 접근성(a11y) 측면에서 좋지 않습니다
적절한 모달/다이얼로그 컴포넌트(예: React Portal 기반 Dialog)를 사용하는 것을 권장합니다.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (4)
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx (2)
31-42:window.confirm과alert사용에 대한 UX 개선 고려.
- 이전 리뷰에서 이미 논의되었습니다. 커스텀 모달/다이얼로그 컴포넌트로 대체하면 일관된 디자인과 더 나은 사용자 경험을 제공할 수 있습니다.
106-116: styled-components를 컴포넌트 함수 외부로 이동하세요 - 성능 문제.
styled()호출이 컴포넌트 본문 내부에 있으면 매 렌더링마다 새로운 컴포넌트가 생성되어 다음 문제가 발생합니다:
- React가 컴포넌트를 매번 새로운 것으로 인식하여 불필요한 언마운트/마운트 발생
- 기존 DOM 노드 재사용 불가로 성능 저하
- 하위 컴포넌트의 상태 손실 가능
스타일 파일로 이동하거나, 최소한 컴포넌트 함수 외부에 정의해야 합니다:
+// 컴포넌트 외부에 정의 +const ActiveListBody = styled(Styled.ApplicationList)` + border-top-left-radius: 0; +`; + +const ActiveApplicationRow = styled(ApplicationRowItem)` + &:hover { + background-color: #F2F2F2; + &:first-child { + border-top-right-radius: 20px; + } + } +`; const ApplicationListTab = () => { // ... - const ActiveListBody = styled(Styled.ApplicationList)` - border-top-left-radius: 0; - `; - const ActiveApplicationRow = styled(ApplicationRowItem)` - &:hover { - background-color: #F2F2F2; - &:first-child { - border-top-right-radius: 20px; - } - } - `;
- 이전 리뷰에서 스타일 파일로 이동하라는 제안이 있었으나, 이 코멘트는 성능 문제에 초점을 맞춥니다.
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (2)
30-41:window.confirm과alert사용에 대한 UX 개선 고려.
- 이전 리뷰에서 이미 논의되었습니다.
105-115: Move styled-components outside the component body to prevent recreation on every render—performance issue.Lines 105-115 define
ActiveListBodyandActiveApplicationRowinside the component function. These are re-created on every render (whenisExpandedoropenMenuIdchanges), causing unnecessary component recreations. Move these styled definitions outside the component or to a.styles.tsfile, matching the pattern used elsewhere in the codebase (e.g.,ApplicationListTab.styles.ts).Additionally, the hover background color
#f8f9fadiffers from the same component structure inApplicationListTab.tsx, which uses#F2F2F2. Verify whether this color difference is intentional or should be standardized for consistency.
🧹 Nitpick comments (3)
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx (1)
21-22: 상수를 컴포넌트 외부로 이동하세요.
MAX_INITIAL_ITEMS는 컴포넌트 내부에서 변경되지 않는 상수이므로, 컴포넌트 외부(파일 상단)로 이동하는 것이 좋습니다. 매 렌더링마다 불필요하게 재정의됩니다.+const MAX_INITIAL_ITEMS = 3; + const ApplicationListTab = () => { const { data: allforms, isLoading, isError, error } = useGetApplicationlist(); const queryClient = useQueryClient(); const navigate = useNavigate(); const { mutate: deleteApplication } = useDeleteApplication(); const [isExpanded, setIsExpanded] = useState(false); - const MAX_INITIAL_ITEMS = 3;Based on learnings, 코딩 가이드라인에 따라 매직 넘버는 명확성을 위해 명명된 상수로 대체하고, 관련 로직 근처에 정의하거나 명확하게 연결되도록 해야 합니다.
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (2)
21-21: 상수를 컴포넌트 외부로 이동하세요.
MAX_INITIAL_ITEMS를 컴포넌트 함수 외부로 이동하세요. ApplicationListTab.tsx와 동일한 이유입니다.Based on learnings, 코딩 가이드라인에 따라 매직 넘버는 명명된 상수로 대체해야 합니다.
15-68: 두 파일 간 상당한 코드 중복이 있습니다.
ApplicationListTab.tsx와ApplicantsListTab.tsx가 거의 동일한 로직을 공유합니다:
- 상태 관리 (
isExpanded,openMenuId)- 핸들러 함수들 (
handleDeleteApplication,handleToggleClick,handleMenuToggle,handleToggleExpand)- 외부 클릭 감지 useEffect
공통 로직을 커스텀 훅으로 추출하는 것을 고려해보세요:
// useApplicationListState.ts 예시 export const useApplicationListState = () => { const [isExpanded, setIsExpanded] = useState(false); const [openMenuId, setOpenMenuId] = useState<string | null>(null); const menuRef = useRef<HTMLDivElement | null>(null); const handleToggleExpand = () => setIsExpanded(prev => !prev); const handleMenuToggle = (e: React.MouseEvent, id: string, contextPrefix: string) => { e.stopPropagation(); const uniqueKey = `${contextPrefix}-${id}`; setOpenMenuId(openMenuId === uniqueKey ? null : uniqueKey); }; // ... useEffect for outside click return { isExpanded, openMenuId, menuRef, handleToggleExpand, handleMenuToggle, setOpenMenuId }; };Based on learnings, 광범위한 상태 관리를 더 작고 집중된 훅/컨텍스트로 분리하여 결합도를 줄이세요.
📜 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/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx(4 hunks)frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx(4 hunks)
🧰 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/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.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/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
🧠 Learnings (6)
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Break down broad state management into smaller, focused hooks/contexts to reduce coupling
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Separate significantly different conditional UI/logic into distinct components
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Colocate simple, localized logic or use inline definitions to reduce context switching
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Use Component Composition instead of Props Drilling to reduce coupling
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Replace magic numbers with named constants for clarity
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
📚 Learning: 2025-11-25T14:08:23.234Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.234Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Abstract complex logic/interactions into dedicated components/HOCs
Applied to files:
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx
🧬 Code graph analysis (1)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (4)
frontend/src/hooks/queries/application/useGetApplicationlist.ts (1)
useGetApplicationlist(4-10)frontend/src/hooks/queries/application/useDeleteApplication.ts (1)
useDeleteApplication(4-19)frontend/src/apis/application/updateApplication.ts (1)
updateApplicationStatus(33-58)frontend/src/types/application.ts (2)
SemesterGroup(77-81)ApplicationFormItem(70-75)
🔇 Additional comments (5)
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx (3)
100-104: LGTM!
activeForms필터링 및formsToDisplay슬라이싱 로직이 명확하고 적절합니다. 확장/축소 상태에 따른 표시 항목 제어가 잘 구현되어 있습니다.
118-158: ActiveList 섹션 구현이 잘 되어 있습니다.게시된 지원서 목록과 빈 상태 메시지 처리가 적절하게 구현되어 있습니다. 확장 버튼과 남은 항목 수 표시도 UX 요구사항에 부합합니다.
164-192: 학기 그룹별 렌더링이 잘 구현되어 있습니다.
groupUniqueKeyPrefix를 활용한 고유 키 생성으로 그룹 간 메뉴 충돌을 방지합니다.ApplicationRowItem으로의 리팩토링이 코드 재사용성을 높입니다.frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx (2)
117-157: ActiveList 섹션 구현이 잘 되어 있습니다.ApplicationListTab.tsx와 일관된 방식으로 게시된 지원서 목록을 렌더링합니다.
163-192: 학기 그룹별 렌더링이 적절합니다.
ApplicationRowItem컴포넌트를 활용한 렌더링과 고유 키 생성이 잘 구현되어 있습니다.
#️⃣연관된 이슈
📝작업 내용
대표 지원서 -> 게시된 지원서로 문구 변경
게시된 지원서가 4개 이상일경우 펼쳐보기 칸 생성
3개 이하일 경우
중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
릴리스 노트
새로운 기능
개선 사항
✏️ Tip: You can customize this high-level summary in your review settings.