Stop calling every event a series

A one-time event opened for editing said "this is a recurring event —
changes apply to the whole series", and deleting one offered to delete
all occurrences of an event that has exactly one.

Three places asked whether an event had a baseEventId and took that for
recurrence. It isn't: the calendar loads its range with expandRecurrences,
and Stalwart puts a baseEventId on everything it returns that way, a
one-off pointing at itself included. The mock never sets the field at
all, which is why this only showed up against a real server.

They now share isRecurring(), which asks about recurrence rules, and
treats a base that is some other event as an occurrence of a series too
— so an expanded instance that travels without its rules is still
described honestly on the way to being deleted.

Fixes #25
This commit is contained in:
2026-08-25 07:01:23 -07:00
parent d4d218f078
commit 6170fc3944
5 changed files with 47 additions and 6 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
import { useState } from "react";
import { AlignLeft, Bell, Calendar as CalIcon, Check, Clock, HelpCircle, Link2, MapPin, Pencil, Repeat, Trash2, Users, X, Mail } from "lucide-react";
import { useCalendar, myParticipantKeys, type EventInstance } from "@/store/calendar";
import { useCalendar, myParticipantKeys, isRecurring, type EventInstance } from "@/store/calendar";
import { Popover, type Anchor } from "@/ui/popover";
import { confirmDialog } from "@/ui/dialog";
import { toast } from "@/ui/toast";
@@ -29,7 +29,7 @@ export function EventPopover({ inst, anchor, onClose, onEdit }: { inst: EventIns
const openCompose = useCompose((s) => s.open);
const del = async () => {
const recurring = Boolean(ev.recurrenceRules?.length || ev.baseEventId);
const recurring = isRecurring(ev);
const ok = await confirmDialog({ title: recurring ? "Delete all occurrences?" : "Delete this event?", message: recurring ? "This will delete the entire series." : undefined, confirmLabel: "Delete", danger: true });
if (!ok) return;
setBusy(true);