Skip to content

Commit e1758e9

Browse files
committed
feat: 에픽별 페이지에 에픽이 없을 경우 에픽 생성 버튼 표시
1 parent 4b1a1bb commit e1758e9

File tree

3 files changed

+117
-9
lines changed

3 files changed

+117
-9
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Plus from "../../assets/icons/plus.svg?react";
2+
3+
interface EpicCreateButtonProps {
4+
onClick: () => void;
5+
}
6+
7+
const EpicCreateButton = ({ onClick }: EpicCreateButtonProps) => (
8+
<button
9+
type="button"
10+
className="flex items-center justify-center w-full gap-2 py-1 rounded-md bg-middle-green"
11+
onClick={onClick}
12+
>
13+
<Plus width={24} height={24} stroke="white" />
14+
<span className="text-white">Epic 생성하기</span>
15+
</button>
16+
);
17+
18+
export default EpicCreateButton;
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { ChangeEvent, useRef, useState } from "react";
2+
import { useOutletContext } from "react-router-dom";
3+
import { Socket } from "socket.io-client";
4+
import { LexoRank } from "lexorank";
5+
import useEpicEmitEvent from "../../hooks/pages/backlog/useEpicEmitEvent";
6+
import { CATEGORY_COLOR } from "../../constants/backlog";
7+
import getNewColor from "../../utils/getNewColor";
8+
import Check from "../../assets/icons/check.svg?react";
9+
import Closed from "../../assets/icons/closed.svg?react";
10+
11+
interface EpicCreateFormProps {
12+
onCloseClick: () => void;
13+
}
14+
15+
const EpicCreateForm = ({ onCloseClick }: EpicCreateFormProps) => {
16+
const [value, setValue] = useState("");
17+
const [epicColor] = useState(getNewColor(Object.keys(CATEGORY_COLOR)));
18+
const { socket }: { socket: Socket } = useOutletContext();
19+
const { emitEpicCreateEvent } = useEpicEmitEvent(socket);
20+
21+
const inputElementRef = useRef<HTMLInputElement | null>(null);
22+
23+
const handleInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
24+
const { value } = target;
25+
26+
setValue(value);
27+
};
28+
29+
const handleSubmit = () => {
30+
if (value.length > 10) {
31+
alert("에픽 이름은 10자 이하여야 합니다.");
32+
return;
33+
}
34+
35+
emitEpicCreateEvent({
36+
name: value,
37+
color: epicColor,
38+
rankValue: LexoRank.middle().toString(),
39+
});
40+
setValue("");
41+
onCloseClick();
42+
};
43+
44+
return (
45+
<form className="flex items-center w-full py-1" onSubmit={handleSubmit}>
46+
<input
47+
className="w-full mr-3 bg-gray-200 rounded-sm focus:outline-none hover:cursor-pointer"
48+
type="text"
49+
ref={inputElementRef}
50+
onChange={handleInputChange}
51+
/>
52+
<div className="flex items-center gap-2">
53+
<button
54+
className="flex items-center justify-center w-6 h-6 rounded-md bg-confirm-green"
55+
type="button"
56+
onClick={handleSubmit}
57+
>
58+
<Check width={20} height={20} stroke="white" />
59+
</button>
60+
<button
61+
className="flex items-center justify-center w-6 h-6 rounded-md bg-error-red"
62+
type="button"
63+
onClick={onCloseClick}
64+
>
65+
<Closed stroke="white" />
66+
</button>
67+
</div>
68+
</form>
69+
);
70+
};
71+
72+
export default EpicCreateForm;

frontend/src/pages/backlog/EpicPage.tsx

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
11
import { DragEvent, useEffect, useMemo, useRef, useState } from "react";
22
import { useOutletContext } from "react-router-dom";
3-
import { BacklogDTO, StoryDTO, TaskDTO } from "../../types/DTO/backlogDTO";
3+
import { Socket } from "socket.io-client";
4+
import { LexoRank } from "lexorank";
5+
import useStoryEmitEvent from "../../hooks/pages/backlog/useStoryEmitEvent";
6+
import useTaskEmitEvent from "../../hooks/pages/backlog/useTaskEmitEvent";
7+
import getDragElementIndex from "../../utils/getDragElementIndex";
8+
import useEpicEmitEvent from "../../hooks/pages/backlog/useEpicEmitEvent";
9+
import useShowDetail from "../../hooks/pages/backlog/useShowDetail";
410
import StoryCreateButton from "../../components/backlog/StoryCreateButton";
511
import StoryCreateForm from "../../components/backlog/StoryCreateForm";
612
import StoryBlock from "../../components/backlog/StoryBlock";
713
import TaskBlock from "../../components/backlog/TaskBlock";
814
import EpicBlock from "../../components/backlog/EpicBlock";
915
import TaskContainer from "../../components/backlog/TaskContainer";
1016
import TaskHeader from "../../components/backlog/TaskHeader";
11-
import { Socket } from "socket.io-client";
12-
import useStoryEmitEvent from "../../hooks/pages/backlog/useStoryEmitEvent";
13-
import useTaskEmitEvent from "../../hooks/pages/backlog/useTaskEmitEvent";
14-
import getDragElementIndex from "../../utils/getDragElementIndex";
15-
import { LexoRank } from "lexorank";
16-
import useEpicEmitEvent from "../../hooks/pages/backlog/useEpicEmitEvent";
17-
import { BacklogSocketData } from "../../types/common/backlog";
1817
import EpicPageStoryDragContainer from "../../components/backlog/EpicPageStoryDragContainer";
1918
import EpicPageTaskDragContainer from "../../components/backlog/EpicPageTaskDragContainer";
2019
import EpicDragContainer from "../../components/backlog/EpicDragContainer";
2120
import TaskCreateBlock from "../../components/backlog/TaskCreateBlock";
21+
import EpicCreateButton from "../../components/backlog/EpicCreateButton";
22+
import { BacklogSocketData } from "../../types/common/backlog";
23+
import { BacklogDTO, StoryDTO, TaskDTO } from "../../types/DTO/backlogDTO";
24+
import EpicCreateForm from "../../components/backlog/EpicCreateForm";
2225

2326
const EpicPage = () => {
2427
const { socket, backlog }: { socket: Socket; backlog: BacklogDTO } =
@@ -29,6 +32,10 @@ const EpicPage = () => {
2932
const [showStory, setShowStory] = useState<{
3033
[key: number]: { showStoryList: boolean; showStoryForm: boolean };
3134
}>({});
35+
const {
36+
showDetail: showEpicCreateForm,
37+
handleShowDetail: handleShowEpicCreateForm,
38+
} = useShowDetail();
3239

3340
useEffect(() => {
3441
setShowStory((prevShowStory) => {
@@ -469,7 +476,18 @@ const EpicPage = () => {
469476
};
470477

471478
return (
472-
<div className="gap-4 pb-10" onDragOver={handleEpicDragOver}>
479+
<div className="gap-4 pb-10 border-t" onDragOver={handleEpicDragOver}>
480+
{!epicList.length && (
481+
<div className="mt-4">
482+
{showEpicCreateForm ? (
483+
<EpicCreateForm
484+
onCloseClick={() => handleShowEpicCreateForm(false)}
485+
/>
486+
) : (
487+
<EpicCreateButton onClick={() => handleShowEpicCreateForm(true)} />
488+
)}
489+
</div>
490+
)}
473491
{...epicList.map(
474492
({ id: epicId, name, color, rankValue, storyList }, epicIndex) => {
475493
storyComponentRefList.current[epicIndex] = [];

0 commit comments

Comments
 (0)