fix(11-05): CR-01 surface reminderIsCustom to preserve custom VALARMs on edit
- expand.ts: add reminderIsCustom:boolean to CalendarOccurrence interface; derived from classifyValarms kind==='custom'; propagated to both non-recurring and recurring occurrence branches - client.ts: mirror reminderIsCustom on CalendarOccurrence (atomic mirror) - EventForm.tsx: extend deriveReminderValue to accept isCustom flag; returns '__custom__' when true, making the existing D-08 preserve branch live — editing a custom-alarm event now omits reminderLeadMinutes from the payload so outboxWorker extractValarms keeps the original VALARM - Fix existing test fixtures (EventForm.test.tsx, EventDetailPopover.test.tsx) to include reminderIsCustom:false on all CalendarOccurrence literals Fixes CAL-14 Pitfall 1: Apple Calendar absolute DATE-TIME / multi-VALARM alarms no longer silently stripped on any edit round-trip from the PWA.
This commit is contained in:
@@ -80,6 +80,13 @@ export interface CalendarOccurrence {
|
||||
* positive — N minutes before event start (timed) or N/1440 days before (all-day)
|
||||
*/
|
||||
reminderLeadMinutes: number | null;
|
||||
/**
|
||||
* True when the master event's alarm is a custom/absolute/multi-VALARM not reducible
|
||||
* to a single before-event lead (CAL-14, CR-01, Phase 11 Plan 05).
|
||||
* When true, reminderLeadMinutes is always null and the edit form must initialize the
|
||||
* picker to '__custom__' to emit an absent payload field and preserve the original VALARM.
|
||||
*/
|
||||
reminderIsCustom: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,9 +248,14 @@ export function expandOccurrences(
|
||||
// event's VALARM via classifyValarms. All occurrences inherit this value (series-level, D-10).
|
||||
// preset/offlist → specific leadMinutes; custom/none → null (D-07/NOTIF-05).
|
||||
// classifyValarms wraps ICAL.parse in try/catch (T-11-07 safe); safe on parse failure → null.
|
||||
//
|
||||
// Phase 11 Plan 05 (CR-01): reminderIsCustom — surface the 'custom' classification so the
|
||||
// edit form can initialize the picker to '__custom__' and emit an absent payload field,
|
||||
// preserving the original VALARM via the outboxWorker D-08 preserve path.
|
||||
const alarmClass = classifyValarms(rawVevent);
|
||||
const reminderLeadMinutes: number | null =
|
||||
alarmClass.kind === 'preset' || alarmClass.kind === 'offlist' ? alarmClass.leadMinutes : null;
|
||||
const reminderIsCustom: boolean = alarmClass.kind === 'custom';
|
||||
|
||||
// --- 4. Non-recurring event: single occurrence check ---
|
||||
if (!isRecurring) {
|
||||
@@ -281,6 +293,7 @@ export function expandOccurrences(
|
||||
description: event.description ?? null,
|
||||
hasRrule: isRecurring, // always false in the non-recurring branch
|
||||
reminderLeadMinutes, // series-level (D-10)
|
||||
reminderIsCustom, // CR-01 (Plan 05): true when alarm is absolute/multi-VALARM
|
||||
});
|
||||
}
|
||||
return occurrences;
|
||||
@@ -329,6 +342,7 @@ export function expandOccurrences(
|
||||
description: event.description ?? null,
|
||||
hasRrule: isRecurring, // always true in the recurring branch
|
||||
reminderLeadMinutes, // series-level — all occurrences inherit the master's value (D-10)
|
||||
reminderIsCustom, // CR-01 (Plan 05): true when alarm is absolute/multi-VALARM
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user