import React, { useCallback, useState } from 'react'; import { useAtomValue } from 'jotai'; import { Box, Button, config, Line, Text } from 'folds'; import { clockSkewAtom } from '../../state/clockSkew'; import { ContainerColor } from '../../styles/ContainerColor.css'; import { clockFixHint, describeSkewVsServer, detectClockFixPlatform } from '../../utils/clockSkew'; const DISMISS_KEY = 'lotus-clock-skew-dismissed-until'; const DISMISS_MS = 24 * 60 * 60 * 1000; const readDismissedUntil = (): number => { try { const raw = localStorage.getItem(DISMISS_KEY); const n = raw ? Number(raw) : 0; return Number.isFinite(n) ? n : 0; } catch { return 0; } }; /** * [Gitea #158] "Your computer's clock is 14 minutes ahead of the server." * Same slot and style as the sync banners. Shown while the skew monitor is * over its threshold; the direction matters, so it is said. Dismissable for * 24 h; never auto-corrects anything. */ export function ClockSkewBanner() { const { skewMs, warning } = useAtomValue(clockSkewAtom); const [dismissedUntil, setDismissedUntil] = useState(readDismissedUntil); const [showHint, setShowHint] = useState(false); const dismiss = useCallback(() => { const until = Date.now() + DISMISS_MS; try { localStorage.setItem(DISMISS_KEY, String(until)); } catch { // storage unavailable — dismiss for this session only } setDismissedUntil(until); }, []); if (!warning || skewMs === null || Date.now() < dismissedUntil) return null; return ( Your computer's clock is {describeSkewVsServer(skewMs)}. Encrypted messages and voice calls will fail until it is fixed. {showHint && ( {clockFixHint(detectClockFixPlatform(navigator.userAgent))} )} ); }