fix: show offline status in pwa
All checks were successful
CI / Lint, test, typecheck and build (push) Successful in 11m21s
All checks were successful
CI / Lint, test, typecheck and build (push) Successful in 11m21s
This commit is contained in:
@@ -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")}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
Reference in New Issue
Block a user