Skip to content

Commit

Permalink
Merge branch 'main' into feature/#35
Browse files Browse the repository at this point in the history
  • Loading branch information
Brightbong92 authored Jul 13, 2024
2 parents 06ae3c5 + 33e8028 commit ab611b8
Show file tree
Hide file tree
Showing 20 changed files with 1,072 additions and 103 deletions.
4 changes: 2 additions & 2 deletions app/course-invitation/_components/Course/Course.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import { StepType } from "../_hooks/useCourseInvitation";

const MENU_LIST: IconInfo[] = [
{ icon: "๐Ÿ”", label: "์Œ์‹", type: "food" },
{ icon: "๐Ÿฅจ", label: "๋””์ €ํŠธ", type: "desert" },
{ icon: "๐Ÿบ", label: "์ˆ ", type: "alchol" },
{ icon: "๐Ÿฅจ", label: "๋””์ €ํŠธ", type: "dessert" },
{ icon: "๐Ÿบ", label: "์ˆ ", type: "beer" },
{ icon: "๐Ÿ•น๏ธ", label: "๋†€๊ฑฐ๋ฆฌ", type: "play" },
];

Expand Down
187 changes: 187 additions & 0 deletions app/edit-course/_components/DragAndDropArea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
"use client";
import React, { useMemo, useState } from "react";
import { DragDropContext, DropResult, Draggable } from "react-beautiful-dnd";
import Image from "next/image";
import CardWithCourse from "@/components/common/Cards/CardWithCourse";
import { SheetWithCourse } from "@/components/common/BottomSheet/SheetWithCourse";
import { iconInfo } from "@/lib/utils";
import { StrictModeDroppable } from "./Droppable";

export type OrderType = "food" | "dessert" | "beer" | "play";

export type ValueType = {
globalIndex: number;
title: string;
type: OrderType;
icon: string;
};

export type ColumnsType = {
course: {
id: "course";
list: Record<OrderType, ValueType[]>;
};
};

type DragAndDropProps = {
initialColumns: ColumnsType;
};

const updateColumnsOnDelete = (
prevColumns: ColumnsType,
globalIndexToDelete: number
): ColumnsType => {
const updatedList: Record<OrderType, ValueType[]> = {
food: [],
dessert: [],
beer: [],
play: [],
};

Object.values(prevColumns.course.list)
.flat()
.forEach((item) => {
if (item.globalIndex !== globalIndexToDelete) {
updatedList[item.type].push(item);
}
});

return {
...prevColumns,
course: {
...prevColumns.course,
list: updatedList,
},
};
};

const reorder = (
list: ValueType[],
startIndex: number,
endIndex: number
): ValueType[] => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);

result.splice(endIndex, 0, removed);
return result;
};

const DragAndDropArea: React.FC<DragAndDropProps> = ({ initialColumns }) => {
const [columns, setColumns] = useState(initialColumns);
const [itemCount, setItemCount] = useState(
Object.values(initialColumns.course.list).flat().length
);

const allItems = useMemo(() => {
return Object.values(columns.course.list)
.flat()
.sort((a, b) => a.globalIndex - b.globalIndex);
}, [columns.course.list]);

const onDragEnd = (result: DropResult) => {
if (!result.destination) {
return;
}

const sourceIndex = result.source.index;
const destinationIndex = result.destination.index;

const reorderedItems = reorder(allItems, sourceIndex, destinationIndex);

const newColumns = { ...columns };
const newList: Record<OrderType, ValueType[]> = {
food: [],
dessert: [],
beer: [],
play: [],
};

reorderedItems.forEach((item, index) => {
item.globalIndex = index;
newList[item.type].push(item);
});

newColumns.course.list = newList;
setColumns(newColumns);
};

const handleItemDelete = (globalIndexToDelete: number) => {
setColumns((prevColumns) =>
updateColumnsOnDelete(prevColumns, globalIndexToDelete)
);
setItemCount(itemCount - 1);
};

const handleItemClick = (type: OrderType) => {
const icon = iconInfo.find((item) => item.type === type);
if (!icon) return;

const newItem = {
globalIndex: itemCount,
title: `${icon.label}`,
type: icon.type,
icon: icon.icon,
};

setColumns((prevColumns) => ({
...prevColumns,
course: {
...prevColumns.course,
list: {
...prevColumns.course.list,
[type]: [...prevColumns.course.list[type], newItem],
},
},
}));
setItemCount(itemCount + 1);
};

return (
<>
<DragDropContext onDragEnd={onDragEnd}>
<StrictModeDroppable droppableId="droppable">
{(provided) => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
className="flex flex-col gap-y-[16px]"
>
{allItems.map((item: ValueType, index: number) => (
<Draggable
key={item.globalIndex}
draggableId={`item-${item.type}-${item.globalIndex}`}
index={index}
>
{(provided) => (
<div
className="flex flex-row items-center justify-center w-[335px] h-[56px] gap-x-[16px]"
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<Image
src="/svg/ic_x.svg"
alt="x"
width={16}
height={16}
priority
unoptimized
onClick={() => handleItemDelete(item.globalIndex)}
/>
<CardWithCourse item={item} />
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</StrictModeDroppable>
</DragDropContext>
{itemCount < 5 && <SheetWithCourse handleItemClick={handleItemClick} />}
</>
);
};

export default DragAndDropArea;
21 changes: 21 additions & 0 deletions app/edit-course/_components/Droppable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useEffect, useState } from "react";
import { Droppable, DroppableProps } from "react-beautiful-dnd";

export const StrictModeDroppable = ({ children, ...props }: DroppableProps) => {
const [enabled, setEnabled] = useState(false);

useEffect(() => {
const animation = requestAnimationFrame(() => setEnabled(true));

return () => {
cancelAnimationFrame(animation);
setEnabled(false);
};
}, []);

if (!enabled) {
return null;
}

return <Droppable {...props}>{children}</Droppable>;
};
26 changes: 26 additions & 0 deletions app/edit-course/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from "react";
import DragAndDropArea, { ColumnsType } from "./_components/DragAndDropArea";

// ์‚ฌ์šฉ์ž๊ฐ€ ์„ค์ •ํ•œ ๋ฐ์ดํ„ฐ๋ผ๊ณ  ๊ฐ€์ •
const initialColumns: ColumnsType = {
course: {
id: "course",
list: {
food: [
{ globalIndex: 0, title: "์Œ์‹", type: "food", icon: "๐Ÿ”" },
{ globalIndex: 2, title: "์Œ์‹", type: "food", icon: "๐Ÿ”" },
],
dessert: [
{ globalIndex: 1, title: "๋””์ €ํŠธ", type: "dessert", icon: "๐Ÿฅจ" },
],
beer: [],
play: [],
},
},
};

const EditCoursePage = () => {
return <DragAndDropArea initialColumns={initialColumns} />;
};

export default EditCoursePage;
9 changes: 6 additions & 3 deletions app/input/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { Input } from "@/components/common/Input/Input";
import PasswordKeypad from "@/components/common/PasswordKeypad/PasswordKeypad";
import React from "react";

const InputPage = () => {
return (
<div className="p-20">
<Input placeholder="๋ชจ์ž„ ๋‚ ์งœ์™€ ์ง€์—ญ ๋“ฑ ์ž์œ ๋กญ๊ฒŒ ๊ธฐ์žฌํ•˜์„ธ์š”" />
<div>
{/* <Input placeholder="๋ชจ์ž„ ๋‚ ์งœ์™€ ์ง€์—ญ ๋“ฑ ์ž์œ ๋กญ๊ฒŒ ๊ธฐ์žฌํ•˜์„ธ์š”" />
<Input
placeholder="๋ชจ์ž„ ๋‚ ์งœ์™€ ์ง€์—ญ ๋“ฑ ์ž์œ ๋กญ๊ฒŒ ๊ธฐ์žฌํ•˜์„ธ์š”"
leftSlot={<div>as</div>}
/>
/> */}

<PasswordKeypad />
</div>
);
};
Expand Down
65 changes: 0 additions & 65 deletions app/test/page.tsx

This file was deleted.

Loading

0 comments on commit ab611b8

Please sign in to comment.