From fdeb7963bab486358179f1e1861cff6c6c0abe38 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Tue, 3 Nov 2026 05:41:35 +0100 Subject: [PATCH] refactor: read event durations without loading the calendar UI --- components/calendar/event-card.tsx | 15 +-------------- lib/calendar-alerts.ts | 2 +- lib/calendar-event-normalization.ts | 15 +++++++++++++++ lib/calendar-utils.ts | 2 +- stores/calendar-store.ts | 2 +- 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/components/calendar/event-card.tsx b/components/calendar/event-card.tsx index d53f88b36..b7618622e 100644 --- a/components/calendar/event-card.tsx +++ b/components/calendar/event-card.tsx @@ -4,6 +4,7 @@ import { useCallback, useRef, useState, type CSSProperties, type DragEvent } fro import { useTranslations } from "next-intl"; import { cn } from "@/lib/utils"; import type { CalendarEvent, Calendar } from "@/lib/jmap/types"; +import { parseDuration } from "@/lib/calendar-event-normalization"; import { format } from "date-fns"; import { ChevronDown, ChevronUp, Users } from "@/components/icons"; import { getParticipantCount, isDeclinedByUser } from "@/lib/calendar-participants"; @@ -101,20 +102,6 @@ export function eventFillClass(tinted: boolean, inactive: boolean): string | und return tinted && !inactive ? "start-bar" : undefined; } -function parseDuration(duration: string | undefined): number { - if (!duration) return 0; - let totalMinutes = 0; - const weekMatch = duration.match(/(\d+)W/); - const hourMatch = duration.match(/(\d+)H/); - const minMatch = duration.match(/(\d+)M/); - const dayMatch = duration.match(/(\d+)D/); - if (weekMatch) totalMinutes += parseInt(weekMatch[1]) * 7 * 24 * 60; - if (dayMatch) totalMinutes += parseInt(dayMatch[1]) * 24 * 60; - if (hourMatch) totalMinutes += parseInt(hourMatch[1]) * 60; - if (minMatch) totalMinutes += parseInt(minMatch[1]); - return totalMinutes; -} - function createEventDragPreview(title: string, timeRange: string, color: string): HTMLElement { const el = document.createElement("div"); el.style.cssText = ` diff --git a/lib/calendar-alerts.ts b/lib/calendar-alerts.ts index bef0151e1..2c5e8ff96 100644 --- a/lib/calendar-alerts.ts +++ b/lib/calendar-alerts.ts @@ -7,7 +7,7 @@ import type { Calendar, CalendarTask, } from '@/lib/jmap/types'; -import { parseDuration } from '@/components/calendar/event-card'; +import { parseDuration } from '@/lib/calendar-event-normalization'; export interface PendingAlert { eventId: string; diff --git a/lib/calendar-event-normalization.ts b/lib/calendar-event-normalization.ts index 6dd31bf83..5305faa8e 100644 --- a/lib/calendar-event-normalization.ts +++ b/lib/calendar-event-normalization.ts @@ -39,6 +39,21 @@ export function parseDurationSeconds(duration: string | undefined): number | nul return (((weeks * 7 + days) * 24 + hours) * 60 + minutes) * 60 + seconds; } +/** A duration in whole minutes, 0 when there is none. */ +export function parseDuration(duration: string | undefined): number { + if (!duration) return 0; + let totalMinutes = 0; + const weekMatch = duration.match(/(\d+)W/); + const hourMatch = duration.match(/(\d+)H/); + const minMatch = duration.match(/(\d+)M/); + const dayMatch = duration.match(/(\d+)D/); + if (weekMatch) totalMinutes += parseInt(weekMatch[1]) * 7 * 24 * 60; + if (dayMatch) totalMinutes += parseInt(dayMatch[1]) * 24 * 60; + if (hourMatch) totalMinutes += parseInt(hourMatch[1]) * 60; + if (minMatch) totalMinutes += parseInt(minMatch[1]); + return totalMinutes; +} + export function normalizeAllDayDurationValue(duration: string | undefined): string | undefined { const totalSeconds = parseDurationSeconds(duration); if (totalSeconds === null || totalSeconds < 86400 || totalSeconds % 86400 !== 0) { diff --git a/lib/calendar-utils.ts b/lib/calendar-utils.ts index 2299fb54c..faff279c4 100644 --- a/lib/calendar-utils.ts +++ b/lib/calendar-utils.ts @@ -1,5 +1,5 @@ import { addDays, differenceInCalendarDays, parseISO, startOfDay, subMilliseconds } from "date-fns"; -import { parseDuration } from "@/components/calendar/event-card"; +import { parseDuration } from "@/lib/calendar-event-normalization"; import type { CalendarEvent } from "@/lib/jmap/types"; import { fromWallClock, isValidTimeZone, parseLocalDateTime, toDisplayDate } from "@/lib/timezone"; diff --git a/stores/calendar-store.ts b/stores/calendar-store.ts index d7f9c53f7..fceb9c4e7 100644 --- a/stores/calendar-store.ts +++ b/stores/calendar-store.ts @@ -5,7 +5,7 @@ import type { Calendar, CalendarEvent, CalendarParticipant, CalendarParticipantI import { debug } from '@/lib/debug'; import { getEventStartDate, normalizeAllDayDuration } from '@/lib/calendar-utils'; import { displayNow } from '@/lib/timezone'; -import { parseDuration } from '@/components/calendar/event-card'; +import { parseDuration } from '@/lib/calendar-event-normalization'; import { sanitizeOutgoingCalendarEventData } from '@/lib/calendar-event-normalization'; import { feedChanged, feedFields } from '@/lib/calendar-feed-diff'; import { expandRecurringEvents } from '@/lib/recurrence-expansion';