fix(notifications): apply backend timestamps via scheduleNotifications API
Stop converting backend timestamps to HH:mm/recurring schedules and remove createSchedule/updateSchedule reconciliation. After a successful refresh payload, clear existing notifications and schedule exact timestamps via the plugin scheduleNotifications API (with back-compat clear fallback) to prevent drift.
This commit is contained in:
@@ -13,7 +13,6 @@
|
||||
|
||||
import { Capacitor } from "@capacitor/core";
|
||||
import type { PushNotificationSchema } from "@capacitor/push-notifications";
|
||||
import { ScheduleKind } from "@timesafari/daily-notification-plugin";
|
||||
import { DailyNotification } from "@/plugins/DailyNotificationPlugin";
|
||||
import { REMINDER_ID_DAILY_REMINDER } from "./reminderIds";
|
||||
import { configureNativeFetcherIfReady } from "./nativeFetcherConfig";
|
||||
@@ -577,52 +576,54 @@ export async function refreshNotifications(): Promise<void> {
|
||||
|
||||
const nextNotifications = (data as { nextNotifications?: unknown })
|
||||
?.nextNotifications;
|
||||
|
||||
// Keep existing behavior: ensure background worker credentials are current.
|
||||
await configureNativeFetcherIfReady();
|
||||
|
||||
if (!Array.isArray(nextNotifications)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Full replacement: clear prior scheduled notifications before applying backend schedule.
|
||||
// (Plugin API name is cancelAllNotifications; equivalent intent to "clearAllNotifications".)
|
||||
await DailyNotification.cancelAllNotifications();
|
||||
const timestamps = nextNotifications
|
||||
.map((n) => (n as { timestamp?: unknown })?.timestamp)
|
||||
.filter((t): t is number => typeof t === "number" && Number.isFinite(t));
|
||||
|
||||
// Apply backend schedule to the native scheduler as recurring notifications.
|
||||
// The plugin's schedule API is cron/clockTime-based (recurring), so we map
|
||||
// the backend timestamps to clockTime (HH:mm) schedules.
|
||||
await Promise.all(
|
||||
nextNotifications.map(async (n) => {
|
||||
const timestamp = (n as { timestamp?: unknown })?.timestamp;
|
||||
if (typeof timestamp !== "number" || !Number.isFinite(timestamp)) {
|
||||
return;
|
||||
}
|
||||
if (timestamps.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dt = new Date(timestamp);
|
||||
const hh = dt.getHours().toString().padStart(2, "0");
|
||||
const mm = dt.getMinutes().toString().padStart(2, "0");
|
||||
const clockTime = `${hh}:${mm}`;
|
||||
const id = `backend-${timestamp}`;
|
||||
// Keep existing behavior: ensure background worker credentials are current.
|
||||
await configureNativeFetcherIfReady();
|
||||
|
||||
const existing = await DailyNotification.getSchedule(id);
|
||||
if (existing) {
|
||||
await DailyNotification.updateSchedule(id, {
|
||||
clockTime,
|
||||
enabled: true,
|
||||
});
|
||||
} else {
|
||||
// DailyNotification plugin typings currently omit `id` on CreateScheduleInput,
|
||||
// but runtime supports deterministic IDs for schedule reconciliation.
|
||||
await DailyNotification.createSchedule({
|
||||
id,
|
||||
kind: ScheduleKind.NOTIFY,
|
||||
clockTime,
|
||||
enabled: true,
|
||||
} as unknown as never);
|
||||
}
|
||||
}),
|
||||
);
|
||||
// Backend is source of truth: apply exact timestamps (no HH:mm / recurring conversion).
|
||||
// Only clear after we have a valid API response payload.
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("[Notifications] Applying timestamps:", nextNotifications);
|
||||
|
||||
const plugin = DailyNotification as unknown as {
|
||||
clearAllNotifications?: () => Promise<void>;
|
||||
scheduleNotifications?: (options: {
|
||||
timestamps: number[];
|
||||
}) => Promise<void>;
|
||||
cancelAllNotifications?: () => Promise<void>;
|
||||
};
|
||||
|
||||
if (typeof plugin.clearAllNotifications === "function") {
|
||||
await plugin.clearAllNotifications();
|
||||
} else if (typeof plugin.cancelAllNotifications === "function") {
|
||||
// Back-compat: older builds expose cancelAllNotifications.
|
||||
await plugin.cancelAllNotifications();
|
||||
} else {
|
||||
logger.warn(
|
||||
"[NativeNotificationService] No clearAllNotifications/cancelAllNotifications on plugin; cannot replace schedule",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof plugin.scheduleNotifications !== "function") {
|
||||
logger.warn(
|
||||
"[NativeNotificationService] scheduleNotifications not available on plugin; cannot apply timestamps",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await plugin.scheduleNotifications({ timestamps });
|
||||
} catch (err) {
|
||||
logger.error("[NativeNotificationService] Refresh failed", err);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user