Skip to content

feat(buy): two-panel Du-zahlst/Du-erhaeltst amount layout - #257

Open
joshuakrueger-dfx wants to merge 26 commits into
developfrom
feat/amount-panel-redesign
Open

feat(buy): two-panel Du-zahlst/Du-erhaeltst amount layout#257
joshuakrueger-dfx wants to merge 26 commits into
developfrom
feat/amount-panel-redesign

Conversation

@joshuakrueger-dfx

@joshuakrueger-dfx joshuakrueger-dfx commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Scope

This PR completes the stacked Buy/Sell/Swap amount-panel redesign on top of #255 and #256. The stack is intentionally retained against develop until those PRs land; no history was rewritten.

  • Buy and Sell use the shared two-panel amount layout, selector geometry, fee card, CTA, security line, and App2-aligned spacing.
  • Swap is a reachable, explicitly disabled placeholder with the same shell, panels, fees surface, background, and mode tabs.
  • Currency and asset glyphs use the app theme tokens; picker sheets use the same glyph sizing and selection behavior.
  • The new E2E path reaches Swap from Receive → Buy → Swap and asserts the amount and fee surfaces.
  • The visual manifest classifies every discovered route; Swap is baselined as swap-placeholder.

Necessity

Symptom (verbatim): Buy, Sell, and Swap did not present the same amount-panel structure; selector widths and backgrounds differed, and the Swap route lacked the shared surface.
Scale: This stack changes 37 files because #257 contains the unmerged #255 and #256 bases; the actual feature is split across those three PRs.
Smaller fix considered: Retargeting this PR to an unmerged feature branch would hide the stack from the required develop integration gate; splitting the stack into its existing three PRs is the smaller review unit.

Validation

  • npm run check passes (typecheck, lint, format; existing warnings only, zero errors).
  • npm test -- --coverage passes: 115 suites, 1438 tests; aggregate coverage 98.9% statements, 93.03% branches, 99.78% functions, 99.83% lines.
  • node scripts/check-feature-matrix.mjs passes.
  • node scripts/check-visual-coverage.mjs and --self-test pass.
  • npm run e2e:build:ios completes for the iPhone simulator build.
  • GitHub CI on the current head is green for typecheck, lint, format, coverage floors, matrix, visual coverage, lockfile, bundles, CodeQL, dependency review, and tests. The audit job is blocked by newly published Browserslist advisories on the unchanged dependency tree (GHSA-73wf-gq98-2v4g and GHSA-c83g-rgw3-j3cx); the repository allowlist currently covers only the existing image-size advisories.
  • aac67ea closes the Swap visual/coverage, theme-token, and CodeQL unused-import findings.
  • 3ab367c updates glyph assertions to the theme-token contract.

Review disposition

No migrations, backend contracts, or new enum/status values are changed. No feature flags or encryption behavior are changed here: .env is local-only, CI MVP intentionally leaves deferred features disabled, and permanent activation belongs to an explicit release/integration PR. The observed Encryption key not found message is WDK’s loadExistingWallet error when the simulator has a stale wallet identity without its SecureStore key; reset simulator app/keychain data and onboard again. Adding a fallback key would weaken wallet security and is intentionally out of scope. The existing quote request state remains backend-authoritative; no new fallback or retry policy was introduced. Existing nullable quote display fallbacks are unchanged from the stacked base and remain documented as a follow-up review item.
Scale (cef9cfa): 37 files, +3417/−860, 26 commits
Final pass (cef9cfa):
Coherent: The diff is one stacked trade-flow UI change: shared Buy/Sell amount panels, the shared mode shell, the Swap placeholder, and their tests/matrix documentation.
Nothing extra: No backend Swap implementation, live quote fixture, wallet/keychain reset, dependency change, or unrelated settings change was added; the larger file count is inherited from the explicitly stacked #255/#256 bases.
Sources closed: #255/#256 stack bases are preserved; PR comments from github-code-quality and github-advanced-security are fixed by removing the unused import; the Swap route is classified and covered by a reachable E2E assertion; repository CI and local gates listed above pass except the documented external audit advisory.

The wallet's local FeeDto type only declared rate/fixed/network/min/dfx/
total, missing bank/bankFixed/bankVariable/platform/networkStart that
the DFX API's FeeDto already sends (api/.../fee.dto.ts). The bank fee
was silently unreadable in the app despite being in every response.
Purely additive: PrimaryButton's new icon prop is optional, existing
callers are unaffected.
- Presets fixed to 50/100/250/500, moved above the amount input
- Quote card collapsed by default: shield icon, effective rate
  ('1 {asset} ~ {price} {currency} incl. fees', using exchangeRate
  directly - verified against the amount/estimatedAmount ratio in the
  quote fixtures, not just the field name), fee-total badge, chevron
- Bank fee row added now that FeeDto carries it
- 'You receive' row highlighted in the accent color
- Static SEPA payment-method row above the CTA (Buy only)
- CTA now names the target asset with a trailing arrow icon

Buy and Sell mirror each other except presets and the payment-method
row, which are Buy-only by design (Sell trades a crypto amount, not a
fiat preset, and has no payment-method choice before confirming).
BuyScreenImpl's CTA test now expects 'buy.title BTC' instead of the old
common.continue placeholder; Icon and PrimaryButton get coverage for
the new arrow-right variant and icon slot.
The wallet's local FeeDto type only declared rate/fixed/network/min/dfx/
total, missing bank/bankFixed/bankVariable/platform/networkStart that
the DFX API's FeeDto already sends (api/.../fee.dto.ts). The bank fee
was silently unreadable in the app despite being in every response.
Purely additive: PrimaryButton's new icon prop is optional, existing
callers are unaffected.
- Presets fixed to 50/100/250/500, moved above the amount input
- Quote card collapsed by default: shield icon, effective rate
  ('1 {asset} ~ {price} {currency} incl. fees', using exchangeRate
  directly - verified against the amount/estimatedAmount ratio in the
  quote fixtures, not just the field name), fee-total badge, chevron
- Bank fee row added now that FeeDto carries it
- 'You receive' row highlighted in the accent color
- Static SEPA payment-method row above the CTA (Buy only)
- CTA now names the target asset with a trailing arrow icon

Buy and Sell mirror each other except presets and the payment-method
row, which are Buy-only by design (Sell trades a crypto amount, not a
fiat preset, and has no payment-method choice before confirming).
BuyScreenImpl's CTA test now expects 'buy.title BTC' instead of the old
common.continue placeholder; Icon and PrimaryButton get coverage for
the new arrow-right variant and icon slot.
Verifies the icon prop is truly additive (absent by default, hidden
during loading) instead of only asserting both texts render.
Adds a TradeModeTabs segmented control (Kaufen/Verkaufen/Tauschen) at
the top of the amount step in Buy and Sell, matching the structure of
the DFX web widget (app2) while using the app's own light-theme
tokens. Adds a new Swap placeholder route/screen ("coming soon") so
all three modes are reachable and switchable, ahead of the real Swap
backend wiring in a follow-up PR.
Replaces the Buy screen's asset-tile grid + chain chips + token row +
currency chips with a two-panel layout matching the DFX web widget
(app2): a "Du zahlst" panel (amount + currency pill) and a "Du
erhaeltst" panel (computed amount + asset/chain pill), with a flip
button between them that switches to Sell. New PayCurrencySheet and
ReceiveAssetSheet bottom sheets replace the old inline grid/chips as
pickers.

Fixes a real touch bug found via manual device testing: the sheets'
option rows were unreachable because the backdrop Pressable wrapped
the sheet as a parent instead of sitting beside it as a sibling,
so taps fell through to the backdrop's onClose instead of the row's
onSelect. Restructured both sheets so the backdrop is an absolutely
positioned sibling, not a wrapping parent.
Replaces the letter-in-circle placeholder badges in the amount
panels and both picker sheets with real, colored icon glyphs:
a Swiss-cross badge for CHF, euro-sign badge for EUR, dollar-sign
badge for USD, and a Bitcoin-orange circle for BTC. Both new
components (CurrencyGlyph, AssetGlyph) are pure inline SVG, no new
dependency or image asset.

Fixes two consistency gaps found via live device review: the badge
size differed between the compact pill (32px) and the sheet rows
(36px) -- unified to 32px everywhere. And ReceiveAssetSheet only
special-cased BTC, leaving CHF/EUR/USD asset sections on the old
grey letter fallback -- it now picks CurrencyGlyph or AssetGlyph
per row based on the asset symbol, matching PayCurrencySheet.

Also swaps the flip button's icon from a plain arrow to the
existing "swap" icon, which better matches its actual action.
Comment thread src/features/buy-sell/TradeAmountPanels.tsx Fixed
Comment thread src/features/buy-sell/TradeAmountPanels.tsx Fixed
@joshuakrueger-dfx joshuakrueger-dfx added the size:override Bypass the 1000-line PR size cap (justify in description) label Sep 1, 2026
@joshuakrueger-dfx
joshuakrueger-dfx marked this pull request as ready for review September 1, 2026 13:48
@joshuakrueger-dfx joshuakrueger-dfx added needs-visual Re-run Visual Regression on this PR and removed needs-visual Re-run Visual Regression on this PR labels Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:override Bypass the 1000-line PR size cap (justify in description)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants