From 79f1f39098f640c7a37cf84f93360cfc1813daa7 Mon Sep 17 00:00:00 2001 From: surinkwon Date: Fri, 12 Jul 2024 16:37:12 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=EC=8A=A4=ED=86=A0=EB=A6=AC=20?= =?UTF-8?q?=ED=83=80=EC=9D=B4=ED=8B=80=20=EA=B8=80=EC=9E=90=EC=88=98=20?= =?UTF-8?q?=EC=A0=9C=ED=95=9C,=20=EC=8A=A4=ED=86=A0=EB=A6=AC=20=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8=20=EB=B2=94=EC=9C=84=20=EC=A0=9C=ED=95=9C,?= =?UTF-8?q?=20=EC=8A=A4=ED=86=A0=EB=A6=AC=20=ED=83=80=EC=9D=B4=ED=8B=80=20?= =?UTF-8?q?=EC=8A=A4=ED=83=80=EC=9D=BC=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 스토리 타이틀 글자 수를 100자 이하로 제한 스토리 포인트를 0이상, 100이하이면서 정수로 제한 스토리 타이틀의 길이가 컨테이너 크기보다 길어지면 말줄임표 표시 --- frontend/src/components/backlog/StoryBlock.tsx | 7 ++++++- .../src/components/backlog/StoryCreateForm.tsx | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/backlog/StoryBlock.tsx b/frontend/src/components/backlog/StoryBlock.tsx index 9a618fcc..0686d04a 100644 --- a/frontend/src/components/backlog/StoryBlock.tsx +++ b/frontend/src/components/backlog/StoryBlock.tsx @@ -206,7 +206,12 @@ const StoryBlock = ({ defaultValue={title} /> ) : ( - {title} + + {title} + )}
{ const handleSubmit = (event: FormEvent) => { event.preventDefault(); + if (epicId === undefined) { alert("에픽을 지정해주세요."); return; @@ -54,6 +55,21 @@ const StoryCreateForm = ({ onCloseClick, epicList }: StoryCreateFormProps) => { return; } + if (title.length > 100) { + alert("스토리 타이틀은 100자 이하여야 합니다."); + return; + } + + if (point < 0 || point > 100) { + alert("포인트는 0이상 100이하여야 합니다."); + return; + } + + if (!Number.isInteger(point)) { + alert("포인트는 정수여야 합니다."); + return; + } + emitStoryCreateEvent({ title, status, epicId, point }); onCloseClick(); }; From 8a950378a5e4e2ff1fc350dd7f760f62ffaf292d Mon Sep 17 00:00:00 2001 From: surinkwon Date: Fri, 12 Jul 2024 23:37:31 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=ED=83=9C=EC=8A=A4=ED=81=AC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20API=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/backlog/StoryBlock.tsx | 4 +- .../components/backlog/TaskCreateBlock.tsx | 25 ++++ .../components/backlog/TaskCreateButton.tsx | 7 +- .../src/components/backlog/TaskCreateForm.tsx | 130 ++++++++++++++++++ .../hooks/pages/backlog/useBacklogSocket.ts | 39 +++++- .../hooks/pages/backlog/useTaskEmitEvent.ts | 12 ++ frontend/src/types/DTO/backlogDTO.ts | 1 + frontend/src/types/common/backlog.ts | 25 +++- 8 files changed, 238 insertions(+), 5 deletions(-) create mode 100644 frontend/src/components/backlog/TaskCreateBlock.tsx create mode 100644 frontend/src/components/backlog/TaskCreateForm.tsx create mode 100644 frontend/src/hooks/pages/backlog/useTaskEmitEvent.ts diff --git a/frontend/src/components/backlog/StoryBlock.tsx b/frontend/src/components/backlog/StoryBlock.tsx index 0686d04a..fa371be0 100644 --- a/frontend/src/components/backlog/StoryBlock.tsx +++ b/frontend/src/components/backlog/StoryBlock.tsx @@ -4,7 +4,6 @@ import useShowDetail from "../../hooks/pages/backlog/useShowDetail"; import { BacklogStatusType, EpicCategoryDTO } from "../../types/DTO/backlogDTO"; import BacklogStatusChip from "./BacklogStatusChip"; import CategoryChip from "./CategoryChip"; -import TaskCreateButton from "./TaskCreateButton"; import ChevronDown from "../../assets/icons/chevron-down.svg?react"; import ChevronRight from "../../assets/icons/chevron-right.svg?react"; import TaskContainer from "./TaskContainer"; @@ -19,6 +18,7 @@ import TrashCan from "../../assets/icons/trash-can.svg?react"; import { useModal } from "../../hooks/common/modal/useModal"; import ConfirmModal from "../common/ConfirmModal"; import EpicDropdown from "./EpicDropdown"; +import TaskCreateBlock from "./TaskCreateBlock"; interface StoryBlockProps { id: number; @@ -263,7 +263,7 @@ const StoryBlock = ({ {children} - + )} diff --git a/frontend/src/components/backlog/TaskCreateBlock.tsx b/frontend/src/components/backlog/TaskCreateBlock.tsx new file mode 100644 index 00000000..ca9f658a --- /dev/null +++ b/frontend/src/components/backlog/TaskCreateBlock.tsx @@ -0,0 +1,25 @@ +import useShowDetail from "../../hooks/pages/backlog/useShowDetail"; +import TaskCreateButton from "./TaskCreateButton"; +import TaskCreateForm from "./TaskCreateForm"; + +interface TaskCreateBlockProps { + storyId: number; +} + +const TaskCreateBlock = ({ storyId }: TaskCreateBlockProps) => { + const { showDetail, handleShowDetail } = useShowDetail(); + return ( + <> + {showDetail ? ( + handleShowDetail(false)} + /> + ) : ( + handleShowDetail(true)} /> + )} + + ); +}; + +export default TaskCreateBlock; diff --git a/frontend/src/components/backlog/TaskCreateButton.tsx b/frontend/src/components/backlog/TaskCreateButton.tsx index 4c981cc0..e39d45ab 100644 --- a/frontend/src/components/backlog/TaskCreateButton.tsx +++ b/frontend/src/components/backlog/TaskCreateButton.tsx @@ -1,10 +1,15 @@ import Plus from "../../assets/icons/plus.svg?react"; -const TaskCreateButton = () => ( +interface TaskCreateButtonProps { + onClick: () => void; +} + +const TaskCreateButton = ({ onClick }: TaskCreateButtonProps) => (
+ +
+
+ + ); +}; + +export default TaskCreateForm; diff --git a/frontend/src/hooks/pages/backlog/useBacklogSocket.ts b/frontend/src/hooks/pages/backlog/useBacklogSocket.ts index aac07e5e..1ea42071 100644 --- a/frontend/src/hooks/pages/backlog/useBacklogSocket.ts +++ b/frontend/src/hooks/pages/backlog/useBacklogSocket.ts @@ -1,11 +1,17 @@ import { useEffect, useState } from "react"; import { Socket } from "socket.io-client"; -import { BacklogDTO, EpicDTO, StoryDTO } from "../../../types/DTO/backlogDTO"; +import { + BacklogDTO, + EpicDTO, + StoryDTO, + TaskDTO, +} from "../../../types/DTO/backlogDTO"; import { BacklogSocketData, BacklogSocketDomain, BacklogSocketEpicAction, BacklogSocketStoryAction, + BacklogSocketTaskAction, } from "../../../types/common/backlog"; const useBacklogSocket = (socket: Socket) => { @@ -96,6 +102,34 @@ const useBacklogSocket = (socket: Socket) => { } }; + const handleTaskEvent = ( + action: BacklogSocketTaskAction, + content: TaskDTO + ) => { + switch (action) { + case BacklogSocketTaskAction.CREATE: + setBacklog((prevBacklog) => { + const newEpicList = prevBacklog.epicList.map((epic) => { + if ( + epic.storyList.filter(({ id }) => id === content.storyId).length + ) { + const newStoryList = epic.storyList.map((story) => { + if (story.id === content.storyId) { + return { ...story, taskList: [...story.taskList, content] }; + } + return story; + }); + + return { ...epic, storyList: newStoryList }; + } + return epic; + }); + return { epicList: newEpicList }; + }); + break; + } + }; + const handleOnBacklog = ({ domain, action, content }: BacklogSocketData) => { switch (domain) { case BacklogSocketDomain.BACKLOG: @@ -107,6 +141,9 @@ const useBacklogSocket = (socket: Socket) => { case BacklogSocketDomain.STORY: handleStoryEvent(action, content); break; + case BacklogSocketDomain.TASK: + handleTaskEvent(action, content); + break; } }; diff --git a/frontend/src/hooks/pages/backlog/useTaskEmitEvent.ts b/frontend/src/hooks/pages/backlog/useTaskEmitEvent.ts new file mode 100644 index 00000000..45cdab79 --- /dev/null +++ b/frontend/src/hooks/pages/backlog/useTaskEmitEvent.ts @@ -0,0 +1,12 @@ +import { Socket } from "socket.io-client"; +import { TaskForm } from "../../../types/common/backlog"; + +const useTaskEmitEvent = (socket: Socket) => { + const emitTaskCreateEvent = (content: TaskForm) => { + socket.emit("task", { action: "create", content }); + }; + + return { emitTaskCreateEvent }; +}; + +export default useTaskEmitEvent; diff --git a/frontend/src/types/DTO/backlogDTO.ts b/frontend/src/types/DTO/backlogDTO.ts index f81ce5db..78fb1c94 100644 --- a/frontend/src/types/DTO/backlogDTO.ts +++ b/frontend/src/types/DTO/backlogDTO.ts @@ -17,6 +17,7 @@ export interface TaskDTO { actualTime: number | null; status: BacklogStatusType; assignedMemberId: number | null; + storyId: number; } export interface StoryDTO { diff --git a/frontend/src/types/common/backlog.ts b/frontend/src/types/common/backlog.ts index 155deaf1..c6401cb0 100644 --- a/frontend/src/types/common/backlog.ts +++ b/frontend/src/types/common/backlog.ts @@ -3,6 +3,7 @@ import { EpicCategoryDTO, EpicDTO, StoryDTO, + TaskDTO, } from "../DTO/backlogDTO"; export type BacklogPath = "backlog" | "epic" | "completed"; @@ -29,6 +30,15 @@ export interface StoryForm { status: "시작전"; } +export interface TaskForm { + storyId: number; + title: string; + expectedTime: number | null | ""; + actualTime: number | null | ""; + status: "시작전"; + assignedMemberId: null; +} + export enum BacklogSocketDomain { BACKLOG = "backlog", EPIC = "epic", @@ -48,6 +58,12 @@ export enum BacklogSocketStoryAction { UPDATE = "update", } +export enum BacklogSocketTaskAction { + CREATE = "create", + DELETE = "delete", + UPDATE = "update", +} + export interface BacklogSocketInitData { domain: BacklogSocketDomain.BACKLOG; action: "init"; @@ -66,7 +82,14 @@ export interface BacklogSocketStoryData { content: StoryDTO; } +export interface BacklogSocketTaskData { + domain: BacklogSocketDomain.TASK; + action: BacklogSocketTaskAction; + content: TaskDTO; +} + export type BacklogSocketData = | BacklogSocketInitData | BacklogSocketEpicData - | BacklogSocketStoryData; + | BacklogSocketStoryData + | BacklogSocketTaskData; From a04db177ea04caca89d1880068f13595bf8a712a Mon Sep 17 00:00:00 2001 From: surinkwon Date: Mon, 15 Jul 2024 11:55:11 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20=EC=8A=A4=ED=86=A0=EB=A6=AC=20?= =?UTF-8?q?=ED=99=94=EC=82=B4=ED=91=9C=20=EB=B2=84=ED=8A=BC=EC=9D=84=20?= =?UTF-8?q?=EB=88=8C=EB=A0=80=EC=9D=84=20=EB=95=8C=20=ED=83=80=EC=9D=B4?= =?UTF-8?q?=ED=8B=80=20=EC=88=98=EC=A0=95=EC=B0=BD=EC=9D=B4=20=EB=82=98?= =?UTF-8?q?=EC=98=A4=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/backlog/StoryBlock.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/backlog/StoryBlock.tsx b/frontend/src/components/backlog/StoryBlock.tsx index fa371be0..33bd7241 100644 --- a/frontend/src/components/backlog/StoryBlock.tsx +++ b/frontend/src/components/backlog/StoryBlock.tsx @@ -182,7 +182,10 @@ const StoryBlock = ({