import { Button } from "@/shared/components/ui/button" import { Card, CardContent } from "@/shared/components/ui/card" import { Switch } from "@/shared/components/ui/switch" import { useDb } from "@/shared/db/provider" import { useDeviceId } from "@/shared/hooks/use-device-id" import { useFollows } from "@/shared/hooks/use-follows" import { usePush } from "@/shared/hooks/use-push" import { usePwaUpdate } from "@/shared/hooks/use-pwa-update" import { fetchTopics } from "@/shared/lib/aw-api" import { APP_VERSION, BACKEND_URL, STORAGE_KEYS, VAPID_PUBLIC_KEY, } from "@/shared/lib/constants" import { useCallback, useEffect, useState } from "react" import { type GeoResult, clearGeoCache, detectFromCoords, loadCachedResult, } from "../../location/lib/geo" import { NotificationGuide } from "./notification-guide" function isStandalone(): boolean { if (typeof window === "undefined") return false return ( window.matchMedia("(display-mode: standalone)").matches || ("standalone" in navigator && (navigator as { standalone?: boolean }).standalone === true) ) } export function SettingsPage() { const db = useDb() const deviceId = useDeviceId() const { needRefresh, checkForUpdate, applyUpdate } = usePwaUpdate() const push = usePush() const { follow, unfollowAllTopics, unfollowAllPoliticians } = useFollows() const [checking, setChecking] = useState(false) const [loading, setLoading] = useState(false) const [result, setResult] = useState(null) const [errorMsg, setErrorMsg] = useState(null) const [showGuide, setShowGuide] = useState(false) const [devHealth, setDevHealth] = useState(null) const [devPush, setDevPush] = useState(null) const [devTopics, setDevTopics] = useState(null) const [devPoliticians, setDevPoliticians] = useState(null) const [devUnfollowTopics, setDevUnfollowTopics] = useState( null, ) const [devUnfollowPoliticians, setDevUnfollowPoliticians] = useState< string | null >(null) const [devReload, setDevReload] = useState(null) const [devMode, setDevMode] = useState( () => localStorage.getItem(STORAGE_KEYS.devMode) === "true", ) useEffect(() => { loadCachedResult(db).then((cached) => { if (cached) setResult(cached) }) }, [db]) const detect = useCallback( (skipCache: boolean) => { if (!navigator.geolocation) { setErrorMsg("Standortbestimmung wird nicht unterstützt") return } setLoading(true) setErrorMsg(null) navigator.geolocation.getCurrentPosition( async (pos) => { try { const r = await detectFromCoords( db, pos.coords.latitude, pos.coords.longitude, skipCache, ) setResult(r) } catch (e) { setErrorMsg(String(e)) } finally { setLoading(false) } }, (err) => { setErrorMsg(err.message) setLoading(false) }, ) }, [db], ) function handleClearCache() { clearGeoCache(db) setResult(null) } async function handleCheckUpdate() { setChecking(true) try { await checkForUpdate() } finally { setChecking(false) } } const hasLocation = result && result.mandates.length > 0 const standalone = isStandalone() if (showGuide) { return setShowGuide(false)} /> } return (
{/* --- Permissions: Push + Location --- */}

Berechtigungen

{VAPID_PUBLIC_KEY && (push.permission === "denied" ? (
Push blockiert — bitte in den Systemeinstellungen aktivieren.
) : (
Push-Benachrichtigungen { if (push.subscribed) push.unsubscribe() else push.subscribe() }} />
))}
Standort {loading && ( {hasLocation ? "Aktualisiere…" : "Erkenne…"} )}
{ if (checked) detect(false) else handleClearCache() }} />
{errorMsg && (
{errorMsg}
)} {!standalone && ( )}
{/* --- Info --- */}

Info

Version
{APP_VERSION} {needRefresh ? ( ) : ( )}
Geräte-ID {deviceId}
Entwicklermodus { setDevMode(checked) localStorage.setItem(STORAGE_KEYS.devMode, String(checked)) try { await fetch(`${BACKEND_URL}/legislation/seed-mock`, { method: checked ? "POST" : "DELETE", }) } catch { // best-effort } }} />
{/* --- Developer (visible only in dev mode) --- */} {devMode && (

Entwickler

Backend Health
{devHealth && ( {devHealth} )}
Test-Push
{devPush && ( {devPush} )}
Alle Themen folgen
{devTopics && ( {devTopics} )}
Allen Themen entfolgen
{devUnfollowTopics && ( {devUnfollowTopics} )}
Alle Abgeordnete folgen
{devPoliticians && ( {devPoliticians} )}
Allen Abgeordneten entfolgen
{devUnfollowPoliticians && ( {devUnfollowPoliticians} )}
Abgeordnete neu laden
{devReload && ( {devReload} )}
)}
) }