Conversation
- duplicateApplication API 함수 구현 - useDuplicateApplication TanStack Query 훅 추가
- '제목 수정하기' 메뉴를 '지원서 복제하기'로 변경 - onDuplicate prop 추가 및 핸들러 연결 - 불필요한 React import 제거
- onDuplicate prop 추가 및 ApplicationMenu에 전달
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | 변경 요약 |
|---|---|
API 및 데이터 계층 frontend/src/apis/application/duplicateApplication.ts, frontend/src/hooks/queries/application/useDuplicateApplication.ts |
새로운 POST 엔드포인트 호출 함수와 useMutation 기반 훅 추가. 성공 시 applicationForm 쿼리 무효화 |
UI 컴포넌트 - 소품 추가 frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsx, frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx |
ApplicationRowItem과 ApplicationMenu에 onDuplicate 콜백 소품 추가 및 전달 |
UI 컴포넌트 - 통합 및 핸들링 frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx |
useDuplicateApplication 훅 통합, 복제 핸들러 구현, Active/grouped 목록 항목에 onDuplicate 연결 및 MAX_INITIAL_ITEMS 상수화 |
Estimated code review effort
🎯 2 (Simple) | ⏱️ ~12 minutes
Possibly related issues
- MOA-499: 동아리 지원서 복제 버튼 추가 — 이 PR이 요청된 지원서 관리에서의 복제 기능 구현을 완료합니다.
Possibly related PRs
- [feat] 동아리 지원자 양식 복제 기능 추가 #1020: 백엔드의 POST /api/club/application/{applicationFormId}/duplicate 엔드포인트 구현과 직접 대응하는 프론트엔드 API 호출입니다.
- [feature] 지원서 목록 페이지 생성 #772: ApplicationListTab과 ApplicationMenu 컴포넌트의 기초 구조를 제공하며, 이 PR에서 복제 기능으로 확장됩니다.
- [refactor] 선택한 지원서 양식 id 새로고침해도 저장된다 #902: ApplicationListTab, ApplicationMenu, ApplicationRowItem 등 동일한 UI 파일들을 수정하며 복제 작업을 추가합니다.
Suggested labels
📬 API
Suggested reviewers
- oesnuj
- suhyun113
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | ✅ Passed | PR 제목 '[feature] 지원서 복제 기능 구현'은 변경 사항의 핵심을 명확하게 설명하고 있으며, 추가된 중복 복제 기능을 직접적으로 반영하고 있습니다. |
| Linked Issues check | ✅ Passed | PR이 MOA-499의 모든 요구사항을 충족하고 있습니다: (1) ApplicationMenu에서 '제목 수정하기' 버튼을 '지원서 복제하기'로 교체, (2) duplicateApplication API 구현 및 useDuplicateApplication 훅을 통한 API 연동. |
| Out of Scope Changes check | ✅ Passed | 모든 변경 사항이 MOA-499의 요구사항 범위 내에 있으며, 문제 해결을 위한 필요한 기능들만 포함되어 있습니다. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing touches
- 📝 Generate docstrings
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: 2
🤖 Fix all issues with AI agents
In @frontend/src/apis/application/duplicateApplication.ts:
- Around line 16-17: The code returns result.data without validating the parsed
JSON; update the duplicateApplication flow to validate the response and shape
before returning: after const result = await response.json() check response.ok
and that result is an object with a defined data property (e.g., result &&
typeof result === 'object' && 'data' in result); if validation fails throw a
descriptive error or return a safe default, and include the response status/text
in the error for easier debugging.
In @frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx:
- Around line 33-35: The MenuItem currently renders unconditionally with
onClick={onDuplicate} which can be undefined; update the component so it either
(a) only renders the Duplicate menu item when the prop onDuplicate is provided
(conditional render using the prop), or (b) renders a visually disabled MenuItem
when onDuplicate is undefined (add a disabled state/aria-disabled, remove or
noop the onClick handler, and apply disabled styling), targeting Styled.MenuItem
and the onDuplicate prop (keep Styled.MenuIcon and Pencil as-is).
🧹 Nitpick comments (6)
frontend/src/apis/application/duplicateApplication.ts (1)
4-4: 반환 타입을 명시하세요.함수의 반환 타입이 명시되지 않았습니다. 타입 안전성을 높이기 위해 반환 타입을 추가하는 것이 좋습니다.
♻️ 제안하는 수정
복제된 지원서의 타입을 정의하고 반환 타입에 명시하세요:
-export const duplicateApplication = async (applicationFormId: string) => { +export const duplicateApplication = async (applicationFormId: string): Promise<any> => {더 나은 방법으로, 실제 반환 데이터의 타입을 정의하여 사용하세요.
코딩 가이드라인: "Use consistent return types for similar functions/hooks"에 따라 명확한 반환 타입을 지정하는 것이 좋습니다.
frontend/src/hooks/queries/application/useDuplicateApplication.ts (1)
4-19: 훅의 반환 타입을 명시하세요.
useDuplicateApplication훅의 반환 타입이 명시되지 않았습니다. 타입 안전성과 IDE 자동완성을 개선하기 위해 반환 타입을 추가하는 것이 좋습니다.♻️ 제안하는 수정
+import { UseMutationResult } from '@tanstack/react-query'; + -export const useDuplicateApplication = () => { +export const useDuplicateApplication = (): UseMutationResult<any, Error, string> => {코딩 가이드라인: "Use consistent return types for similar functions/hooks"에 따라 다른 훅들과 일관되게 반환 타입을 지정하는 것이 좋습니다.
frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsx (1)
17-17:ApplicationMenu와의 타입 일관성을 확인하세요.
ApplicationRowItem에서onDuplicate는 필수 prop으로 정의되어 있지만,ApplicationMenu에서는onDuplicate?: () => void로 선택적 prop으로 정의되어 있습니다.타입 일관성을 위해 두 컴포넌트에서 동일한 선택성(required vs optional)을 사용하는 것이 좋습니다. 현재 구조에서는
ApplicationRowItem이 항상onDuplicate를 제공하므로ApplicationMenu에서도 필수로 만들거나, 또는ApplicationRowItem에서 선택적으로 만들어 유연성을 높일 수 있습니다.♻️ 제안하는 수정 (선택적으로 만드는 경우)
- onDuplicate: (id: string) => void; + onDuplicate?: (id: string) => void;그리고 line 80에서:
- onDuplicate={() => onDuplicate(application.id)} + onDuplicate={onDuplicate ? () => onDuplicate(application.id) : undefined}frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx (1)
34-34: 복제 작업에 적합한 아이콘을 사용하세요.현재 연필(
Pencil) 아이콘을 사용하고 있는데, 이는 일반적으로 "편집" 작업을 나타냅니다. "복제" 작업에는 복사(copy) 또는 복제(duplicate) 아이콘을 사용하는 것이 사용자 경험 측면에서 더 직관적입니다.💡 제안
복제를 나타내는 아이콘(예: Copy 아이콘)을 import하여 사용하세요:
+import Copy from '@/assets/images/icons/copy_icon.svg'; import Pencil from '@/assets/images/icons/pencil_icon_3.svg'; - <Styled.MenuIcon src={Pencil} /> 지원서 복제하기 + <Styled.MenuIcon src={Copy} /> 지원서 복제하기(적절한 복제 아이콘이 없다면 디자인 팀에 요청하거나, 기존 아이콘을 그대로 사용하되 추후 개선하는 것을 고려하세요.)
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx (2)
53-63: 사용자 피드백을 토스트 알림으로 개선하세요.
alert()를 사용한 사용자 피드백은 페이지를 차단하며 현대적인 UX 패턴이 아닙니다. 토스트(toast) 알림 시스템을 사용하는 것이 더 나은 사용자 경험을 제공합니다.💡 제안하는 개선
토스트 라이브러리(예: react-toastify, sonner 등)를 사용하거나, 프로젝트에 이미 토스트 컴포넌트가 있다면 그것을 활용하세요:
+import { toast } from '@/components/common/Toast'; // 또는 사용 중인 토스트 라이브러리 const handleDuplicateApplication = (applicationFormId: string) => { duplicateApplication(applicationFormId, { onSuccess: () => { setOpenMenuId(null); - alert('지원서가 성공적으로 복제되었습니다.'); + toast.success('지원서가 성공적으로 복제되었습니다.'); }, onError: () => { - alert('지원서 복제에 실패했습니다.'); + toast.error('지원서 복제에 실패했습니다.'); }, }); };참고: 동일한 개선을
handleDeleteApplication의onError(line 47)에도 적용할 수 있습니다.
53-63: 로딩 상태 처리를 고려하세요.복제 작업 중 사용자에게 진행 상태를 알려주는 로딩 인디케이터가 없습니다. 네트워크가 느린 경우 사용자가 작업이 진행 중인지 알 수 없습니다.
💡 제안하는 개선
useDuplicateApplication훅에서 제공하는isPending상태를 활용하여 로딩 상태를 표시할 수 있습니다:- const { mutate: duplicateApplication } = useDuplicateApplication(); + const { mutate: duplicateApplication, isPending: isDuplicating } = useDuplicateApplication();그리고 UI에 로딩 상태를 반영:
- 메뉴 아이템을 비활성화
- 로딩 스피너 표시
- 또는 전역 로딩 인디케이터 사용
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
frontend/src/apis/application/duplicateApplication.tsfrontend/src/hooks/queries/application/useDuplicateApplication.tsfrontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx
🧰 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/components/ApplicationRow/ApplicationRowItem.tsxfrontend/src/apis/application/duplicateApplication.tsfrontend/src/hooks/queries/application/useDuplicateApplication.tsfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsxfrontend/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/components/ApplicationRow/ApplicationRowItem.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.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/components/ApplicationRow/ApplicationRowItem.tsxfrontend/src/apis/application/duplicateApplication.tsfrontend/src/hooks/queries/application/useDuplicateApplication.tsfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx
🧠 Learnings (1)
📚 Learning: 2025-05-19T05:45:52.957Z
Learnt from: lepitaaar
Repo: Moadong/moadong PR: 406
File: backend/src/main/java/moadong/club/service/ClubApplyService.java:34-38
Timestamp: 2025-05-19T05:45:52.957Z
Learning: The code duplication between createClubApplication and editClubApplication methods in ClubApplyService.java is acknowledged but will be addressed in a future refactoring, as per the developer's plan.
Applied to files:
frontend/src/apis/application/duplicateApplication.ts
🧬 Code graph analysis (2)
frontend/src/apis/application/duplicateApplication.ts (1)
frontend/src/apis/auth/secureFetch.ts (1)
secureFetch(3-41)
frontend/src/hooks/queries/application/useDuplicateApplication.ts (1)
frontend/src/apis/application/duplicateApplication.ts (1)
duplicateApplication(4-22)
🔇 Additional comments (5)
frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsx (1)
80-80: 코드 변경사항이 올바르게 구현되었습니다.
onDuplicateprop이ApplicationMenu에 올바르게 전달되고 있으며, 클로저를 통해application.id가 정확히 바인딩되어 있습니다.frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationListTab.tsx (3)
17-17: 상수 추출이 잘 되었습니다.매직 넘버를 모듈 레벨의 명명된 상수로 추출하여 가독성과 유지보수성이 향상되었습니다.
코딩 가이드라인: "Replace magic numbers with named constants for clarity"를 잘 따르고 있습니다.
46-48: 삭제 실패 시 에러 핸들링이 추가되었습니다.
onError콜백을 추가하여 삭제 실패 시 사용자에게 피드백을 제공하도록 개선되었습니다. 좋은 개선사항입니다.참고: 앞서 언급한 것처럼
alert()대신 토스트 알림을 사용하면 더 나은 UX를 제공할 수 있습니다.
166-166: 복제 핸들러가 올바르게 연결되었습니다.
handleDuplicateApplication이 활성 목록과 그룹 목록의 모든ApplicationRowItem에 올바르게 전달되고 있습니다. 다른 핸들러들과 일관된 패턴을 따르고 있습니다.Also applies to: 223-223
frontend/src/hooks/queries/application/useDuplicateApplication.ts (1)
11-13: 쿼리 키 구조의 일관성을 조정하세요.
useDuplicateApplication에서['applicationForm']으로 무효화할 때, 실제로는 다음과 같은 쿼리 키들이 사용 중입니다:
useGetApplicationlist:['applicationForm']useGetApplication:['applicationForm', clubId, applicationFormId]useDeleteApplication: 역시['applicationForm']로 무효화React Query의 prefix 매칭 방식으로 인해 현재 코드는 함수적으로 작동하지만, 쿼리 키 구조가 일관성이 없습니다. 목록 조회와 상세 조회의 쿼리 키 구조를 명확하게 정의하거나, 모든 관련 쿼리 키를 문서화하여 의도를 명확히 하세요.
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx
Show resolved
Hide resolved
- TOGGLE_BUTTON_TEXT 상수 객체로 추출 - 가독성 및 유지보수성 향상
- 재사용 가능한 유틸 함수로 추출 - 단위 테스트 추가 - ApplicationRowItem 코드 간소화
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/components/ApplicationRow/ApplicationRowItem.tsx (1)
7-18:ApplicantsListTab.tsx에서onDuplicateprop이 누락되었습니다.
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsListTab/ApplicantsListTab.tsx라인 198-209의<ApplicationRowItem>컴포넌트 호출부에onDuplicateprop을 전달해야 합니다. 현재onDelete까지만 전달되고 있어 필수 prop 부재로 인한 타입 에러가 발생합니다.현재 상태 (ApplicantsListTab.tsx)
<ApplicationRowItem key={application.id} application={application} isActive={application.status === 'ACTIVE'} uniqueKeyPrefix={groupUniqueKeyPrefix} openMenuId={openMenuId} menuRef={menuRef} onEdit={handleGoToDetailForm} onMenuToggle={handleMenuToggle} onToggleStatus={handleToggleClick} onDelete={handleDeleteApplication} // onDuplicate prop 누락 ← 필수 추가 />또한
useDuplicateApplication훅을 import 및 호출하여 duplicate 기능을 구현해야 합니다 (ApplicationListTab.tsx와 유사하게).
🤖 Fix all issues with AI agents
In @frontend/src/utils/formatRelativeDateTime.ts:
- Around line 6-18: The function formatRelativeDateTime should guard against
empty or invalid dateTimeString inputs: before using date.toLocaleString, check
if dateTimeString is falsy or if new Date(dateTimeString) yields an invalid Date
(isNaN(date.getTime())), and in that case return a safe fallback (e.g. empty
string or '-' ) instead of letting "Invalid Date" reach the UI; keep the
existing logic for computing isToday and options unchanged and only add the
validation early in formatRelativeDateTime around the date/dateTimeString
handling.
🧹 Nitpick comments (2)
frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsx (1)
46-49:application.editedAt비어있음/비정상 값일 때 표시가 깨질 수 있어 fallback 고려✅ 제안 수정(diff)
<Styled.ApplicationDate> - {formatRelativeDateTime(application.editedAt)} + {application.editedAt + ? formatRelativeDateTime(application.editedAt) + : '-'} </Styled.ApplicationDate>frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx (1)
12-17:onDuplicate가 optional인데 메뉴는 항상 노출되어 “눌러도 아무 반응 없음” 상태가 될 수 있습니다.
둘 중 하나를 추천합니다: (1)onDuplicate를 required로 변경, 또는 (2) 핸들러 없으면 메뉴 아이템을 숨김.✅ 옵션(2): 조건부 렌더링(diff)
interface ApplicationMenuProps { isActive: boolean; onDelete: () => void; onToggleStatus?: () => void; onDuplicate?: () => void; } @@ <Styled.Separator /> - <Styled.MenuItem onClick={onDuplicate}> - <Styled.MenuIcon src={Pencil} /> 지원서 복제하기 - </Styled.MenuItem> + {onDuplicate && ( + <Styled.MenuItem onClick={onDuplicate}> + <Styled.MenuIcon src={Pencil} /> 지원서 복제하기 + </Styled.MenuItem> + )} <Styled.MenuItem onClick={onDelete} className='delete'>Also applies to: 40-42
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsxfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsxfrontend/src/utils/formatRelativeDateTime.test.tsfrontend/src/utils/formatRelativeDateTime.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/utils/formatRelativeDateTime.tsfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsxfrontend/src/utils/formatRelativeDateTime.test.tsfrontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsx
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/utils/formatRelativeDateTime.tsfrontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsxfrontend/src/utils/formatRelativeDateTime.test.tsfrontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.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/ApplicationMenu.tsxfrontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsx
🧬 Code graph analysis (2)
frontend/src/utils/formatRelativeDateTime.test.ts (1)
frontend/src/utils/formatRelativeDateTime.ts (1)
formatRelativeDateTime(6-19)
frontend/src/pages/AdminPage/components/ApplicationRow/ApplicationRowItem.tsx (1)
frontend/src/utils/formatRelativeDateTime.ts (1)
formatRelativeDateTime(6-19)
🔇 Additional comments (4)
frontend/src/utils/formatRelativeDateTime.ts (1)
9-18: “오늘” 판단 기준(timezone)이 서비스 기대와 일치하는지 확인 필요
서버가 UTC(Z)로 내려주거나 사용자가 다른 timezone이면 “오늘/과거” 분기가 의도와 다를 수 있어요(특히 자정 근처).frontend/src/utils/formatRelativeDateTime.test.ts (2)
3-99: 케이스 커버리지 구성이 깔끔합니다(오늘/과거/미래/경계).
4-10:jest.setSystemTime가 동작하는 “modern fake timers” 설정인지 확인 필요
프로젝트 설정이 legacy timers면 해당 API가 기대대로 동작하지 않을 수 있습니다.Also applies to: 14-18
frontend/src/pages/AdminPage/tabs/ApplicationListTab/ApplicationMenu.tsx (1)
7-10: 토글 텍스트 상수화는 유지보수에 도움 됩니다.Also applies to: 25-28
| export const formatRelativeDateTime = (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); |
There was a problem hiding this comment.
Invalid Date 입력/파싱 실패 케이스를 UI로 노출할 수 있어 가드가 있으면 좋겠습니다.
현재 dateTimeString가 빈 값/비정상 값이면 toLocaleString 결과가 그대로 노출될 수 있습니다(UX 이슈).
✅ 제안 수정(diff)
export const formatRelativeDateTime = (dateTimeString: string): string => {
const now = new Date();
const date = new Date(dateTimeString);
+ if (Number.isNaN(date.getTime())) return '-';
+
const isToday =
now.getFullYear() === date.getFullYear() &&
now.getMonth() === date.getMonth() &&
now.getDate() === date.getDate();📝 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 formatRelativeDateTime = (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); | |
| export const formatRelativeDateTime = (dateTimeString: string): string => { | |
| const now = new Date(); | |
| const date = new Date(dateTimeString); | |
| if (Number.isNaN(date.getTime())) return '-'; | |
| 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); | |
| }; |
🤖 Prompt for AI Agents
In @frontend/src/utils/formatRelativeDateTime.ts around lines 6 - 18, The
function formatRelativeDateTime should guard against empty or invalid
dateTimeString inputs: before using date.toLocaleString, check if dateTimeString
is falsy or if new Date(dateTimeString) yields an invalid Date
(isNaN(date.getTime())), and in that case return a safe fallback (e.g. empty
string or '-' ) instead of letting "Invalid Date" reach the UI; keep the
existing logic for computing isToday and options unchanged and only add the
validation early in formatRelativeDateTime around the date/dateTimeString
handling.
lepitaaar
left a comment
There was a problem hiding this comment.
복제하기 추가 뿐아니라 전체적인 코드 리팩토링 잘봤습니다
| <Styled.MenuItem onClick={onEditTitle}> | ||
| <Styled.MenuIcon src={Pencil} /> 제목 수정하기 | ||
| <Styled.MenuItem onClick={onDuplicate}> | ||
| <Styled.MenuIcon src={Pencil} /> 지원서 복제하기 |
There was a problem hiding this comment.
임시로 변경한거라 아이콘이 Pencil인데 이것도 추가로 변경하면좋을꺼같습니다
| const TOGGLE_BUTTON_TEXT = { | ||
| ACTIVE: '지원서 비활성화', | ||
| INACTIVE: '지원서 활성화', | ||
| } as const; | ||
|
|
| @@ -39,13 +42,26 @@ const ApplicationListTab = () => { | |||
| deleteApplication(applicationFormId, { | |||
| onSuccess: () => { | |||
| setOpenMenuId(null); | |||
There was a problem hiding this comment.
혹시 성공 alert를 삭제하신 이유가뭘까요?
#️⃣연관된 이슈
📝작업 내용
2026-01-11.11.09.37.mov
1. API 및 훅 구현
POST /api/club/application/{id}/duplicate엔드포인트 호출useDuplicateApplicationtanstack 훅 구현2. UI 연결
onDuplicateprop 추가 및 메뉴에 전달3. 개선사항
4. 유틸 함수 개선
중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
릴리스 노트
New Features
Tests
✏️ Tip: You can customize this high-level summary in your review settings.