-
Notifications
You must be signed in to change notification settings - Fork 2
✨ Feat: create card modal 카드 생성 모달 구현 #82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
✨ Feat: create card modal 카드 생성 모달 구현 #82
Conversation
- UI, 기능 적용. 완성도 80% - 폴더 구조 변경
-폼데이터의 디폴트값을 빈 문자열로 설정 - onSubmit함수에서는 해당 란을 제외한 데이터를 보냄. (빈 문자열로 디폴트값 설정 안하면, 기본 파일리스트 객체가 전달되기 때문에 이미지 URL이 있는지 참,거짓 측정이 불가함)
Walkthrough이 변경사항은 대시보드 상세 페이지의 카드 및 컬럼 관리 기능을 대폭 확장하고, 관련 API 훅, 타입, 저장소, 컴포넌트들을 Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant DashboardPage
participant Column
participant CreateCardModal
participant CreateCardForm
participant API
User->>DashboardPage: 대시보드 상세 진입
DashboardPage->>Column: 컬럼/카드 데이터 로드
User->>Column: "카드 추가" 클릭
Column->>CreateCardModal: 모달 오픈
CreateCardModal->>CreateCardForm: 카드 생성 폼 렌더
User->>CreateCardForm: 폼 입력/담당자/태그/이미지 선택
CreateCardForm->>API: 이미지 업로드 (선택 시)
API-->>CreateCardForm: 이미지 URL 반환
User->>CreateCardForm: 제출 클릭
CreateCardForm->>API: 카드 생성 요청
API-->>CreateCardForm: 생성 성공 응답
CreateCardForm->>Column: 모달 닫기, 카드 목록 갱신
sequenceDiagram
participant User
participant Column
participant Card
participant useDragStore
participant API
User->>Card: 카드 드래그 시작
Card->>useDragStore: draggingCard 상태 저장
User->>Column: 카드 드롭
Column->>useDragStore: draggingCard 상태 확인
Column->>API: 카드 컬럼 이동 요청
API-->>Column: 이동 성공 응답
Column->>useDragStore: draggingCard 상태 초기화
Column->>Column: 카드 목록 갱신
Possibly related PRs
Suggested labels
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
npm error Exit handler never called! ✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 19
🔭 Outside diff range comments (1)
src/app/dashboard/[id]/page.tsx (1)
26-124: 드래그 앤 드롭 로직이 복잡하므로 별도 훅으로 분리를 고려해주세요.터치 이벤트 핸들링 로직이 매우 복잡하고 컴포넌트를 무겁게 만들고 있습니다.
useDragAndDrop같은 커스텀 훅으로 분리하는 것을 고려해보세요. 또한 한국어 주석들을 영어로 통일해주세요.주석 언어 통일 예시:
- // 1. 터치 대상 찾기 + // 1. Find touch target - // 2. 카드 영역 내 터치 좌표 계산 (저장) + // 2. Calculate and store touch coordinates within card area
🧹 Nitpick comments (17)
src/app/shared/lib/testAxios.ts (1)
3-5: 임시 파일의 정리 계획을 확인해주세요.변수명 변경과 URL 업데이트는 적절하지만, PR 목표에서 언급한 대로 이 파일이 임시 테스트용이라면 향후 정리 계획을 추적하는 것이 좋겠습니다.
Also applies to: 10-10, 18-18
src/app/features/dashboard_Id/api/fetchColumns.ts (1)
7-9: 환경 변수 유효성 검사 추가를 고려해보세요.dashboardId는 검증하지만
process.env.NEXT_PUBLIC_TEAM_ID에 대한 검증은 없습니다. 환경 변수가 설정되지 않았을 경우 런타임 에러가 발생할 수 있습니다.export async function fetchColumns(dashboardId: number): Promise<Column[]> { if (!dashboardId) { throw new Error('dashboardId가 유효하지 않습니다.') } + + if (!process.env.NEXT_PUBLIC_TEAM_ID) { + throw new Error('NEXT_PUBLIC_TEAM_ID가 설정되지 않았습니다.') + }src/app/features/dashboard_Id/api/usePostCard.ts (1)
13-13: 쿼리 키를 더 구체적으로 만드는 것을 고려해보세요.현재
['columnId']로 모든 컬럼 관련 쿼리를 무효화하고 있습니다. 특정 대시보드의 카드만 무효화하도록 더 구체적인 키를 사용하는 것이 좋을 것 같습니다.- queryClient.invalidateQueries({ queryKey: ['columnId'] }) + queryClient.invalidateQueries({ queryKey: ['cards', dashboardId] })이렇게 하려면
dashboardId를 훅의 매개변수로 받아야 합니다.src/app/features/dashboard_Id/api/useColumns.ts (1)
6-6: export 방식의 일관성을 고려해보세요.다른 API 함수들은 named export를 사용하고 있는데, 이 훅만 default export를 사용하고 있습니다. 프로젝트의 일관성을 위해 named export 사용을 고려해보세요.
-export default function useColumns(dashboardId: number) { +export function useColumns(dashboardId: number) {src/app/features/dashboard_Id/api/fetchMembers.ts (1)
6-11: 입력 검증 추가를 고려해보세요.
fetchColumns함수와 달리 이 함수는dashboardId검증이 없습니다. 일관성을 위해 동일한 검증 로직을 추가하는 것이 좋겠습니다.export async function fetchMembers(dashboardId: number): Promise<Member[]> { + if (!dashboardId) { + throw new Error('dashboardId가 유효하지 않습니다.') + } + const res = await api.get<MembersResponse>(src/app/features/dashboard_Id/api/postCardImage.ts (1)
4-7: 함수명이 복수형이지만 단일 파일을 처리합니다.함수명
postCardImages는 복수형이지만 실제로는 하나의 파일만 처리합니다. 일관성을 위해 단수형으로 변경하는 것이 좋습니다.-export async function postCardImages( +export async function postCardImage(src/app/features/dashboard_Id/api/updateCardColumn.ts (1)
11-13: 객체 프로퍼티 축약형을 사용하세요.
columnId: columnId는 중복입니다. ES6 축약형을 사용할 수 있습니다.`/${process.env.NEXT_PUBLIC_TEAM_ID}/cards/${cardId}`, { - columnId: columnId, + columnId, },src/app/features/dashboard_Id/api/useCards.ts (1)
1-1: 주석 언어 일관성을 맞춰주세요.영문 코드베이스에서는 주석도 영어로 작성하는 것이 일관성 측면에서 좋습니다.
-//size일단 10으로 하고, 나중에 커서아이디 받아서 무한 스크롤 구현해야 함. +// TODO: Implement infinite scrolling with cursor ID, currently using fixed size of 10src/app/features/dashboard_Id/lib/getDashboardMembers.ts (1)
8-10: 주석 언어 일관성과 반환 타입 명시를 개선해주세요.영문 코드베이스에서는 주석도 영어로 작성하고, 함수의 반환 타입을 명시하는 것이 좋습니다.
-// 서버에서 받아온 Member 객체 배열을 Assignee 배열로 가공 -// → 불필요한 필드는 제거하고 필요한 userId, nickname만 추출 -export default function getDashboardMembers(data: Member[] | undefined) { +// Transform Member array to Assignee array, extracting only required fields +export default function getDashboardMembers(data: Member[] | undefined): Assignee[] {src/app/dashboard/[id]/page.tsx (1)
130-132: 하드코딩된 마진 값을 개선해주세요.
ml-300같은 하드코딩된 값들은 사이드바 상태에 따라 동적으로 조정되어야 합니다.- <div className="ml-300 select-none"> + <div className={`${isSidebarOpen ? 'ml-300' : 'ml-0'} select-none transition-all duration-300`}>src/app/features/dashboardId/Card/cardFormModals/AssigneeList.tsx (1)
21-21: 디버깅 코드 제거 필요프로덕션 코드에서 console.log 문을 제거해야 합니다.
src/app/features/dashboard_Id/Card/cardFormModals/input/Input.tsx (1)
2-7: 인터페이스명을 더 구체적으로 변경 권장
Input이라는 인터페이스명이 너무 일반적입니다.InputProps또는LabeledInputProps와 같이 더 구체적인 이름을 사용하는 것이 좋습니다.-interface Input { +interface InputProps { children: React.ReactNode labelName: string labelFor: string accent?: boolean } export default function Input({ children, labelName, labelFor, accent, -}: Input) { +}: InputProps) {src/app/features/dashboard_Id/Card/Tags.tsx (1)
4-5: 중복 태그 방지 기능 구현 고려주석에 언급된 "동일 태그 입력 불가하도록" 기능을 카드 생성 폼에서 구현하는 것을 고려해보세요.
중복 태그 방지 로직 구현에 도움이 필요하시면 알려주세요.
src/app/dashboard/[id]/layout.tsx (1)
12-12: 주석 처리된 Sidebar 정리 필요Sidebar가 주석 처리되어 있는데, 사용할 계획이 없다면 import와 함께 제거하거나, 향후 사용 예정이라면 TODO 주석을 추가하는 것이 좋습니다.
-import Sidebar from '@/app/shared/components/common/sidebar/Sidebar'또는
- {/* <Sidebar /> */} + {/* TODO: Sidebar 기능 구현 예정 */} + {/* <Sidebar /> */}src/app/features/dashboard_Id/Card/cardFormModals/AssigneeList.tsx (1)
9-12: 중복 인터페이스 정의를 확인해주세요.
Assignee인터페이스가getDashboardMembers.ts파일에도 정의되어 있는 것 같습니다. 중복을 피하기 위해 한 곳에서 export하여 재사용하는 것을 고려해보세요.
getDashboardMembers.ts에서Assignee를 export하고 여기서 import하도록 수정:-export interface Assignee { - userId: number - nickname: string -} +import { Assignee } from '../../lib/getDashboardMembers'src/app/features/dashboard_Id/Card/cardFormModals/CreateCardForm.tsx (2)
91-92: console.log 제거가 필요합니다.프로덕션 코드에서 디버깅용 console.log는 제거해야 합니다.
- console.log('🌀', data.imageUrl) - console.log('submitted', payload)
204-204: TODO 주석을 해결해주세요.태그 클릭으로 삭제 기능 구현이 필요해 보입니다. 사용자 경험 개선을 위해 이 기능을 추가하는 것을 고려해보세요.
태그 삭제 기능 구현을 도와드릴까요? 클릭 핸들러와 UI 개선 코드를 생성해드릴 수 있습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
package-lock.jsonis excluded by!**/package-lock.jsonpublic/images/plus.svgis excluded by!**/*.svg
📒 Files selected for processing (38)
package.json(1 hunks)src/app/api/useCards.ts(0 hunks)src/app/api/useColumns.ts(0 hunks)src/app/dashboard/[id]/api/updateCardColumn.ts(0 hunks)src/app/dashboard/[id]/layout.tsx(1 hunks)src/app/dashboard/[id]/page.tsx(2 hunks)src/app/features/dashboardId/Card/Tags.tsx(1 hunks)src/app/features/dashboardId/Card/cardFormModals/AssigneeList.tsx(1 hunks)src/app/features/dashboard_Id/Card/Card.tsx(3 hunks)src/app/features/dashboard_Id/Card/Tags.tsx(1 hunks)src/app/features/dashboard_Id/Card/cardFormModals/AssigneeList.tsx(1 hunks)src/app/features/dashboard_Id/Card/cardFormModals/CreateCardForm.tsx(1 hunks)src/app/features/dashboard_Id/Card/cardFormModals/CreateCardModal.tsx(1 hunks)src/app/features/dashboard_Id/Card/cardFormModals/input/DateInput.tsx(1 hunks)src/app/features/dashboard_Id/Card/cardFormModals/input/Input.tsx(1 hunks)src/app/features/dashboard_Id/Column/Column.tsx(6 hunks)src/app/features/dashboard_Id/api/fetchCards.ts(1 hunks)src/app/features/dashboard_Id/api/fetchColumns.ts(1 hunks)src/app/features/dashboard_Id/api/fetchMembers.ts(1 hunks)src/app/features/dashboard_Id/api/postCard.ts(1 hunks)src/app/features/dashboard_Id/api/postCardImage.ts(1 hunks)src/app/features/dashboard_Id/api/updateCardColumn.ts(1 hunks)src/app/features/dashboard_Id/api/useCardMutation.ts(2 hunks)src/app/features/dashboard_Id/api/useCards.ts(1 hunks)src/app/features/dashboard_Id/api/useColumns.ts(1 hunks)src/app/features/dashboard_Id/api/useMembers.ts(1 hunks)src/app/features/dashboard_Id/api/usePostCard.ts(1 hunks)src/app/features/dashboard_Id/api/useUploadCardImage.ts(1 hunks)src/app/features/dashboard_Id/lib/getDashboardMembers.ts(1 hunks)src/app/features/dashboard_Id/type/Card.type.ts(1 hunks)src/app/features/dashboard_Id/type/CardFormData.type.ts(1 hunks)src/app/features/dashboard_Id/type/Column.type.ts(1 hunks)src/app/features/dashboard_Id/type/Member.type.ts(1 hunks)src/app/globals.css(2 hunks)src/app/layout.tsx(1 hunks)src/app/shared/components/common/Avatar.tsx(1 hunks)src/app/shared/lib/getColor.ts(1 hunks)src/app/shared/lib/testAxios.ts(1 hunks)
💤 Files with no reviewable changes (3)
- src/app/dashboard/[id]/api/updateCardColumn.ts
- src/app/api/useColumns.ts
- src/app/api/useCards.ts
🧰 Additional context used
🧬 Code Graph Analysis (18)
src/app/features/dashboardId/Card/Tags.tsx (1)
src/app/shared/lib/getColor.ts (1)
getColor(1-5)
src/app/shared/components/common/Avatar.tsx (1)
src/app/shared/lib/getColor.ts (1)
getColor(1-5)
src/app/features/dashboard_Id/api/useMembers.ts (2)
src/app/features/dashboard_Id/type/Member.type.ts (1)
Member(1-10)src/app/features/dashboard_Id/api/fetchMembers.ts (1)
fetchMembers(6-11)
src/app/features/dashboard_Id/api/fetchColumns.ts (1)
src/app/features/dashboard_Id/type/Column.type.ts (2)
Column(1-8)ColumnsResponse(9-11)
src/app/features/dashboard_Id/api/fetchMembers.ts (1)
src/app/features/dashboard_Id/type/Member.type.ts (2)
Member(1-10)MembersResponse(11-14)
src/app/features/dashboard_Id/api/postCard.ts (1)
src/app/features/dashboard_Id/type/CardFormData.type.ts (1)
CardFormData(1-10)
src/app/features/dashboard_Id/api/usePostCard.ts (1)
src/app/features/dashboard_Id/api/postCard.ts (1)
postCard(10-16)
src/app/features/dashboard_Id/api/useUploadCardImage.ts (1)
src/app/features/dashboard_Id/api/postCardImage.ts (1)
postCardImages(4-21)
src/app/features/dashboard_Id/api/fetchCards.ts (1)
src/app/features/dashboard_Id/type/Card.type.ts (1)
CardResponse(21-25)
src/app/features/dashboard_Id/lib/getDashboardMembers.ts (2)
src/app/features/dashboard_Id/Card/cardFormModals/AssigneeList.tsx (1)
Assignee(9-12)src/app/features/dashboard_Id/type/Member.type.ts (1)
Member(1-10)
src/app/dashboard/[id]/page.tsx (1)
src/app/features/dashboard_Id/api/useColumns.ts (1)
useColumns(6-11)
src/app/dashboard/[id]/layout.tsx (1)
src/app/shared/components/common/header/Header.tsx (1)
Header(12-66)
src/app/features/dashboard_Id/Card/Card.tsx (2)
src/app/features/dashboard_Id/Card/Tags.tsx (1)
Tags(3-29)src/app/shared/components/common/Avatar.tsx (1)
Avatar(32-61)
src/app/features/dashboard_Id/Card/Tags.tsx (1)
src/app/shared/lib/getColor.ts (1)
getColor(1-5)
src/app/features/dashboard_Id/api/useCards.ts (2)
src/app/features/dashboard_Id/type/Card.type.ts (1)
CardResponse(21-25)src/app/features/dashboard_Id/api/fetchCards.ts (1)
fetchCards(6-14)
src/app/features/dashboardId/Card/cardFormModals/AssigneeList.tsx (3)
src/app/features/dashboard_Id/Card/cardFormModals/AssigneeList.tsx (2)
AssigneeList(24-50)Assignee(9-12)src/app/features/dashboard_Id/type/Card.type.ts (1)
Assignee(1-5)src/app/shared/lib/cn.ts (1)
cn(4-6)
src/app/features/dashboard_Id/Column/Column.tsx (5)
src/app/features/dashboard_Id/type/Column.type.ts (1)
Column(1-8)src/app/features/dashboard_Id/api/useCards.ts (1)
useCards(7-12)src/app/features/dashboard_Id/store/useDragStore.ts (1)
useDragStore(13-17)src/app/features/dashboard_Id/Card/cardFormModals/CreateCardModal.tsx (1)
CreateCardModal(7-19)src/app/features/dashboard_Id/Card/cardFormModals/CreateCardForm.tsx (1)
CreateCardForm(19-281)
src/app/features/dashboard_Id/Card/cardFormModals/AssigneeList.tsx (5)
src/app/features/dashboard_Id/lib/getDashboardMembers.ts (2)
Assignee(3-6)getDashboardMembers(10-18)src/app/features/dashboard_Id/type/Member.type.ts (1)
Member(1-10)src/app/features/dashboard_Id/type/CardFormData.type.ts (1)
CardFormData(1-10)src/app/features/dashboardId/Card/cardFormModals/AssigneeList.tsx (1)
AssigneeList(7-29)src/app/shared/lib/cn.ts (1)
cn(4-6)
🪛 Biome (1.9.4)
src/app/features/dashboard_Id/Card/cardFormModals/CreateCardForm.tsx
[error] 92-92: Avoid the delete operator which can impact performance.
Unsafe fix: Use an undefined assignment instead.
(lint/performance/noDelete)
[error] 94-97: Avoid the delete operator which can impact performance.
Unsafe fix: Use an undefined assignment instead.
(lint/performance/noDelete)
🔇 Additional comments (35)
package.json (1)
16-16: 새로운 의존성 추가가 적절합니다.카드 생성 모달의 날짜 선택 기능을 위한
date-fns와react-datepicker라이브러리 추가가 기능 요구사항과 잘 맞습니다.Also applies to: 20-20
src/app/layout.tsx (1)
28-28: 모달 포털을 위한 DOM 노드 추가가 적절합니다.React 포털을 통한 모달 렌더링을 위한
modal-rootdiv 추가는 표준적인 구현 방식입니다.src/app/shared/lib/getColor.ts (1)
1-5: 함수 시그니처 개선이 우수합니다.배열 전체 대신 배열 길이만 받도록 변경한 것은 성능상 효율적이고 함수의 의도를 더 명확하게 만듭니다.
src/app/shared/components/common/Avatar.tsx (1)
34-34: getColor 함수 호출 업데이트가 일관성 있게 적용되었습니다.함수 시그니처 변경에 맞춰
customColors.length를 전달하도록 수정한 것이 올바릅니다.src/app/features/dashboardId/Card/Tags.tsx (1)
12-12: 타입 안전성 개선을 위한 올바른 수정입니다.
getColor함수가 배열 길이를 숫자로 받도록 업데이트됨에 따라,bgColors배열 대신bgColors.length를 전달하는 것이 올바릅니다. 이는 함수 시그니처와 일치하며 타입 안전성을 보장합니다.src/app/features/dashboard_Id/type/Card.type.ts (1)
21-25: 페이지네이션을 위한 잘 구조화된 응답 타입입니다.
CardResponse인터페이스는 카드 데이터와 페이지네이션 메타데이터를 포함한 표준적인 API 응답 구조를 제공합니다.cursorId를 통한 커서 기반 페이지네이션 지원이 적절합니다.src/app/features/dashboard_Id/api/useCardMutation.ts (2)
4-4: feature 폴더 구조로의 리팩토링이 적절합니다.전역 API 훅에서 feature별 로컬 타입으로 임포트 경로를 변경한 것은 모듈화와 코드 구조 개선에 도움이 됩니다.
78-79: 포맷팅 개선이 코드 가독성을 향상시킵니다.
clearDraggingCard()호출 후 빈 줄 추가로 코드 블록 구분이 더 명확해졌습니다.src/app/features/dashboard_Id/api/useMembers.ts (1)
7-12: 표준적인 React Query 패턴을 잘 따르는 훅입니다.
useMembers훅은 적절한 쿼리 키 구조와 타입 안전성을 제공하며,fetchMembers함수와의 통합이 올바르게 구현되었습니다.src/app/features/dashboard_Id/api/useUploadCardImage.ts (1)
8-19: 포괄적인 에러 처리를 갖춘 잘 구현된 뮤테이션 훅입니다.이미지 업로드 뮤테이션이 적절히 구현되었습니다:
- 서버 에러 메시지 우선 사용 후 폴백 메시지 제공
- toast를 통한 사용자 친화적 에러 피드백
postCardImages함수와의 올바른 통합src/app/features/dashboard_Id/api/fetchColumns.ts (1)
1-3: testAxios 사용 확인이 필요합니다.실제 axios 대신 testAxios를 사용하고 있습니다. PR 목적에 따르면 testAxios.ts는 테스트용으로 나중에 삭제될 예정이라고 하는데, 프로덕션 코드에서 사용하는 것이 적절한지 확인이 필요합니다.
src/app/features/dashboard_Id/api/usePostCard.ts (1)
15-22: 에러 처리 로직이 잘 구현되었습니다.axios 에러와 일반 에러를 구분하여 처리하고 있으며, 서버 응답 메시지를 적절히 추출하고 있습니다.
src/app/features/dashboard_Id/api/useColumns.ts (1)
7-10: 쿼리 구성이 적절합니다.dashboardId를 포함한 쿼리 키 구성과 타입 정의가 올바르게 되어 있습니다.
src/app/features/dashboard_Id/type/Column.type.ts (1)
1-11: 타입 정의가 명확하고 잘 구조화되어 있습니다.Column 인터페이스와 ColumnsResponse 인터페이스가 적절히 정의되어 있으며, API 응답 구조와 잘 매칭됩니다.
src/app/features/dashboard_Id/type/CardFormData.type.ts (1)
1-10: 타입 정의가 잘 되어 있습니다.인터페이스 구조가 명확하고 옵셔널 필드들이 적절히 표시되어 있습니다. 다만
assigneeUserId가 필수 필드인데, 담당자를 지정하지 않는 경우는 어떻게 처리할 계획인지 확인이 필요합니다.담당자 미지정 케이스 처리 방식 확인이 필요합니다.
src/app/features/dashboard_Id/Card/cardFormModals/input/Input.tsx (1)
15-28: 컴포넌트 구조 양호입력 필드 래퍼로서 잘 구성되어 있습니다. accent 프롭을 통한 필수 필드 표시 기능도 유용합니다.
src/app/globals.css (2)
45-47: 새로운 텍스트 유틸리티 클래스 추가 양호입력 필드를 위한
.Text-Input클래스가 다크 모드를 포함하여 잘 구현되었습니다.
84-96: 입력 관련 유틸리티 클래스들 잘 구성됨
.BG-Input-hovered,.Input,.Input-readOnly클래스들이 일관된 스타일링을 제공하며 다크 모드도 적절히 지원합니다. 읽기 전용 입력에서 캐럿을 숨기는caret-transparent설정도 좋습니다.src/app/features/dashboard_Id/Card/Tags.tsx (2)
3-8: 색상 할당 로직 잘 구현됨
getColor함수를 활용한 일관된 색상 할당이 잘 구현되었습니다. 배경색과 텍스트 색상 배열의 인덱스 매칭도 적절합니다.
9-29: 태그 렌더링 로직 양호태그들이 적절한 스타일링과 함께 깔끔하게 렌더링됩니다.
whitespace-nowrap을 통한 텍스트 줄바꿈 방지도 좋은 선택입니다.src/app/dashboard/[id]/layout.tsx (1)
5-17: 기본 레이아웃 구조 양호Header와 children을 포함한 기본적인 레이아웃 구조가 적절합니다. 향후 필요에 따라 브레드크럼이나 추가 네비게이션을 고려할 수 있습니다.
src/app/features/dashboard_Id/Card/Card.tsx (3)
6-6: 상대 import 경로로 변경이 적절합니다.기존 절대 import 경로에서 상대 경로로 변경하여 feature-scoped 구조에 맞게 잘 리팩토링되었습니다.
20-20: data 속성 최적화가 좋습니다.구조분해할당된
id변수를 사용하여card.id대신 직접 참조하는 것이 더 효율적입니다.
50-73: 조건부 렌더링으로 UI 개선이 잘 되었습니다.
dueDate와assignee가 존재할 때만 해당 섹션을 렌더링하도록 개선하여 빈 데이터로 인한 UI 문제를 방지했습니다. 한국어 주석도 코드 이해에 도움이 됩니다.src/app/features/dashboard_Id/type/Member.type.ts (1)
1-14: 타입 정의가 명확하고 완전합니다.
Member와MembersResponse인터페이스가 멤버 관리에 필요한 모든 필드를 포함하고 있으며, 명명 규칙도 일관성 있게 잘 정의되었습니다.profileImageUrl이null가능하도록 정의된 것도 적절합니다.src/app/features/dashboard_Id/Column/Column.tsx (5)
7-12: import 경로 리팩토링이 적절합니다.절대 경로에서 상대 경로로 변경하여 feature-scoped 아키텍처에 맞게 잘 정리되었습니다.
31-32: 드래그 오버 성능 최적화가 우수합니다.같은 컬럼 내에서의 드래그를 체크하여 불필요한 상태 업데이트를 방지하는 로직이 성능상 좋습니다.
41-44: 드롭 로직의 조기 반환이 효율적입니다.드래그 중인 카드가 없거나 같은 컬럼에 드롭하는 경우 조기 반환하여 불필요한 API 호출을 방지하는 것이 좋습니다.
95-102: 모달 통합이 깔끔합니다.
CreateCardModal과CreateCardForm컴포넌트를 조건부로 렌더링하는 구조가 깔끔하고 명확합니다.
50-52: 스크립트에서ts타입만 지정되어tsx파일이 검색되지 않았습니다..tsx파일을 glob 패턴으로 지정해 드래그 이벤트 핸들링 패턴을 다시 확인해주세요.#!/bin/bash # .tsx 파일에서 onMouseUp, onDragEnd, onDrop 핸들러 패턴 재검색 rg -g '*.tsx' -A 10 -B 5 "onMouseUp|onDragEnd|onDrop"src/app/features/dashboard_Id/Card/cardFormModals/AssigneeList.tsx (2)
19-23: 컴포넌트 설명 주석이 유용합니다.컴포넌트의 역할과 상태 관리 방식을 명확히 설명하는 주석이 코드 이해에 도움이 됩니다.
40-43: 이중 상태 관리가 적절합니다.UI 표시용 assignee 객체와 form 제출용 userId를 분리하여 관리하는 방식이 명확하고 적절합니다.
src/app/features/dashboard_Id/Card/cardFormModals/CreateCardForm.tsx (3)
189-198: 태그 입력 로직이 우수합니다.Enter 키로 태그를 추가하고 중복을 방지하는 로직이 잘 구현되었습니다.
trimEnd()와trim()사용으로 공백 처리도 적절합니다.
162-177: 날짜 선택기 통합이 깔끔합니다.
react-datepicker와react-hook-form의 Controller를 사용한 날짜 입력 구현이 잘 되어 있습니다. 시간 선택 기능도 포함되어 사용자 경험이 좋습니다.
63-76: 이미지 업로드 처리가 적절합니다.비동기 이미지 업로드와 미리보기 기능이 잘 구현되었습니다. 성공 콜백에서 form state와 preview state를 모두 업데이트하는 것이 좋습니다.
|
|
||
| export async function fetchMembers(dashboardId: number): Promise<Member[]> { | ||
| const res = await api.get<MembersResponse>( | ||
| `/${process.env.NEXT_PUBLIC_TEAM_ID}/members?&dashboardId=${dashboardId}`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
쿼리 파라미터 형식을 수정해주세요.
URL에 불필요한 &가 있습니다. 첫 번째 파라미터이므로 ? 바로 다음에 파라미터 이름이 와야 합니다.
- `/${process.env.NEXT_PUBLIC_TEAM_ID}/members?&dashboardId=${dashboardId}`,
+ `/${process.env.NEXT_PUBLIC_TEAM_ID}/members?dashboardId=${dashboardId}`,📝 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.
| `/${process.env.NEXT_PUBLIC_TEAM_ID}/members?&dashboardId=${dashboardId}`, | |
| `/${process.env.NEXT_PUBLIC_TEAM_ID}/members?dashboardId=${dashboardId}`, |
🤖 Prompt for AI Agents
In src/app/features/dashboard_Id/api/fetchMembers.ts at line 8, remove the
unnecessary '&' character immediately following the '?' in the URL query string.
The query parameters should start directly after the '?' without an '&' since
this is the first parameter. Update the URL string to have the format
`?dashboardId=${dashboardId}` without the extra '&'.
| <input | ||
| ref={ref} | ||
| {...props} | ||
| inputMode="none" | ||
| readOnly | ||
| className="Input-readOnly" | ||
| id="dueDate" | ||
| placeholder="날짜와 시간을 선택하세요" | ||
| /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
props 순서와 id 중복 문제를 해결해야 합니다.
현재 구현에서 두 가지 문제가 있습니다:
{...props}스프레드가 특정 props보다 먼저 오면서 중요한 속성들이 덮어쓰일 수 있습니다- 하드코딩된
id="dueDate"로 인해 컴포넌트를 여러 번 사용할 때 DOM id 중복이 발생할 수 있습니다
다음과 같이 수정하는 것을 권장합니다:
- <input
- ref={ref}
- {...props}
- inputMode="none"
- readOnly
- className="Input-readOnly"
- id="dueDate"
- placeholder="날짜와 시간을 선택하세요"
- />
+ <input
+ {...props}
+ ref={ref}
+ inputMode="none"
+ readOnly
+ className="Input-readOnly"
+ placeholder="날짜와 시간을 선택하세요"
+ />id는 props로 전달받거나 상위 컴포넌트에서 관리하도록 하는 것이 좋습니다.
📝 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.
| <input | |
| ref={ref} | |
| {...props} | |
| inputMode="none" | |
| readOnly | |
| className="Input-readOnly" | |
| id="dueDate" | |
| placeholder="날짜와 시간을 선택하세요" | |
| /> | |
| <input | |
| {...props} | |
| ref={ref} | |
| inputMode="none" | |
| readOnly | |
| className="Input-readOnly" | |
| placeholder="날짜와 시간을 선택하세요" | |
| /> |
🤖 Prompt for AI Agents
In src/app/features/dashboard_Id/Card/cardFormModals/input/DateInput.tsx around
lines 9 to 17, the spread operator {...props} is placed before specific
attributes, which can cause important props to be overwritten, and the hardcoded
id="dueDate" can lead to duplicate DOM ids when the component is used multiple
times. To fix this, move {...props} after the specific attributes so that passed
props can override defaults, and remove the hardcoded id, instead accepting id
as a prop or managing it from the parent component.
| import api from '@/app/shared/lib/testAxios' | ||
|
|
||
| // import api from '@/app/shared/lib/axios' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
프로덕션 환경에서 테스트용 axios 클라이언트를 사용하고 있습니다.
현재 testAxios를 사용하고 있는데, 이는 임시 파일로 명시되어 있습니다. 프로덕션 코드에서는 정식 axios 클라이언트를 사용해야 합니다.
주석 처리된 정식 axios import를 사용하는 것을 권장합니다:
-import api from '@/app/shared/lib/testAxios'
-
-// import api from '@/app/shared/lib/axios'
+import api from '@/app/shared/lib/axios'📝 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.
| import api from '@/app/shared/lib/testAxios' | |
| // import api from '@/app/shared/lib/axios' | |
| import api from '@/app/shared/lib/axios' |
🤖 Prompt for AI Agents
In src/app/features/dashboard_Id/api/postCard.ts at lines 1 to 3, replace the
import of the testAxios client with the production-ready axios client by
uncommenting the line importing from '@/app/shared/lib/axios' and commenting out
or removing the import from '@/app/shared/lib/testAxios'. This ensures the
production environment uses the correct axios instance.
| export async function postCard(payload: CardFormData): Promise<ApiResponse> { | ||
| const res = await api.post( | ||
| `/${process.env.NEXT_PUBLIC_TEAM_ID}/cards`, | ||
| payload, | ||
| ) | ||
| return res.data | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
환경 변수 검증과 에러 처리가 필요합니다.
현재 구현에서 다음 사항들이 누락되어 있습니다:
NEXT_PUBLIC_TEAM_ID환경 변수의 존재 여부 검증- API 요청 실패 시 에러 처리
- 응답 데이터 유효성 검증
다음과 같은 개선을 권장합니다:
export async function postCard(payload: CardFormData): Promise<ApiResponse> {
+ const teamId = process.env.NEXT_PUBLIC_TEAM_ID
+ if (!teamId) {
+ throw new Error('NEXT_PUBLIC_TEAM_ID 환경 변수가 설정되지 않았습니다.')
+ }
+
+ try {
const res = await api.post(
- `/${process.env.NEXT_PUBLIC_TEAM_ID}/cards`,
+ `/${teamId}/cards`,
payload,
)
return res.data
+ } catch (error) {
+ console.error('카드 생성 실패:', error)
+ throw error
+ }
}📝 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 async function postCard(payload: CardFormData): Promise<ApiResponse> { | |
| const res = await api.post( | |
| `/${process.env.NEXT_PUBLIC_TEAM_ID}/cards`, | |
| payload, | |
| ) | |
| return res.data | |
| } | |
| export async function postCard(payload: CardFormData): Promise<ApiResponse> { | |
| const teamId = process.env.NEXT_PUBLIC_TEAM_ID | |
| if (!teamId) { | |
| throw new Error('NEXT_PUBLIC_TEAM_ID 환경 변수가 설정되지 않았습니다.') | |
| } | |
| try { | |
| const res = await api.post( | |
| `/${teamId}/cards`, | |
| payload, | |
| ) | |
| return res.data | |
| } catch (error) { | |
| console.error('카드 생성 실패:', error) | |
| throw error | |
| } | |
| } |
🤖 Prompt for AI Agents
In src/app/features/dashboard_Id/api/postCard.ts around lines 10 to 16, the code
lacks validation for the NEXT_PUBLIC_TEAM_ID environment variable, error
handling for the API request, and response data validation. To fix this, first
check if NEXT_PUBLIC_TEAM_ID is defined and throw an error if not. Then, wrap
the API call in a try-catch block to handle request failures gracefully.
Finally, validate the structure or presence of expected fields in res.data
before returning it, throwing an error if validation fails.
| import api from '@/app/shared/lib/testAxios' | ||
|
|
||
| // import api from '@/app/shared/lib/axios' | ||
| import { CardResponse } from '../type/Card.type' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
프로덕션 환경에서 테스트용 axios 클라이언트를 사용하고 있습니다.
postCard.ts와 동일한 문제로, 테스트용 axios 클라이언트 대신 정식 클라이언트를 사용해야 합니다.
-import api from '@/app/shared/lib/testAxios'
-
-// import api from '@/app/shared/lib/axios'
+import api from '@/app/shared/lib/axios'📝 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.
| import api from '@/app/shared/lib/testAxios' | |
| // import api from '@/app/shared/lib/axios' | |
| import { CardResponse } from '../type/Card.type' | |
| import api from '@/app/shared/lib/axios' | |
| import { CardResponse } from '../type/Card.type' |
🤖 Prompt for AI Agents
In src/app/features/dashboard_Id/api/fetchCards.ts at lines 1 to 4, the code
imports a test axios client instead of the production axios client. Replace the
import statement to use the official axios client by uncommenting the production
import line and removing the test client import to ensure the correct client is
used in production.
| const params = useParams() | ||
| const dashboardId = Number(params.id) | ||
| const { data: columns, isLoading, error } = useColumns(dashboardId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
타입 안전성을 개선해주세요.
params.id가 undefined일 수 있고, Number() 변환 결과가 NaN일 수 있습니다. 타입 안전성을 위해 검증 로직을 추가해주세요.
const params = useParams()
- const dashboardId = Number(params.id)
+ const dashboardId = params.id ? Number(params.id) : null
+
+ if (!dashboardId || isNaN(dashboardId)) {
+ return <div>잘못된 대시보드 ID입니다.</div>
+ }
+
const { data: columns, isLoading, error } = useColumns(dashboardId)📝 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.
| const params = useParams() | |
| const dashboardId = Number(params.id) | |
| const { data: columns, isLoading, error } = useColumns(dashboardId) | |
| const params = useParams() | |
| const dashboardId = params.id ? Number(params.id) : null | |
| if (!dashboardId || isNaN(dashboardId)) { | |
| return <div>잘못된 대시보드 ID입니다.</div> | |
| } | |
| const { data: columns, isLoading, error } = useColumns(dashboardId) |
🤖 Prompt for AI Agents
In src/app/dashboard/[id]/page.tsx around lines 14 to 16, the code directly
converts params.id to a number without checking if params.id is undefined or if
the conversion results in NaN, which can cause runtime errors. Add validation to
ensure params.id exists and is a valid number before using it; if invalid,
handle the case appropriately, such as showing an error or returning early to
maintain type safety.
| @@ -0,0 +1,29 @@ | |||
| import { cn } from '@/app/shared/lib/cn' | |||
| const mockData = ['aaa', 'bbb', 'ccc'] | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
목 데이터를 실제 데이터로 교체 필요
하드코딩된 목 데이터 대신 실제 멤버 데이터를 사용해야 합니다. src/app/features/dashboard_Id/Card/cardFormModals/AssigneeList.tsx에 있는 완전한 구현체를 참고하세요.
🤖 Prompt for AI Agents
In src/app/features/dashboardId/Card/cardFormModals/AssigneeList.tsx at line 2,
replace the hardcoded mockData array with the actual member data source. Refer
to the full implementation in
src/app/features/dashboard_Id/Card/cardFormModals/AssigneeList.tsx to correctly
fetch and use real member data instead of static mock values.
| {mockData.map((Assignee, index) => ( | ||
| <div | ||
| className={cn( | ||
| 'BG-Input-hovered w-full cursor-pointer px-16 py-11 pt-14 placeholder-gray-400 caret-transparent', | ||
| index !== 0 && 'border-t', | ||
| )} | ||
| key={index} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
변수명과 키 사용 개선 필요
몇 가지 문제점이 있습니다:
- 변수명
Assignee가 타입명과 혼동될 수 있습니다 (소문자assignee권장) - 배열 인덱스를 키로 사용하는 것은 React 모범 사례에 어긋납니다
- {mockData.map((Assignee, index) => (
+ {mockData.map((assignee, index) => (
<div
className={cn(
'BG-Input-hovered w-full cursor-pointer px-16 py-11 pt-14 placeholder-gray-400 caret-transparent',
index !== 0 && 'border-t',
)}
- key={index}
+ key={assignee}
onClick={() => {
- setSelectedAssignee(Assignee)
- console.log(Assignee)
+ setSelectedAssignee(assignee)
}}
>
- {Assignee}
+ {assignee}
</div>
))}📝 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.
| {mockData.map((Assignee, index) => ( | |
| <div | |
| className={cn( | |
| 'BG-Input-hovered w-full cursor-pointer px-16 py-11 pt-14 placeholder-gray-400 caret-transparent', | |
| index !== 0 && 'border-t', | |
| )} | |
| key={index} | |
| {mockData.map((assignee, index) => ( | |
| <div | |
| className={cn( | |
| 'BG-Input-hovered w-full cursor-pointer px-16 py-11 pt-14 placeholder-gray-400 caret-transparent', | |
| index !== 0 && 'border-t', | |
| )} | |
| key={assignee} | |
| onClick={() => { | |
| setSelectedAssignee(assignee) | |
| }} | |
| > | |
| {assignee} | |
| </div> | |
| ))} |
🤖 Prompt for AI Agents
In src/app/features/dashboardId/Card/cardFormModals/AssigneeList.tsx around
lines 12 to 18, rename the variable from `Assignee` to `assignee` to avoid
confusion with type names, and replace the use of the array index as the React
key with a unique and stable identifier from the `assignee` object, such as an
`id` property, to follow React best practices for list rendering.
| import Header from '@components/common/header/Header' | ||
|
|
||
| import Sidebar from '@/app/shared/components/common/sidebar/Sidebar' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
import 경로 일관성 개선 필요
Header와 Sidebar의 import 경로가 일관되지 않습니다. 둘 다 같은 패턴을 사용하는 것이 좋습니다.
-import Header from '@components/common/header/Header'
-
-import Sidebar from '@/app/shared/components/common/sidebar/Sidebar'
+import Header from '@/app/shared/components/common/header/Header'
+import Sidebar from '@/app/shared/components/common/sidebar/Sidebar'📝 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.
| import Header from '@components/common/header/Header' | |
| import Sidebar from '@/app/shared/components/common/sidebar/Sidebar' | |
| import Header from '@/app/shared/components/common/header/Header' | |
| import Sidebar from '@/app/shared/components/common/sidebar/Sidebar' |
🤖 Prompt for AI Agents
In src/app/dashboard/[id]/layout.tsx at lines 1 to 3, the import paths for
Header and Sidebar are inconsistent. Update the import statements so both use
the same path pattern, either both using '@components' or both using
'@/app/shared/components', to maintain consistency across the codebase.
| if (!data.dueDate) delete payload.dueDate | ||
| if (!data.imageUrl || !preview) delete payload.imageUrl // delete로 아예 필드의 해당 key를 지워야, 서버가 "없음"으로 인식함.. | ||
| console.log('🌀', data.imageUrl) | ||
| console.log('submitted', payload) | ||
| createCard(payload) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
delete 연산자 성능 최적화가 필요합니다.
정적 분석 도구에서 지적한 대로 delete 연산자는 성능에 영향을 줄 수 있습니다. undefined 할당을 사용하는 것이 더 좋습니다.
다음과 같이 수정하세요:
- if (!data.dueDate) delete payload.dueDate
- if (!data.imageUrl || !preview) delete payload.imageUrl
+ if (!data.dueDate) payload.dueDate = undefined
+ if (!data.imageUrl || !preview) payload.imageUrl = undefined📝 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 (!data.dueDate) delete payload.dueDate | |
| if (!data.imageUrl || !preview) delete payload.imageUrl // delete로 아예 필드의 해당 key를 지워야, 서버가 "없음"으로 인식함.. | |
| console.log('🌀', data.imageUrl) | |
| console.log('submitted', payload) | |
| createCard(payload) | |
| if (!data.dueDate) payload.dueDate = undefined | |
| if (!data.imageUrl || !preview) payload.imageUrl = undefined | |
| console.log('🌀', data.imageUrl) | |
| console.log('submitted', payload) | |
| createCard(payload) |
🧰 Tools
🪛 Biome (1.9.4)
[error] 92-92: Avoid the delete operator which can impact performance.
Unsafe fix: Use an undefined assignment instead.
(lint/performance/noDelete)
🤖 Prompt for AI Agents
In src/app/features/dashboard_Id/Card/cardFormModals/CreateCardForm.tsx around
lines 89 to 93, replace the delete operations on payload.dueDate and
payload.imageUrl with assignments to undefined to improve performance. Instead
of using 'delete payload.dueDate' and 'delete payload.imageUrl', set these
properties to undefined when the conditions are met, ensuring the server still
interprets the absence correctly while avoiding the performance cost of delete.
Insung-Jo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
모달 구현 수고 많으셨습니다!
| ref={ref} | ||
| {...props} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ref가 위에 있으면 아래에 있는 ...props 때문에 ref 값이 바뀔 수도 있으니 아래 처럼 배치해 주세요!
{...props}
ref={ref}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
앗 수정하겠습니다, 감사합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 배워갑니당
LeeCh0129
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
모달 구현 고생많으셨습니다~👍
yuj2n
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
지윤님 카드 생성 모달 구현 수고많으셨고 가능하면 중복되는 코드의 경우 공용으로 사용하면 좋을 것 같아용!!
| "next": "14.2.25", | ||
| "next-themes": "^0.4.6", | ||
| "react": "18.2.0", | ||
| "react-datepicker": "^8.4.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
date-picker 사용해주셨군용!
| ref={ref} | ||
| {...props} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 배워갑니당
📌 변경 사항 개요
변경 파일이 많이 뜰거같은데,
이번 작업은 CreateCardForm 파일 중심으로 진행되었고,
관련 파일은 아래 사진에 보이는, feature/dashboard_id경로 내에서 확인 가능합니다.
큰 틀은 CreateCardForm에 집중되어 있으니 이 파일 위주로 검토해주시면 됩니다.
✨ 요약
CreateCardModal: 모달 껍데기
타이틀, 설명만 필수 입력.
마감일, 이미지는 미입력 시 필드에서 해당 키 자체를 제거하고 post요청에 전달하면 에러 안 남..
2025-06-19.4.38.37.mov
thub.com/user-attachments/assets/918e9fc4-628b-4cfa-8363-06cdedc660a9
📝 상세 내용
🔗 관련 이슈
🖼️ 스크린샷
✅ 체크리스트
💡 참고 사항
Summary by CodeRabbit
신규 기능
버그 수정
스타일
리팩터링
기타