Skip to content

Commit 42d729a

Browse files
authored
fix(web): delete draft events immediately (#1881)
1 parent 4ddc2b3 commit 42d729a

4 files changed

Lines changed: 107 additions & 19 deletions

File tree

packages/web/src/views/Forms/EventForm/EventForm.test.tsx

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { type Schema_Event } from "@core/types/event.types";
77
import dayjs from "@core/util/date/dayjs";
88
import { type Props as DateTimeSectionProps } from "@web/views/Forms/EventForm/DateControlsSection/DateTimeSection/DateTimeSection";
99
import { getFormDates } from "@web/views/Forms/EventForm/DateControlsSection/DateTimeSection/form.datetime.util";
10-
import { beforeEach, describe, expect, it, mock } from "bun:test";
10+
import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test";
1111

1212
type CapturedDateTimeSectionProps = Pick<
1313
DateTimeSectionProps,
@@ -36,7 +36,14 @@ mock.module(
3636
);
3737

3838
mock.module("@web/views/Forms/EventForm/EventActionMenu", () => ({
39-
EventActionMenu: () => <button type="button">Event actions</button>,
39+
EventActionMenu: ({ onDelete }: { onDelete: () => void }) => (
40+
<>
41+
<button type="button">Event actions</button>
42+
<button type="button" onClick={onDelete}>
43+
Delete event
44+
</button>
45+
</>
46+
),
4047
}));
4148

4249
mock.module("@web/views/Forms/EventForm/PrioritySection", () => ({
@@ -91,12 +98,18 @@ const createEvent = (overrides: Partial<Schema_Event> = {}): Schema_Event => ({
9198
});
9299

93100
describe("EventForm", () => {
101+
const originalConfirm = window.confirm;
102+
94103
beforeEach(() => {
95104
HotkeyManager.resetInstance();
96105
capturedDateControlsSectionProps = null;
97106
document.body.removeAttribute("data-app-locked");
98107
});
99108

109+
afterEach(() => {
110+
window.confirm = originalConfirm;
111+
});
112+
100113
it("renders the title before the actions on the same row", () => {
101114
render(
102115
<EventForm
@@ -185,6 +198,33 @@ describe("EventForm", () => {
185198
expect(afterTyping.defaultPrevented).toBe(false);
186199
});
187200

201+
it("closes a draft event immediately when deleting from the menu", async () => {
202+
const user = userEvent.setup();
203+
const onClose = mock();
204+
const onDelete = mock();
205+
const confirm = mock(() => true);
206+
window.confirm = confirm;
207+
208+
render(
209+
<EventForm
210+
event={createEvent({ _id: undefined, title: "Unsaved draft" })}
211+
isDraft={true}
212+
isExistingEvent={false}
213+
onClose={onClose}
214+
onDelete={onDelete}
215+
onDuplicate={mock()}
216+
onSubmit={mock()}
217+
setEvent={mock()}
218+
/>,
219+
);
220+
221+
await user.click(screen.getByRole("button", { name: "Delete event" }));
222+
223+
expect(confirm).not.toHaveBeenCalled();
224+
expect(onDelete).not.toHaveBeenCalled();
225+
expect(onClose).toHaveBeenCalledTimes(1);
226+
});
227+
188228
it("resets title editing state when an unsaved draft session changes", async () => {
189229
const user = userEvent.setup();
190230
const event = { ...createEvent(), _id: undefined, title: "" };

packages/web/src/views/Forms/EventForm/EventForm.tsx

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,23 @@ const resolveDateTimeState = (
9797
return createDateTimeState(sourceStartDate, sourceEndDate);
9898
};
9999

100+
const handleEventFormDelete = ({
101+
isDraft,
102+
onClose,
103+
onDelete,
104+
}: {
105+
isDraft: boolean;
106+
onClose: () => void;
107+
onDelete: () => void;
108+
}) => {
109+
if (isDraft) {
110+
onClose();
111+
return;
112+
}
113+
114+
onDelete();
115+
};
116+
100117
export const EventForm: React.FC<Omit<FormProps, "category">> = memo(
101118
({
102119
event,
@@ -262,6 +279,10 @@ export const EventForm: React.FC<Omit<FormProps, "category">> = memo(
262279
}, 1);
263280
}, [_onClose]);
264281

282+
const onDeleteEvent = useCallback(() => {
283+
handleEventFormDelete({ isDraft, onClose, onDelete });
284+
}, [isDraft, onClose, onDelete]);
285+
265286
const onDuplicateEvent = useCallback(() => {
266287
onDuplicate?.(event);
267288
onClose();
@@ -389,18 +410,7 @@ export const EventForm: React.FC<Omit<FormProps, "category">> = memo(
389410
setEvent: setLatestEvent,
390411
};
391412

392-
useAppHotkey(
393-
"Delete",
394-
() => {
395-
if (isDraft) {
396-
onClose();
397-
return;
398-
}
399-
400-
onDelete();
401-
},
402-
EVENT_FORM_PLAIN_HOTKEY_OPTIONS,
403-
);
413+
useAppHotkey("Delete", onDeleteEvent, EVENT_FORM_PLAIN_HOTKEY_OPTIONS);
404414

405415
useAppHotkey(
406416
"Enter",
@@ -498,7 +508,7 @@ export const EventForm: React.FC<Omit<FormProps, "category">> = memo(
498508
onConvert?.();
499509
}}
500510
onDuplicate={onDuplicateEvent}
501-
onDelete={onDelete}
511+
onDelete={onDeleteEvent}
502512
/>
503513
}
504514
/>

packages/web/src/views/Forms/SomedayEventForm/SomedayEventForm.test.tsx

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,17 @@ mock.module(
1717
);
1818

1919
mock.module("@web/views/Forms/SomedayEventForm/SomedayEventActionMenu", () => ({
20-
SomedayEventActionMenu: () => (
21-
<button type="button">Someday event actions</button>
20+
SomedayEventActionMenu: ({
21+
onDeleteClick,
22+
}: {
23+
onDeleteClick: () => void;
24+
}) => (
25+
<>
26+
<button type="button">Someday event actions</button>
27+
<button type="button" onClick={onDeleteClick}>
28+
Delete someday event
29+
</button>
30+
</>
2231
),
2332
}));
2433

@@ -72,4 +81,28 @@ describe("SomedayEventForm", () => {
7281
expect(row?.firstElementChild?.contains(title)).toBe(true);
7382
expect(row?.lastElementChild?.contains(actions)).toBe(true);
7483
});
84+
85+
it("closes a someday draft immediately when deleting from the menu", () => {
86+
const onClose = mock();
87+
const onDelete = mock();
88+
89+
render(
90+
<SomedayEventForm
91+
category={Categories_Event.SOMEDAY_WEEK}
92+
event={{ ...event, _id: undefined, title: "Someday draft" }}
93+
isDraft={true}
94+
isExistingEvent={false}
95+
onClose={onClose}
96+
onDelete={onDelete}
97+
onDuplicate={mock()}
98+
onSubmit={mock()}
99+
setEvent={mock()}
100+
/>,
101+
);
102+
103+
screen.getByRole("button", { name: "Delete someday event" }).click();
104+
105+
expect(onDelete).not.toHaveBeenCalled();
106+
expect(onClose).toHaveBeenCalledTimes(1);
107+
});
75108
});

packages/web/src/views/Forms/SomedayEventForm/SomedayEventForm.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { useSomedayFormShortcuts } from "@web/views/Forms/SomedayEventForm/useSo
3131
export const SomedayEventForm: React.FC<FormProps> = ({
3232
event,
3333
category,
34-
isDraft: _isDraft,
34+
isDraft,
3535
isExistingEvent: _isExistingEvent,
3636
onClose,
3737
onMigrate,
@@ -128,9 +128,14 @@ export const SomedayEventForm: React.FC<FormProps> = ({
128128
};
129129

130130
const onDelete = useCallback(() => {
131+
if (isDraft) {
132+
onClose();
133+
return;
134+
}
135+
131136
onDeleteEvent();
132137
onClose();
133-
}, [onDeleteEvent, onClose]);
138+
}, [isDraft, onDeleteEvent, onClose]);
134139

135140
const onKeyDown = (e: KeyboardEvent<HTMLFormElement>) => {
136141
if (e.key === "Backspace") {

0 commit comments

Comments
 (0)