From 366aaadb016a1bbc9dd2276fb737fd56db7f725d Mon Sep 17 00:00:00 2001 From: openhands Date: Wed, 24 Jun 2026 16:18:29 +0100 Subject: [PATCH 1/2] feat: resolve issues #725, #727, #728, #731 - #725: Add vault-critical skeleton components (SharePriceSkeleton, VaultStatSkeleton, TransactionRowSkeleton, PortfolioCardSkeleton, AnalyticsWidgetSkeleton) for deterministic loading placeholders - #727: Add wallet session heartbeat via useWalletHeartbeat hook and WalletSessionIndicator component with contextual reconnect suggestions - #728: Add useSharableViewState hook for deterministic query state serialization into stable URL params for fully shareable dashboard deep links - #731: Add useNetworkQuality hook for latency measurement, useAdaptivePolling for adaptive cadence based on network quality, and HighLatencyBanner component for visual treatment when network degrades --- frontend/src/components/HighLatencyBanner.tsx | 73 ++++++++ frontend/src/components/Skeleton.tsx | 80 +++++++++ frontend/src/components/WalletConnect.tsx | 2 + .../src/components/WalletSessionIndicator.tsx | 156 ++++++++++++++++ frontend/src/components/icons.ts | 3 + frontend/src/hooks/useAdaptivePolling.ts | 59 ++++++ frontend/src/hooks/useNetworkQuality.ts | 118 ++++++++++++ frontend/src/hooks/useSharableViewState.ts | 169 ++++++++++++++++++ frontend/src/hooks/useWalletHeartbeat.ts | 93 ++++++++++ frontend/src/i18n/locales/en.ts | 11 ++ frontend/src/i18n/locales/es.ts | 11 ++ 11 files changed, 775 insertions(+) create mode 100644 frontend/src/components/HighLatencyBanner.tsx create mode 100644 frontend/src/components/WalletSessionIndicator.tsx create mode 100644 frontend/src/hooks/useAdaptivePolling.ts create mode 100644 frontend/src/hooks/useNetworkQuality.ts create mode 100644 frontend/src/hooks/useSharableViewState.ts create mode 100644 frontend/src/hooks/useWalletHeartbeat.ts diff --git a/frontend/src/components/HighLatencyBanner.tsx b/frontend/src/components/HighLatencyBanner.tsx new file mode 100644 index 00000000..0fdeab54 --- /dev/null +++ b/frontend/src/components/HighLatencyBanner.tsx @@ -0,0 +1,73 @@ +import React, { useState } from "react"; +import { useNetworkQuality, type NetworkQuality } from "../hooks/useNetworkQuality"; +import { AlertTriangle, Clock, Wifi, X } from "./icons"; + +const CONFIG: Record = { + fast: { color: "#22c55e", bg: "rgba(34, 197, 94, 0.1)", label: "Fast network", icon: }, + normal: { color: "var(--text-secondary)", bg: "transparent", label: "Normal network", icon: }, + slow: { + color: "#eab308", + bg: "rgba(234, 179, 8, 0.1)", + label: "Slow network — reduced refresh rate", + icon: , + }, + degraded: { + color: "#ef4444", + bg: "rgba(239, 68, 68, 0.1)", + label: "Degraded network — data may be stale", + icon: , + }, +}; + +const HighLatencyBanner: React.FC = () => { + const { quality, latencyMs, jitterMs } = useNetworkQuality(); + const [dismissed, setDismissed] = useState(false); + + if (quality === "fast" || quality === "normal" || dismissed) return null; + + const cfg = CONFIG[quality]; + + return ( +
+ {cfg.icon} + + {cfg.label} + + ({latencyMs}ms{quality === "degraded" ? `, jitter ${jitterMs}ms` : ""}) + + + +
+ ); +}; + +export default HighLatencyBanner; diff --git a/frontend/src/components/Skeleton.tsx b/frontend/src/components/Skeleton.tsx index 7c2a31c7..ae5cf1c0 100644 --- a/frontend/src/components/Skeleton.tsx +++ b/frontend/src/components/Skeleton.tsx @@ -165,5 +165,85 @@ export const ChartSkeleton: React.FC = () => { ); }; +export const SharePriceSkeleton: React.FC = () => ( + +); + +export const VaultStatSkeleton: React.FC = () => ( + +); + +export const TransactionRowSkeleton: React.FC = () => ( + +); + +export const PortfolioCardSkeleton: React.FC = () => ( +