diff --git a/src/components/__tests__/calendar-default-alert-ids.test.ts b/src/components/__tests__/calendar-default-alert-ids.test.ts new file mode 100644 index 00000000..bc56bad6 --- /dev/null +++ b/src/components/__tests__/calendar-default-alert-ids.test.ts @@ -0,0 +1,30 @@ +import { describe, it, expect, vi } from 'vitest'; + +// The calendar sheet's default reminders. Alert ids must be unique in the +// account on Stalwart 1.0: an alert the lists can't show kept the id +// another client gave it, and when another calendar used that id too, the +// whole Calendar/set was refused, the new name and colour with it. + +vi.mock('../icons', () => ({ Check: () => null, Plus: () => null, X: () => null })); +vi.mock('../Button', () => ({ default: () => null })); +vi.mock('../../lib/use-layout', () => ({ useSheetInsets: () => ({}) })); +vi.mock('../../theme/colors', () => ({ useColors: () => ({}) })); + +import type { Alert } from '../../api/types'; +import { defaultAlertsToSave } from '../calendar/CalendarEditSheet'; + +// An email alert: the reminder lists show display alerts only. +const email: Alert = { '@type': 'Alert', trigger: { '@type': 'OffsetTrigger', offset: '-PT30M', relativeTo: 'start' }, action: 'email' }; + +describe('the default alerts a calendar saves', () => { + it('puts the alerts it keeps under the calendar\'s own ids too', () => { + const timed = defaultAlertsToSave({ id: 'acc-2:b', originalId: 'b' }, false, [{ minutesBefore: 10 }], { 'default-1': email }); + const allDay = defaultAlertsToSave({ id: 'b' }, true, [], { x1: email }); + + expect(timed).toEqual({ + 'cal-b-timed-1': email, + 'cal-b-timed-2': expect.objectContaining({ action: 'display' }), + }); + expect(allDay).toEqual({ 'cal-b-allday-1': email }); + }); +}); diff --git a/src/components/calendar/CalendarEditSheet.tsx b/src/components/calendar/CalendarEditSheet.tsx index 60b65a0b..eb435147 100644 --- a/src/components/calendar/CalendarEditSheet.tsx +++ b/src/components/calendar/CalendarEditSheet.tsx @@ -110,6 +110,27 @@ function DefaultRemindersEditor({ ); } +/** + * The default alerts saved for `calendar`'s timed or all-day events: the + * reminders, and the alerts the lists can't show (`kept`), every one under + * the calendar's own id prefix. Ids must be unique in the account, and a kept + * alert had the id another client gave it: when another calendar used that + * id too, Stalwart 1.0 refused the whole Calendar/set, its name and colour + * with it. + */ +export function defaultAlertsToSave( + calendar: Pick, + allDay: boolean, + reminders: Reminder[], + kept: Record, +): Record { + const prefix = defaultAlertIdPrefix(calendar, allDay); + const rekeyed: Record = {}; + let n = 0; + for (const alert of Object.values(kept)) rekeyed[`${prefix}-${++n}`] = alert; + return remindersToDefaultAlerts(reminders, rekeyed, prefix); +} + interface CalendarEditSheetProps { visible: boolean; // Existing calendar to edit; null creates a new one. @@ -161,10 +182,10 @@ export function CalendarEditSheet({ visible, calendar, onSave, onClose }: Calend const values: CalendarEditValues = { name: trimmed, color, description: description.trim() }; // Ids unique in the account: Stalwart 1.0 refuses one another calendar uses. if (calendar && editsDefaults && !sameReminders(timedReminders, initialTimed)) { - values.defaultAlertsWithTime = remindersToDefaultAlerts(timedReminders, keptTimed, defaultAlertIdPrefix(calendar, false)); + values.defaultAlertsWithTime = defaultAlertsToSave(calendar, false, timedReminders, keptTimed); } if (calendar && editsDefaults && !sameReminders(allDayReminders, initialAllDay)) { - values.defaultAlertsWithoutTime = remindersToDefaultAlerts(allDayReminders, keptAllDay, defaultAlertIdPrefix(calendar, true)); + values.defaultAlertsWithoutTime = defaultAlertsToSave(calendar, true, allDayReminders, keptAllDay); } await onSave(values); onClose();