From 9083c183927c3e3e68c71aa36ad8ae5c94df19c7 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 16 Mar 2025 19:53:20 +0200 Subject: [PATCH] feat(calendar): support start & end date --- .../view_widgets/calendar_view.spec.ts | 16 +++++++-- .../app/widgets/view_widgets/calendar_view.ts | 34 ++++++++++++++----- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/public/app/widgets/view_widgets/calendar_view.spec.ts b/src/public/app/widgets/view_widgets/calendar_view.spec.ts index 286792325..10ab38160 100644 --- a/src/public/app/widgets/view_widgets/calendar_view.spec.ts +++ b/src/public/app/widgets/view_widgets/calendar_view.spec.ts @@ -124,7 +124,7 @@ describe("Promoted attributes", () => { "#calendar:displayedAttributes": "weight,mood" }); - const event = await CalendarView.buildEvent(note, "2025-04-04"); + const event = await CalendarView.buildEvent(note, { startDate: "2025-04-04" }); expect(event).toHaveLength(1); expect(event[0]?.promotedAttributes).toMatchObject([ [ "weight", "75" ], @@ -142,10 +142,22 @@ describe("Promoted attributes", () => { "#relation:assignee": "promoted,alias=Assignee,single,text", }); - const event = await CalendarView.buildEvent(note, "2025-04-04"); + const event = await CalendarView.buildEvent(note, { startDate: "2025-04-04" }); expect(event).toHaveLength(1); expect(event[0]?.promotedAttributes).toMatchObject([ [ "assignee", "Target note" ] ]) }); + + it("supports start time and end time", async () => { + const noteIds = buildNotes([ + { title: "Note 1", "#startDate": "2025-05-05", "#startTime": "13:36", "#endTime": "14:56" }, + { title: "Note 2", "#startDate": "2025-05-07", "#endDate": "2025-05-08", "#startTime": "13:36", "#endTime": "14:56" }, + ]); + const events = await CalendarView.buildEvents(noteIds); + + expect(events).toHaveLength(2); + expect(events[0]).toMatchObject({ title: "Note 1", start: "2025-05-05T13:36:00", end: "2025-05-05T14:56:00" }); + expect(events[1]).toMatchObject({ title: "Note 2", start: "2025-05-07T13:36:00", end: "2025-05-08T14:56:00" }); + }); }); diff --git a/src/public/app/widgets/view_widgets/calendar_view.ts b/src/public/app/widgets/view_widgets/calendar_view.ts index c3ee15c68..700a74615 100644 --- a/src/public/app/widgets/view_widgets/calendar_view.ts +++ b/src/public/app/widgets/view_widgets/calendar_view.ts @@ -277,7 +277,7 @@ export default class CalendarView extends ViewMode { continue; } - events.push(await CalendarView.buildEvent(dateNote, startDate)); + events.push(await CalendarView.buildEvent(dateNote, { startDate })); if (dateNote.hasChildren()) { const childNoteIds = dateNote.getChildNoteIds(); @@ -292,7 +292,7 @@ export default class CalendarView extends ViewMode { const childNotes = await froca.getNotes(childNoteIds); for (const childNote of childNotes) { const startDate = childNoteToDateMapping[childNote.noteId]; - const event = await CalendarView.buildEvent(childNote, startDate); + const event = await CalendarView.buildEvent(childNote, { startDate }); events.push(event); } @@ -318,7 +318,9 @@ export default class CalendarView extends ViewMode { } const endDate = CalendarView.#getCustomisableLabel(note, "endDate", "calendar:endDate"); - events.push(await CalendarView.buildEvent(note, startDate, endDate)); + const startTime = CalendarView.#getCustomisableLabel(note, "startTime", "calendar:startTime"); + const endTime = CalendarView.#getCustomisableLabel(note, "endTime", "calendar:endTime"); + events.push(await CalendarView.buildEvent(note, { startDate, endDate, startTime, endTime })); } return events.flat(); @@ -346,7 +348,12 @@ export default class CalendarView extends ViewMode { return note.getLabelValue(defaultLabelName); } - static async buildEvent(note: FNote, startDate: string, endDate?: string | null) { + static async buildEvent(note: FNote, { startDate, endDate, startTime, endTime }: { + startDate: string, + endDate?: string | null, + startTime?: string | null, + endTime?: string | null + }) { const customTitleAttributeName = note.getLabelValue("calendar:title"); const titles = await CalendarView.#parseCustomTitle(customTitleAttributeName, note); const color = note.getLabelValue("calendar:color") ?? note.getLabelValue("color"); @@ -359,6 +366,19 @@ export default class CalendarView extends ViewMode { } for (const title of titles) { + if (!endDate) { + if (endTime) { + endDate = startDate; + } else { + const endDateOffset = CalendarView.#offsetDate(endDate ?? startDate, 1); + if (endDateOffset) { + endDate = CalendarView.#formatDateToLocalISO(endDateOffset); + } + } + } + + startDate = (startTime ? `${startDate}T${startTime}:00` : startDate); + endDate = (endTime ? `${endDate}T${endTime}:00` : endDate); const eventData: EventInput = { title: title, start: startDate, @@ -368,10 +388,8 @@ export default class CalendarView extends ViewMode { iconClass: note.getLabelValue("iconClass"), promotedAttributes: displayedAttributesData }; - - const endDateOffset = CalendarView.#offsetDate(endDate ?? startDate, 1); - if (endDateOffset) { - eventData.end = CalendarView.#formatDateToLocalISO(endDateOffset); + if (endDate) { + eventData.end = endDate; } events.push(eventData); }