Skip to content

wallet: show resource fee and balance in TxModal; add accessibility a… - #77

Merged
elizabetheonoja-art merged 1 commit into
Utility-Protocol:mainfrom
BarryArinze:feat/txmodal-show-fee
Jun 25, 2026
Merged

wallet: show resource fee and balance in TxModal; add accessibility a…#77
elizabetheonoja-art merged 1 commit into
Utility-Protocol:mainfrom
BarryArinze:feat/txmodal-show-fee

Conversation

@BarryArinze

Copy link
Copy Markdown
Contributor

Summary

  • Purpose: Add visible estimated resource fee and balance checks to the transaction signing modal so users see the XLM fee, current balance, and an insufficiency warning before signing. Disable signing when funds are insufficient and show a loading spinner while submitting.

Motivation

  • Problem: Users were prompted to sign transactions without seeing the estimated resource fee in XLM. This caused signature rejections from insufficient balances or unexpected fees, forcing users to cancel and restart flows.
  • Goal: Improve UX and reduce failed transaction attempts by surfacing fee and balance information, preventing blind approvals.

What this PR does

  • Operation Display: Shows the operation name (e.g., "Update Tariff" or "Deposit Collateral") in the modal.
  • Fee Display: Shows the estimated resource fee in XLM, formatted to 7-decimal precision.
  • Balance Display: Shows the current account balance formatted to 7-decimal precision.
  • Insufficiency Warning: Renders a clear visual warning (destructive alert) when balance < fee.
  • Confirm State: Disables the confirm button when insufficiency is true.
  • Loading State: Adds a spinner and text on the confirm button while submission is in progress.
  • Stateless API: Modal accepts props only; parent retains state control. Props: open, onClose, onConfirm, operation, resourceFee, balance.
  • Accessibility: Adds focus trapping, Escape to close, role="dialog", aria-modal="true", aria-labelledby and restores focus to previously focused element on close.
  • Styling/UX: Uses fixed positioning and backdrop blur to isolate focus; minimal visual changes to match existing design tokens.

Files changed

  • Modified: TxModal.tsx

Implementation details (technical)

  • BigNumber usage: Uses BigNumber for robust decimal comparison: the insufficiency check runs in useEffect:
    • const fee = new BigNumber(resourceFee || "0");
    • const bal = new BigNumber(balance || "0");
    • setInsufficient(fee.isGreaterThan(bal));
  • Formatting: Fee and balance are formatted via BigNumber(...).toFixed(7) with try/catch fallback to raw strings in case of invalid input.
  • Confirm handler: handleConfirm is wrapped in useCallback and sets confirming state to true during onConfirm() until completion; on success it calls onClose() and always resets confirming.
  • Focus management:
    • On open, save document.activeElement and focus the first focusable element inside the dialog (or the dialog itself).
    • Global keydown handler handles Escape to call onClose().
    • Tab key handling traps focus within the dialog (wraps to first/last).
    • On close, restores previously focused element (if available).
  • ARIA: role="dialog", aria-modal="true", aria-labelledby="tx-modal-title", and the close button has aria-label="Close dialog".
  • Spinner: A small inline SVG spinner (CSS animate-spin) is rendered in the confirm button during confirming.

Testing performed

  • Ran unit test suite after changes:
    • Commands used: npm run test
    • Result: All tests pass (Test Files: 7 passed, Tests: 82 passed).
  • Verified local install issue with native binding was resolved by clean install (rm -rf node_modules package-lock.json && npm i) before test run.

How to review / QA checklist

  • Functional checks:
      • Open modal: Provide resourceFee and balance props and confirm modal renders operation, fee and balance.
      • Fee formatting: Confirm values display with 7 decimal places (e.g., 0.0123456 XLM).
      • Insufficiency: Set balance < resourceFee → verify alert shows and confirm button is disabled.
      • Confirm flow: Set balance >= resourceFee → click confirm → confirm button shows spinner and onConfirm is invoked; on success, dialog closes.
  • Accessibility checks:
      • Focus trap: Tab cycles and does not escape modal.
      • Escape to close: Press Escape to close the modal.
      • Screen reader: role="dialog" and aria-modal="true" are present; aria-labelledby points to visible title.
      • Focus restore: After closing, previously focused element receives focus again.
  • Integration checks:
      • Ensure parent components pass resourceFee and balance as decimal strings (or numbers/string-convertible). Any invalid inputs gracefully fall back to display raw values.
  • Visual checks:
      • Confirm destructive alert styles match design tokens and are visible on insufficiency.
      • Confirm spinner and confirm button layout are visually correct across breakpoints.

How to run locally

  • Install dependencies (if needed):
    • rm -rf node_modules package-lock.json && npm i
  • Run unit tests:
    • npm run test
  • Run app to test in browser (Next dev):
    • npm run dev and exercise modal flows in UI.

Backward compatibility & migration notes8

  • The modal remains stateless and preserves the existing prop signature except that the component now expects the parent to pass resourceFee and balance (strings). No breaking API changes beyond those props already indicated by the issue. If parents did not previously pass resourceFee/balance, the modal will render 0.0000000 fallback values and continue to work.

Potential follow-ups / improvement ideas

  • Show currency conversion (XLM → fiat) next to the fee.
  • Add tooltips or a small explainer about what the resource fee covers.
  • Expose a callback to request a top-up flow when insufficient is true (CTA inside modal).
  • Add unit tests specifically for TxModal behavior (focus trap, insufficiency rendering, formatted output). If you want, I can add those tests in a follow-up.

Security & performance

  • Security: No secrets or crypto operations are handled inside the modal — it is purely a UI layer. onConfirm remains the caller-provided async handler that performs signing/submission.
  • Performance: Minor runtime cost for formatting and BigNumber comparisons; these are trivial for a single modal instance.

Files to inspect

  • TxModal.tsx

Closes #12

@elizabetheonoja-art
elizabetheonoja-art merged commit b967956 into Utility-Protocol:main Jun 25, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Issue 12: Pre-Flight Resource Fee Projection Modal for Complex Operations

2 participants