fix(11-05): CR-02 all-day-aware push body (no "Starts in 0 min")
- humanizeLeadMinutes: add isAllDay=false param; all-day branch returns "Today" (lead=0), "Tomorrow" (1440), "In 1 week" (10080), "In N days" (other) - byKey map: store isAllDay flag (false for timed, true for all-day) - dispatch loop: pass event.isAllDay to humanizeLeadMinutes All-day same-day reminder push now reads "Today" instead of "Starts in 0 min". Timed event wording unchanged (isAllDay defaults to false).
This commit is contained in:
@@ -79,11 +79,23 @@ function yyyyMmDd(d: Date): string {
|
|||||||
/**
|
/**
|
||||||
* Humanize a lead time in minutes to a human-readable string.
|
* Humanize a lead time in minutes to a human-readable string.
|
||||||
*
|
*
|
||||||
|
* CR-02 (Phase 11 Plan 05): added isAllDay parameter. All-day events use day-granularity
|
||||||
|
* wording ("Today", "Tomorrow", "In N days/1 week") because the lead is day-based
|
||||||
|
* and "Starts in 0 min" for a same-day all-day event (lead=0) is factually wrong.
|
||||||
|
* Timed events keep the existing "Starts in N min/hours/days" wording (default isAllDay=false).
|
||||||
|
*
|
||||||
* D-09: "Starts in 30 min" / "Starts in 1 hour" / "Starts in 1 day" etc.
|
* D-09: "Starts in 30 min" / "Starts in 1 hour" / "Starts in 1 day" etc.
|
||||||
* Branch order is important — check < 120 before the hours calculation to
|
* Branch order is important — check < 120 before the hours calculation to
|
||||||
* prevent Math.round(90/60)=2 erroneously giving "2 hours" for a 90-min lead.
|
* prevent Math.round(90/60)=2 erroneously giving "2 hours" for a 90-min lead.
|
||||||
*/
|
*/
|
||||||
export function humanizeLeadMinutes(leadMinutes: number): string {
|
export function humanizeLeadMinutes(leadMinutes: number, isAllDay = false): string {
|
||||||
|
if (isAllDay) {
|
||||||
|
// Day-granularity wording for all-day event reminders
|
||||||
|
if (leadMinutes === 0) return 'Today';
|
||||||
|
if (leadMinutes <= 1440) return 'Tomorrow';
|
||||||
|
if (leadMinutes === 10080) return 'In 1 week';
|
||||||
|
return `In ${Math.round(leadMinutes / 1440)} days`;
|
||||||
|
}
|
||||||
if (leadMinutes < 60) return `Starts in ${leadMinutes} min`;
|
if (leadMinutes < 60) return `Starts in ${leadMinutes} min`;
|
||||||
if (leadMinutes < 120) return 'Starts in 1 hour';
|
if (leadMinutes < 120) return 'Starts in 1 hour';
|
||||||
if (leadMinutes < 1440) return `Starts in ${Math.round(leadMinutes / 60)} hours`;
|
if (leadMinutes < 1440) return `Starts in ${Math.round(leadMinutes / 60)} hours`;
|
||||||
@@ -186,6 +198,7 @@ export async function runReminderCheck(now = new Date()): Promise<void> {
|
|||||||
dtstartMs: number; // key component — used for compound dedup key
|
dtstartMs: number; // key component — used for compound dedup key
|
||||||
pruneMs: number; // when to prune: dtstartUtc for timed; end-of-event-date for all-day
|
pruneMs: number; // when to prune: dtstartUtc for timed; end-of-event-date for all-day
|
||||||
reminderLeadMinutes: number;
|
reminderLeadMinutes: number;
|
||||||
|
isAllDay: boolean; // CR-02 (Plan 05): needed for allDay-aware humanizeLeadMinutes
|
||||||
dateStr: string;
|
dateStr: string;
|
||||||
subs: SubRow[];
|
subs: SubRow[];
|
||||||
}
|
}
|
||||||
@@ -214,6 +227,7 @@ export async function runReminderCheck(now = new Date()): Promise<void> {
|
|||||||
dtstartMs,
|
dtstartMs,
|
||||||
pruneMs: dtstartMs, // timed: prune when event has started (dtstartUtc <= now)
|
pruneMs: dtstartMs, // timed: prune when event has started (dtstartUtc <= now)
|
||||||
reminderLeadMinutes: lead,
|
reminderLeadMinutes: lead,
|
||||||
|
isAllDay: false, // CR-02: timed events use the existing "Starts in N..." wording
|
||||||
dateStr: yyyyMmDd(dtstartUtc),
|
dateStr: yyyyMmDd(dtstartUtc),
|
||||||
subs: [],
|
subs: [],
|
||||||
});
|
});
|
||||||
@@ -262,6 +276,7 @@ export async function runReminderCheck(now = new Date()): Promise<void> {
|
|||||||
dtstartMs,
|
dtstartMs,
|
||||||
pruneMs,
|
pruneMs,
|
||||||
reminderLeadMinutes: lead,
|
reminderLeadMinutes: lead,
|
||||||
|
isAllDay: true, // CR-02: all-day events use day-granularity wording
|
||||||
dateStr: dtstartDate,
|
dateStr: dtstartDate,
|
||||||
subs: [],
|
subs: [],
|
||||||
});
|
});
|
||||||
@@ -289,7 +304,8 @@ export async function runReminderCheck(now = new Date()): Promise<void> {
|
|||||||
// Null-safe title fallback (D-02 / NOTIF-01): use uid if title is NULL.
|
// Null-safe title fallback (D-02 / NOTIF-01): use uid if title is NULL.
|
||||||
title: event.title ?? event.uid,
|
title: event.title ?? event.uid,
|
||||||
// D-09: humanized body driven by the configured lead (DB ground truth), not live delta.
|
// D-09: humanized body driven by the configured lead (DB ground truth), not live delta.
|
||||||
body: humanizeLeadMinutes(event.reminderLeadMinutes),
|
// CR-02 (Plan 05): pass isAllDay so all-day events get day-granularity wording.
|
||||||
|
body: humanizeLeadMinutes(event.reminderLeadMinutes, event.isAllDay),
|
||||||
tag: `reminder-${event.uid}`,
|
tag: `reminder-${event.uid}`,
|
||||||
navigate: `/calendar?date=${event.dateStr}&event=${event.uid}`,
|
navigate: `/calendar?date=${event.dateStr}&event=${event.uid}`,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user