fix: show offline status in pwa
All checks were successful
CI / Lint, test, typecheck and build (push) Successful in 11m21s

This commit is contained in:
zv
2026-07-04 20:53:13 +02:00
parent 6bec7060e0
commit 2c2515abba
3 changed files with 26 additions and 1 deletions

View File

@@ -2,7 +2,8 @@
import Link from "next/link"; import Link from "next/link";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
import { CloudSun, Droplets, Settings, TriangleAlert } from "lucide-react"; import { useEffect, useState } from "react";
import { CloudSun, Droplets, Settings, TriangleAlert, WifiOff } from "lucide-react";
import type { LucideIcon } from "lucide-react"; import type { LucideIcon } from "lucide-react";
import { isAppNavItemVisible } from "@/lib/app-sections"; import { isAppNavItemVisible } from "@/lib/app-sections";
import { NAV_ITEMS } from "@/lib/constants"; import { NAV_ITEMS } from "@/lib/constants";
@@ -23,6 +24,18 @@ export function AppShell({ children }: { children: React.ReactNode }) {
const { t } = useI18n(); const { t } = useI18n();
const appSections = useWeatherStore((state) => state.appSections); const appSections = useWeatherStore((state) => state.appSections);
const visibleNavItems = NAV_ITEMS.filter((item) => isAppNavItemVisible(item.href, appSections)); const visibleNavItems = NAV_ITEMS.filter((item) => isAppNavItemVisible(item.href, appSections));
const [isOffline, setIsOffline] = useState(false);
useEffect(() => {
const updateConnectionStatus = () => setIsOffline(!navigator.onLine);
updateConnectionStatus();
window.addEventListener("online", updateConnectionStatus);
window.addEventListener("offline", updateConnectionStatus);
return () => {
window.removeEventListener("online", updateConnectionStatus);
window.removeEventListener("offline", updateConnectionStatus);
};
}, []);
return ( return (
<div className="min-h-screen overflow-x-hidden bg-background"> <div className="min-h-screen overflow-x-hidden bg-background">
@@ -56,6 +69,14 @@ export function AppShell({ children }: { children: React.ReactNode }) {
</div> </div>
</div> </div>
</header> </header>
{isOffline && (
<div className="border-b border-warning/25 bg-warning/10 px-4 py-2 text-sm font-medium text-warning sm:px-6 lg:px-8">
<div className="mx-auto flex max-w-7xl items-center gap-2">
<WifiOff className="size-4 shrink-0" aria-hidden="true" />
<span>{t("offline.banner")}</span>
</div>
</div>
)}
<main className="app-main-safe mx-auto max-w-7xl px-4 pt-5 sm:px-6 sm:pt-8 lg:px-8">{children}</main> <main className="app-main-safe mx-auto max-w-7xl px-4 pt-5 sm:px-6 sm:pt-8 lg:px-8">{children}</main>
<nav <nav
aria-label={t("nav.mobile")} aria-label={t("nav.mobile")}

View File

@@ -327,6 +327,7 @@ const translations = {
"offline.description": "offline.description":
"wtr. nie może teraz pobrać aktualnych danych IMGW. Ostatnio odwiedzone widoki mogą być dostępne z pamięci urządzenia.", "wtr. nie może teraz pobrać aktualnych danych IMGW. Ostatnio odwiedzone widoki mogą być dostępne z pamięci urządzenia.",
"offline.back": "Wróć do aplikacji", "offline.back": "Wróć do aplikacji",
"offline.banner": "Brak połączenia · dane mogą być nieaktualne",
}, },
en: { en: {
"nav.weather": "Weather", "nav.weather": "Weather",
@@ -647,6 +648,7 @@ const translations = {
"offline.description": "offline.description":
"wtr. cannot fetch current IMGW data right now. Recently visited views may still be available from your device cache.", "wtr. cannot fetch current IMGW data right now. Recently visited views may still be available from your device cache.",
"offline.back": "Back to the app", "offline.back": "Back to the app",
"offline.banner": "Offline · data may be out of date",
}, },
} as const; } as const;

View File

@@ -7,6 +7,8 @@ const ACTIVE_CACHES = new Set([SHELL_CACHE, RUNTIME_CACHE, API_CACHE]);
const SHELL = [ const SHELL = [
"/", "/",
"/warnings",
"/hydro",
"/settings", "/settings",
"/offline", "/offline",
"/manifest.json", "/manifest.json",