Files
crowd-funder-for-time-pwa/src/services/notifications/dualScheduleConfig.ts
Jose Olarte III b9f19d3898 fix(notifications): set dual-schedule fallbackBehavior to skip
Avoid showing default New Activity copy when dual content is missing or
outside contentTimeout, per PLUGIN_NOTIFICATION_FIX_ANDROID.md.
2026-04-16 21:21:37 +08:00

85 lines
2.6 KiB
TypeScript

/**
* Builds DualScheduleConfiguration for the Daily Notification plugin.
* Used for API-driven "New Activity" notifications (prefetch + notify).
*/
import type { DualScheduleConfiguration } from "@timesafari/daily-notification-plugin";
/** Matches `plugins.DailyNotification.networkConfig` in capacitor.config.ts */
const CONTENT_FETCH_NETWORK = {
timeout: 30_000,
retryAttempts: 3,
retryDelay: 1_000,
} as const;
/**
* Convert "HH:mm" (24h) to cron expression "minute hour * * *" (daily at that time).
*/
export function timeToCron(timeHHmm: string): string {
const [h, m] = timeHHmm.split(":").map(Number);
const hour = Math.max(0, Math.min(23, h ?? 0));
const minute = Math.max(0, Math.min(59, m ?? 0));
return `${minute} ${hour} * * *`;
}
/**
* Cron for 5 minutes before the given "HH:mm" (so prefetch runs before the notification).
*/
export function timeToCronFiveMinutesBefore(timeHHmm: string): string {
const [h, m] = timeHHmm.split(":").map(Number);
let hour = Math.max(0, Math.min(23, h ?? 0));
let minute = Math.max(0, Math.min(59, m ?? 0));
minute -= 5;
if (minute < 0) {
minute += 60;
hour -= 1;
if (hour < 0) hour += 24;
}
return `${minute} ${hour} * * *`;
}
export interface DualScheduleConfigInput {
/** Time in HH:mm (24h) for the user notification */
notifyTime: string;
/** Optional title; default "New Activity" */
title?: string;
/** Optional body; default describes API-driven content */
body?: string;
}
/**
* Build plugin DualScheduleConfiguration for scheduleDualNotification().
* contentFetch runs 5 minutes before notifyTime; userNotification at notifyTime.
*/
export function buildDualScheduleConfig(
input: DualScheduleConfigInput,
): DualScheduleConfiguration {
const notifyTime = input.notifyTime || "09:00";
const fetchCron = timeToCronFiveMinutesBefore(notifyTime);
const notifyCron = timeToCron(notifyTime);
return {
contentFetch: {
enabled: true,
schedule: fetchCron,
timeout: CONTENT_FETCH_NETWORK.timeout,
retryAttempts: CONTENT_FETCH_NETWORK.retryAttempts,
retryDelay: CONTENT_FETCH_NETWORK.retryDelay,
callbacks: {},
},
userNotification: {
enabled: true,
schedule: notifyCron,
title: input.title ?? "New Activity",
body: input.body ?? "Check your starred projects and offers for updates.",
sound: true,
vibration: true,
priority: "normal",
},
relationship: {
autoLink: true,
contentTimeout: 5 * 60 * 1000, // 5 minutes
fallbackBehavior: "skip", // was "show_default"
},
};
}