// Initial-sync progress UX (SPEC §12 M2). Shows a small floating card while any // account is importing its history; reads the accounts query, which the WS // `sync.progress` event invalidates so the bar advances live. import { useQuery } from "@tanstack/react-query"; import { useEffect, useState } from "react"; import { useT } from "../i18n"; import { api } from "../lib/api"; export function BackfillBanner() { const t = useT(); const accounts = useQuery({ queryKey: ["accounts"], queryFn: api.accounts }); const importing = (accounts.data ?? []).filter( // Show while backfilling — including the brief start window before the worker has // counted the total (total === 0). Hide only once done, so a completed account // whose state event was missed (e.g. a dropped WS) never leaves a stuck banner. (a) => a.state === "backfilling" && (a.backfill_total === 0 || a.backfill_done < a.backfill_total), ); const active = importing.length > 0; // Dissolve the card 10s after it appears; the sidebar ring keeps showing // progress until the sync finishes. const [dismissed, setDismissed] = useState(false); useEffect(() => { if (!active) { setDismissed(false); return; } const timer = window.setTimeout(() => setDismissed(true), 10000); return () => window.clearTimeout(timer); }, [active]); if (!active) return null; return (