diff --git a/src/public/app/widgets/view_widgets/calendar_view.ts b/src/public/app/widgets/view_widgets/calendar_view.ts
index 31572e2f3..0a6ef4df5 100644
--- a/src/public/app/widgets/view_widgets/calendar_view.ts
+++ b/src/public/app/widgets/view_widgets/calendar_view.ts
@@ -1,9 +1,10 @@
-import type { EventSourceInput, PluginDef } from "@fullcalendar/core";
+import type { EventChangeArg, EventDropArg, EventSourceInput, PluginDef } from "@fullcalendar/core";
import froca from "../../services/froca.js";
import ViewMode, { type ViewModeArgs } from "./view_mode.js";
import type FNote from "../../entities/fnote.js";
import server from "../../services/server.js";
import ws from "../../services/ws.js";
+import type { EventDragStopArg, EventResizeDoneArg } from "@fullcalendar/interaction";
const TPL = `
@@ -57,38 +58,40 @@ export default class CalendarView extends ViewMode {
initialView: "dayGridMonth",
events: await CalendarView.#buildEvents(this.noteIds),
editable,
- eventDragStop: async (e) => {
- const startDate = e.event.start?.toISOString().substring(0, 10);
- let endDate = e.event.end?.toISOString().substring(0, 10);
- const noteId = e.event.extendedProps.noteId;
-
- // Fullcalendar end date is exclusive, not inclusive but we store it the other way around.
- if (endDate) {
- const endDateParsed = new Date(endDate);
- endDateParsed.setDate(endDateParsed.getDate() - 1);
- endDate = endDateParsed.toISOString().substring(0, 10);
- }
-
- // Don't store the end date if it's empty.
- if (endDate === startDate) {
- endDate = undefined;
- }
-
- // Update start date
- const note = await froca.getNote(noteId);
- if (!note) {
- return;
- }
-
- CalendarView.#setAttribute(note, "label", "startDate", startDate);
- CalendarView.#setAttribute(note, "label", "endDate", endDate);
- }
+ eventChange: (e) => this.#onEventMoved(e),
});
calendar.render();
return this.$root;
}
+ async #onEventMoved(e: EventChangeArg) {
+ const startDate = CalendarView.#formatDateToLocalISO(e.event.start);
+ let endDate = CalendarView.#formatDateToLocalISO(e.event.end);
+ const noteId = e.event.extendedProps.noteId;
+
+ // Fullcalendar end date is exclusive, not inclusive but we store it the other way around.
+ if (endDate) {
+ const endDateParsed = new Date(endDate);
+ endDateParsed.setDate(endDateParsed.getDate() - 1);
+ endDate = CalendarView.#formatDateToLocalISO(endDateParsed);
+ }
+
+ // Don't store the end date if it's empty.
+ if (endDate === startDate) {
+ endDate = undefined;
+ }
+
+ // Update start date
+ const note = await froca.getNote(noteId);
+ if (!note) {
+ return;
+ }
+
+ CalendarView.#setAttribute(note, "label", "startDate", startDate);
+ CalendarView.#setAttribute(note, "label", "endDate", endDate);
+ }
+
static async #buildEvents(noteIds: string[]) {
const notes = await froca.getNotes(noteIds);
const events: EventSourceInput = [];
@@ -114,7 +117,7 @@ export default class CalendarView extends ViewMode {
if (endDate) {
// Fullcalendar end date is exclusive, not inclusive.
endDate.setDate(endDate.getDate() + 1);
- eventData.end = endDate.toISOString().substring(0, 10);
+ eventData.end = CalendarView.#formatDateToLocalISO(endDate);
}
events.push(eventData);
@@ -159,7 +162,7 @@ export default class CalendarView extends ViewMode {
await server.put(`notes/${note.noteId}/set-attribute`, { type, name, value });
} else {
// Remove the attribute if it exists on the server but we don't define a value for it.
- const attributeId = note.getAttribute(type, name);
+ const attributeId = note.getAttribute(type, name)?.attributeId;
if (attributeId) {
await server.remove(`notes/${note.noteId}/attributes/${attributeId}`);
}
@@ -167,4 +170,14 @@ export default class CalendarView extends ViewMode {
await ws.waitForMaxKnownEntityChangeId();
}
+ static #formatDateToLocalISO(date: Date | null | undefined) {
+ if (!date) {
+ return undefined;
+ }
+
+ const offset = date.getTimezoneOffset();
+ const localDate = new Date(date.getTime() - offset * 60 * 1000);
+ return localDate.toISOString().split('T')[0];
+ }
+
}