diff --git a/apps/client/src/services/utils.ts b/apps/client/src/services/utils.ts index 4b425f832..015c509d6 100644 --- a/apps/client/src/services/utils.ts +++ b/apps/client/src/services/utils.ts @@ -47,27 +47,6 @@ function parseDate(str: string) { } } -// Source: https://stackoverflow.com/a/30465299/4898894 -function getMonthsInDateRange(startDate: string, endDate: string) { - const start = startDate.split("-"); - const end = endDate.split("-"); - const startYear = parseInt(start[0]); - const endYear = parseInt(end[0]); - const dates: string[] = []; - - for (let i = startYear; i <= endYear; i++) { - const endMonth = i != endYear ? 11 : parseInt(end[1]) - 1; - const startMon = i === startYear ? parseInt(start[1]) - 1 : 0; - - for (let j = startMon; j <= endMonth; j = j > 12 ? j % 12 || 11 : j + 1) { - const month = j + 1; - const displayMonth = month < 10 ? "0" + month : month; - dates.push([i, displayMonth].join("-")); - } - } - return dates; -} - function padNum(num: number) { return `${num <= 9 ? "0" : ""}${num}`; } @@ -835,7 +814,6 @@ export default { restartDesktopApp, reloadTray, parseDate, - getMonthsInDateRange, formatDateISO, formatDateTime, formatTimeInterval, diff --git a/apps/client/src/widgets/collections/calendar/event_builder.ts b/apps/client/src/widgets/collections/calendar/event_builder.ts index 4a256728b..c9a13c816 100644 --- a/apps/client/src/widgets/collections/calendar/event_builder.ts +++ b/apps/client/src/widgets/collections/calendar/event_builder.ts @@ -1,7 +1,8 @@ -import { EventInput, EventSourceInput } from "@fullcalendar/core/index.js"; +import { EventInput, EventSourceFuncArg, EventSourceInput } from "@fullcalendar/core/index.js"; import froca from "../../../services/froca"; -import { formatDateToLocalISO, getCustomisableLabel, offsetDate } from "./utils"; +import { formatDateToLocalISO, getCustomisableLabel, getMonthsInDateRange, offsetDate } from "./utils"; import FNote from "../../../entities/fnote"; +import server from "../../../services/server"; interface Event { startDate: string, @@ -30,6 +31,50 @@ export async function buildEvents(noteIds: string[]) { return events.flat(); } +export async function buildEventsForCalendar(note: FNote, e: EventSourceFuncArg) { + const events: EventInput[] = []; + + // Gather all the required date note IDs. + const dateRange = getMonthsInDateRange(e.startStr, e.endStr); + let allDateNoteIds: string[] = []; + for (const month of dateRange) { + // TODO: Deduplicate get type. + const dateNotesForMonth = await server.get>(`special-notes/notes-for-month/${month}?calendarRoot=${note.noteId}`); + const dateNoteIds = Object.values(dateNotesForMonth); + allDateNoteIds = [...allDateNoteIds, ...dateNoteIds]; + } + + // Request all the date notes. + const dateNotes = await froca.getNotes(allDateNoteIds); + const childNoteToDateMapping: Record = {}; + for (const dateNote of dateNotes) { + const startDate = dateNote.getLabelValue("dateNote"); + if (!startDate) { + continue; + } + + events.push(await buildEvent(dateNote, { startDate })); + + if (dateNote.hasChildren()) { + const childNoteIds = await dateNote.getSubtreeNoteIds(); + for (const childNoteId of childNoteIds) { + childNoteToDateMapping[childNoteId] = startDate; + } + } + } + + // Request all child notes of date notes in a single run. + const childNoteIds = Object.keys(childNoteToDateMapping); + const childNotes = await froca.getNotes(childNoteIds); + for (const childNote of childNotes) { + const startDate = childNoteToDateMapping[childNote.noteId]; + const event = await buildEvent(childNote, { startDate }); + events.push(event); + } + + return events.flat(); +} + async function buildEvent(note: FNote, { startDate, endDate, startTime, endTime }: Event) { const customTitleAttributeName = note.getLabelValue("calendar:title"); const titles = await parseCustomTitle(customTitleAttributeName, note); diff --git a/apps/client/src/widgets/collections/calendar/index.tsx b/apps/client/src/widgets/collections/calendar/index.tsx index 803f1f2cc..6ed019df1 100644 --- a/apps/client/src/widgets/collections/calendar/index.tsx +++ b/apps/client/src/widgets/collections/calendar/index.tsx @@ -1,4 +1,4 @@ -import { DateSelectArg, LocaleInput, PluginDef } from "@fullcalendar/core/index.js"; +import { DateSelectArg, EventSourceFuncArg, LocaleInput, PluginDef } from "@fullcalendar/core/index.js"; import { ViewModeProps } from "../interface"; import Calendar from "./calendar"; import { useCallback, useEffect, useMemo, useRef, useState } from "preact/hooks"; @@ -12,7 +12,7 @@ import server from "../../../services/server"; import { parseStartEndDateFromEvent, parseStartEndTimeFromEvent } from "./utils"; import dialog from "../../../services/dialog"; import { t } from "../../../services/i18n"; -import { buildEvents } from "./event_builder"; +import { buildEvents, buildEventsForCalendar } from "./event_builder"; interface CalendarViewData { @@ -58,6 +58,8 @@ export default function CalendarView({ note, noteIds }: ViewModeProps { if (!isCalendarRoot) { return async () => await buildEvents(noteIds); + } else { + return async (e: EventSourceFuncArg) => await buildEventsForCalendar(note, e); } }, [isCalendarRoot, noteIds]); diff --git a/apps/client/src/widgets/collections/calendar/utils.ts b/apps/client/src/widgets/collections/calendar/utils.ts index e13ad4b3e..992e1a1a0 100644 --- a/apps/client/src/widgets/collections/calendar/utils.ts +++ b/apps/client/src/widgets/collections/calendar/utils.ts @@ -1,5 +1,6 @@ import { DateSelectArg } from "@fullcalendar/core/index.js"; import { EventImpl } from "@fullcalendar/core/internal"; +import FNote from "../../../entities/fnote"; export function parseStartEndDateFromEvent(e: DateSelectArg | EventImpl) { const startDate = formatDateToLocalISO(e.start); @@ -79,3 +80,24 @@ export function getCustomisableLabel(note: FNote, defaultLabelName: string, cust return note.getLabelValue(defaultLabelName); } + +// Source: https://stackoverflow.com/a/30465299/4898894 +export function getMonthsInDateRange(startDate: string, endDate: string) { + const start = startDate.split("-"); + const end = endDate.split("-"); + const startYear = parseInt(start[0]); + const endYear = parseInt(end[0]); + const dates: string[] = []; + + for (let i = startYear; i <= endYear; i++) { + const endMonth = i != endYear ? 11 : parseInt(end[1]) - 1; + const startMon = i === startYear ? parseInt(start[1]) - 1 : 0; + + for (let j = startMon; j <= endMonth; j = j > 12 ? j % 12 || 11 : j + 1) { + const month = j + 1; + const displayMonth = month < 10 ? "0" + month : month; + dates.push([i, displayMonth].join("-")); + } + } + return dates; +} diff --git a/apps/client/src/widgets/view_widgets/calendar_view.ts b/apps/client/src/widgets/view_widgets/calendar_view.ts index e8dc01bf9..73b92aa5b 100644 --- a/apps/client/src/widgets/view_widgets/calendar_view.ts +++ b/apps/client/src/widgets/view_widgets/calendar_view.ts @@ -30,22 +30,11 @@ export default class CalendarView extends ViewMode<{}> { this.$root = $(TPL); this.$calendarContainer = this.$root.find(".calendar-container"); - this.isCalendarRoot = false; args.$parent.append(this.$root); } async renderList(): Promise | undefined> { - const { Calendar } = await import("@fullcalendar/core"); - - let eventBuilder: EventSourceFunc; - if (!this.isCalendarRoot) { - eventBuilder = - } else { - eventBuilder = async (e: EventSourceFuncArg) => await this.#buildEventsForCalendar(e); - } - const calendar = new Calendar(this.$calendarContainer[0], { - events: eventBuilder, select: (e) => this.#onCalendarSelection(e), eventChange: (e) => this.#onEventMoved(e), height: "100%", @@ -183,50 +172,6 @@ export default class CalendarView extends ViewMode<{}> { } } - async #buildEventsForCalendar(e: EventSourceFuncArg) { - const events: EventInput[] = []; - - // Gather all the required date note IDs. - const dateRange = utils.getMonthsInDateRange(e.startStr, e.endStr); - let allDateNoteIds: string[] = []; - for (const month of dateRange) { - // TODO: Deduplicate get type. - const dateNotesForMonth = await server.get>(`special-notes/notes-for-month/${month}?calendarRoot=${this.parentNote.noteId}`); - const dateNoteIds = Object.values(dateNotesForMonth); - allDateNoteIds = [...allDateNoteIds, ...dateNoteIds]; - } - - // Request all the date notes. - const dateNotes = await froca.getNotes(allDateNoteIds); - const childNoteToDateMapping: Record = {}; - for (const dateNote of dateNotes) { - const startDate = dateNote.getLabelValue("dateNote"); - if (!startDate) { - continue; - } - - events.push(await CalendarView.buildEvent(dateNote, { startDate })); - - if (dateNote.hasChildren()) { - const childNoteIds = await dateNote.getSubtreeNoteIds(); - for (const childNoteId of childNoteIds) { - childNoteToDateMapping[childNoteId] = startDate; - } - } - } - - // Request all child notes of date notes in a single run. - const childNoteIds = Object.keys(childNoteToDateMapping); - const childNotes = await froca.getNotes(childNoteIds); - for (const childNote of childNotes) { - const startDate = childNoteToDateMapping[childNote.noteId]; - const event = await CalendarView.buildEvent(childNote, { startDate }); - events.push(event); - } - - return events.flat(); - } - buildTouchBarCommand({ TouchBar, buildIcon }: CommandListenerData<"buildTouchBar">) { if (!this.calendar) { return;