"use client"; import { useEffect, useMemo, useRef, useState } from "react"; import { useConvexConnectionState } from "convex/react"; import { cn } from "@/lib/utils"; type BannerState = "hidden" | "reconnecting" | "disconnected" | "reconnected"; const RECONNECTED_HIDE_DELAY_MS = 1800; export default function ConnectionBanner() { const connectionState = useConvexConnectionState(); const previousConnectedRef = useRef(connectionState.isWebSocketConnected); const [showReconnected, setShowReconnected] = useState(false); const [isBrowserOnline, setIsBrowserOnline] = useState( typeof navigator === "undefined" ? true : navigator.onLine, ); useEffect(() => { const handleOnline = () => setIsBrowserOnline(true); const handleOffline = () => setIsBrowserOnline(false); window.addEventListener("online", handleOnline); window.addEventListener("offline", handleOffline); return () => { window.removeEventListener("online", handleOnline); window.removeEventListener("offline", handleOffline); }; }, []); useEffect(() => { const wasConnected = previousConnectedRef.current; const isConnected = connectionState.isWebSocketConnected; const didReconnect = !wasConnected && isConnected && connectionState.connectionCount > 1; if (didReconnect) { setShowReconnected(true); } if (!isConnected) { setShowReconnected(false); } previousConnectedRef.current = isConnected; }, [connectionState.connectionCount, connectionState.isWebSocketConnected]); useEffect(() => { if (!showReconnected) { return; } const timeoutId = window.setTimeout(() => { setShowReconnected(false); }, RECONNECTED_HIDE_DELAY_MS); return () => window.clearTimeout(timeoutId); }, [showReconnected]); const bannerState = useMemo(() => { if (connectionState.isWebSocketConnected) { return showReconnected ? "reconnected" : "hidden"; } if (!isBrowserOnline) { return "disconnected"; } if (connectionState.hasEverConnected || connectionState.connectionRetries > 0) { return "reconnecting"; } return "hidden"; }, [ connectionState.connectionRetries, connectionState.hasEverConnected, connectionState.isWebSocketConnected, isBrowserOnline, showReconnected, ]); if (bannerState === "hidden") { return null; } const contentByState: Record, { dotClass: string; text: string }> = { reconnecting: { dotClass: "bg-amber-500", text: "Verbindung wird wiederhergestellt…", }, disconnected: { dotClass: "bg-destructive", text: "Keine Verbindung. Wir verbinden uns automatisch erneut.", }, reconnected: { dotClass: "bg-emerald-500", text: "Verbindung wiederhergestellt", }, }; const content = contentByState[bannerState]; return (
); }