-
Notifications
You must be signed in to change notification settings - Fork 4
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
[#54] Drag & Drop UI 구현 #55
Changes from all commits
a567ce6
f5512e6
45ebcb5
37f7b6d
23518da
39ab817
2edc94f
d28de4b
3579ebd
b53fb51
6ba5b8a
73a1bbe
c7c8f25
d8977d1
c3c721a
1d9ce0f
f5ab1aa
687efbe
b82e3b6
adb7645
bc44506
4c4b008
c51d1be
8d193a2
fccbd0d
171a5da
bb50263
39e17b5
db582ac
46fcc53
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 |
---|---|---|
|
@@ -13,14 +13,8 @@ class Api { | |
if (typeof result === "string") { | ||
return result; | ||
} | ||
if (typeof result === "function" && "dashboardId" in obj) { | ||
return result(obj.dashboardId, obj.invitationId); | ||
} | ||
if (typeof result === "function" && "id" in obj) { | ||
return result(obj.id); | ||
} | ||
if (typeof result === "function" && "method" in obj) { | ||
return result(obj.method); | ||
if (typeof result === "function") { | ||
return result(obj); | ||
} | ||
}; | ||
|
||
|
@@ -47,7 +41,7 @@ class Api { | |
}, | ||
}); | ||
const data = await res.json(); | ||
return { status: res.status, data }; | ||
return { status: res.status, data, message: data.message }; | ||
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. 서버에서 오류 메시지가 있을 경우, 메시지를 담는 속성을 추가해두었습니다. |
||
}; | ||
|
||
put: HTTP<"put"> = async (obj) => { | ||
|
@@ -59,11 +53,11 @@ class Api { | |
}); | ||
|
||
if (res.status === 204) { | ||
return { status: res.status, data: null }; | ||
return { status: res.status, data: null as any }; | ||
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. delete 일때는 데이터가 안 담겨져서 오는데 data 속성을 null 로 해도 타입 통과가 안돼서, 일단은 any 선언했습니다. |
||
} | ||
|
||
const data = await res.json(); | ||
return { status: res.status, data }; | ||
|
||
return { status: res.status, data, message: data.message }; | ||
}; | ||
|
||
delete: HTTP<"delete"> = async (obj) => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,6 +54,9 @@ | |
} | ||
|
||
.cardCountWrapper { | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
padding: 0.4rem 0.6rem; | ||
width: fit-content; | ||
height: 2rem; | ||
|
@@ -92,32 +95,44 @@ | |
.cardContainer { | ||
flex-direction: row; | ||
align-items: center; | ||
gap: 2rem; | ||
} | ||
.imageContent { | ||
width: 11rem; | ||
|
||
.imageWrapper { | ||
width: 100%; | ||
height: auto; | ||
} | ||
Comment on lines
+101
to
104
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. 카드에 담긴 imge를 반응형으로 창 크기에 따라서 너비가 커지게 만들었습니다. 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. 화긴요 |
||
|
||
.allContentContainer { | ||
align-items: center; | ||
flex-direction: row; | ||
} | ||
|
||
.cardTagsWrapper { | ||
justify-content: start; | ||
max-width: 20rem; | ||
} | ||
|
||
.cardTagCotainer { | ||
margin-right: 1.6rem; | ||
} | ||
|
||
.cardCountWrapper { | ||
display: none; | ||
} | ||
|
||
.cardInfoWrapper { | ||
justify-content: space-between; | ||
margin-top: 0; | ||
} | ||
|
||
.imageWrapper { | ||
max-width: 50%; | ||
} | ||
|
||
.imageWrapper img { | ||
width: 9.08rem; | ||
height: 5.3rem; | ||
width: 100%; | ||
height: 8em; | ||
} | ||
} | ||
|
||
|
@@ -127,43 +142,59 @@ | |
align-items: flex-start; | ||
width: 100%; | ||
} | ||
|
||
.cardContentContainer { | ||
width: 100%; | ||
} | ||
|
||
.imageContent { | ||
width: 26rem; | ||
height: 15.2rem; | ||
} | ||
|
||
.allContentContainer { | ||
flex-direction: column; | ||
align-items: flex-start; | ||
} | ||
|
||
.cardTitleWrapper { | ||
font-size: 1.4rem; | ||
} | ||
|
||
.cardTagCotainer { | ||
margin: 0; | ||
width: 100%; | ||
gap: 0.8rem; | ||
} | ||
|
||
.dateIcon { | ||
width: 1.4rem; | ||
height: 1.4rem; | ||
} | ||
|
||
.date { | ||
font-size: 1rem; | ||
} | ||
|
||
.cardInfoWrapper { | ||
width: 100%; | ||
} | ||
|
||
.cardTagsWrapper { | ||
max-width: 100%; | ||
} | ||
|
||
.cardCountWrapper { | ||
display: flex; | ||
} | ||
|
||
.imageWrapper { | ||
width: 100%; | ||
max-width: 100%; | ||
} | ||
|
||
.imageWrapper img { | ||
width: 26rem; | ||
height: 15.2rem; | ||
width: 100%; | ||
height: 20rem; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,21 @@ | ||
import ProfileIcon from "@/components/Members/ProfileIcon"; | ||
import { CardData } from "@/types/api.type"; | ||
import { CardData, EntireData } from "@/types/api.type"; | ||
import Image from "next/image"; | ||
import ChipTag from "../Chips/ChipTag/ChipTag"; | ||
import styles from "./Card.module.css"; | ||
import formatDateString from "@/utils/formatDateString"; | ||
import { Dispatch, SetStateAction, useState } from "react"; | ||
import TaskCardModal from "@/modals/TaskCardModal"; | ||
import { Draggable } from "@hello-pangea/dnd"; | ||
|
||
interface CardProps { | ||
data: CardData; | ||
index: number; | ||
columnTitle: string; | ||
setCardList: Dispatch<SetStateAction<CardData[]>>; | ||
setEntireList: Dispatch<SetStateAction<EntireData>>; | ||
} | ||
|
||
const Card = ({ data, columnTitle, setCardList }: CardProps) => { | ||
const Card = ({ data, index, columnTitle, setEntireList }: CardProps) => { | ||
const [isCardModalOpen, setIsCardModalOpen] = useState(false); | ||
const { slicedTagList, etc } = tagSlicer(data.tags); | ||
|
||
|
@@ -22,60 +24,70 @@ const Card = ({ data, columnTitle, setCardList }: CardProps) => { | |
}; | ||
|
||
return ( | ||
<> | ||
<div className={styles.cardContainer} onClick={handleCardModalToggle}> | ||
{/* 카드 이미지 */} | ||
{data.imageUrl && ( | ||
<div className={styles.imageWrapper}> | ||
<Image width={274} height={160} className={styles.imageContent} src={data.imageUrl} alt="카드" /> | ||
</div> | ||
)} | ||
{/* 카드 내용 */} | ||
<div className={styles.cardContentContainer}> | ||
{/* 카드 제목 */} | ||
<span className={styles.cardTitleWrapper}>{data.title}</span> | ||
<div className={styles.allContentContainer}> | ||
{/* 카드 태그들 */} | ||
<div className={styles.cardTagContainer}> | ||
<div className={styles.cardTagsWrapper}> | ||
{slicedTagList.map((tag: string) => ( | ||
<ChipTag size="sm" key={tag}> | ||
{tag} | ||
</ChipTag> | ||
))} | ||
<Draggable draggableId={String(data.id)} index={index}> | ||
{(provided) => ( | ||
<> | ||
<article | ||
{...provided.draggableProps} | ||
{...provided.dragHandleProps} | ||
ref={provided.innerRef} | ||
className={styles.cardContainer} | ||
onClick={handleCardModalToggle} | ||
> | ||
{/* 카드 이미지 */} | ||
{data.imageUrl && ( | ||
<div className={styles.imageWrapper}> | ||
<Image width={274} height={160} className={styles.imageContent} src={data.imageUrl} alt="카드" /> | ||
</div> | ||
{etc > 0 && ( | ||
<div className={styles.cardCountWrapper}> | ||
<span>그 외 {etc}개</span> | ||
)} | ||
{/* 카드 내용 */} | ||
<div className={styles.cardContentContainer}> | ||
{/* 카드 제목 */} | ||
<span className={styles.cardTitleWrapper}>{data.title}</span> | ||
<div className={styles.allContentContainer}> | ||
{/* 카드 태그들 */} | ||
<div className={styles.cardTagContainer}> | ||
<div className={styles.cardTagsWrapper}> | ||
{slicedTagList.map((tag: string) => ( | ||
<ChipTag size="sm" key={tag}> | ||
{tag} | ||
</ChipTag> | ||
))} | ||
</div> | ||
{etc > 0 && ( | ||
<div className={styles.cardCountWrapper}> | ||
<span>그 외 {etc}개</span> | ||
</div> | ||
)} | ||
</div> | ||
{/* 카드 하단 날짜, 지정자 */} | ||
<div className={styles.cardInfoWrapper}> | ||
<div className={styles.dateWrapper}> | ||
<Image | ||
className={styles.dateIcon} | ||
src="/icons/icon-calendar.svg" | ||
alt="Calendar Icon" | ||
width={20} | ||
height={20} | ||
/> | ||
<span className={styles.date}>{formatDateString(data.dueDate, "KOREA", "yyyy.MM.dd")}</span> | ||
</div> | ||
<ProfileIcon member={data.assignee} size="sm" /> | ||
</div> | ||
)} | ||
</div> | ||
{/* 카드 하단 날짜, 지정자 */} | ||
<div className={styles.cardInfoWrapper}> | ||
<div className={styles.dateWrapper}> | ||
<Image | ||
className={styles.dateIcon} | ||
src="/icons/icon-calendar.svg" | ||
alt="Calendar Icon" | ||
width={20} | ||
height={20} | ||
/> | ||
<span className={styles.date}>{formatDateString(data.dueDate, "KOREA", "yyyy.MM.dd")}</span> | ||
</div> | ||
<ProfileIcon member={data.assignee} size="sm" /> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
{isCardModalOpen && ( | ||
<TaskCardModal | ||
data={data} | ||
columnTitle={columnTitle} | ||
handleModalClose={handleCardModalToggle} | ||
setCardList={setCardList} | ||
/> | ||
</article> | ||
{isCardModalOpen && ( | ||
<TaskCardModal | ||
data={data} | ||
columnTitle={columnTitle} | ||
handleModalClose={handleCardModalToggle} | ||
setEntireList={setEntireList} | ||
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. 이건 결국 그럼 모든 컬럼에 있는 모든 카드를 하나의 스테이트에서 가져오기로 한 거군요 |
||
/> | ||
)} | ||
</> | ||
)} | ||
</> | ||
</Draggable> | ||
); | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,7 +40,7 @@ | |
|
||
/* 화이트 버전일 때 */ | ||
.white { | ||
background-color: white; | ||
background-color: var(--gray10); | ||
} | ||
|
||
.whiteText { | ||
|
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.
sender 내부에서 makeUrl 함수를 호출 할 때 각각의 파라미터 순서를 지키는게 불편해서
객체로 받아서 내부에서 처리하도록 했습니다~