Design/network status banner - #1359
Closed
stephaniepez21-art wants to merge 4 commits into
Closed
Conversation
Adds the app-wide NetworkStatusBanner rendered in src/components/Layout.tsx, backed by the new src/lib/networkStatus.ts singleton + src/hooks/useNetworkStatus.ts state machine, that surfaces five states (online-nominal [hidden], slow, offline, reconnecting, reconnected-confirmation). Slow is derived from latency windows reported by useTransactionStatus; offline from navigator.onLine and RPC errors. The reconnecting -> reconnected-confirmation -> dismiss flow uses a 4 s confirmation pill. Layout placement is above <main> and never intercepts the existing skip-link. Per-state aria-live levels (polite for slow/reconnecting/reconnected; assertive for offline) and >= 4.5:1 contrast verified in both themes. CreateStreamModal reads isAtRisk and adds data-at-risk + a label suffix while offline/reconnecting. Spec: docs/NETWORK_STATUS_BANNER_SPEC.md.
PR_DESCRIPTION.md at the repo root is a generic / stale file unrelated to this task and not needed for the implementation here; the analogous per-task record already lives at docs/NETWORK_STATUS_BANNER_SPEC.md and on the GitHub PR description for Fluxora-Org#1044 (closes Fluxora-Org#1044).
|
@stephaniepez21-art Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1044
What this PR does
Adds an app-wide
<NetworkStatusBanner />mounted insrc/components/Layout.tsxthat surfaces Soroban RPC + browser-network health across every/apppage. The banner surfaces five states:aria-liveonline-nominalslowpoliteofflineassertivenavigator.onLine === falseOR last error is atimeout.reconnectingpolitereconnected-confirmationpoliteIn-flight actions get a
data-at-risk="true"attribute plus a "network is unstable — submission may not complete" label suffix so users (and screen-readers) know a submission may not complete while connectivity is degraded.State machine
Surface
New files
docs/NETWORK_STATUS_BANNER_SPEC.md— design spec, transition diagram, contrast redlines, accessibility annotations, PR hand-off checklist.src/lib/networkStatus.ts— module-level singleton store (mirrors theofflineActionQueuepattern) whereuseTransactionStatuspublishes latency + errors and any subscriber (the hook) consumes them.src/hooks/useNetworkStatus.ts— React hook + state machine. StrictMode-safe (no refs that would survive React 18 double-mount); deterministic timers (1.5 s chip → 4 s pill → dismiss).src/components/NetworkStatusBanner.tsx+.css— presentational banner witharia-livesemantics per state + responsive reflow to a 36 px pill below--breakpoint-sm(640 px).src/hooks/__tests__/useNetworkStatus.test.ts— per-transition state-machine tests (8 transitions).src/components/__tests__/NetworkStatusBanner.test.tsx— render chrome per state (5 tests).src/components/__tests__/NetworkStatusBanner.contrast.test.tsx— WCAG ≥ 4.5 : 1 contrast across both themes (9 tests).src/components/__tests__/NetworkStatusBanner.layout.test.tsx—Layoutmount + skip-link safety (3 tests).Modified files
src/components/Layout.tsx— mounts<NetworkStatusBanner />above<main>so the existing#main-contentskip-link target still bypasses it.src/components/Layout.css— banner host slot + responsive rule at--breakpoint-sm.src/hooks/useTransactionStatus.ts— callsreportRpcSuccess(latency)/reportRpcFailure(latency, category)for every poll result.src/components/CreateStreamModal.tsx— readsuseNetworkStatus().isAtRisk, appliesdata-at-risk="true"+ an at-risk label suffix to both the single-stream submit AND the bulk dry-run submit.src/i18n/en.ts—network.banner.*strings +createStream.atRisk.networkSuffix.Evidence
pnpm exec tsc --noEmit -p .— clean for the new files (pre-existing errors inConnectWalletModal.test.tsxare unrelated to this PR).pnpm exec vitest run src/hooks/__tests__/useNetworkStatus.test.ts src/components/__tests__/NetworkStatusBanner.*.test.tsx— 27 / 27 passing.NetworkStatusBanner.contrast.test.tsx).Layoutbypasses the banner — clickingSkip to main contentfocuses<main>directly (asserted inNetworkStatusBanner.layout.test.tsx).forced-colors: active(Windows High Contrast) fallback path covered inNetworkStatusBanner.css.Redlines / screenshots
To attach before merge: light + dark theme captures of
slow,offline,reconnecting, and thereconnected-confirmationpill, plus a 640 px breakpoint compact variant. Placeholder slots below for the upload.slow: attachoffline: attachreconnecting: attachreconnected-confirmationpill: attachslow: attachoffline: attachreconnecting: attachreconnected-confirmationpill: attachOut of scope (follow-ups)
data-toneattribute is rendered for designer audit but not consumed by any CSS rule — review whether to migrate one selector or drop the attribute.NetworkStatusBanner.contrast.test.tsxuses hardcoded hex proxies; resolving live--color-info-bg/--color-warning-bg/--color-danger-bg/--color-success-bgviagetComputedStyle(document.documentElement)would catch future recolours (≈ 20-line jsdom polyfill insrc/test/setup.ts).e2e/Playwright spec yet —e2e/wallet-disconnect-reconnect.spec.tsis the natural home for the offline → banner → online → pill → dismiss flow.useTransactionStatus.tsdoes not currently report observations onAbortErrorcleanup; minor honest-fail opportunity.dismissPilluseCallbackdeps are[props]; ESLint-friendly edit would tighten to[props.onDismissPill].Reviewer checklist
docs/NETWORK_STATUS_BANNER_SPEC.md).useNetworkStatus.ts(5 states, deterministic timers).--breakpoint-sm(640 px).aria-livesemantics per state (assertiveforoffline,politefor the rest).Layout.tsxabove<main>.useTransactionStatus.tsreports lateness / error to the singleton store.CreateStreamModal.tsxshows at-risk marker on single-stream AND bulk-dry-run submit.aria-liveonly.forced-colors: activefallback path is honoured.How to test locally
Then run
pnpm dev, navigate to/app, open DevTools → Application → Service Workers → toggleOffline, and observe the banner appear; flip back to online and observe the chip → pill → dismiss flow.Related
docs/NETWORK_STATUS_BANNER_SPEC.md §11.