From 5587a559a4728572be956be21edcda9fc78165f3 Mon Sep 17 00:00:00 2001 From: Kjiw0n Date: Fri, 19 Jul 2024 06:01:34 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20timeblock=20delete=20api=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../deleteTimeBlock/DeleteTimeBlockType.ts | 4 ++ src/apis/timeBlocks/deleteTimeBlock/axios.ts | 10 +++++ src/apis/timeBlocks/deleteTimeBlock/query.ts | 17 +++++++++ .../common/fullCalendar/FullCalendarBox.tsx | 38 +++++++++++++------ .../common/fullCalendar/processEvents.tsx | 23 +++++++++-- src/components/common/modal/Modal.tsx | 19 ++++++++-- .../common/modal/ModalDeleteBtn.tsx | 8 +++- .../common/modal/ModalDeleteDetail.tsx | 2 +- .../common/modal/ModalHeaderBtn.tsx | 8 +++- 9 files changed, 104 insertions(+), 25 deletions(-) create mode 100644 src/apis/timeBlocks/deleteTimeBlock/DeleteTimeBlockType.ts create mode 100644 src/apis/timeBlocks/deleteTimeBlock/query.ts diff --git a/src/apis/timeBlocks/deleteTimeBlock/DeleteTimeBlockType.ts b/src/apis/timeBlocks/deleteTimeBlock/DeleteTimeBlockType.ts new file mode 100644 index 00000000..e9a2b517 --- /dev/null +++ b/src/apis/timeBlocks/deleteTimeBlock/DeleteTimeBlockType.ts @@ -0,0 +1,4 @@ +export interface DeleteTimeBlokType { + taskId: number; + timeBlockId: number; +} diff --git a/src/apis/timeBlocks/deleteTimeBlock/axios.ts b/src/apis/timeBlocks/deleteTimeBlock/axios.ts index e69de29b..3f1c933e 100644 --- a/src/apis/timeBlocks/deleteTimeBlock/axios.ts +++ b/src/apis/timeBlocks/deleteTimeBlock/axios.ts @@ -0,0 +1,10 @@ +import { DeleteTimeBlokType } from './DeleteTimeBlockType'; + +import { privateInstance } from '@/apis/instance'; + +/** TimeBlock 삭제 */ +const deleteTimeBlock = async ({ taskId, timeBlockId }: DeleteTimeBlokType) => { + await privateInstance.delete(`/api/tasks/${taskId}/time-blocks/${timeBlockId}`); +}; + +export default deleteTimeBlock; diff --git a/src/apis/timeBlocks/deleteTimeBlock/query.ts b/src/apis/timeBlocks/deleteTimeBlock/query.ts new file mode 100644 index 00000000..378612e4 --- /dev/null +++ b/src/apis/timeBlocks/deleteTimeBlock/query.ts @@ -0,0 +1,17 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import deleteTimeBlock from './axios'; +import { DeleteTimeBlokType } from './DeleteTimeBlockType'; + +/** TimeBlock 삭제 */ +const useDeleteTimeBlock = () => { + const queryClient = useQueryClient(); + const mutation = useMutation({ + mutationFn: ({ taskId, timeBlockId }: DeleteTimeBlokType) => deleteTimeBlock({ taskId, timeBlockId }), + onSuccess: () => queryClient.invalidateQueries({ queryKey: ['timeblock'] }), + }); + + return { mutate: mutation.mutate }; +}; + +export default useDeleteTimeBlock; diff --git a/src/components/common/fullCalendar/FullCalendarBox.tsx b/src/components/common/fullCalendar/FullCalendarBox.tsx index e9120cd9..40b51ae2 100644 --- a/src/components/common/fullCalendar/FullCalendarBox.tsx +++ b/src/components/common/fullCalendar/FullCalendarBox.tsx @@ -34,6 +34,8 @@ function FullCalendarBox({ size, selectDate, selectedTarget }: FullCalendarBoxPr const [startDate, setStartDate] = useState(todayDate); const [isModalOpen, setModalOpen] = useState(false); + const [modalTaskId, setModalTaskId] = useState(null); + const [modalTimeBlockId, setModalTimeBlockId] = useState(null); const handleViewChange = (view: ViewMountArg) => { setCurrentView(view.view.type); @@ -84,21 +86,38 @@ function FullCalendarBox({ size, selectDate, selectedTarget }: FullCalendarBoxPr const adjustedTop = Math.min(calculatedTop, MODAL.SCREEN_HEIGHT - MODAL.TASK_MODAL_HEIGHT); setTop(adjustedTop); setLeft(rect.left - MODAL.TASK_MODAL_WIDTH + 40); - setModalOpen(true); + + // eslint-disable-next-line no-underscore-dangle + const clickedEvent = info.event._def.extendedProps; + + if (clickedEvent) { + setModalTaskId(clickedEvent.taskId); + setModalTimeBlockId(clickedEvent.timeBlockId); + setModalOpen(true); + } }; /** 모달 닫기 */ const closeModal = () => { setModalOpen(false); + setModalTaskId(null); + setModalTimeBlockId(null); }; // Get timeblock const { data: timeBlockData } = useGetTimeBlock({ startDate, range }); - console.log('timeBlockData.data.data', timeBlockData?.data.data); + console.log(timeBlockData?.data.data); const { mutate } = usePostTimeBlock(); - const calendarEvents = timeBlockData ? processEvents(timeBlockData.data.data) : []; + const { events, taskEvents } = timeBlockData + ? processEvents(timeBlockData.data.data) + : { events: [], taskEvents: [] }; + + // TODO: 캘린더 모달 상세조회 부분 구현 시 해당 부분 참고 + console.log('taskEvents', taskEvents); + + const calendarEvents = timeBlockData ? events : []; /** 드래그해서 이벤트 추가하기 */ const addEventWhenDragged = (selectInfo: DateSelectArg) => { @@ -123,20 +142,15 @@ function FullCalendarBox({ size, selectDate, selectedTarget }: FullCalendarBoxPr classNames: 'tasks', }); - // console.log('selectedTarget.name,', selectedTarget.name); - const removeTimezone = (str: string) => str.replace(/:\d{2}[+-]\d{2}:\d{2}$/, ''); const startStr = removeTimezone(selectInfo.startStr); const endStr = removeTimezone(selectInfo.endStr); - // console.log('selectedTarget.id.toString(),', selectedTarget.id.toString()); - // console.log('startStr:', startStr); - // console.log('endStr:', endStr); - mutate({ taskId: selectedTarget.id, startTime: startStr, endTime: endStr }); } }; + return ( @@ -199,15 +213,15 @@ function FullCalendarBox({ size, selectDate, selectedTarget }: FullCalendarBoxPr eventClick={handleEventClick} select={addEventWhenDragged} /> - {isModalOpen && ( - // 🚨 임시 taskID ... 데이터 형식 확정 후 수정할 것 🚨 + {isModalOpen && modalTaskId !== null && modalTimeBlockId !== null && ( )} diff --git a/src/components/common/fullCalendar/processEvents.tsx b/src/components/common/fullCalendar/processEvents.tsx index 66bedb79..9964c605 100644 --- a/src/components/common/fullCalendar/processEvents.tsx +++ b/src/components/common/fullCalendar/processEvents.tsx @@ -8,18 +8,33 @@ interface EventData { classNames: string; } -const processEvents = (timeBlockData: TimeBlockData): EventData[] => { +interface TasksEventData { + taskId: number; + timeBlockId: number; + title: string; + start: string; + end: string; + allDay?: boolean; + classNames: string; +} + +const processEvents = (timeBlockData: TimeBlockData): { events: EventData[]; taskEvents: TasksEventData[] } => { const events: EventData[] = []; + const taskEvents: TasksEventData[] = []; // tasks 데이터 처리 timeBlockData.tasks.forEach((task) => { task.timeBlocks.forEach((timeBlock) => { - events.push({ + const taskEvent = { + taskId: task.id, + timeBlockId: timeBlock.id, title: task.name, start: timeBlock.startTime, end: timeBlock.endTime, classNames: 'tasks', - }); + }; + events.push(taskEvent); + taskEvents.push(taskEvent); }); }); @@ -36,7 +51,7 @@ const processEvents = (timeBlockData: TimeBlockData): EventData[] => { }); }); - return events; + return { events, taskEvents }; }; export default processEvents; diff --git a/src/components/common/modal/Modal.tsx b/src/components/common/modal/Modal.tsx index eb4df9ec..2d8c2ea3 100644 --- a/src/components/common/modal/Modal.tsx +++ b/src/components/common/modal/Modal.tsx @@ -2,6 +2,7 @@ import styled from '@emotion/styled'; import ModalBackdrop from './ModalBackdrop'; +import useDeleteTimeBlock from '@/apis/timeBlocks/deleteTimeBlock/query'; import BtnDate from '@/components/common/BtnDate/BtnDate'; import OkayCancelBtn from '@/components/common/button/OkayCancelBtn'; import ModalHeaderBtn from '@/components/common/modal/ModalHeaderBtn'; @@ -16,12 +17,12 @@ interface ModalProps { left: number; onClose: () => void; taskId: number; + timeBlockId: number; } -function Modal({ isOpen, sizeType, top, left, onClose, taskId }: ModalProps) { - // taskId 가지고 api로 상세정보 요청하면 됨 +function Modal({ isOpen, sizeType, top, left, onClose, taskId, timeBlockId }: ModalProps) { const dummyData = { - id: taskId, // 안쓰는 변수 린트 통과용 필드 + id: taskId, name: 'task name', description: 'task description', deadLine: { @@ -35,13 +36,23 @@ function Modal({ isOpen, sizeType, top, left, onClose, taskId }: ModalProps) { endTime: '2024-07-08T14:30', }, }; + + const { mutate } = useDeleteTimeBlock(); + + const handleDelete = () => { + console.log('taskId, timeBlockId', taskId, timeBlockId); + mutate({ taskId, timeBlockId }); + + onClose(); + }; + return ( isOpen && ( e.stopPropagation()}> - + diff --git a/src/components/common/modal/ModalDeleteBtn.tsx b/src/components/common/modal/ModalDeleteBtn.tsx index 0676efe5..c93b6816 100644 --- a/src/components/common/modal/ModalDeleteBtn.tsx +++ b/src/components/common/modal/ModalDeleteBtn.tsx @@ -4,7 +4,11 @@ import { useState } from 'react'; import SettingDeleteBtn from '@/components/common/button/settingBtn/SettingDeleteBtn'; import ModalDeleteDetail from '@/components/common/modal/ModalDeleteDetail'; -function ModalDeleteBtn() { +interface ModalDeleteBtnProps { + onDelete: (e: React.MouseEvent) => void; +} + +function ModalDeleteBtn({ onDelete }: ModalDeleteBtnProps) { const [isClicked, setIsClicked] = useState(false); const [top, setTop] = useState(0); @@ -22,7 +26,7 @@ function ModalDeleteBtn() { {isClicked && ( - + )} diff --git a/src/components/common/modal/ModalDeleteDetail.tsx b/src/components/common/modal/ModalDeleteDetail.tsx index f33fbd6d..7eae6a99 100644 --- a/src/components/common/modal/ModalDeleteDetail.tsx +++ b/src/components/common/modal/ModalDeleteDetail.tsx @@ -8,7 +8,7 @@ interface ModalDeleteDetailProps { top: number; left: number; onClose: (e: React.MouseEvent) => void; - onDelete?: () => void; + onDelete: (e: React.MouseEvent) => void; } function ModalDeleteDetail({ top, left, onClose, onDelete }: ModalDeleteDetailProps) { diff --git a/src/components/common/modal/ModalHeaderBtn.tsx b/src/components/common/modal/ModalHeaderBtn.tsx index fce74b42..ef982767 100644 --- a/src/components/common/modal/ModalHeaderBtn.tsx +++ b/src/components/common/modal/ModalHeaderBtn.tsx @@ -4,10 +4,14 @@ import SettingCheckBtn from '@/components/common/button/settingBtn/SettingCheckB import ModalDeleteBtn from '@/components/common/modal/ModalDeleteBtn'; import { SizeType } from '@/types/textInputType'; -function ModalHeaderBtn({ type }: SizeType) { +interface ModalHeaderBtnProps extends SizeType { + onDelete: () => void; +} + +function ModalHeaderBtn({ type, onDelete }: ModalHeaderBtnProps) { return ( - + {type === 'long' && }