-
Notifications
You must be signed in to change notification settings - Fork 2
✨ Feat: 카드 수정 모달 구현 #91
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
Changes from all commits
28122d5
1bcd962
39b8d7b
d237bfe
c0dbf8d
7573566
2b003df
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,20 +1,26 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import Image from 'next/image' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useState } from 'react' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Avatar } from '@/app/shared/components/common/Avatar' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useDragStore } from '../store/useDragStore' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { Card as CardType } from '../type/Card.type' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { Column as ColumnType } from '../type/Column.type' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import CardContent from './cardModal/CardContent' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import CardModal from './cardModal/CardModal' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import Tags from './Tags' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export default function Card({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| card, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| columnId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| column, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| card: CardType | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| columnId: number | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| column: ColumnType | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { id, imageUrl, title, tags, dueDate, assignee } = card | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { setDraggingCard } = useDragStore() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [openCard, setOpenCard] = useState(false) //card.tsx | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data-card-id={id} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -23,6 +29,7 @@ export default function Card({ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onDragStart={() => setDraggingCard({ cardData: card })} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onContextMenu={(e: React.MouseEvent) => e.preventDefault()} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className="BG-white Border-section relative rounded-6 border-solid px-20 py-16" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick={() => setOpenCard(true)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {imageUrl && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Image | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -42,36 +49,46 @@ export default function Card({ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </h3> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/* 태그 */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Tags tags={tags} /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {tags.length !== 0 && <Tags tags={tags} />} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/* 마감일 & 담당자 */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="mt-8 flex content-around items-center"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/* :마감일 */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {dueDate && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="flex size-full items-center gap-6"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Image | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| src={'/images/calendar.svg'} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| alt="마감일" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| width={18} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| height={18} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="flex size-full items-center gap-6"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Image | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| src={'/images/calendar.svg'} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| alt="마감일" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| width={18} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| height={18} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {dueDate && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="Text-gray mt-4 text-12 font-medium leading-none"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {dueDate} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {dueDate.split(' ')[0]} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+57
to
+69
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 마감일이 없을 때 캘린더 아이콘 조건부 렌더링 마감일이 없어도 캘린더 아이콘이 항상 표시됩니다. 사용자 혼란을 방지하기 위해 마감일이 있을 때만 아이콘을 표시하세요. - <div className="flex size-full items-center gap-6">
- <Image
- src={'/images/calendar.svg'}
- alt="마감일"
- width={18}
- height={18}
- />
- {dueDate && (
- <div className="Text-gray mt-4 text-12 font-medium leading-none">
- {dueDate.split(' ')[0]}
- </div>
- )}
- </div>
+ {dueDate && (
+ <div className="flex size-full items-center gap-6">
+ <Image
+ src={'/images/calendar.svg'}
+ alt="마감일"
+ width={18}
+ height={18}
+ />
+ <div className="Text-gray mt-4 text-12 font-medium leading-none">
+ {dueDate.split(' ')[0]}
+ </div>
+ </div>
+ )}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/* :담당자 */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {assignee && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="shrink-0"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Avatar | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nickname={assignee.nickname} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| imageUrl={assignee.profileImageUrl} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size={24} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name={assignee.nickname} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| imageUrl={assignee.profileImageUrl} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/* 카드 모달 */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {openCard && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <CardModal> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <CardContent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClose={() => setOpenCard(false)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| card={card} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| column={column} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </CardModal> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| export default function ColumnTitle({ title }: { title: string }) { | ||
| return ( | ||
| <div className="BG-lightblue flex w-fit items-center gap-6 rounded-16 px-10 py-4"> | ||
| <div className="size-6 rounded-25 bg-[#228DFF]"></div> | ||
| <div className="Text-deepblue pb-4 pt-6 text-14 font-medium leading-none"> | ||
| {title} | ||
| </div> | ||
| </div> | ||
| ) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import { Avatar } from '@/app/shared/components/common/Avatar' | ||
|
|
||
| import { Assignee } from '../type/Card.type' | ||
|
|
||
| export default function MyAssignee({ assignee }: { assignee: Assignee }) { | ||
| return ( | ||
| <div className="flex items-center gap-6"> | ||
| <Avatar | ||
| size={26} | ||
| name={assignee.nickname} | ||
| imageUrl={assignee.profileImageUrl} | ||
| /> | ||
| <span className="regular Text-black block pt-1 text-16 leading-none"> | ||
| {assignee.nickname} | ||
| </span> | ||
| </div> | ||
| ) | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,23 +1,39 @@ | ||||||||||||||||
| import { useTheme } from 'next-themes' | ||||||||||||||||
|
|
||||||||||||||||
| import { getColor } from '@/app/shared/lib/getColor' | ||||||||||||||||
|
|
||||||||||||||||
| export default function Tags({ tags }: { tags: string[] }) { | ||||||||||||||||
| //태그 컬러 - 랜덤 배정 | ||||||||||||||||
| //카드 생성 시 - 동일 태그 입력 불가하도록 | ||||||||||||||||
| const bgColors = ['#F9EEE3', '#E7F7DB', '#F7DBF0', '#DBE6F7'] | ||||||||||||||||
| const bgColorsDark = ['#774212', '#366712', '#711E5C', '#0F3167'] | ||||||||||||||||
| const textColors = ['#D58D49', '#86D549', '#D549B6', '#4981D5'] | ||||||||||||||||
|
|
||||||||||||||||
| const { resolvedTheme } = useTheme() | ||||||||||||||||
| const isDark = resolvedTheme === 'dark' | ||||||||||||||||
|
|
||||||||||||||||
| return ( | ||||||||||||||||
| <div className="flex flex-wrap gap-6"> | ||||||||||||||||
| {tags.map((tag) => { | ||||||||||||||||
| const colorIndex = getColor(tag, bgColors.length) | ||||||||||||||||
| // const colorIndex = getColor(tag, bgColors.length) | ||||||||||||||||
| // getColors함수 사용하면 NaN값이 떠서 작동을 안함.. 원래 문제 없었는데 이유를 모르겠음. | ||||||||||||||||
| const hash = tag | ||||||||||||||||
| .split('') | ||||||||||||||||
| .reduce((acc, char) => acc + char.charCodeAt(0), 0) | ||||||||||||||||
| const colorIndex = hash % 4 | ||||||||||||||||
|
Comment on lines
+18
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 코드 중복 및 getColor 함수 문제 해결 필요 수동 해시 계산 로직이 다음과 같이 개선할 수 있습니다: - // const colorIndex = getColor(tag, bgColors.length)
- // getColors함수 사용하면 NaN값이 떠서 작동을 안함.. 원래 문제 없었는데 이유를 모르겠음.
- const hash = tag
- .split('')
- .reduce((acc, char) => acc + char.charCodeAt(0), 0)
- const colorIndex = hash % 4
+ const colorIndex = getColor(tag, bgColors.length)getColor 함수의 NaN 문제를 먼저 해결하고, 공통 해시 함수를 만들어 중복을 제거하세요. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||
|
|
||||||||||||||||
| const backgroundColor = isDark | ||||||||||||||||
| ? bgColorsDark[colorIndex] | ||||||||||||||||
| : bgColors[colorIndex] | ||||||||||||||||
| const textColor = isDark ? bgColors[colorIndex] : textColors[colorIndex] | ||||||||||||||||
|
|
||||||||||||||||
| return ( | ||||||||||||||||
| <span | ||||||||||||||||
| key={tag} | ||||||||||||||||
| className="inline-block whitespace-nowrap rounded-4 px-9 pb-3 pt-5" | ||||||||||||||||
| style={{ | ||||||||||||||||
| backgroundColor: bgColors[colorIndex], | ||||||||||||||||
| color: textColors[colorIndex], | ||||||||||||||||
| backgroundColor: backgroundColor, | ||||||||||||||||
| color: textColor, | ||||||||||||||||
| }} | ||||||||||||||||
| > | ||||||||||||||||
| {tag} | ||||||||||||||||
|
|
||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,49 @@ | ||||||||||||||||||||||||||||||||||||||||||
| import { useTheme } from 'next-themes' | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| import { getColor } from '@/app/shared/lib/getColor' | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| export default function TagsCanDelete({ | ||||||||||||||||||||||||||||||||||||||||||
| tags, | ||||||||||||||||||||||||||||||||||||||||||
| setTags, | ||||||||||||||||||||||||||||||||||||||||||
| }: { | ||||||||||||||||||||||||||||||||||||||||||
| tags: string[] | ||||||||||||||||||||||||||||||||||||||||||
| setTags: React.Dispatch<React.SetStateAction<string[]>> | ||||||||||||||||||||||||||||||||||||||||||
| }) { | ||||||||||||||||||||||||||||||||||||||||||
| //태그 컬러 - 랜덤 배정 | ||||||||||||||||||||||||||||||||||||||||||
| //카드 생성 시 - 동일 태그 입력 불가하도록 | ||||||||||||||||||||||||||||||||||||||||||
| const bgColors = ['#F9EEE3', '#E7F7DB', '#F7DBF0', '#DBE6F7'] | ||||||||||||||||||||||||||||||||||||||||||
| const textColors = ['#D58D49', '#86D549', '#D549B6', '#4981D5'] | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| const { resolvedTheme } = useTheme() | ||||||||||||||||||||||||||||||||||||||||||
| const isDark = resolvedTheme === 'dark' | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||
| <div className="flex flex-wrap gap-6"> | ||||||||||||||||||||||||||||||||||||||||||
| {tags.map((tag) => { | ||||||||||||||||||||||||||||||||||||||||||
| const hash = tag | ||||||||||||||||||||||||||||||||||||||||||
| .split('') | ||||||||||||||||||||||||||||||||||||||||||
| .reduce((acc, char) => acc + char.charCodeAt(0), 0) | ||||||||||||||||||||||||||||||||||||||||||
| const colorIndex = hash % 4 | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+23
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 코드 중복 제거 필요 Tags.tsx와 동일한 해시 계산 로직이 중복됩니다. 공통 유틸리티 함수로 추출하세요. 공통 함수를 만들어 중복을 제거하세요: // utils/tagColorUtils.ts
export function getTagColorIndex(tag: string): number {
const hash = tag
.split('')
.reduce((acc, char) => acc + char.charCodeAt(0), 0)
return hash % 4
}그 후 두 컴포넌트에서 사용: - const hash = tag
- .split('')
- .reduce((acc, char) => acc + char.charCodeAt(0), 0)
- const colorIndex = hash % 4
+ const colorIndex = getTagColorIndex(tag)🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| const backgroundColor = isDark | ||||||||||||||||||||||||||||||||||||||||||
| ? textColors[colorIndex] | ||||||||||||||||||||||||||||||||||||||||||
| : bgColors[colorIndex] | ||||||||||||||||||||||||||||||||||||||||||
| const textColor = isDark ? bgColors[colorIndex] : textColors[colorIndex] | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+28
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Tags.tsx와 다크 모드 색상 로직 불일치
일관성을 위해 동일한 색상 로직을 사용하세요: const backgroundColor = isDark
- ? textColors[colorIndex]
+ ? ['#774212', '#366712', '#711E5C', '#0F3167'][colorIndex]
: bgColors[colorIndex]📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||
| <span | ||||||||||||||||||||||||||||||||||||||||||
| key={tag} | ||||||||||||||||||||||||||||||||||||||||||
| className="inline-block whitespace-nowrap rounded-4 px-9 pb-3 pt-5" | ||||||||||||||||||||||||||||||||||||||||||
| style={{ | ||||||||||||||||||||||||||||||||||||||||||
| backgroundColor: backgroundColor, | ||||||||||||||||||||||||||||||||||||||||||
| color: textColor, | ||||||||||||||||||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||||||||||||||||||
| onClick={() => setTags(tags.filter((t) => t !== tag))} | ||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 키보드 접근성 개선 필요 태그 삭제가 마우스 클릭으로만 가능합니다. 키보드 접근성을 위해 Enter/Space 키 지원을 추가하세요. <span
key={tag}
className="inline-block whitespace-nowrap rounded-4 px-9 pb-3 pt-5"
+ role="button"
+ tabIndex={0}
style={{
backgroundColor: backgroundColor,
color: textColor,
}}
onClick={() => setTags(tags.filter((t) => t !== tag))}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault()
+ setTags(tags.filter((t) => t !== tag))
+ }
+ }}
>📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||
| {tag} | ||||||||||||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
| })} | ||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import { ControllerRenderProps } from 'react-hook-form' | ||
|
|
||
| import { cn } from '@/app/shared/lib/cn' | ||
|
|
||
| import { SimpleColumn, useColumnsStore } from '../../store/useColumnsStore' | ||
| import { CardFormData } from '../../type/CardFormData.type' | ||
| import ColumnTitle from '../ColumnTitle' | ||
|
|
||
| interface ColumnListProps { | ||
| setColumn: (selectedColumn: SimpleColumn) => void | ||
| controlField: ControllerRenderProps<CardFormData, 'columnId'> | ||
| } | ||
|
|
||
| // ✅ ColumnList 컴포넌트: 컬럼 목록을 보여주는 드롭다운 리스트 | ||
| // 1. 컬럼 목록을 클릭하면: | ||
| // - setColumn(column) 실행 → 선택된 담당자 객체를 부모 컴포넌트 하에 관리 (ex. UI에서 닉네임 표시용) | ||
| // - controlField.onChange(column.columnId) 실행 → react-hook-form에 columnId 값을 전달 (form 제출에는 Id 데이터만 전달함) | ||
|
|
||
| export default function ColumnList({ | ||
| setColumn, | ||
| controlField, | ||
| }: ColumnListProps) { | ||
| const { ColumnsInDashboard } = useColumnsStore() // 컬럼 목록 데이터는 store에서 불러옴 | ||
|
|
||
| return ( | ||
| <div className="BG-white Border-btn absolute left-0 top-full z-10 mt-4 w-full rounded-6"> | ||
| {ColumnsInDashboard.map((column, 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={column.columnId} | ||
| onClick={() => { | ||
| setColumn(column) // 담당자 업데이트 | ||
| controlField.onChange(column.columnId) // controlField: 폼의 'columnId' 필드와 연결되어 있음. .columnId 값으로 업데이트 | ||
| }} | ||
| > | ||
| <ColumnTitle title={column.columnTitle} /> | ||
| </div> | ||
| ))} | ||
| </div> | ||
| ) | ||
| } |
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
클릭 가능한 카드에 커서 스타일 추가
카드가 클릭 가능하다는 것을 사용자에게 명확히 알려주기 위해 커서 스타일을 추가하세요.
📝 Committable suggestion
🤖 Prompt for AI Agents