Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] Task 타임블로킹 삭제 api 연결 #220

Merged
merged 2 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/apis/timeBlocks/deleteTimeBlock/DeleteTimeBlockType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface DeleteTimeBlokType {
taskId: number;
timeBlockId: number;
}
10 changes: 10 additions & 0 deletions src/apis/timeBlocks/deleteTimeBlock/axios.ts
Original file line number Diff line number Diff line change
@@ -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;
17 changes: 17 additions & 0 deletions src/apis/timeBlocks/deleteTimeBlock/query.ts
Original file line number Diff line number Diff line change
@@ -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({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

태스크 삭제 적용까지 시간이 많이 걸려서 isLoading이면 스피너를 추가하면 더욱 좋을 것 같습니다!

mutationFn: ({ taskId, timeBlockId }: DeleteTimeBlokType) => deleteTimeBlock({ taskId, timeBlockId }),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['timeblock'] }),
});

return { mutate: mutation.mutate };
};

export default useDeleteTimeBlock;
38 changes: 26 additions & 12 deletions src/components/common/fullCalendar/FullCalendarBox.tsx
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존에 같은 id 가진 이벤트가 캘린더에 있다면 삭제 주석 달아둔 부분에도 삭제 기능이 달려야 할 것 같습니다!
오늘 안에 한 태스크를 한번만 긁을 수 있기 때문에 새로 긁으면 기존에 있던 블럭이 지워져야 해서 이쪽에 그 처리를 해주면 될 것 같아요

Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ function FullCalendarBox({ size, selectDate, selectedTarget }: FullCalendarBoxPr
const [startDate, setStartDate] = useState<string>(todayDate);

const [isModalOpen, setModalOpen] = useState(false);
const [modalTaskId, setModalTaskId] = useState<number | null>(null);
const [modalTimeBlockId, setModalTimeBlockId] = useState<number | null>(null);

const handleViewChange = (view: ViewMountArg) => {
setCurrentView(view.view.type);
Expand Down Expand Up @@ -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) => {
Expand All @@ -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);
Comment on lines 145 to 148
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


주석한줄 달아주시면 너무너무 좋을 것 같아요!!


// 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 (
<FullCalendarLayout size={size}>
<CustomButtonContainer>
Expand Down Expand Up @@ -199,15 +213,15 @@ function FullCalendarBox({ size, selectDate, selectedTarget }: FullCalendarBoxPr
eventClick={handleEventClick}
select={addEventWhenDragged}
/>
{isModalOpen && (
// 🚨 임시 taskID ... 데이터 형식 확정 후 수정할 것 🚨
{isModalOpen && modalTaskId !== null && modalTimeBlockId !== null && (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

모달 테스크 아이디와 타임블록 아이디가 존재할 때만 모달이 열리도록 처리해주셨군용! 쪼아요

<Modal
isOpen={isModalOpen}
sizeType={{ type: 'short' }}
top={top}
left={left}
onClose={closeModal}
taskId={5}
taskId={modalTaskId}
timeBlockId={modalTimeBlockId}
/>
)}
</FullCalendarLayout>
Expand Down
23 changes: 19 additions & 4 deletions src/components/common/fullCalendar/processEvents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Comment on lines +11 to +19
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
interface TasksEventData {
taskId: number;
timeBlockId: number;
title: string;
start: string;
end: string;
allDay?: boolean;
classNames: string;
}
interface TasksEventData extends EventData {
taskId: number;
timeBlockId: number;
}

여기 인터페이스 상속으로 이렇게 써줄 수 있을 것 같네요!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 오 이렇게도 할 수 있군요 배우고 갑니닷 👍👍👍


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);
});
});

Expand All @@ -36,7 +51,7 @@ const processEvents = (timeBlockData: TimeBlockData): EventData[] => {
});
});

return events;
return { events, taskEvents };
};

export default processEvents;
26 changes: 21 additions & 5 deletions src/components/common/modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -15,13 +16,13 @@ interface ModalProps {
top: number;
left: number;
onClose: () => void;
taskId: number;
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: {
Expand All @@ -35,13 +36,28 @@ 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);

if (taskId && timeBlockId) {
mutate({ taskId, timeBlockId });
} else {
console.error('taskId 또는 timeBlockId가 존재하지 않습니다.');
}

onClose();
};

return (
isOpen && (
<ModalBackdrop onClick={onClose}>
<ModalLayout type={sizeType.type} top={top} left={left} onClick={(e) => e.stopPropagation()}>
<ModalHeader>
<BtnDate date={dummyData.deadLine.date} time={dummyData.deadLine.time} />
<ModalHeaderBtn type={sizeType.type} />
<ModalHeaderBtn type={sizeType.type} onDelete={handleDelete} />
</ModalHeader>
<ModalBody>
<TextInputBox type={sizeType.type} name={dummyData.name} desc={dummyData.description} />
Expand Down
8 changes: 6 additions & 2 deletions src/components/common/modal/ModalDeleteBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -22,7 +26,7 @@ function ModalDeleteBtn() {
<SettingDeleteBtn size="big" isHover isPressed={false} isActive onClick={handleBtnClick} />
{isClicked && (
<ModalDeleteDetailWapper>
<ModalDeleteDetail top={top} left={left} onClose={handleBtnClick} />
<ModalDeleteDetail top={top} left={left} onClose={handleBtnClick} onDelete={onDelete} />
</ModalDeleteDetailWapper>
)}
</ModalDeleteBtnLayout>
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/modal/ModalDeleteDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
8 changes: 6 additions & 2 deletions src/components/common/modal/ModalHeaderBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<ModalHeaderBtnLayout>
<ModalDeleteBtn />
<ModalDeleteBtn onDelete={onDelete} />
{type === 'long' && <SettingCheckBtn type="progress" size="big" isHover isPressed={false} isActive />}
<SettingCheckBtn type="complete" size="big" isHover isPressed={false} isActive />
</ModalHeaderBtnLayout>
Expand Down
Loading