diff --git a/src/features/Calendar/components/EventDetailCard/EventDetailCard.style.ts b/src/features/Calendar/components/EventDetailCard/EventDetailCard.style.ts index 0112e53..80d45aa 100644 --- a/src/features/Calendar/components/EventDetailCard/EventDetailCard.style.ts +++ b/src/features/Calendar/components/EventDetailCard/EventDetailCard.style.ts @@ -43,6 +43,7 @@ export const Content = styled.div` export const TextWrapper = styled.div` display: flex; flex-direction: column; + align-items: flex-start; gap: 8px; ` diff --git a/src/features/Calendar/hooks/useCalendarDraftEvent.ts b/src/features/Calendar/hooks/useCalendarDraftEvent.ts index f8d9d50..f794066 100644 --- a/src/features/Calendar/hooks/useCalendarDraftEvent.ts +++ b/src/features/Calendar/hooks/useCalendarDraftEvent.ts @@ -32,11 +32,16 @@ export const useCalendarDraftEvent = ({ updateEventTiming, }: UseCalendarDraftEventArgs) => { const handleCloseModalWithCleanup = useCallback(() => { - if (!isModalEditing && modal.eventId != null) { - removeEvent(modal.eventId) + if (modal.eventId != null) { + const shouldRemoveDraft = + !isModalEditing || + events.some((eventItem) => eventItem.id === modal.eventId && eventItem.isTemporary) + if (shouldRemoveDraft) { + removeEvent(modal.eventId) + } } handleCloseModal() - }, [handleCloseModal, isModalEditing, modal.eventId, removeEvent]) + }, [events, handleCloseModal, isModalEditing, modal.eventId, removeEvent]) const clearPendingDraftEvent = useCallback(() => { if (!modal.isOpen || isModalEditing || modal.eventId == null) return diff --git a/src/features/Calendar/hooks/useCalendarEvents.ts b/src/features/Calendar/hooks/useCalendarEvents.ts index c7653be..ff780a6 100644 --- a/src/features/Calendar/hooks/useCalendarEvents.ts +++ b/src/features/Calendar/hooks/useCalendarEvents.ts @@ -144,7 +144,9 @@ export const useCalendarEvents = (options: UseCalendarEventsOptions = {}) => { // 서버 응답 후 임시 이벤트 id를 실제 id로 교체 const updateEventId = useCallback((tempId: CalendarEvent['id'], nextId: CalendarEvent['id']) => { setEvents((prev) => - prev.map((event) => (event.id === tempId ? { ...event, id: nextId } : event)), + prev.map((event) => + event.id === tempId ? { ...event, id: nextId, isTemporary: false } : event, + ), ) }, []) diff --git a/src/features/Calendar/utils/helpers/calendarPageHelpers.ts b/src/features/Calendar/utils/helpers/calendarPageHelpers.ts index 7ca43ed..5dbfc6c 100644 --- a/src/features/Calendar/utils/helpers/calendarPageHelpers.ts +++ b/src/features/Calendar/utils/helpers/calendarPageHelpers.ts @@ -34,6 +34,7 @@ export const createEvent = (date: Date, index: number, allDay = false): Calendar recurrenceGroup: null, friendIds: [], type: 'schedule', + isTemporary: true, } } diff --git a/src/features/Todo/components/TodoCard/TodoCard.style.ts b/src/features/Todo/components/TodoCard/TodoCard.style.ts index a37edf2..40a3adb 100644 --- a/src/features/Todo/components/TodoCard/TodoCard.style.ts +++ b/src/features/Todo/components/TodoCard/TodoCard.style.ts @@ -45,6 +45,15 @@ export const ButtonWrapper = styled.div` } } ` +export const DeleteButton = styled.button` + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0; + border: 0; + background: transparent; + cursor: pointer; +` export const TodoLeftWrapper = styled.div` display: flex; gap: 16px; diff --git a/src/features/Todo/components/TodoCard/TodoCard.tsx b/src/features/Todo/components/TodoCard/TodoCard.tsx index 832c1ae..5f19aa0 100644 --- a/src/features/Todo/components/TodoCard/TodoCard.tsx +++ b/src/features/Todo/components/TodoCard/TodoCard.tsx @@ -86,13 +86,16 @@ const TodoCard = ({ - { event.stopPropagation() handleDelete() }} - /> + > + + {openDeleteModal && isRecurringTodo && ( useCallback( (values: ScheduleEditorFormValues, scope?: RecurrenceEventScope, occurrenceDate?: string) => { - if (eventId == null || eventId === 0) return Promise.resolve() + if (eventId == null || eventId === 0 || initialEvent?.isTemporary) return Promise.resolve() const startDate = values.eventStartDate ?? new Date(date) const endDate = values.eventEndDate ?? startDate const [start, end] = values.isAllday diff --git a/src/shared/hooks/addSchedule/useScheduleSubmitFlow.ts b/src/shared/hooks/addSchedule/useScheduleSubmitFlow.ts index ad0771e..cd2de0b 100644 --- a/src/shared/hooks/addSchedule/useScheduleSubmitFlow.ts +++ b/src/shared/hooks/addSchedule/useScheduleSubmitFlow.ts @@ -81,6 +81,7 @@ export const useScheduleSubmitFlow = ({ }, []) const showToast = useToastStore.getState().showToast + const isTemporaryEvent = Boolean(initialEvent?.isTemporary) const confirmTitle = useCallback( (values: ScheduleEditorFormValues) => { @@ -163,7 +164,7 @@ export const useScheduleSubmitFlow = ({ return } await submitScheduleValues(values, { - mode: isEditing ? 'patch' : 'create', + mode: isEditing && !isTemporaryEvent ? 'patch' : 'create', }) }, (errors) => { diff --git a/src/shared/hooks/addTodo/useTodoDetailHydration.ts b/src/shared/hooks/addTodo/useTodoDetailHydration.ts index 21fb664..3c8a119 100644 --- a/src/shared/hooks/addTodo/useTodoDetailHydration.ts +++ b/src/shared/hooks/addTodo/useTodoDetailHydration.ts @@ -12,6 +12,7 @@ type UseTodoDetailHydrationProps = { date: string eventId: CalendarEvent['id'] isEditing: boolean + initialEvent?: CalendarEvent | null todoDate: Date | null setValue: UseFormSetValue } @@ -20,11 +21,13 @@ export const useTodoDetailHydration = ({ date, eventId, isEditing, + initialEvent, todoDate, setValue, }: UseTodoDetailHydrationProps) => { const hydratedDetailKeyRef = useRef(null) - const isPersistedTodo = isEditing && eventId != null && eventId !== 0 + const isPersistedTodo = + isEditing && eventId != null && eventId !== 0 && !initialEvent?.isTemporary const shouldFetchDetail = isPersistedTodo const detailOccurrenceDate = moment(date).format('YYYY-MM-DD') const { data: detailData } = useGetDetailTodoQuery( diff --git a/src/shared/hooks/addTodo/useTodoFooter.tsx b/src/shared/hooks/addTodo/useTodoFooter.tsx index 6140ff0..2aa6e70 100644 --- a/src/shared/hooks/addTodo/useTodoFooter.tsx +++ b/src/shared/hooks/addTodo/useTodoFooter.tsx @@ -99,7 +99,12 @@ export const useTodoFooter = ({ if (eventIdRef.current != null && eventIdRef.current !== 0) { onEventColorChangeRef.current?.(eventIdRef.current, value) } - if (!isEditingRef.current || eventIdRef.current == null || eventIdRef.current === 0) { + if ( + !isEditingRef.current || + eventIdRef.current == null || + eventIdRef.current === 0 || + !isPersistedTodoRef.current + ) { return } patchTodoMutateRef.current( diff --git a/src/shared/hooks/form/useTodoEditorForm.ts b/src/shared/hooks/form/useTodoEditorForm.ts index 8c7150a..d74e459 100644 --- a/src/shared/hooks/form/useTodoEditorForm.ts +++ b/src/shared/hooks/form/useTodoEditorForm.ts @@ -127,7 +127,7 @@ export const useTodoEditorForm = ({ recurrenceGroup, } - const isPersistedTodoId = typeof id === 'number' && id > 0 + const isPersistedTodoId = typeof id === 'number' && id > 0 && !initialEvent?.isTemporary if (isEditing && isPersistedTodoId) { const occurrenceDate = options?.occurrenceDate ?? formatIsoDate(date) return patchTodoMutate({ diff --git a/src/shared/types/calendar/types.ts b/src/shared/types/calendar/types.ts index 3661414..413e456 100644 --- a/src/shared/types/calendar/types.ts +++ b/src/shared/types/calendar/types.ts @@ -31,6 +31,7 @@ export type CalendarEvent = Omit & { type?: 'todo' | 'schedule' isDone?: boolean isRecurring?: boolean + isTemporary?: boolean } export type GetEventsResponseDTO = { diff --git a/src/shared/ui/Modals/TodoEditor/TodoEditorContent.tsx b/src/shared/ui/Modals/TodoEditor/TodoEditorContent.tsx index 81f0c4f..4d7cacc 100644 --- a/src/shared/ui/Modals/TodoEditor/TodoEditorContent.tsx +++ b/src/shared/ui/Modals/TodoEditor/TodoEditorContent.tsx @@ -39,6 +39,7 @@ const TodoEditorContent = ({ date, eventId, isEditing, + initialEvent, todoDate: todo.todoDate, setValue, })