fix: preserve brief notification preferences
All checks were successful
CI / Lint, test, typecheck and build (push) Successful in 10m45s
All checks were successful
CI / Lint, test, typecheck and build (push) Successful in 10m45s
This commit is contained in:
@@ -54,12 +54,24 @@ export async function GET(request: Request) {
|
||||
|
||||
const now = new Date();
|
||||
const briefTime = normalizeTime(process.env.NOTIFICATIONS_MORNING_BRIEF_TIME, DEFAULT_MORNING_BRIEF_TIME);
|
||||
const subscriptions = getPushSubscriptions().filter(
|
||||
const allSubscriptions = getPushSubscriptions();
|
||||
const subscriptions = allSubscriptions.filter(
|
||||
(subscription) =>
|
||||
subscription.morningBriefEnabled &&
|
||||
Number.isFinite(subscription.latitude) &&
|
||||
Number.isFinite(subscription.longitude),
|
||||
);
|
||||
const skippedReasons = {
|
||||
disabled: allSubscriptions.filter((subscription) => !subscription.morningBriefEnabled).length,
|
||||
missingLocation: allSubscriptions.filter(
|
||||
(subscription) =>
|
||||
subscription.morningBriefEnabled &&
|
||||
(!Number.isFinite(subscription.latitude) || !Number.isFinite(subscription.longitude)),
|
||||
).length,
|
||||
beforeTime: 0,
|
||||
alreadySent: 0,
|
||||
noBrief: 0,
|
||||
};
|
||||
let warningsUnavailable = false;
|
||||
const hasPolishSubscriptions = subscriptions.some((subscription) => subscription.region === "PL");
|
||||
const warnings = hasPolishSubscriptions
|
||||
@@ -76,11 +88,13 @@ export async function GET(request: Request) {
|
||||
const localTime = getLocalDateParts(subscription.timezone, now);
|
||||
if (localTime.time < briefTime) {
|
||||
skipped += 1;
|
||||
skippedReasons.beforeTime += 1;
|
||||
continue;
|
||||
}
|
||||
const dateKey = localTime.dateKey;
|
||||
if (hasSentMorningBrief(subscription.endpoint, dateKey)) {
|
||||
skipped += 1;
|
||||
skippedReasons.alreadySent += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -103,6 +117,7 @@ export async function GET(request: Request) {
|
||||
});
|
||||
if (!brief) {
|
||||
skipped += 1;
|
||||
skippedReasons.noBrief += 1;
|
||||
continue;
|
||||
}
|
||||
await sendMorningBriefNotification(subscription, brief);
|
||||
@@ -119,10 +134,12 @@ export async function GET(request: Request) {
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
time: briefTime,
|
||||
subscriptions: subscriptions.length,
|
||||
subscriptions: allSubscriptions.length,
|
||||
eligibleSubscriptions: subscriptions.length,
|
||||
warningsUnavailable,
|
||||
sent,
|
||||
skipped,
|
||||
skippedReasons,
|
||||
failed,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -66,12 +66,24 @@ export async function GET(request: Request) {
|
||||
|
||||
const now = new Date();
|
||||
const briefTime = normalizeTime(process.env.NOTIFICATIONS_TOMORROW_BRIEF_TIME, DEFAULT_TOMORROW_BRIEF_TIME);
|
||||
const subscriptions = getPushSubscriptions().filter(
|
||||
const allSubscriptions = getPushSubscriptions();
|
||||
const subscriptions = allSubscriptions.filter(
|
||||
(subscription) =>
|
||||
subscription.tomorrowBriefEnabled &&
|
||||
Number.isFinite(subscription.latitude) &&
|
||||
Number.isFinite(subscription.longitude),
|
||||
);
|
||||
const skippedReasons = {
|
||||
disabled: allSubscriptions.filter((subscription) => !subscription.tomorrowBriefEnabled).length,
|
||||
missingLocation: allSubscriptions.filter(
|
||||
(subscription) =>
|
||||
subscription.tomorrowBriefEnabled &&
|
||||
(!Number.isFinite(subscription.latitude) || !Number.isFinite(subscription.longitude)),
|
||||
).length,
|
||||
beforeTime: 0,
|
||||
alreadySent: 0,
|
||||
noBrief: 0,
|
||||
};
|
||||
let warningsUnavailable = false;
|
||||
const hasPolishSubscriptions = subscriptions.some((subscription) => subscription.region === "PL");
|
||||
const warnings = hasPolishSubscriptions
|
||||
@@ -88,11 +100,13 @@ export async function GET(request: Request) {
|
||||
const localToday = getLocalDateParts(subscription.timezone, now);
|
||||
if (localToday.time < briefTime) {
|
||||
skipped += 1;
|
||||
skippedReasons.beforeTime += 1;
|
||||
continue;
|
||||
}
|
||||
const targetDateKey = getLocalDateParts(subscription.timezone, now, 1).dateKey;
|
||||
if (hasSentTomorrowBrief(subscription.endpoint, targetDateKey)) {
|
||||
skipped += 1;
|
||||
skippedReasons.alreadySent += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -115,6 +129,7 @@ export async function GET(request: Request) {
|
||||
});
|
||||
if (!brief) {
|
||||
skipped += 1;
|
||||
skippedReasons.noBrief += 1;
|
||||
continue;
|
||||
}
|
||||
await sendTomorrowBriefNotification(subscription, brief);
|
||||
@@ -131,10 +146,12 @@ export async function GET(request: Request) {
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
time: briefTime,
|
||||
subscriptions: subscriptions.length,
|
||||
subscriptions: allSubscriptions.length,
|
||||
eligibleSubscriptions: subscriptions.length,
|
||||
warningsUnavailable,
|
||||
sent,
|
||||
skipped,
|
||||
skippedReasons,
|
||||
failed,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -428,14 +428,15 @@ export function SettingsPage() {
|
||||
setMorningBriefEnabled(enabled);
|
||||
if (!notificationsEnabled || !canUsePush || notificationStatus !== "granted") return;
|
||||
try {
|
||||
const preferences = useWeatherStore.getState();
|
||||
const registration = await navigator.serviceWorker?.getRegistration();
|
||||
const subscription = await registration?.pushManager.getSubscription();
|
||||
if (!subscription) return;
|
||||
await savePushSubscription(subscription, effectiveProvince, language, {
|
||||
region: selectedRegion,
|
||||
officialWarningsEnabled: canUseOfficialWarnings && notificationsEnabled,
|
||||
morningBriefEnabled: enabled,
|
||||
tomorrowBriefEnabled,
|
||||
morningBriefEnabled: preferences.morningBriefNotificationsEnabled,
|
||||
tomorrowBriefEnabled: preferences.tomorrowBriefNotificationsEnabled,
|
||||
latitude: notificationLatitude,
|
||||
longitude: notificationLongitude,
|
||||
locationName: notificationLocationName,
|
||||
@@ -453,14 +454,15 @@ export function SettingsPage() {
|
||||
setTomorrowBriefEnabled(enabled);
|
||||
if (!notificationsEnabled || !canUsePush || notificationStatus !== "granted") return;
|
||||
try {
|
||||
const preferences = useWeatherStore.getState();
|
||||
const registration = await navigator.serviceWorker?.getRegistration();
|
||||
const subscription = await registration?.pushManager.getSubscription();
|
||||
if (!subscription) return;
|
||||
await savePushSubscription(subscription, effectiveProvince, language, {
|
||||
region: selectedRegion,
|
||||
officialWarningsEnabled: canUseOfficialWarnings && notificationsEnabled,
|
||||
morningBriefEnabled,
|
||||
tomorrowBriefEnabled: enabled,
|
||||
morningBriefEnabled: preferences.morningBriefNotificationsEnabled,
|
||||
tomorrowBriefEnabled: preferences.tomorrowBriefNotificationsEnabled,
|
||||
latitude: notificationLatitude,
|
||||
longitude: notificationLongitude,
|
||||
locationName: notificationLocationName,
|
||||
|
||||
@@ -102,6 +102,15 @@ Worker:
|
||||
|
||||
Endpointy harmonogramu nie uruchamiają się same bez workera albo zewnętrznego crona.
|
||||
|
||||
Endpointy briefów zwracają diagnostykę JSON z polami `subscriptions`, `eligibleSubscriptions`, `sent`, `skipped`,
|
||||
`failed` oraz `skippedReasons`. Dla problemów z harmonogramem najważniejsze powody to:
|
||||
|
||||
- `disabled` - subskrypcja istnieje, ale dany brief nie jest włączony w zapisanym stanie serwera,
|
||||
- `missingLocation` - brief jest włączony, ale subskrypcja nie ma współrzędnych,
|
||||
- `beforeTime` - lokalny czas subskrypcji jest jeszcze przed skonfigurowaną godziną,
|
||||
- `alreadySent` - brief dla tej lokalnej daty został już oznaczony jako wysłany,
|
||||
- `noBrief` - prognoza nie pozwoliła zbudować treści briefu.
|
||||
|
||||
## Zewnętrzny Cron
|
||||
|
||||
Jeśli nie używasz `npm run notifications:worker`, zewnętrzny cron powinien wywoływać:
|
||||
|
||||
Reference in New Issue
Block a user