From 938d8f007c556b4e733662793055b8bed311bde3 Mon Sep 17 00:00:00 2001 From: Kjiw0n Date: Thu, 18 Jul 2024 01:21:11 +0900 Subject: [PATCH 1/8] =?UTF-8?q?feat:=20api=20axios=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tasks/updateTaskStatus/UpdateTaskStatusType.ts | 5 +++++ src/apis/tasks/updateTaskStatus/axios.ts | 12 ++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/apis/tasks/updateTaskStatus/UpdateTaskStatusType.ts create mode 100644 src/apis/tasks/updateTaskStatus/axios.ts diff --git a/src/apis/tasks/updateTaskStatus/UpdateTaskStatusType.ts b/src/apis/tasks/updateTaskStatus/UpdateTaskStatusType.ts new file mode 100644 index 00000000..132d8b63 --- /dev/null +++ b/src/apis/tasks/updateTaskStatus/UpdateTaskStatusType.ts @@ -0,0 +1,5 @@ +export interface UpdateTaskStatusType { + taskId: number; + targetDate: string | null; + status: string; +} diff --git a/src/apis/tasks/updateTaskStatus/axios.ts b/src/apis/tasks/updateTaskStatus/axios.ts new file mode 100644 index 00000000..5d59a73f --- /dev/null +++ b/src/apis/tasks/updateTaskStatus/axios.ts @@ -0,0 +1,12 @@ +import axios from 'axios'; + +import { UpdateTaskStatusType } from './UpdateTaskStatusType'; + +const updateTaskStatus = async ({ taskId, targetDate, status }: UpdateTaskStatusType) => { + await axios.patch(`/api/tasks/${taskId}`, { + targetDate, + status, + }); +}; + +export default updateTaskStatus; From 9ca9a4d85a718a018eeb5641f4343d24bcdd3072 Mon Sep 17 00:00:00 2001 From: Kjiw0n Date: Thu, 18 Jul 2024 03:05:17 +0900 Subject: [PATCH 2/8] =?UTF-8?q?refactor:=20task=20=EB=93=9C=EB=9E=98?= =?UTF-8?q?=EA=B7=B8=EC=95=A4=EB=93=9C=EB=A1=AD=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20api=20=EC=97=B0=EA=B2=B0=20=EC=9C=84=EC=B9=98=20?= =?UTF-8?q?=EB=B0=8F=20props=20=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/StagingArea/StagingArea.tsx | 14 ++- .../common/StagingArea/StagingAreaSetting.tsx | 8 +- .../StagingArea/StagingAreaTaskContainer.tsx | 48 ++-------- src/components/targetArea/TargetArea.tsx | 47 ++++------ src/components/targetArea/TargetAreaDate.tsx | 3 + .../targetArea/TargetControlSection.tsx | 9 +- .../targetArea/TargetTaskSection.tsx | 13 +-- src/pages/Today.tsx | 93 ++++++++++++++++--- 8 files changed, 127 insertions(+), 108 deletions(-) diff --git a/src/components/common/StagingArea/StagingArea.tsx b/src/components/common/StagingArea/StagingArea.tsx index 5d444750..6b09f186 100644 --- a/src/components/common/StagingArea/StagingArea.tsx +++ b/src/components/common/StagingArea/StagingArea.tsx @@ -3,21 +3,31 @@ import { Droppable } from 'react-beautiful-dnd'; import StagingAreaTaskContainer from './StagingAreaTaskContainer'; +import StagingAreaSetting from '@/components/common/StagingArea/StagingAreaSetting'; import TextInputStaging from '@/components/common/textbox/TextInputStaging'; import { TaskType } from '@/types/tasks/taskType'; +import { StagingAreaSettingProps } from '@/types/today/stagingAreaSettingProps'; -interface StagingAreaProps { +interface StagingAreaProps extends StagingAreaSettingProps { handleSelectedTarget: (task: TaskType | null) => void; selectedTarget: TaskType | null; tasks: TaskType[]; } + function StagingArea(props: StagingAreaProps) { - const { handleSelectedTarget, selectedTarget, tasks } = props; + const { handleSelectedTarget, selectedTarget, tasks, activeButton, sortOrder, handleTextBtnClick, handleSortOrder } = + props; return ( 쏟아내기 + {(provided) => (
diff --git a/src/components/common/StagingArea/StagingAreaSetting.tsx b/src/components/common/StagingArea/StagingAreaSetting.tsx index 27eb1fa1..bc7c6e1d 100644 --- a/src/components/common/StagingArea/StagingAreaSetting.tsx +++ b/src/components/common/StagingArea/StagingAreaSetting.tsx @@ -6,14 +6,8 @@ import TextBtn from '../button/textBtn/TextBtn'; import ModalArrange from '../modal/ModalArrange/ModalArrange'; import ModalBackdrop from '../modal/ModalBackdrop'; -import { SortOrderType } from '@/types/sortOrderType'; +import { StagingAreaSettingProps } from '@/types/today/stagingAreaSettingProps'; -interface StagingAreaSettingProps { - handleTextBtnClick: (button: '전체' | '지연') => void; - activeButton: '전체' | '지연'; - sortOrder: SortOrderType; - handleSortOrder: (order: SortOrderType) => void; -} function StagingAreaSetting({ handleTextBtnClick, activeButton, sortOrder, handleSortOrder }: StagingAreaSettingProps) { const [isModalOpen, setIsModalOpen] = useState(false); diff --git a/src/components/common/StagingArea/StagingAreaTaskContainer.tsx b/src/components/common/StagingArea/StagingAreaTaskContainer.tsx index 616101b6..04dceeb5 100644 --- a/src/components/common/StagingArea/StagingAreaTaskContainer.tsx +++ b/src/components/common/StagingArea/StagingAreaTaskContainer.tsx @@ -1,15 +1,10 @@ import styled from '@emotion/styled'; -import { useState } from 'react'; import { Draggable } from 'react-beautiful-dnd'; import BtnTaskContainer from '../BtnTaskContainer'; import EmptyContainer from '../EmptyContainer'; -import ScrollGradient from '../ScrollGradient'; -import useGetTasks from '@/apis/tasks/getTask/query'; import BtnTask from '@/components/common/BtnTask/BtnTask'; -import StagingAreaSetting from '@/components/common/StagingArea/StagingAreaSetting'; -import { SortOrderType } from '@/types/sortOrderType'; import { TaskType } from '@/types/tasks/taskType'; interface StagingAreaTaskContainerProps { @@ -18,38 +13,15 @@ interface StagingAreaTaskContainerProps { tasks: TaskType[]; } -function StagingAreaTaskContainer({ handleSelectedTarget, selectedTarget }: StagingAreaTaskContainerProps) { - const [activeButton, setActiveButton] = useState<'전체' | '지연'>('전체'); - const [sortOrder, setSortOrder] = useState('recent'); - const isTotal = activeButton === '전체'; - - // Task 목록 Get - const { data } = useGetTasks({ isTotal, sortOrder }); - - /** isTotal 핸들링 함수 */ - const handleTextBtnClick = (button: '전체' | '지연') => { - setActiveButton(button); - }; - - const handleSortOrder = (order: SortOrderType) => { - setSortOrder(order); - }; - console.log(data); - +function StagingAreaTaskContainer({ handleSelectedTarget, selectedTarget, tasks }: StagingAreaTaskContainerProps) { return ( - - {data.data.tasks.length === 0 ? ( + {tasks.length === 0 ? ( ) : ( <> - {data.data.tasks.map((task: TaskType, index: number) => ( + {tasks.map((task: TaskType, index: number) => ( {(provided, snapshot) => (
@@ -76,8 +48,6 @@ function StagingAreaTaskContainer({ handleSelectedTarget, selectedTarget }: Stag ))} )} - -
); @@ -88,7 +58,7 @@ export default StagingAreaTaskContainer; const StagingAreaTaskContainerLayout = styled.div` display: flex; flex-direction: column; - gap: 1.3rem; align-items: flex-start; align-self: stretch; + margin-top: 1.3rem; `; diff --git a/src/components/targetArea/TargetArea.tsx b/src/components/targetArea/TargetArea.tsx index 33f845a9..a76524b0 100644 --- a/src/components/targetArea/TargetArea.tsx +++ b/src/components/targetArea/TargetArea.tsx @@ -1,5 +1,4 @@ import styled from '@emotion/styled'; -import { useState } from 'react'; import { Droppable } from 'react-beautiful-dnd'; import TargetAreaDate from './TargetAreaDate'; @@ -7,36 +6,24 @@ import TargetControlSection from './TargetControlSection'; import TargetTaskSection from './TargetTaskSection'; import { TaskType } from '@/types/tasks/taskType'; +import { TargetControlSectionProps } from '@/types/today/TargetControlSectionProps'; -interface TargetAreaProps { +interface TargetAreaProps extends TargetControlSectionProps { handleSelectedTarget: (task: TaskType | null) => void; selectedTarget: TaskType | null; tasks: TaskType[]; } -function TargetArea({ handleSelectedTarget, selectedTarget }: TargetAreaProps) { - const [targetDate, setTargetDate] = useState(new Date()); - - const handlePrevBtn = () => { - const newDate = new Date(targetDate); - newDate.setDate(newDate.getDate() - 1); - setTargetDate(newDate); - }; - - const handleNextBtn = () => { - const newDate = new Date(targetDate); - newDate.setDate(newDate.getDate() + 1); - setTargetDate(newDate); - }; - - const handleTodayBtn = () => { - setTargetDate(new Date()); - }; - - const handleChangeDate = (target: Date) => { - setTargetDate(target); - }; - +function TargetArea({ + handleSelectedTarget, + selectedTarget, + tasks, + onClickPrevDate, + onClickNextDate, + onClickTodayDate, + onClickDatePicker, + targetDate, +}: TargetAreaProps) { return ( {/* 날짜 */} @@ -46,10 +33,10 @@ function TargetArea({ handleSelectedTarget, selectedTarget }: TargetAreaProps) { {/* 버튼 */} {/* 태스크 목록 */} @@ -59,7 +46,7 @@ function TargetArea({ handleSelectedTarget, selectedTarget }: TargetAreaProps) { {provided.placeholder}
diff --git a/src/components/targetArea/TargetAreaDate.tsx b/src/components/targetArea/TargetAreaDate.tsx index 16cc3255..7db730e3 100644 --- a/src/components/targetArea/TargetAreaDate.tsx +++ b/src/components/targetArea/TargetAreaDate.tsx @@ -6,12 +6,15 @@ import formatDatetoStrinKor from '@/utils/formatDatetoStringKor'; interface TargetAreaDateProps { targetDate: Date; } + function TargetAreaDate({ targetDate }: TargetAreaDateProps) { const formatDate = formatDatetoStrinKor(targetDate); return {formatDate}; } + const DateText = styled.h2` ${({ theme }) => theme.fontTheme.HEADLINE_02}; padding: 0.7rem 0.2rem 0.7rem 1rem; `; + export default TargetAreaDate; diff --git a/src/components/targetArea/TargetControlSection.tsx b/src/components/targetArea/TargetControlSection.tsx index 2bd49b15..9c295756 100644 --- a/src/components/targetArea/TargetControlSection.tsx +++ b/src/components/targetArea/TargetControlSection.tsx @@ -6,16 +6,9 @@ import TextBtn from '@/components/common/button/textBtn/TextBtn'; import DateCorrectionModal from '@/components/common/datePicker/DateCorrectionModal'; import ModalBackdrop from '@/components/common/modal/ModalBackdrop'; import MODAL from '@/constants/modalLocation'; +import { TargetControlSectionProps } from '@/types/today/TargetControlSectionProps'; import formatDatetoString from '@/utils/formatDatetoString'; -interface TargetControlSectionProps { - onClickPrevDate: () => void; - onClickNextDate: () => void; - onClickTodayDate: () => void; - onClickDatePicker: (target: Date) => void; - targetDate: Date; -} - function TargetControlSection({ onClickPrevDate, onClickNextDate, diff --git a/src/components/targetArea/TargetTaskSection.tsx b/src/components/targetArea/TargetTaskSection.tsx index 51491472..61bfaccd 100644 --- a/src/components/targetArea/TargetTaskSection.tsx +++ b/src/components/targetArea/TargetTaskSection.tsx @@ -5,28 +5,25 @@ import BtnTask from '../common/BtnTask/BtnTask'; import BtnTaskContainer from '../common/BtnTaskContainer'; import EmptyContainer from '../common/EmptyContainer'; -import useGetTasks from '@/apis/tasks/getTask/query'; import { TaskType } from '@/types/tasks/taskType'; -import formatDatetoLocalDate from '@/utils/formatDatetoLocalDate'; interface TargetTaskSectionProps { handleSelectedTarget: (task: TaskType | null) => void; selectedTarget: TaskType | null; - selectedDate: Date | null; + tasks: TaskType[]; } function TargetTaskSection(props: TargetTaskSectionProps) { - const { handleSelectedTarget, selectedTarget, selectedDate } = props; - const targetDate = formatDatetoLocalDate(selectedDate); - const { data } = useGetTasks({ targetDate }); + const { handleSelectedTarget, selectedTarget, tasks } = props; + return ( - {data.data.tasks.length === 0 ? ( + {tasks.length === 0 ? ( ) : ( <> - {data.data.tasks.map((task: TaskType, index: number) => ( + {tasks.map((task: TaskType, index: number) => ( {(provided, snapshot) => (
(dummyTasks); const [selectedTarget, setSelectedTarget] = useState(null); + const [activeButton, setActiveButton] = useState<'전체' | '지연'>('전체'); + const [sortOrder, setSortOrder] = useState('recent'); + const isTotal = activeButton === '전체'; + + // Task 목록 Get + + /** StagingArea */ + const { isFetched: isStagingFetched, data: stagingData } = useGetTasks({ isTotal, sortOrder }); + + console.log('stagingArea_taskList', stagingData); + + /** isTotal 핸들링 함수 */ + const handleTextBtnClick = (button: '전체' | '지연') => { + setActiveButton(button); + }; + + const handleSortOrder = (order: SortOrderType) => { + setSortOrder(order); + }; + const handleSelectedTarget = (task: TaskType | null) => { setSelectedTarget(task); }; + /** TargetArea */ + const [selectedDate, setTargetDate] = useState(new Date()); + + const targetDate = formatDatetoLocalDate(selectedDate); + + const { isFetched: isTargetFetched, data: targetData } = useGetTasks({ targetDate }); + + console.log('targetArea_taskList', stagingData); + + const handlePrevBtn = () => { + const newDate = new Date(selectedDate); + newDate.setDate(newDate.getDate() - 1); + setTargetDate(newDate); + }; + + const handleNextBtn = () => { + const newDate = new Date(selectedDate); + newDate.setDate(newDate.getDate() + 1); + setTargetDate(newDate); + }; + + const handleTodayBtn = () => { + setTargetDate(new Date()); + }; + + const handleChangeDate = (target: Date) => { + setTargetDate(target); + }; + const handleDragEnd = (result: DropResult) => { const { source, destination } = result; @@ -59,10 +111,10 @@ function Today() { // TODO: api 연결 시에는 밑에 부분 지우고 api 호출 예정 - // 같은 위치로 드래그 - if (source.droppableId === destination.droppableId && source.index === destination.index) { - return; - } + // // 같은 위치로 드래그 -> 되면 안됨 + // if (source.droppableId === destination.droppableId && source.index === destination.index) { + // return; + // } // 다른 위치로 드래그 const sourceClone = Array.from(tasks[source.droppableId as keyof typeof tasks]); @@ -93,16 +145,29 @@ function Today() { - - + {isStagingFetched && ( + + )} + {isTargetFetched && ( + + )} From b0a28d9d21f8f9b732c034ccf4196edabd44ca26 Mon Sep 17 00:00:00 2001 From: Kjiw0n Date: Thu, 18 Jul 2024 03:07:25 +0900 Subject: [PATCH 3/8] =?UTF-8?q?refactor:=20api=20=EC=97=B0=EA=B2=B0=20?= =?UTF-8?q?=EC=8B=9C=20=ED=99=94=EB=A9=B4=20=EA=B9=9C=EB=B9=A1=EC=9E=84=20?= =?UTF-8?q?=EC=B5=9C=EC=86=8C=ED=99=94=EB=A5=BC=20=EC=9C=84=ED=95=B4=20pla?= =?UTF-8?q?ceholderData=20=EC=A7=80=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/tasks/getTask/query.ts | 3 ++- src/pages/Today.tsx | 21 ++++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/apis/tasks/getTask/query.ts b/src/apis/tasks/getTask/query.ts index 2d91fcab..c796297d 100644 --- a/src/apis/tasks/getTask/query.ts +++ b/src/apis/tasks/getTask/query.ts @@ -1,6 +1,7 @@ import { useQuery } from '@tanstack/react-query'; import getTasks from './axios'; +import { GetTasksResponse } from './GetTasksResponse'; import { GetTasksType } from './GetTasksType'; const placeholderData = { @@ -29,7 +30,7 @@ const placeholderData = { }; /** Task 리스트 조회 */ -const useGetTasks = ({ isTotal, sortOrder, targetDate }: GetTasksType) => +const useGetTasks = ({ isTotal, sortOrder, targetDate }: GetTasksType, placeholderData?: GetTasksResponse) => useQuery({ queryKey: ['today', isTotal, sortOrder, targetDate], queryFn: () => getTasks({ isTotal, sortOrder, targetDate }), diff --git a/src/pages/Today.tsx b/src/pages/Today.tsx index 7e6b3728..b211b098 100644 --- a/src/pages/Today.tsx +++ b/src/pages/Today.tsx @@ -1,7 +1,8 @@ import styled from '@emotion/styled'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { DragDropContext, DropResult } from 'react-beautiful-dnd'; +import { GetTasksResponse } from '@/apis/tasks/getTask/GetTasksResponse'; import useGetTasks from '@/apis/tasks/getTask/query'; import FullCalendarBox from '@/components/common/fullCalendar/FullCalendarBox'; import NavBar from '@/components/common/NavBar'; @@ -55,9 +56,17 @@ function Today() { const isTotal = activeButton === '전체'; // Task 목록 Get + const [previousStagingData, setPreviousStagingData] = useState(undefined); + const [previousTargetData, setPreviousTargetData] = useState(undefined); /** StagingArea */ - const { isFetched: isStagingFetched, data: stagingData } = useGetTasks({ isTotal, sortOrder }); + const { isFetched: isStagingFetched, data: stagingData } = useGetTasks({ isTotal, sortOrder }, previousStagingData); + + useEffect(() => { + if (isStagingFetched && stagingData) { + setPreviousStagingData(stagingData); + } + }, [isStagingFetched, stagingData]); console.log('stagingArea_taskList', stagingData); @@ -79,7 +88,13 @@ function Today() { const targetDate = formatDatetoLocalDate(selectedDate); - const { isFetched: isTargetFetched, data: targetData } = useGetTasks({ targetDate }); + const { isFetched: isTargetFetched, data: targetData } = useGetTasks({ targetDate }, previousTargetData); + + useEffect(() => { + if (isTargetFetched && targetData) { + setPreviousTargetData(targetData); + } + }, [isTargetFetched, targetData]); console.log('targetArea_taskList', stagingData); From e9800e0ed539bc6eca4fea7f6cb66fdc61de3cad Mon Sep 17 00:00:00 2001 From: Kjiw0n Date: Thu, 18 Jul 2024 14:49:50 +0900 Subject: [PATCH 4/8] =?UTF-8?q?refactor:=20api=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0(=ED=83=80=EC=9E=85=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=93=B1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/tasks/getTask/GetTasksResponse.ts | 9 +++++++++ src/apis/tasks/updateTaskStatus/UpdateTaskStatusType.ts | 4 ++-- src/apis/tasks/updateTaskStatus/axios.ts | 6 +++--- 3 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 src/apis/tasks/getTask/GetTasksResponse.ts diff --git a/src/apis/tasks/getTask/GetTasksResponse.ts b/src/apis/tasks/getTask/GetTasksResponse.ts new file mode 100644 index 00000000..f7e22cbf --- /dev/null +++ b/src/apis/tasks/getTask/GetTasksResponse.ts @@ -0,0 +1,9 @@ +import { TaskType } from '@/types/tasks/taskType'; + +export interface GetTasksResponse { + code: string; + data: { + tasks: TaskType[]; + }; + message: string | null; +} diff --git a/src/apis/tasks/updateTaskStatus/UpdateTaskStatusType.ts b/src/apis/tasks/updateTaskStatus/UpdateTaskStatusType.ts index 132d8b63..cb391571 100644 --- a/src/apis/tasks/updateTaskStatus/UpdateTaskStatusType.ts +++ b/src/apis/tasks/updateTaskStatus/UpdateTaskStatusType.ts @@ -1,5 +1,5 @@ export interface UpdateTaskStatusType { taskId: number; - targetDate: string | null; - status: string; + targetDate?: string | null; + status?: string | null; } diff --git a/src/apis/tasks/updateTaskStatus/axios.ts b/src/apis/tasks/updateTaskStatus/axios.ts index 5d59a73f..1f77bc49 100644 --- a/src/apis/tasks/updateTaskStatus/axios.ts +++ b/src/apis/tasks/updateTaskStatus/axios.ts @@ -1,9 +1,9 @@ -import axios from 'axios'; - import { UpdateTaskStatusType } from './UpdateTaskStatusType'; +import { privateInstance } from '@/apis/instance'; + const updateTaskStatus = async ({ taskId, targetDate, status }: UpdateTaskStatusType) => { - await axios.patch(`/api/tasks/${taskId}`, { + await privateInstance.patch(`/api/tasks/${taskId}/status`, { targetDate, status, }); From 69d869953dc5a3dd909d738a3ee8d9db1d748afa Mon Sep 17 00:00:00 2001 From: Kjiw0n Date: Thu, 18 Jul 2024 14:50:29 +0900 Subject: [PATCH 5/8] =?UTF-8?q?feat:=20=EB=93=9C=EB=9E=98=EA=B7=B8?= =?UTF-8?q?=EC=95=A4=EB=93=9C=EB=A1=AD=20api=20=EC=97=B0=EA=B2=B0=20?= =?UTF-8?q?=EB=B0=8F=20useMutation=EC=9D=84=20=ED=86=B5=ED=95=9C=20?= =?UTF-8?q?=EC=9E=90=EB=8F=99=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Today.tsx | 101 ++++++++----------- src/types/today/TargetControlSectionProps.ts | 7 ++ src/types/today/stagingAreaSettingProps.ts | 8 ++ 3 files changed, 59 insertions(+), 57 deletions(-) create mode 100644 src/types/today/TargetControlSectionProps.ts create mode 100644 src/types/today/stagingAreaSettingProps.ts diff --git a/src/pages/Today.tsx b/src/pages/Today.tsx index b211b098..6b378d02 100644 --- a/src/pages/Today.tsx +++ b/src/pages/Today.tsx @@ -1,9 +1,12 @@ import styled from '@emotion/styled'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useEffect, useState } from 'react'; import { DragDropContext, DropResult } from 'react-beautiful-dnd'; import { GetTasksResponse } from '@/apis/tasks/getTask/GetTasksResponse'; import useGetTasks from '@/apis/tasks/getTask/query'; +import updateTaskStatus from '@/apis/tasks/updateTaskStatus/axios'; +import { UpdateTaskStatusType } from '@/apis/tasks/updateTaskStatus/UpdateTaskStatusType'; import FullCalendarBox from '@/components/common/fullCalendar/FullCalendarBox'; import NavBar from '@/components/common/NavBar'; import StagingArea from '@/components/common/StagingArea/StagingArea'; @@ -18,38 +21,8 @@ interface TaskState { target: TaskType[]; } -const dummyTasks: TaskState = { - staging: [ - { - id: 0, - name: '바보~', - deadLine: { date: '2024-06-30', time: '12:30' }, - hasDescription: false, - status: '진행중', - }, - { id: 1, name: '넛수레', deadLine: { date: '2024-06-30', time: '12:30' }, hasDescription: true, status: '지연' }, - { id: 2, name: '콘하스', deadLine: { date: '2024-06-30', time: '12:30' }, hasDescription: true, status: '완료' }, - { - id: 3, - name: '김지원', - deadLine: { date: '2024-06-30', time: '12:30' }, - hasDescription: true, - status: '미완료', - }, - ], - target: [ - { - id: 4, - name: '먀먀', - deadLine: { date: '2024-06-30', time: '12:30' }, - hasDescription: true, - status: '미완료', - }, - ], -}; - function Today() { - const [tasks, setTasks] = useState(dummyTasks); + const [tasks, setTasks] = useState({ staging: [], target: [] }); const [selectedTarget, setSelectedTarget] = useState(null); const [activeButton, setActiveButton] = useState<'전체' | '지연'>('전체'); const [sortOrder, setSortOrder] = useState('recent'); @@ -118,40 +91,54 @@ function Today() { setTargetDate(target); }; + const queryClient = useQueryClient(); + const { mutate } = useMutation({ + mutationFn: (updateData: UpdateTaskStatusType) => updateTaskStatus(updateData), + onSuccess: () => queryClient.invalidateQueries({ queryKey: ['today'] }), + }); + const handleDragEnd = (result: DropResult) => { const { source, destination } = result; // 드래그가 끝난 위치가 없으면 리턴 if (!destination) return; - // TODO: api 연결 시에는 밑에 부분 지우고 api 호출 예정 - - // // 같은 위치로 드래그 -> 되면 안됨 - // if (source.droppableId === destination.droppableId && source.index === destination.index) { - // return; - // } - - // 다른 위치로 드래그 - const sourceClone = Array.from(tasks[source.droppableId as keyof typeof tasks]); - const destClone = - source.droppableId === destination.droppableId - ? sourceClone - : Array.from(tasks[destination.droppableId as keyof typeof tasks]); - - const [removed] = sourceClone.splice(source.index, 1); - - destClone.splice(destination.index, 0, removed); - - const newTasks: TaskState = { - ...tasks, - [source.droppableId]: sourceClone, - }; - - if (source.droppableId !== destination.droppableId) { - newTasks[destination.droppableId] = destClone; + // sourceTasks와 destinationTasks를 배열로 변환 + const sourceTasks = source.droppableId === 'target' ? [...targetData.data.tasks] : [...stagingData.data.tasks]; + const destinationTasks = + destination.droppableId === 'target' ? [...targetData.data.tasks] : [...stagingData.data.tasks]; + + // 드래그된 항목을 sourceTasks에서 제거하고 destinationTasks에 추가 + const [movedTask] = sourceTasks.splice(source.index, 1); + destinationTasks.splice(destination.index, 0, movedTask); + + // 상태 업데이트 + if (source.droppableId === 'target') { + setTasks({ + target: { ...targetData, data: { ...targetData.data, tasks: sourceTasks } }, + staging: { ...stagingData, data: { ...stagingData.data, tasks: destinationTasks } }, + }); + } else { + setTasks({ + target: { ...targetData, data: { ...targetData.data, tasks: destinationTasks } }, + staging: { ...stagingData, data: { ...stagingData.data, tasks: sourceTasks } }, + }); } - setTasks(newTasks); + // API 호출 + if (destination.droppableId === 'target') { + mutate({ + taskId: movedTask.id, + targetDate, + status: '미완료', + }); + } else if (destination.droppableId === 'staging') { + mutate({ + taskId: movedTask.id, + targetDate: null, + status: null, + }); + } }; return ( diff --git a/src/types/today/TargetControlSectionProps.ts b/src/types/today/TargetControlSectionProps.ts new file mode 100644 index 00000000..4d8e780b --- /dev/null +++ b/src/types/today/TargetControlSectionProps.ts @@ -0,0 +1,7 @@ +export interface TargetControlSectionProps { + onClickPrevDate: () => void; + onClickNextDate: () => void; + onClickTodayDate: () => void; + onClickDatePicker: (target: Date) => void; + targetDate: Date; +} diff --git a/src/types/today/stagingAreaSettingProps.ts b/src/types/today/stagingAreaSettingProps.ts new file mode 100644 index 00000000..e75ea7c9 --- /dev/null +++ b/src/types/today/stagingAreaSettingProps.ts @@ -0,0 +1,8 @@ +import { SortOrderType } from '../sortOrderType'; + +export interface StagingAreaSettingProps { + handleTextBtnClick: (button: '전체' | '지연') => void; + activeButton: '전체' | '지연'; + sortOrder: SortOrderType; + handleSortOrder: (order: SortOrderType) => void; +} From c4abb3331d360f5da154aa0c61feee00a3ec823e Mon Sep 17 00:00:00 2001 From: Kjiw0n Date: Thu, 18 Jul 2024 15:12:38 +0900 Subject: [PATCH 6/8] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=B3=80=EC=88=98=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Today.tsx | 37 +++++-------------------------------- 1 file changed, 5 insertions(+), 32 deletions(-) diff --git a/src/pages/Today.tsx b/src/pages/Today.tsx index 6b378d02..af3970cd 100644 --- a/src/pages/Today.tsx +++ b/src/pages/Today.tsx @@ -1,9 +1,8 @@ import styled from '@emotion/styled'; import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { DragDropContext, DropResult } from 'react-beautiful-dnd'; -import { GetTasksResponse } from '@/apis/tasks/getTask/GetTasksResponse'; import useGetTasks from '@/apis/tasks/getTask/query'; import updateTaskStatus from '@/apis/tasks/updateTaskStatus/axios'; import { UpdateTaskStatusType } from '@/apis/tasks/updateTaskStatus/UpdateTaskStatusType'; @@ -15,33 +14,15 @@ import { SortOrderType } from '@/types/sortOrderType'; import { TaskType } from '@/types/tasks/taskType'; import formatDatetoLocalDate from '@/utils/formatDatetoLocalDate'; -interface TaskState { - [key: string]: TaskType[]; - staging: TaskType[]; - target: TaskType[]; -} - function Today() { - const [tasks, setTasks] = useState({ staging: [], target: [] }); const [selectedTarget, setSelectedTarget] = useState(null); const [activeButton, setActiveButton] = useState<'전체' | '지연'>('전체'); const [sortOrder, setSortOrder] = useState('recent'); const isTotal = activeButton === '전체'; // Task 목록 Get - const [previousStagingData, setPreviousStagingData] = useState(undefined); - const [previousTargetData, setPreviousTargetData] = useState(undefined); - /** StagingArea */ - const { isFetched: isStagingFetched, data: stagingData } = useGetTasks({ isTotal, sortOrder }, previousStagingData); - - useEffect(() => { - if (isStagingFetched && stagingData) { - setPreviousStagingData(stagingData); - } - }, [isStagingFetched, stagingData]); - - console.log('stagingArea_taskList', stagingData); + const { isFetched: isStagingFetched, data: stagingData } = useGetTasks({ isTotal, sortOrder }); /** isTotal 핸들링 함수 */ const handleTextBtnClick = (button: '전체' | '지연') => { @@ -61,15 +42,7 @@ function Today() { const targetDate = formatDatetoLocalDate(selectedDate); - const { isFetched: isTargetFetched, data: targetData } = useGetTasks({ targetDate }, previousTargetData); - - useEffect(() => { - if (isTargetFetched && targetData) { - setPreviousTargetData(targetData); - } - }, [isTargetFetched, targetData]); - - console.log('targetArea_taskList', stagingData); + const { isFetched: isTargetFetched, data: targetData } = useGetTasks({ targetDate }); const handlePrevBtn = () => { const newDate = new Date(selectedDate); @@ -114,12 +87,12 @@ function Today() { // 상태 업데이트 if (source.droppableId === 'target') { - setTasks({ + queryClient.setQueryData(['tasks'], { target: { ...targetData, data: { ...targetData.data, tasks: sourceTasks } }, staging: { ...stagingData, data: { ...stagingData.data, tasks: destinationTasks } }, }); } else { - setTasks({ + queryClient.setQueryData(['tasks'], { target: { ...targetData, data: { ...targetData.data, tasks: destinationTasks } }, staging: { ...stagingData, data: { ...stagingData.data, tasks: sourceTasks } }, }); From ea0ff1302ee71be35146648e234dc7c5a68f878c Mon Sep 17 00:00:00 2001 From: Kjiw0n Date: Thu, 18 Jul 2024 15:50:44 +0900 Subject: [PATCH 7/8] =?UTF-8?q?feat:=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20get?= =?UTF-8?q?=20=EC=BF=BC=EB=A6=AC=EC=97=90=20placeholderData=20=EB=94=94?= =?UTF-8?q?=ED=8F=B4=ED=8A=B8=EA=B0=92=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/tasks/getTask/query.ts | 11 ++++-- src/pages/Today.tsx | 59 ++++++++++++++++----------------- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/apis/tasks/getTask/query.ts b/src/apis/tasks/getTask/query.ts index c796297d..7dccd4ee 100644 --- a/src/apis/tasks/getTask/query.ts +++ b/src/apis/tasks/getTask/query.ts @@ -1,7 +1,6 @@ import { useQuery } from '@tanstack/react-query'; import getTasks from './axios'; -import { GetTasksResponse } from './GetTasksResponse'; import { GetTasksType } from './GetTasksType'; const placeholderData = { @@ -30,11 +29,17 @@ const placeholderData = { }; /** Task 리스트 조회 */ -const useGetTasks = ({ isTotal, sortOrder, targetDate }: GetTasksType, placeholderData?: GetTasksResponse) => +const useGetTasks = ({ isTotal, sortOrder, targetDate }: GetTasksType) => useQuery({ queryKey: ['today', isTotal, sortOrder, targetDate], queryFn: () => getTasks({ isTotal, sortOrder, targetDate }), - placeholderData, + placeholderData: { + code: 'success', + data: { + tasks: [], + }, + message: null, + }, }); export default useGetTasks; diff --git a/src/pages/Today.tsx b/src/pages/Today.tsx index af3970cd..c5305ba7 100644 --- a/src/pages/Today.tsx +++ b/src/pages/Today.tsx @@ -19,10 +19,11 @@ function Today() { const [activeButton, setActiveButton] = useState<'전체' | '지연'>('전체'); const [sortOrder, setSortOrder] = useState('recent'); const isTotal = activeButton === '전체'; + const [selectedDate, setTargetDate] = useState(new Date()); // Task 목록 Get /** StagingArea */ - const { isFetched: isStagingFetched, data: stagingData } = useGetTasks({ isTotal, sortOrder }); + const { data: stagingData } = useGetTasks({ isTotal, sortOrder }); /** isTotal 핸들링 함수 */ const handleTextBtnClick = (button: '전체' | '지연') => { @@ -37,13 +38,6 @@ function Today() { setSelectedTarget(task); }; - /** TargetArea */ - const [selectedDate, setTargetDate] = useState(new Date()); - - const targetDate = formatDatetoLocalDate(selectedDate); - - const { isFetched: isTargetFetched, data: targetData } = useGetTasks({ targetDate }); - const handlePrevBtn = () => { const newDate = new Date(selectedDate); newDate.setDate(newDate.getDate() - 1); @@ -64,7 +58,13 @@ function Today() { setTargetDate(target); }; + const targetDate = formatDatetoLocalDate(selectedDate); + + /** TargetArea */ + const { data: targetData } = useGetTasks({ targetDate }); + const queryClient = useQueryClient(); + const { mutate } = useMutation({ mutationFn: (updateData: UpdateTaskStatusType) => updateTaskStatus(updateData), onSuccess: () => queryClient.invalidateQueries({ queryKey: ['today'] }), @@ -120,29 +120,26 @@ function Today() { - {isStagingFetched && ( - - )} - {isTargetFetched && ( - - )} + + + From ac7ce3f2d1cf159fb0c4761ba2ff43bc627ceb55 Mon Sep 17 00:00:00 2001 From: Kjiw0n Date: Thu, 18 Jul 2024 16:42:42 +0900 Subject: [PATCH 8/8] =?UTF-8?q?refactor:=20=EB=A6=AC=EC=97=91=ED=8A=B8?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=EC=82=AC=EC=9A=A9=20=EB=B6=80=EB=B6=84=20?= =?UTF-8?q?=EB=94=B0=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/tasks/getTask/query.ts | 25 ------------------------ src/apis/tasks/updateTaskStatus/query.ts | 17 ++++++++++++++++ src/pages/Today.tsx | 22 +++++---------------- 3 files changed, 22 insertions(+), 42 deletions(-) create mode 100644 src/apis/tasks/updateTaskStatus/query.ts diff --git a/src/apis/tasks/getTask/query.ts b/src/apis/tasks/getTask/query.ts index 7dccd4ee..607c86fd 100644 --- a/src/apis/tasks/getTask/query.ts +++ b/src/apis/tasks/getTask/query.ts @@ -3,31 +3,6 @@ import { useQuery } from '@tanstack/react-query'; import getTasks from './axios'; import { GetTasksType } from './GetTasksType'; -const placeholderData = { - code: 'success', - data: { - tasks: [ - { - id: 1, - name: 'task name', - deadLine: { - date: '2024-06-30', - time: '12:30', - }, - }, - { - id: 2, - name: 'task name', - deadLine: { - date: '2024-06-30', - time: '12:30', - }, - }, - ], - }, - message: null, -}; - /** Task 리스트 조회 */ const useGetTasks = ({ isTotal, sortOrder, targetDate }: GetTasksType) => useQuery({ diff --git a/src/apis/tasks/updateTaskStatus/query.ts b/src/apis/tasks/updateTaskStatus/query.ts new file mode 100644 index 00000000..1a12efd6 --- /dev/null +++ b/src/apis/tasks/updateTaskStatus/query.ts @@ -0,0 +1,17 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import updateTaskStatus from './axios'; +import { UpdateTaskStatusType } from './UpdateTaskStatusType'; + +const useUpdateTaskStatus = () => { + const queryClient = useQueryClient(); + + const mutation = useMutation({ + mutationFn: (updateData: UpdateTaskStatusType) => updateTaskStatus(updateData), + onSuccess: () => queryClient.invalidateQueries({ queryKey: ['today'] }), + }); + + return { mutate: mutation.mutate, queryClient }; +}; + +export default useUpdateTaskStatus; diff --git a/src/pages/Today.tsx b/src/pages/Today.tsx index c5305ba7..f1da3505 100644 --- a/src/pages/Today.tsx +++ b/src/pages/Today.tsx @@ -1,11 +1,9 @@ import styled from '@emotion/styled'; -import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useState } from 'react'; import { DragDropContext, DropResult } from 'react-beautiful-dnd'; import useGetTasks from '@/apis/tasks/getTask/query'; -import updateTaskStatus from '@/apis/tasks/updateTaskStatus/axios'; -import { UpdateTaskStatusType } from '@/apis/tasks/updateTaskStatus/UpdateTaskStatusType'; +import useUpdateTaskStatus from '@/apis/tasks/updateTaskStatus/query'; import FullCalendarBox from '@/components/common/fullCalendar/FullCalendarBox'; import NavBar from '@/components/common/NavBar'; import StagingArea from '@/components/common/StagingArea/StagingArea'; @@ -18,12 +16,14 @@ function Today() { const [selectedTarget, setSelectedTarget] = useState(null); const [activeButton, setActiveButton] = useState<'전체' | '지연'>('전체'); const [sortOrder, setSortOrder] = useState('recent'); - const isTotal = activeButton === '전체'; const [selectedDate, setTargetDate] = useState(new Date()); + const isTotal = activeButton === '전체'; + const targetDate = formatDatetoLocalDate(selectedDate); // Task 목록 Get - /** StagingArea */ const { data: stagingData } = useGetTasks({ isTotal, sortOrder }); + const { data: targetData } = useGetTasks({ targetDate }); + const { mutate, queryClient } = useUpdateTaskStatus(); /** isTotal 핸들링 함수 */ const handleTextBtnClick = (button: '전체' | '지연') => { @@ -58,18 +58,6 @@ function Today() { setTargetDate(target); }; - const targetDate = formatDatetoLocalDate(selectedDate); - - /** TargetArea */ - const { data: targetData } = useGetTasks({ targetDate }); - - const queryClient = useQueryClient(); - - const { mutate } = useMutation({ - mutationFn: (updateData: UpdateTaskStatusType) => updateTaskStatus(updateData), - onSuccess: () => queryClient.invalidateQueries({ queryKey: ['today'] }), - }); - const handleDragEnd = (result: DropResult) => { const { source, destination } = result;