Skip to content

Commit 6c77a6e

Browse files
authored
TokenAmountInput (#2556)
1 parent 7f35713 commit 6c77a6e

File tree

11 files changed

+489
-317
lines changed

11 files changed

+489
-317
lines changed

packages/core-mobile/app/new/routes/(signedIn)/(modals)/addStake/amount.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
Button,
55
SafeAreaView,
66
ScrollView,
7-
TokenAmountInputWidget,
7+
TokenUnitInputWidget,
88
View
99
} from '@avalabs/k2-alpine'
1010
import ScreenHeader from 'common/components/ScreenHeader'
@@ -119,7 +119,7 @@ const StakeAmountScreen = (): JSX.Element => {
119119
style={{ flex: 1 }}
120120
contentContainerSx={{ padding: 16, paddingTop: 0 }}>
121121
<ScreenHeader title="How much would you like to stake?" />
122-
<TokenAmountInputWidget
122+
<TokenUnitInputWidget
123123
sx={{
124124
marginTop: 16
125125
}}

packages/core-mobile/app/new/routes/(signedIn)/(modals)/claimStakeReward/index.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,15 @@ import { useClaimRewards } from 'hooks/earn/useClaimRewards'
2424
import { SendErrorMessage } from 'screens/send/utils/types'
2525
import { useFormatCurrency } from 'common/hooks/useFormatCurrency'
2626
import { showSnackbar } from 'common/utils/toast'
27-
import {
28-
TokenAmountInput,
29-
TokenAmountInputHandle
30-
} from '@avalabs/k2-alpine/src/components/TokenAmountInput/TokenAmountInput'
27+
import { TokenUnitInput, TokenUnitInputHandle } from '@avalabs/k2-alpine'
3128
import { useConfetti } from 'common/contexts/ConfettiContext'
3229
import { StakeTokenUnitValue } from 'features/stake/components/StakeTokenUnitValue'
3330

3431
const ClaimStakeRewardScreen = (): JSX.Element => {
3532
const { navigate, back } = useRouter()
3633
const { formatTokenInCurrency } = useFormatCurrency()
3734
const { data } = usePChainBalance()
38-
const ref = useRef<TokenAmountInputHandle>(null)
35+
const ref = useRef<TokenUnitInputHandle>(null)
3936
const [claimableAmountInAvax, setClaimableAmountInAvax] =
4037
useState<TokenUnit>()
4138
const isDeveloperMode = useSelector(selectIsDeveloperMode)
@@ -188,7 +185,7 @@ const ClaimStakeRewardScreen = (): JSX.Element => {
188185
paddingHorizontal: 16,
189186
borderRadius: 12
190187
}}>
191-
<TokenAmountInput
188+
<TokenUnitInput
192189
ref={ref}
193190
amount={claimableAmountInAvax}
194191
editable={false}

packages/k2-alpine/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
"@storybook/addon-ondevice-backgrounds": "7.6.20",
7575
"@storybook/addon-ondevice-controls": "7.6.20",
7676
"@storybook/react-native": "7.6.20",
77+
"@types/big.js": "6.2.2",
7778
"@types/d3": "7.4.3",
7879
"@types/jest": "29.5.13",
7980
"@types/lodash.debounce": "4.0.9",
Lines changed: 15 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import React, { useCallback, useState } from 'react'
1+
import React, { useState } from 'react'
22
import { GestureHandlerRootView } from 'react-native-gesture-handler'
3-
import { TokenUnit } from '@avalabs/core-utils-sdk'
43
import { ScrollView, Text, View } from '../Primitives'
5-
import { Icons, useTheme } from '../..'
6-
import { TokenAmountInputWidget } from './TokenAmountInputWidget'
7-
import { TokenAmountInput } from './TokenAmountInput'
4+
import { useTheme } from '../..'
5+
import { TokenAmount, TokenAmountInput } from './TokenAmountInput'
86

97
export default {
108
title: 'Token Amount Input'
@@ -27,112 +25,31 @@ export const All = (): JSX.Element => {
2725
}}
2826
contentContainerStyle={{ padding: 16, gap: 40 }}
2927
keyboardShouldPersistTaps="always">
30-
<TokenAmountInputStory />
31-
<StakingTokenAmountInputWidgetStory />
32-
<SwapTokenAmountInputWidgetStory />
28+
<TokenUnitInputStory />
3329
</ScrollView>
3430
</GestureHandlerRootView>
3531
)
3632
}
3733

38-
const TokenAmountInputStory = (): JSX.Element => {
39-
const [amount, setAmount] = useState<TokenUnit | undefined>(
40-
new TokenUnit(1000000000, xpChainToken.maxDecimals, xpChainToken.symbol)
41-
)
34+
const TokenUnitInputStory = (): JSX.Element => {
35+
const [amount, setAmount] = useState<TokenAmount>()
4236

43-
const handleChange = (value: TokenUnit): void => {
37+
const handleChange = (value: TokenAmount): void => {
4438
setAmount(value)
4539
}
4640

4741
return (
4842
<View sx={{ gap: 12 }}>
49-
<Text variant="heading6">Amount Input: {amount?.toString()} AVAX</Text>
43+
<Text variant="heading6">Amount Input: {amount?.valueString} AVAX</Text>
5044
<TokenAmountInput
51-
amount={amount}
52-
token={xpChainToken}
45+
value={amount?.value}
46+
denomination={xpChainToken.maxDecimals}
5347
onChange={handleChange}
54-
formatInCurrency={testFormatInCurrency}
55-
/>
56-
</View>
57-
)
58-
}
59-
60-
const StakingTokenAmountInputWidgetStory = (): JSX.Element => {
61-
const [stakeAmount, setStakeAmount] = useState<TokenUnit | undefined>(
62-
new TokenUnit(25000000000, xpChainToken.maxDecimals, xpChainToken.symbol)
63-
)
64-
65-
const handleChange = (amount: TokenUnit): void => {
66-
setStakeAmount(amount)
67-
}
68-
69-
const validateStakingAmount = useCallback(async (amount: TokenUnit) => {
70-
if (!amount.isZero() && amount.lt(minStakeAmount)) {
71-
throw new Error(
72-
`Minimum amount to stake is ${minStakeAmount.toString()} AVAX`
73-
)
74-
} else if (amount.gt(balanceInAvax)) {
75-
throw new Error(
76-
'The specified staking amount exceeds the available balance'
77-
)
78-
}
79-
}, [])
80-
81-
// we can't stake the full amount because of fees
82-
// to give a good user experience, when user presses max
83-
// we will stake 99.99% of the balance
84-
// this is to ensure that the user has enough balance to cover the fees
85-
const STAKING_MAX_BALANCE_PERCENTAGE = 0.9999
86-
87-
return (
88-
<View sx={{ gap: 12 }}>
89-
<Text variant="heading6">
90-
Staking Amount Input Widget: {stakeAmount?.toString()} AVAX
91-
</Text>
92-
<TokenAmountInputWidget
93-
amount={stakeAmount}
94-
token={xpChainToken}
95-
balance={balanceInAvax}
96-
formatInCurrency={testFormatInCurrency}
97-
onChange={handleChange}
98-
maxPercentage={STAKING_MAX_BALANCE_PERCENTAGE}
99-
validateAmount={validateStakingAmount}
100-
/>
101-
</View>
102-
)
103-
}
104-
105-
const SwapTokenAmountInputWidgetStory = (): JSX.Element => {
106-
const { theme } = useTheme()
107-
const [swapAmount, setSwapAmount] = useState<TokenUnit | undefined>(undefined)
108-
109-
const handleChange = (amount: TokenUnit): void => {
110-
setSwapAmount(amount)
111-
}
112-
113-
const validateSwapAmount = useCallback(async (amount: TokenUnit) => {
114-
if (amount.gt(balanceInAvax)) {
115-
throw new Error('The specified swap amount exceeds the available balance')
116-
}
117-
}, [])
118-
119-
const renderAccessory = useCallback(() => {
120-
return <Icons.Custom.Switch color={theme.colors.$textPrimary} />
121-
}, [theme])
122-
123-
return (
124-
<View sx={{ gap: 12 }}>
125-
<Text variant="heading6">
126-
Swap Amount Input Widget: {swapAmount?.toString()} AVAX
127-
</Text>
128-
<TokenAmountInputWidget
129-
amount={swapAmount}
130-
token={ethereumToken}
131-
balance={balanceInAvax}
132-
formatInCurrency={testFormatInCurrency}
133-
onChange={handleChange}
134-
validateAmount={validateSwapAmount}
135-
accessory={renderAccessory()}
48+
placeholder="0.00"
49+
style={{
50+
fontFamily: 'Aeonik-Medium',
51+
fontSize: 60
52+
}}
13653
/>
13754
</View>
13855
)
@@ -142,25 +59,3 @@ const xpChainToken = {
14259
maxDecimals: 9,
14360
symbol: 'AVAX'
14461
}
145-
146-
const ethereumToken = {
147-
maxDecimals: 18,
148-
symbol: 'ETH'
149-
}
150-
151-
const testFormatInCurrency = (amount: TokenUnit): string => {
152-
const nativeTokenPrice = 22.0
153-
return `$${amount.mul(nativeTokenPrice).toDisplay({ fixedDp: 2 })} USD`
154-
}
155-
156-
const balanceInAvax = new TokenUnit(
157-
28142000000,
158-
xpChainToken.maxDecimals,
159-
xpChainToken.symbol
160-
)
161-
162-
const minStakeAmount = new TokenUnit(
163-
0,
164-
xpChainToken.maxDecimals,
165-
xpChainToken.symbol
166-
).add(25)

0 commit comments

Comments
 (0)