Skip to content

Commit b693606

Browse files
authored
Merge pull request #323 from boostcampwm2023/feature/drag-and-drop
fix: 스토리 우선순위 변경 로직 수정
2 parents 352531b + bc286d9 commit b693606

File tree

4 files changed

+80
-48
lines changed

4 files changed

+80
-48
lines changed

frontend/src/components/backlog/EpicDropdown.tsx

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
import { ChangeEvent, useEffect, useMemo, useRef, useState } from "react";
1+
import { ChangeEvent, useEffect, useRef, useState } from "react";
22
import { useOutletContext } from "react-router-dom";
33
import { Socket } from "socket.io-client";
44
import { EpicCategoryDTO } from "../../types/DTO/backlogDTO";
55
import CategoryChip from "./CategoryChip";
66
import useEpicEmitEvent from "../../hooks/pages/backlog/useEpicEmitEvent";
77
import { CATEGORY_COLOR } from "../../constants/backlog";
8-
import getRandomNumber from "../../utils/getRandomNumber";
98
import {
10-
BacklogCategoryColor,
119
BacklogSocketData,
1210
BacklogSocketDomain,
1311
BacklogSocketEpicAction,
1412
} from "../../types/common/backlog";
1513
import EpicDropdownOption from "./EpicDropdownOption";
1614
import { LexoRank } from "lexorank";
15+
import getNewColor from "../../utils/getNewColor";
1716

1817
interface EpicDropdownProps {
1918
selectedEpic?: EpicCategoryDTO;
@@ -29,13 +28,10 @@ const EpicDropdown = ({
2928
const { socket }: { socket: Socket } = useOutletContext();
3029
const { emitEpicCreateEvent } = useEpicEmitEvent(socket);
3130
const [value, setValue] = useState("");
31+
const [epicColor, setEpicColor] = useState(
32+
getNewColor(Object.keys(CATEGORY_COLOR))
33+
);
3234
const inputElementRef = useRef<HTMLInputElement | null>(null);
33-
const epicColor = useMemo(() => {
34-
const colors = Object.keys(CATEGORY_COLOR);
35-
return colors[
36-
getRandomNumber(0, colors.length - 1)
37-
] as BacklogCategoryColor;
38-
}, []);
3935

4036
const handleInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
4137
const { value } = target;
@@ -60,8 +56,9 @@ const EpicDropdown = ({
6056
.toString()
6157
: LexoRank.middle().toString();
6258

63-
setValue("");
6459
emitEpicCreateEvent({ name: value, color: epicColor, rankValue });
60+
setValue("");
61+
setEpicColor(getNewColor(Object.keys(CATEGORY_COLOR)));
6562
}
6663
};
6764

@@ -109,27 +106,28 @@ const EpicDropdown = ({
109106
ref={inputElementRef}
110107
/>
111108
</div>
112-
<ul className="pt-1">
113-
{...epicList.map((epic) => (
114-
<li
115-
key={epic.id}
116-
onClick={() => {
117-
handleEpicChange(epic.id);
118-
}}
119-
>
120-
<EpicDropdownOption
121-
key={epic.id}
122-
epic={epic}
123-
onEpicChange={handleEpicChange}
124-
/>
125-
</li>
126-
))}
127-
</ul>
128-
{value && (
109+
{value ? (
129110
<div className="flex items-center gap-2 p-1">
130111
<span>생성</span>
131112
<CategoryChip content={value} bgColor={epicColor} />
132113
</div>
114+
) : (
115+
<ul className="max-h-[16rem] overflow-y-auto scrollbar-thin pt-1">
116+
{...epicList.map((epic) => (
117+
<li
118+
key={epic.id}
119+
onClick={() => {
120+
handleEpicChange(epic.id);
121+
}}
122+
>
123+
<EpicDropdownOption
124+
key={epic.id}
125+
epic={epic}
126+
onEpicChange={handleEpicChange}
127+
/>
128+
</li>
129+
))}
130+
</ul>
133131
)}
134132
</div>
135133
);

frontend/src/pages/backlog/UnfinishedStoryPage.tsx

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,35 @@ import { LexoRank } from "lexorank";
44
import { BacklogDTO } from "../../types/DTO/backlogDTO";
55
import StoryCreateButton from "../../components/backlog/StoryCreateButton";
66
import StoryCreateForm from "../../components/backlog/StoryCreateForm";
7-
import { DragEvent, useMemo, useRef, useState } from "react";
7+
import { DragEvent, useEffect, useMemo, useRef, useState } from "react";
88
import changeEpicListToStoryList from "../../utils/changeEpicListToStoryList";
99
import StoryBlock from "../../components/backlog/StoryBlock";
1010
import TaskBlock from "../../components/backlog/TaskBlock";
1111
import useShowDetail from "../../hooks/pages/backlog/useShowDetail";
1212
import useStoryEmitEvent from "../../hooks/pages/backlog/useStoryEmitEvent";
1313
import getDragElementIndex from "../../utils/getDragElementIndex";
14+
import { BacklogSocketData } from "../../types/common/backlog";
1415

1516
const UnfinishedStoryPage = () => {
1617
const { socket, backlog }: { socket: Socket; backlog: BacklogDTO } =
1718
useOutletContext();
1819
const { showDetail, handleShowDetail } = useShowDetail();
1920
const [storyElementIndex, setStoryElementIndex] = useState<number>();
2021
const storyComponentRefList = useRef<HTMLDivElement[]>([]);
21-
const draggingComponentIndexRef = useRef<number>();
22+
const draggingComponentIdRef = useRef<number>();
2223
const storyList = useMemo(
2324
() =>
24-
changeEpicListToStoryList(backlog.epicList).sort((storyA, storyB) => {
25-
if (storyA.rankValue < storyB.rankValue) {
26-
return -1;
27-
}
28-
if (storyA.rankValue > storyB.rankValue) {
29-
return 1;
30-
}
31-
return 0;
32-
}),
25+
changeEpicListToStoryList(backlog.epicList)
26+
.sort((storyA, storyB) => {
27+
if (storyA.rankValue < storyB.rankValue) {
28+
return -1;
29+
}
30+
if (storyA.rankValue > storyB.rankValue) {
31+
return 1;
32+
}
33+
return 0;
34+
})
35+
.filter(({ status }) => status !== "완료"),
3336
[backlog.epicList]
3437
);
3538
const epicCategoryList = useMemo(
@@ -52,23 +55,26 @@ const UnfinishedStoryPage = () => {
5255
event.preventDefault();
5356
const index = getDragElementIndex(
5457
storyComponentRefList.current,
55-
draggingComponentIndexRef.current,
58+
draggingComponentIdRef.current,
5659
event.clientY
5760
);
5861

5962
setStoryElementIndex(index);
6063
};
6164

62-
const handleDragStart = (index: number) => {
63-
draggingComponentIndexRef.current = index;
65+
const handleDragStart = (id: number) => {
66+
draggingComponentIdRef.current = id;
6467
};
6568

6669
const handleDragEnd = (event: DragEvent) => {
6770
event.stopPropagation();
71+
const targetIndex = storyList.findIndex(
72+
({ id }) => id === draggingComponentIdRef.current
73+
);
6874
let rankValue;
6975

70-
if (storyElementIndex === draggingComponentIndexRef.current) {
71-
draggingComponentIndexRef.current = undefined;
76+
if (storyElementIndex === targetIndex) {
77+
draggingComponentIdRef.current = undefined;
7278
setStoryElementIndex(undefined);
7379
return;
7480
}
@@ -90,14 +96,36 @@ const UnfinishedStoryPage = () => {
9096
}
9197

9298
emitStoryUpdateEvent({
93-
id: storyList[draggingComponentIndexRef.current as number].id,
99+
id: draggingComponentIdRef.current as number,
94100
rankValue,
95101
});
96102

97-
draggingComponentIndexRef.current = undefined;
103+
draggingComponentIdRef.current = undefined;
98104
setStoryElementIndex(undefined);
99105
};
100106

107+
useEffect(() => {
108+
const handleDragEvent = ({
109+
domain,
110+
action,
111+
content,
112+
}: BacklogSocketData) => {
113+
if (
114+
domain === "story" &&
115+
action === "delete" &&
116+
content.id === draggingComponentIdRef.current
117+
) {
118+
setStoryElementIndex(undefined);
119+
}
120+
};
121+
122+
socket.on("backlog", handleDragEvent);
123+
124+
return () => {
125+
socket.off("backlog", handleDragEvent);
126+
};
127+
}, []);
128+
101129
return (
102130
<div className="flex flex-col items-center gap-4">
103131
<div className="w-full border-b" onDragOver={handleDragOver}>
@@ -116,7 +144,7 @@ const UnfinishedStoryPage = () => {
116144
className="relative"
117145
ref={setStoryComponentRef(index)}
118146
draggable={true}
119-
onDragStart={() => handleDragStart(index)}
147+
onDragStart={() => handleDragStart(id)}
120148
onDragEnd={handleDragEnd}
121149
>
122150
<div
@@ -146,7 +174,7 @@ const UnfinishedStoryPage = () => {
146174
ref={setStoryComponentRef(storyList.length)}
147175
className={`${
148176
storyElementIndex === storyList.length
149-
? "w-full h-1 bg-blue-400"
177+
? "w-[67.9rem] h-1 bg-blue-400"
150178
: ""
151179
} absolute`}
152180
/>

frontend/src/utils/getDragElementIndex.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ const getDragElementIndex = (
77
(closest, child, index) => {
88
const box = child.getBoundingClientRect();
99
const offset = y - box.top - box.height / 2;
10-
console.log(offset);
1110

1211
if (offset < 0 && offset > closest.offset) {
1312
return { offset, index };

frontend/src/utils/getNewColor.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { BacklogCategoryColor } from "../types/common/backlog";
2+
import getRandomNumber from "./getRandomNumber";
3+
4+
const getNewColor = (colors: string[]) =>
5+
colors[getRandomNumber(0, colors.length - 1)] as BacklogCategoryColor;
6+
7+
export default getNewColor;

0 commit comments

Comments
 (0)