-
Notifications
You must be signed in to change notification settings - Fork 14
feat(withdraw): tap the balance to withdraw everything #2842
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
abalinda
wants to merge
16
commits into
fix/21991-network-fee-one-source
Choose a base branch
from
feat/withdraw-use-full-balance
base: fix/21991-network-fee-one-source
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 4 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
b984cc9
feat(withdraw): tap the balance to withdraw everything
abalinda 09187b2
comment: name exponential notation as a case the inert balance row co…
abalinda ca67be6
fix(withdraw): keep the balance tap from opening the keyboard over th…
abalinda e959d37
feat(withdraw): underline only the amount, and fill it floored to cents
abalinda 29cd908
fix(ui): write the dollar symbol against the amount
abalinda b2cc434
a11y: floor the balance action's tap target width too
abalinda 149bae3
feat(withdraw): withdraw everything on crypto, still show two decimals
abalinda 6de65ff
docs: resolveWithdrawAmount does not clamp — say so
abalinda b2409d1
Merge origin/dev — resolve the balance row onto the DS-migrated Amoun…
abalinda 80c0b05
a11y(ds): keyboard focus ring on the balance action (law 8)
abalinda acc2b39
Merge remote-tracking branch 'origin/fix/21991-network-fee-one-source…
abalinda c92839b
fix(withdraw): quote a withdraw by what the user spends; gate the spe…
abalinda 75de393
Merge remote-tracking branch 'origin/fix/21991-network-fee-one-source…
abalinda db33891
Merge remote-tracking branch 'origin/fix/21991-network-fee-one-source…
abalinda 271f163
Merge remote-tracking branch 'origin/fix/21991-network-fee-one-source…
abalinda d7c82ce
Merge remote-tracking branch 'origin/fix/21991-network-fee-one-source…
abalinda File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
140 changes: 140 additions & 0 deletions
140
src/components/Global/AmountInput/__tests__/balance-fill.test.tsx
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,140 @@ | ||
| import { fireEvent, screen } from '@testing-library/react' | ||
| import { renderWithIntl } from '@/test-utils/intl' | ||
| import AmountInput from '@/components/Global/AmountInput' | ||
|
|
||
| /** | ||
| * Tapping the balance amount fills the whole spendable amount (TASK-21899). | ||
| * The point of these tests is that the fill is floored to cents and can never | ||
| * exceed the balance — the user is never told they can withdraw more than | ||
| * they hold, and the fill matches the label, which truncates the same way. | ||
| */ | ||
|
|
||
| // USDC, as the withdraw amount screen configures it | ||
| const USDC = { symbol: '$', price: 1, decimals: 6 } | ||
|
|
||
| function setup(props: Partial<React.ComponentProps<typeof AmountInput>> = {}) { | ||
| const setPrimaryAmount = jest.fn() | ||
| renderWithIntl( | ||
| <AmountInput | ||
| setPrimaryAmount={setPrimaryAmount} | ||
| primaryDenomination={USDC} | ||
| hideCurrencyToggle | ||
| walletBalance="12.34" | ||
| balanceFillAmount={12.345678} | ||
| {...props} | ||
| /> | ||
| ) | ||
| const field = screen.getByRole('textbox') as HTMLInputElement | ||
| return { | ||
| setPrimaryAmount, | ||
| field, | ||
| useFullBalance: () => screen.queryByRole('button', { name: /use full balance/i }), | ||
| lastReported: () => setPrimaryAmount.mock.lastCall?.[0], | ||
| } | ||
| } | ||
|
|
||
| describe('AmountInput full-balance fill', () => { | ||
| it('fills the balance floored to cents', () => { | ||
| const { field, useFullBalance, lastReported } = setup() | ||
|
|
||
| fireEvent.click(useFullBalance()!) | ||
|
|
||
| expect(field.value).toBe('12.34') | ||
| expect(lastReported()).toBe('12.34') | ||
| }) | ||
|
|
||
| it('rounds down, never up, so the fill cannot exceed the balance', () => { | ||
| // 10.126123 must become 10.12, not 10.13 — the 0.006123 stays behind. | ||
| const { field, useFullBalance } = setup({ walletBalance: '10.12', balanceFillAmount: 10.126123 }) | ||
|
|
||
| fireEvent.click(useFullBalance()!) | ||
|
|
||
| expect(field.value).toBe('10.12') | ||
| expect(Number(field.value)).toBeLessThanOrEqual(10.126123) | ||
| }) | ||
|
|
||
| it('stays at cents even when the field accepts more decimals', () => { | ||
| // The withdraw screen runs this input at 6 decimals so a user CAN type | ||
| // them; the fill still stops at the two the balance label shows. | ||
| const { field, useFullBalance } = setup({ | ||
| primaryDenomination: { symbol: '$', price: 1, decimals: 6 }, | ||
| balanceFillAmount: 12.345678, | ||
| }) | ||
|
|
||
| fireEvent.click(useFullBalance()!) | ||
|
|
||
| expect(field.value).toBe('12.34') | ||
| }) | ||
|
|
||
| it('does not fill more decimals than a coarse denomination holds', () => { | ||
| const { field, useFullBalance } = setup({ | ||
| primaryDenomination: { symbol: '$', price: 1, decimals: 0 }, | ||
| balanceFillAmount: 12.345678, | ||
| }) | ||
|
|
||
| fireEvent.click(useFullBalance()!) | ||
|
|
||
| expect(field.value).toBe('12') | ||
| }) | ||
|
|
||
| it('makes only the amount tappable, not the word Balance', () => { | ||
| const { useFullBalance } = setup() | ||
|
|
||
| expect(useFullBalance()).toHaveTextContent('$ 12.34') | ||
| expect(useFullBalance()).not.toHaveTextContent(/Balance/) | ||
| expect(screen.getByText('Balance:')).toBeInTheDocument() | ||
| }) | ||
|
|
||
| it('keeps the balance plain text when there is nothing to withdraw', () => { | ||
| const { field, useFullBalance, setPrimaryAmount } = setup({ | ||
| walletBalance: '0.00', | ||
| balanceFillAmount: 0, | ||
| }) | ||
|
|
||
| expect(useFullBalance()).toBeNull() | ||
| expect(screen.getByText(/Balance:/)).toBeInTheDocument() | ||
| expect(field.value).toBe('') | ||
| expect(setPrimaryAmount).not.toHaveBeenCalledWith(expect.stringMatching(/[1-9]/)) | ||
| }) | ||
|
|
||
| it('keeps the balance plain text when it is smaller than a cent', () => { | ||
| const { field, useFullBalance } = setup({ | ||
| walletBalance: '0.00', | ||
| balanceFillAmount: 0.004, | ||
| }) | ||
|
|
||
| expect(useFullBalance()).toBeNull() | ||
| expect(field.value).toBe('') | ||
| }) | ||
|
|
||
| it('restores the full balance after a manual edit', () => { | ||
| const { field, useFullBalance, lastReported } = setup() | ||
|
|
||
| fireEvent.click(useFullBalance()!) | ||
| fireEvent.change(field, { target: { value: '5' } }) | ||
| expect(lastReported()).toBe('5') | ||
|
|
||
| fireEvent.click(useFullBalance()!) | ||
|
|
||
| expect(field.value).toBe('12.34') | ||
| expect(lastReported()).toBe('12.34') | ||
| }) | ||
|
|
||
| it('does not open the keyboard over the CTA when filling', () => { | ||
| // The form wrapper focuses the field on any click inside it; the fill | ||
| // button must not ride that path. | ||
| const { field, useFullBalance } = setup() | ||
| field.blur() | ||
|
|
||
| fireEvent.click(useFullBalance()!) | ||
|
|
||
| expect(document.activeElement).not.toBe(field) | ||
| expect(field.value).toBe('12.34') | ||
| }) | ||
|
|
||
| it('does not offer the fill while the input is disabled', () => { | ||
| const { useFullBalance } = setup({ disabled: true }) | ||
|
|
||
| expect(useFullBalance()).toBeNull() | ||
| }) | ||
| }) |
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
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
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
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
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.