Skip to content

Feat/420 421 422 423 send flow validation states success qr - #523

Merged
phertyameen merged 4 commits into
bridgelet-org:mainfrom
A6dulmalik:feat/420-421-422-423-send-flow-validation-states-success-qr
Aug 29, 2026
Merged

Feat/420 421 422 423 send flow validation states success qr#523
phertyameen merged 4 commits into
bridgelet-org:mainfrom
A6dulmalik:feat/420-421-422-423-send-flow-validation-states-success-qr

Conversation

@A6dulmalik

Copy link
Copy Markdown
Contributor

Summary

Four related send-flow issues, implemented in dependency order (validation → pending
states → success screen → QR code), one commit per issue.

#420 — Send form input validation for amount and destination

Extracted the existing Stellar-address regex from WalletAddressInput into a shared
lib/validation/stellar-address.ts. ConnectStep now rejects a malformed address
from Freighter or persisted storage. DetailsStep enforces a per-asset minimum
amount and blocks amounts above the wallet's actual balance (new
lib/wallet-balance.ts, Horizon lookup, fails open on lookup error). Errors also
validate on blur, not just on submit.

Note: this flow uses claim links rather than a manual destination-address field, so
validation targets the sender's connected wallet address (the actual Stellar address
the form collects) rather than a recipient-address input.

#421 — Send flow loading and pending transaction states

Added a distinct confirming phase separate from preparing/awaiting-Freighter/
submitting/success. A visible pending panel is shown throughout. The submit button
stays disabled for the entire window to prevent double-send. A non-blocking 15s
"taking longer than usual" notice appears if confirmation is slow — it does not
abort the transaction, since the payment may already have landed on-chain.

#422 — Send flow success screen with shareable claim link

The claim URL is now displayed prominently as a link, with one-click copy via the
previously-unused CopyToClipboard component, and an absolute expiration deadline
(prefers the server-provided expiresAt when available).

#423 — QR code generation for claim links

Found and fixed a real bug: the existing QRCode component's matrix was a
hash-scrambled fake — not a real QR encoding, and not actually scannable. Replaced
it with the qrcode package's real encoder plus a proper quiet zone. Added
round-trip decode tests using an independent decoder (jsqr) that confirm the
generated QR actually decodes back to the exact claim URL. Wired into the success
screen with accessible alt text and a downloadable image.

Also fixed (necessary prerequisite)

lib/create-bridgelet-client.ts had every template literal written with literally-
escaped backticks — a pre-existing syntax error that blocked the entire test suite
from compiling. Fixed as part of the first commit since no test could run without
it. Added the missing @testing-library/dom devDependency.

Tests/checks performed

  • npm test: 268 passing (was 0 before the prerequisite syntax fix, since the
    corrupted file blocked test collection entirely; 231 passing on a version of
    main with just that one file manually patched, for comparison — this branch
    adds ~55 new/updated tests on top of that).
  • 19 pre-existing failures remain across 7 files, confirmed present on main
    before any of these changes and unrelated to these issues (mock-shape mismatches
    in create-bridgelet-client.test.ts, next-config-headers.test.ts,
    how-it-works.test.tsx, keyboard-navigation.test.tsx).
  • tsc --noEmit and eslint clean on every file this PR touches.
  • Flagging for maintainers: 4 other pre-existing files repo-wide
    (auto-sweep-retry.tsx, education-tooltip.tsx, mobile-deep-link.tsx,
    multi-step-progress.tsx) have the same kind of backtick corruption — untouched
    here since they're unrelated to and not imported by anything these issues cover.

Closes #420
Closes #421
Closes #422
Closes #423

A6dulmalik and others added 4 commits August 28, 2026 18:02
… before submit

Adds client-side validation to the send form so bad input never reaches
the API (Issue bridgelet-org#420):

- Extracts the Stellar public-key regex that already existed in
  WalletAddressInput into a shared lib/validation/stellar-address.ts
  utility, and reuses it in ConnectStep (reject a malformed address
  returned by Freighter or restored from localStorage before it can
  become the funding/recovery address) and WalletAddressInput itself.
- DetailsStep now enforces a minimum send amount per asset and blocks
  amounts above the connected wallet's actual balance, looked up via a
  new lib/wallet-balance.ts (Horizon fetch, fails open/never blocks when
  the balance can't be determined).
- Field errors are now also validated on blur, not just on submit.

Also fixes a pre-existing, unrelated bug that was blocking this repo's
whole test suite from compiling: lib/create-bridgelet-client.ts had
every template literal written with literally-escaped backticks
(\` / \${) instead of real ones, a syntax error that made the file (and
everything importing it, including the send flow) fail to parse. Fixed
so `npm test` actually exercises the send flow's existing coverage, and
added the missing @testing-library/dom devDependency the test suite
needs.

Tests: lib/validation/stellar-address.test.ts,
lib/wallet-balance.test.ts, and new/updated coverage in
details-step.test.tsx and connect-step.test.tsx (53 tests, all passing).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds dedicated visual states for the gap between submitting a send
transaction and getting confirmation back (Issue bridgelet-org#421):

- New 'confirming' SubmitPhase, entered ~2.5s into a still-pending
  request, distinct from the initial 'preparing'/'awaiting-freighter'/
  'submitting' phases and from 'success'.
- A visible pending panel (role="status", spinner + phase label) is
  shown for the whole submitting/confirming window, replacing the
  previous "only the button label changes" feedback.
- The Confirm/Try Again button is already disabled for the entire
  pending window (submitPhase !== 'idle' && !== 'success'), so this
  also prevents double-submitting the same payment.
- Timeout handling: after 15s still waiting, a non-blocking "this is
  taking longer than usual" notice appears. It does not abort the
  request — the client already retries with backoff, and the payment
  may have already landed on-chain even if the HTTP response is slow,
  so cancelling client-side could desync the UI from reality.

Also adds the Issue bridgelet-org#420 defense-in-depth check to this same submit
handler: the funding/recovery address is validated with the shared
isValidStellarAddress() helper before the create-account request is
ever built, so a corrupted address can't reach the API from here either
(ConnectStep already blocks it earlier, in the previous commit).

Updates the pre-existing ConfirmStep test fixture's placeholder public
key (was 41 chars, not a valid Stellar address shape) to a valid one so
it isn't rejected by the new guard.

Tests: components/send-form/steps/confirm-step.test.tsx (new — pending
panel, button disabled while submitting, and the invalid-address
rejection), plus the existing 9 ConfirmStep error/signing tests
continue to pass unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
After a successful send, ConfirmStep's success view now surfaces the
claim link itself, not just a description of it (Issue bridgelet-org#422):

- The full claim URL is displayed prominently as a link, in a
  dedicated "Claim link" panel (previously the URL was only used
  internally for the WhatsApp/NFC share actions and never shown to the
  sender as readable/selectable text).
- A one-click copy-to-clipboard button next to it, using the existing
  (previously unused anywhere) CopyToClipboard component.
- The panel states the link's absolute expiration deadline (e.g.
  "September 4, 2026 at 3:45 PM"), preferring the server-reported
  account.expiresAt and falling back to a client-computed one from the
  chosen expiry window — so the sender knows exactly when the link
  stops working, not just the relative "7 days" window shown above it.

Tests: components/copy-to-clipboard.test.tsx (new — this component had
no coverage before) and new ConfirmStep cases covering the visible
claim link, the copy button, and the expiry deadline text.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a QR code of the claim link to the success screen for in-person /
SMS-limited disbursement (Issue bridgelet-org#423).

The QRCode component already existed (components/qr-code.tsx, wired up
via QRCodeModalButton) but its "QR code" was actually a hash-scrambled
21x21 grid dressed up with finder/timing patterns — genuinely QR-shaped,
but not a real encoding, so nothing could ever scan or decode it. Swaps
the matrix generation to the `qrcode` package's synchronous, pure-JS
`create()` encoder (real Reed–Solomon error correction, no network
calls, safe for SSR) while keeping the component's public API and SVG
rendering approach unchanged, so none of its existing tests needed to
change. Also adds a proper quiet zone around the modules, which the
previous edge-to-edge rendering lacked and real scanners rely on.

- Round-trip verified: added tests that encode a claim URL with
  generateQrMatrix(), rasterize the module matrix into a plain RGBA
  bitmap (no canvas/DOM rasterization needed), and decode it with an
  independent decoder (`jsqr`) — asserting the decoded text matches the
  original claim URL exactly, for several URL shapes.
- Downloadable as an image: the component's existing SVG download
  button (unchanged) now downloads a real, scannable QR code instead of
  a fake one.
- Accessible alt text: QRCodeModalButton passes a purpose-specific
  label ("Scannable QR code — scan to open the claim link: ...") to the
  underlying <QRCode>'s aria-label, describing what the code is for.

Wires QRCodeModalButton into ConfirmStep's success screen, next to the
claim link and copy button added in the previous commit.

Tests: components/qr-code.test.tsx (existing 2 tests unchanged/passing
+ 4 new round-trip/structural tests) and a new ConfirmStep case
covering reveal-QR-on-demand.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 28, 2026

Copy link
Copy Markdown

@A6dulmalik is attempting to deploy a commit to the aminubabafatima8-gmailcom's projects Team on Vercel.

A member of the Team first needs to authorize it.

@phertyameen
phertyameen merged commit bdc1930 into bridgelet-org:main Aug 29, 2026
0 of 10 checks passed
@phertyameen

Copy link
Copy Markdown
Contributor

Merged to \main\ as part of a consolidated integration (branch \merge-final, now pushed as commit \5155235\ on main).

Validation on main:

  • Frontend CI: green
  • Lighthouse CI: green
  • Mobile CI: Lint & Type Check, Unit Tests, and Android/iOS prebuild all green

Note: the Mobile CI Android/iOS native debug build jobs still fail on pre-existing repo issues unrelated to this PR (react-native-reanimated vs RN 0.81 compile error, and the macos-14 runner's Xcode 15.4 vs RN's required Xcode >= 16.1). Tracked as follow-up work, not blocked by this change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants