diff --git a/AGENTS.md b/AGENTS.md index a3bdb7c..872d929 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -45,7 +45,7 @@ Repozytorium nie ma obecnie skryptu testów, osobnego skryptu type-check ani for - Ostrzeżenia hydro zawierają jawne województwa, a ostrzeżenia meteo kody powiatów TERYT. Normalizuj oba warianty przez `lib/provinces.ts`; nie filtruj ostrzeżeń wyłącznie po opisach tekstowych. - Listy ostrzeżeń zachowują priorytet lokalnego województwa, a wewnątrz każdej grupy pokazują ostrzeżenia meteorologiczne przed hydrologicznymi. W obrębie rodzaju zachowuj kolejność publikacji od najnowszych. - Dashboard pokazuje kompaktowo wyłącznie aktywne i nadchodzące ostrzeżenia meteo dla wybranego województwa. Filtruj je po `validTo` względem czasu przeglądarki i automatycznie usuwaj wygasłe komunikaty bez przeładowania strony. -- Powiadomienia Web Push o ostrzeżeniach meteo konfiguruj przez `/settings`, `public/sw.js` i route handlery `app/api/notifications/*`, w tym testowy `/api/notifications/test`. Wymagają kluczy VAPID w zmiennych środowiskowych. Obecny `lib/push-store.ts` jest pamięciowy i przed produkcją musi zostać zastąpiony trwałym magazynem subskrypcji. +- Powiadomienia Web Push o ostrzeżeniach meteo konfiguruj przez `/settings`, `public/sw.js` i route handlery `app/api/notifications/*`, w tym testowy `/api/notifications/test`. Wymagają kluczy VAPID w zmiennych środowiskowych. iOS/iPadOS wymaga PWA z ekranu początkowego, ale Android i desktop nie powinny być blokowane wymogiem `standalone`. Obecny `lib/push-store.ts` jest pamięciowy i przed produkcją musi zostać zastąpiony trwałym magazynem subskrypcji. - GPS wymaga świadomej zgody użytkownika i HTTPS. Zaokrąglaj współrzędne przed użyciem i utrzymuj widoczną atrybucję OpenStreetMap dla reverse geocodingu Nominatim. - Normalizuj zewnętrzne odpowiedzi i obsługuj `null`, puste pola oraz błędne wartości. Brak danych pokazuj jawnie zamiast uzupełniać estymacją. - Dla pobierania danych używaj TanStack Query z sensownym `queryKey`, cache i retry. W UI zachowuj loading, error, retry oraz empty states. diff --git a/README.md b/README.md index 5f79f02..5359cac 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ public/ manifest, ikony i service worker Manifest znajduje się w `public/manifest.json`, a service worker w `public/sw.js`. Rejestracja service workera działa w buildzie produkcyjnym. Powłoka aplikacji ma podstawowy offline fallback. Odpowiedzi API mogą być dostępne z pamięci urządzenia przy braku sieci, ale UI nadal prezentuje czas pomiaru i status świeżości. -Widok `/settings` zawiera konfigurację powiadomień o ostrzeżeniach meteorologicznych IMGW: wybór województwa, zgodę Web Push, zapis subskrypcji urządzenia i wysłanie powiadomienia testowego. Na iOS powiadomienia webowe wymagają dodania PWA do ekranu początkowego i uruchomienia aplikacji z ikony. Endpoint `/api/notifications/check` sprawdza `warningsmeteo` i wysyła tylko nowe ostrzeżenia meteo do pasujących subskrypcji, a `/api/notifications/test` wysyła test na wskazany endpoint subskrypcji. Obecny magazyn subskrypcji działa w pamięci procesu, więc produkcja wymaga podmiany `lib/push-store.ts` na trwałą bazę lub KV. +Widok `/settings` zawiera konfigurację powiadomień o ostrzeżeniach meteorologicznych IMGW: wybór województwa, zgodę Web Push, zapis subskrypcji urządzenia i wysłanie powiadomienia testowego. Na iOS/iPadOS powiadomienia webowe wymagają dodania PWA do ekranu początkowego i uruchomienia aplikacji z ikony. Na Androidzie i desktopie wystarczy HTTPS oraz przeglądarka obsługująca Web Push; instalacja PWA nie jest wymagana. Endpoint `/api/notifications/check` sprawdza `warningsmeteo` i wysyła tylko nowe ostrzeżenia meteo do pasujących subskrypcji, a `/api/notifications/test` wysyła test na wskazany endpoint subskrypcji. Obecny magazyn subskrypcji działa w pamięci procesu, więc produkcja wymaga podmiany `lib/push-store.ts` na trwałą bazę lub KV. Do wysyłki Web Push wymagane są zmienne środowiskowe: diff --git a/components/settings/settings-page.tsx b/components/settings/settings-page.tsx index 95ecc4d..1a7407d 100644 --- a/components/settings/settings-page.tsx +++ b/components/settings/settings-page.tsx @@ -21,10 +21,18 @@ function isStandaloneApp() { return window.matchMedia("(display-mode: standalone)").matches || navigatorWithStandalone.standalone === true; } +function isAppleMobilePlatform() { + if (typeof window === "undefined") return false; + const userAgent = window.navigator.userAgent; + const platform = window.navigator.platform; + const isIPadOSDesktopMode = platform === "MacIntel" && window.navigator.maxTouchPoints > 1; + return /iPad|iPhone|iPod/.test(userAgent) || isIPadOSDesktopMode; +} + function getNotificationSupportStatus(): NotificationSupportStatus { if (typeof window === "undefined") return "checking"; if (!("Notification" in window) || !("serviceWorker" in navigator) || !("PushManager" in window)) return "unsupported"; - if (!isStandaloneApp()) return "needs-install"; + if (isAppleMobilePlatform() && !isStandaloneApp()) return "needs-install"; return Notification.permission; } diff --git a/lib/i18n.tsx b/lib/i18n.tsx index 4ca77ac..2724a59 100644 --- a/lib/i18n.tsx +++ b/lib/i18n.tsx @@ -53,7 +53,7 @@ const translations = { "settings.notifications.statusNeedsInstall": "Na iPhonie dodaj aplikację do ekranu początkowego przez Udostępnij → Dodaj do ekranu początkowego, a potem otwórz ją z ikony.", "settings.notifications.statusDenied": "Powiadomienia są zablokowane w ustawieniach systemu lub przeglądarki.", "settings.notifications.statusGranted": "To urządzenie ma zgodę na powiadomienia.", - "settings.notifications.statusReady": "Możesz poprosić system o zgodę na powiadomienia.", + "settings.notifications.statusReady": "Możesz poprosić system o zgodę na powiadomienia. Android i desktop działają bez instalowania PWA, jeśli przeglądarka obsługuje Web Push.", "settings.notifications.implementationNote": "Serwerowy sprawdzacz wysyła nowe ostrzeżenia meteo IMGW przez Web Push. W aktualnej wersji subskrypcje są przechowywane w pamięci procesu, więc produkcja wymaga podmiany magazynu na trwałą bazę lub KV.", "pwa.install": "Zainstaluj", "common.noData": "Brak danych", @@ -276,7 +276,7 @@ const translations = { "settings.notifications.statusNeedsInstall": "On iPhone, add the app to the Home Screen using Share → Add to Home Screen, then open it from the icon.", "settings.notifications.statusDenied": "Notifications are blocked in system or browser settings.", "settings.notifications.statusGranted": "This device has notification permission.", - "settings.notifications.statusReady": "You can ask the system for notification permission.", + "settings.notifications.statusReady": "You can ask the system for notification permission. Android and desktop work without installing the PWA when the browser supports Web Push.", "settings.notifications.implementationNote": "The server checker sends new IMGW meteorological warnings through Web Push. This version stores subscriptions in process memory, so production needs a durable database or KV store.", "pwa.install": "Install", "common.noData": "No data",