Skip to content
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

Merged
merged 30 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a567ce6
feat : 이것저것 ..
youdame Jan 2, 2024
f5512e6
feat : 추가적 구현
youdame Jan 2, 2024
45ebcb5
feat(input disabled) : 인풋 값이 충족되지 않았을 때 disabled 로직 넣어줌
ayden94 Jan 2, 2024
37f7b6d
feat() : 추가
ayden94 Jan 2, 2024
23518da
feat()
ayden94 Jan 2, 2024
39ab817
feat(mydashboard) : 리다이렉션 기능 구현
ayden94 Jan 2, 2024
2edc94f
Co-authored-by: haneul-kimm <han-kimm@users.noreply.github.com>
ayden94 Jan 2, 2024
d28de4b
feat: 디너쇼 1부
han-kimm Jan 2, 2024
3579ebd
feat(무한 스크롤) : 구현
ayden94 Jan 2, 2024
b53fb51
feat(column.tsx) : 카드 무한 스크롤 구현
ayden94 Jan 2, 2024
6ba5b8a
feat : 대시보드 초대 취소, 대시보드 멤버 삭제 기능 구현
youdame Jan 2, 2024
73a1bbe
feat : 반응형 구현
youdame Jan 2, 2024
c7c8f25
feat (무한스크롤): fetch -> sender
han-kimm Jan 3, 2024
d8977d1
feat (초대받은 목록) 무한스크롤
han-kimm Jan 3, 2024
c3c721a
feat (TabalScroll.tsx) : 무한스크롤 구현
han-kimm Jan 3, 2024
1d9ce0f
feat: 커밋
han-kimm Jan 3, 2024
f5ab1aa
feat : 런치쇼
youdame Jan 3, 2024
687efbe
feat : 모달 바깥 부분 클릭시 모달 닫히기 구현 중 및 드래그 앤 드롭 라이브러리 설치
youdame Jan 3, 2024
b82e3b6
feat: 드래그앤드롭 구현중
han-kimm Jan 3, 2024
adb7645
feat : 모달 바깥부분 클릭 시 닫힘 기능 구현
youdame Jan 3, 2024
bc44506
feat : 자신이 쓴 댓글이 아니면 수정 삭제 기능 안 보이게 구현
youdame Jan 3, 2024
4c4b008
feat : ESC 키 누르면 모달 닫기 기능 구현
youdame Jan 3, 2024
c51d1be
Merge branch 'page/co_op' of https://github.com/harigari/taskify into…
han-kimm Jan 3, 2024
8d193a2
feat: 드래그앤드롭~ 핸들러 함수 작성
han-kimm Jan 3, 2024
fccbd0d
feat: 드래그앤드랍~ 아직 put 메서드 실행안함
han-kimm Jan 3, 2024
171a5da
feat: 드래그앤드롭 완성
han-kimm Jan 3, 2024
bb50263
feat (useDragScroll) : 마우스클릭으로 터치스와이핑 구현
han-kimm Jan 3, 2024
39e17b5
feat (useDragScroll) : 카드 이동 시 좌우 스크롤 중지
han-kimm Jan 3, 2024
db582ac
feat: Card 반응형 css 수정
han-kimm Jan 4, 2024
46fcc53
fix: 카드 생성 시 동기화 안되는 오류 수정
han-kimm Jan 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions components/Card/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
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";
Expand All @@ -12,10 +12,10 @@ interface CardProps {
data: CardData;
index: number;
columnTitle: string;
setCardList: Dispatch<SetStateAction<CardData[]>>;
setEntireList: Dispatch<SetStateAction<EntireData>>;
}

const Card = ({ data, index, columnTitle, setCardList }: CardProps) => {
const Card = ({ data, index, columnTitle, setEntireList }: CardProps) => {
const [isCardModalOpen, setIsCardModalOpen] = useState(false);
const { slicedTagList, etc } = tagSlicer(data.tags);

Expand Down Expand Up @@ -82,7 +82,7 @@ const Card = ({ data, index, columnTitle, setCardList }: CardProps) => {
data={data}
columnTitle={columnTitle}
handleModalClose={handleCardModalToggle}
setCardList={setCardList}
setEntireList={setEntireList}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 결국 그럼 모든 컬럼에 있는 모든 카드를 하나의 스테이트에서 가져오기로 한 거군요

/>
)}
</>
Expand Down
65 changes: 29 additions & 36 deletions components/Column/Column.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@ export const Column = ({
});

// 카드리스트 가져오기
const [cardList, setCardList] = useState<CardData[]>([]);

const getComments = async () => {
const { id, size, cursorId } = pagination;
let response;
Expand All @@ -91,7 +89,6 @@ export const Column = ({
setPagination((prevValue) => {
return { ...prevValue, cursorId: cursor };
});
setCardList((prevValue) => [...prevValue, ...cards]);
setEntireList((prev) => ({
...prev,
cards: { ...prev.cards, [columnId]: [...(prev.cards[columnId] ?? []), ...cards] },
Expand Down Expand Up @@ -168,41 +165,38 @@ export const Column = ({

return (
<>
<div className={style.totalContainer}>
{/* 칼럼 상단 */}
<div className={style.headerContainer}>
<div className={style.todoWrapper}>
<ChipTodo size="sm" color="white">
{title}
</ChipTodo>
<ChipNum>{totalCount}</ChipNum>
</div>
<button onClick={handleSettingModalToggle}>
<Image width={24} height={24} src="/icons/icon-settings.svg" alt="칼럼 설정하기" />
</button>
</div>

<div className={style.contentContainer}>
{/* 컴포넌트로 바꾸기 */}
<Button buttonType="plus_icon" color="white" onClick={handleCreateModalToggle}>
<ChipPlus size="lg" />
</Button>
<Droppable droppableId={String(columnId)}>
{(provided) => (
<div {...provided.droppableProps} ref={provided.innerRef}>
{entireList.cards[columnId]?.map((card, index) => (
<Card key={card.id} columnTitle={title} data={card} index={index} setCardList={setCardList} />
))}
{provided.placeholder}
<Droppable droppableId={String(columnId)}>
{(provided) => (
<div {...provided.droppableProps} ref={provided.innerRef} className={style.totalContainer}>
{/* 칼럼 상단 */}
<div className={style.headerContainer}>
<div className={style.todoWrapper}>
<ChipTodo size="sm" color="white">
{title}
</ChipTodo>
<ChipNum>{totalCount}</ChipNum>
</div>
)}
</Droppable>
<p ref={myRef}></p>
</div>
</div>
<button onClick={handleSettingModalToggle}>
<Image width={24} height={24} src="/icons/icon-settings.svg" alt="칼럼 설정하기" />
</button>
</div>

<div className={style.contentContainer}>
{/* 컴포넌트로 바꾸기 */}
<Button buttonType="plus_icon" color="white" onClick={handleCreateModalToggle}>
<ChipPlus size="lg" />
</Button>
{entireList.cards[columnId]?.map((card, index) => (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[ cards: {
  columnA : [{컬럼 A 카드 A}, {컬럼 A 카드 B}],
  columnB : [{컬럼 B 카드 A}, {컬럼 B 카드 B}],
  columnC : [{컬럼 C 카드 A}, {컬럼 C 카드 B}],
 }]

대충 이런 형태인가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ayden94
맞아요~

<Card key={card.id} columnTitle={title} data={card} index={index} setEntireList={setEntireList} />
))}
<p ref={myRef}></p>
</div>
{provided.placeholder}
</div>
)}
</Droppable>
{isSettingModalOpen && (
<ModalWrapper size="md">
<ModalWrapper size="md" handleModalClose={handleSettingModalToggle}>
<form className={stylesFromSingle.form} onSubmit={handleModifyColumn} noValidate>
<div className={stylesFromSingle.modal}>
<div className={stylesFromSingle.modalTitle}>컬럼 관리</div>
Expand Down Expand Up @@ -236,7 +230,6 @@ export const Column = ({
)}
{isCreateModalOpen && (
<MultiInputModal
setCardList={setCardList}
setEntireList={setEntireList}
title="할 일 생성"
buttonText="생성"
Expand Down
24 changes: 15 additions & 9 deletions modals/EditInputModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Input from "@/components/Input/Input";
import InputWrapper from "@/components/Input/InputWrapper";
import useDropdownController from "@/hooks/useDropdownController";
import useInputController from "@/hooks/useInputController";
import { CardData, ColumnData, Member } from "@/types/api.type";
import { CardData, ColumnData, EntireData, Member } from "@/types/api.type";
import formatDateString from "@/utils/formatDateString";
import { getAccessTokenFromDocument } from "@/utils/getAccessToken";
import Image from "next/image";
Expand Down Expand Up @@ -49,7 +49,7 @@ const findColumnId = (columnList: ColumnData[], value: string | undefined) => {
interface EditInputModalProp {
title: string;
buttonText: string;
setCardList: Dispatch<SetStateAction<CardData[]>>;
setEntireList: Dispatch<SetStateAction<EntireData>>;
handleModalClose: () => void;
initialvalue: CardData;
columnTitle: string;
Expand All @@ -59,7 +59,7 @@ const EditInputModal = ({
title,
buttonText,
handleModalClose,
setCardList,
setEntireList,
initialvalue,
columnTitle,
}: EditInputModalProp) => {
Expand Down Expand Up @@ -134,11 +134,14 @@ const EditInputModal = ({
e.preventDefault();

if (imageFile === null) {
const cardUpdateRes = await putData({ path: "card", id: initialvalue.id, data, accessToken });
const cardNoImageRes = await putData({ path: "card", id: initialvalue.id, data, accessToken });

if (cardUpdateRes?.status === 200) {
if (cardNoImageRes?.status === 200) {
handleModalClose();
setCardList((prev) => prev.map((v) => (v.id === cardUpdateRes.data.id ? cardUpdateRes.data : v)));
setEntireList((prev) => ({
...prev,
columns: { ...prev.columns, [cardNoImageRes.data.id]: cardNoImageRes.data },
}));
}
}

Expand All @@ -147,11 +150,14 @@ const EditInputModal = ({

const dataWithImage = { ...data, imageUrl };

const cardRes = await putData({ path: "card", id: initialvalue.id, data: dataWithImage, accessToken });
const cardWithImageRes = await putData({ path: "card", id: initialvalue.id, data: dataWithImage, accessToken });

if (cardRes?.status === 200) {
if (cardWithImageRes?.status === 200) {
handleModalClose();
setCardList((prev) => prev.map((v) => (v.id === cardRes.data.id ? cardRes.data : v)));
setEntireList((prev) => ({
...prev,
columns: { ...prev.columns, [cardWithImageRes.data.id]: cardWithImageRes.data },
}));
}
}
};
Expand Down
2 changes: 0 additions & 2 deletions modals/MultiInputModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ interface MultiInputModalProp {
buttonText: string;
columnId: number;
dashboardId: number;
setCardList: Dispatch<SetStateAction<CardData[]>>;
setEntireList: Dispatch<SetStateAction<EntireData>>;
assigneeList: Member[];
handleModalClose: () => void;
Expand All @@ -33,7 +32,6 @@ const MultiInputModal = ({
buttonText,
handleModalClose,
columnId,
setCardList,
setEntireList,
dashboardId,
assigneeList,
Expand Down
21 changes: 13 additions & 8 deletions modals/TaskCardModal.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import useApi from "@/hooks/useApi";
import EditInputModal from "@/modals/EditInputModal";
import CommentList from "@/modals/components/Comment/CommentList";
import { CardData } from "@/types/api.type";
import { CardData, EntireData } from "@/types/api.type";
import { getAccessTokenFromDocument } from "@/utils/getAccessToken";
import Image from "next/image";
import { Dispatch, FocusEvent, FormEvent, SetStateAction, useRef, useState } from "react";
Expand All @@ -15,11 +15,11 @@ import AssigneeAndDueDateInfo from "./components/AssigneeAndDueDateInfo/Assignee
interface TaskCardInfoProps {
columnTitle: string;
data: CardData;
setCardList: Dispatch<SetStateAction<CardData[]>>;
setEntireList: Dispatch<SetStateAction<EntireData>>;
handleModalClose: () => void;
}

const TaskCardModal = ({ data, columnTitle, setCardList, handleModalClose }: TaskCardInfoProps) => {
const TaskCardModal = ({ data, columnTitle, setEntireList, handleModalClose }: TaskCardInfoProps) => {
const [isKebabOpen, setIsKebabOpen] = useState(false);
const [isCardModifyModalOpen, setCardModifyModalOpen] = useState(false);
const [isCardDeleteModalOpen, setCardDeleteModalOpen] = useState(false);
Expand Down Expand Up @@ -62,10 +62,15 @@ const TaskCardModal = ({ data, columnTitle, setCardList, handleModalClose }: Tas
if (res?.status === 204) {
handleDeleteModalToggle();
handleModalClose();
setCardList((prevValue) => {
const newCardList = prevValue.filter((card) => card.id !== data.id);
return newCardList;
});
setEntireList(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

모든 카드 부분을 이거로 바꾸다니.. 갱장한 노가다였겠군요 ㄷㄷ

(prev) => (
delete prev.columns[data.columnId],
{
...prev,
columnOrder: prev.columnOrder.filter((id) => id !== data.columnId),
}
)
);
}
};

Expand Down Expand Up @@ -94,7 +99,7 @@ const TaskCardModal = ({ data, columnTitle, setCardList, handleModalClose }: Tas
title="할 일 수정"
columnTitle={columnTitle}
buttonText="수정"
setCardList={setCardList}
setEntireList={setEntireList}
handleModalClose={handleModifyModalToggle}
/>
)}
Expand Down
42 changes: 31 additions & 11 deletions pages/dashboard/[boardId]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import { getAccessTokenFromCookie } from "@/utils/getAccessToken";
import { GetServerSidePropsContext, InferGetServerSidePropsType } from "next";
import { FormEvent, useCallback, useEffect, useState } from "react";
import style from "./dashboard.module.css";
import { DragDropContext } from "@hello-pangea/dnd";
import { DragDropContext, DropResult } from "@hello-pangea/dnd";
import { useRouter } from "next/router";

export const getServerSideProps = async (context: GetServerSidePropsContext) => {
const accessToken = getAccessTokenFromCookie(context) as string;
Expand Down Expand Up @@ -102,18 +103,37 @@ const Dashboard = ({
}
};

const [mounted, setMounted] = useState(false);
const [mount, setMount] = useState(false);
const router = useRouter();

useEffect(() => {
setMounted(true);
setMount(true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거는 혹시 다른 코드랑 중복되는, 가령 라이브러리의 예약어라던가, 그런 게 있었던 건가요??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아뇨?? 아마 코드가 지워졌는데 제가 mounted 랑 mount 헷갈린거같아요

setEntireList(entireData);
}, [entireData]);

const onDragEnd = useCallback(() => {}, []);

if (!mounted) return null;

console.log(entireList);
}, [router.query.boardId]);

const onDragEnd = useCallback((result: DropResult) => {
const { destination, source, draggableId } = result;
if (!destination) return;
if (destination.droppableId === source.droppableId) return;
if (destination.droppableId === source.droppableId && source.index === destination.index) return;

console.log(entireList);
console.log(source.droppableId, destination.droppableId);
const dragStartColumnId = Number(source.droppableId);
const startCardList = entireList.cards[dragStartColumnId];
const movingCard = startCardList.splice(source.index, 1);

const dragEndColumnId = Number(destination.droppableId);
const endCardList = entireList.cards[dragEndColumnId];
endCardList.splice(destination.index, 0, ...movingCard);

setEntireList((prev) => ({
...prev,
cards: { ...prev.cards, [dragStartColumnId]: startCardList, [dragEndColumnId]: endCardList },
}));
}, []);

if (!mount) return;
return (
<>
{/* 대시보드에 맞는 레이아웃으로 설정-헤더 수정 */}
Expand Down Expand Up @@ -150,7 +170,7 @@ const Dashboard = ({
</MenuLayout>

{isCreateModal && (
<ModalWrapper size="md">
<ModalWrapper size="md" handleModalClose={handleCreateNewColumnModalToggle}>
<form className={stylesFromSingle.form} onSubmit={handleSubmit} noValidate>
<div className={stylesFromSingle.modal}>
<div className={stylesFromSingle.modalTitle}>새 컬럼 생성</div>
Expand Down