feat: add tomorrow weather brief notifications

This commit is contained in:
zv
2026-06-12 22:10:22 +02:00
parent 3309e03acb
commit 7c3706c3f6
15 changed files with 414 additions and 15 deletions

View File

@@ -69,10 +69,12 @@ export function SettingsPage() {
const selectedLocation = useWeatherStore((state) => state.selectedLocation);
const notificationsEnabled = useWeatherStore((state) => state.warningNotificationsEnabled);
const morningBriefEnabled = useWeatherStore((state) => state.morningBriefNotificationsEnabled);
const tomorrowBriefEnabled = useWeatherStore((state) => state.tomorrowBriefNotificationsEnabled);
const provinceMode = useWeatherStore((state) => state.warningNotificationProvinceMode);
const manualProvince = useWeatherStore((state) => state.warningNotificationProvince);
const setNotificationsEnabled = useWeatherStore((state) => state.setWarningNotificationsEnabled);
const setMorningBriefEnabled = useWeatherStore((state) => state.setMorningBriefNotificationsEnabled);
const setTomorrowBriefEnabled = useWeatherStore((state) => state.setTomorrowBriefNotificationsEnabled);
const setProvinceMode = useWeatherStore((state) => state.setWarningNotificationProvinceMode);
const setManualProvince = useWeatherStore((state) => state.setWarningNotificationProvince);
@@ -119,6 +121,7 @@ export function SettingsPage() {
if (!subscription || cancelled) return;
await savePushSubscription(subscription, province, language, {
morningBriefEnabled,
tomorrowBriefEnabled,
latitude: notificationLatitude,
longitude: notificationLongitude,
locationName: notificationLocationName,
@@ -130,7 +133,7 @@ export function SettingsPage() {
return () => {
cancelled = true;
};
}, [effectiveProvince, language, morningBriefEnabled, notificationCountyTeryt, notificationLatitude, notificationLocationName, notificationLongitude, notificationStatus, notificationsEnabled, vapidPublicKey]);
}, [effectiveProvince, language, morningBriefEnabled, notificationCountyTeryt, notificationLatitude, notificationLocationName, notificationLongitude, notificationStatus, notificationsEnabled, tomorrowBriefEnabled, vapidPublicKey]);
const notificationStatusLabel = useMemo(() => {
switch (notificationStatus) {
@@ -184,6 +187,7 @@ export function SettingsPage() {
});
await savePushSubscription(subscription, effectiveProvince, language, {
morningBriefEnabled,
tomorrowBriefEnabled,
latitude: notificationLatitude,
longitude: notificationLongitude,
locationName: notificationLocationName,
@@ -211,6 +215,7 @@ export function SettingsPage() {
}
setNotificationsEnabled(false);
setMorningBriefEnabled(false);
setTomorrowBriefEnabled(false);
setNotificationMessage(t("settings.notifications.disableSuccess"));
} catch {
setNotificationMessage(t("settings.notifications.saveError"));
@@ -244,6 +249,27 @@ export function SettingsPage() {
if (!subscription) return;
await savePushSubscription(subscription, effectiveProvince, language, {
morningBriefEnabled: enabled,
tomorrowBriefEnabled,
latitude: notificationLatitude,
longitude: notificationLongitude,
locationName: notificationLocationName,
countyTeryt: notificationCountyTeryt,
});
} catch {
setNotificationMessage(t("settings.notifications.saveError"));
}
}
async function updateTomorrowBriefPreference(enabled: boolean) {
setTomorrowBriefEnabled(enabled);
if (!notificationsEnabled || !effectiveProvince || notificationStatus !== "granted") return;
try {
const registration = await navigator.serviceWorker?.getRegistration();
const subscription = await registration?.pushManager.getSubscription();
if (!subscription) return;
await savePushSubscription(subscription, effectiveProvince, language, {
morningBriefEnabled,
tomorrowBriefEnabled: enabled,
latitude: notificationLatitude,
longitude: notificationLongitude,
locationName: notificationLocationName,
@@ -368,6 +394,23 @@ export function SettingsPage() {
</span>
</label>
<label className="mt-3 flex items-start gap-3 rounded-card border border-border/60 bg-surface px-3 py-3 text-sm">
<input
type="checkbox"
checked={tomorrowBriefEnabled}
disabled={!notificationsEnabled}
onChange={(event) => updateTomorrowBriefPreference(event.target.checked)}
className="mt-1 accent-accent"
/>
<span>
<span className="flex items-center gap-2 font-medium">
<Clock3 className="size-3.5 text-accent" aria-hidden="true" />
{t("settings.notifications.tomorrowBrief")}
</span>
<span className="mt-0.5 block text-xs leading-5 text-muted">{t("settings.notifications.tomorrowBriefDescription")}</span>
</span>
</label>
<div className="mt-4 flex flex-col gap-2 sm:flex-row">
<Button type="button" disabled={(!notificationsEnabled && !canUsePush) || isSavingSubscription} onClick={notificationsEnabled ? disableWarningNotifications : enableWarningNotifications}>
<Bell className="size-4" />