wallet-stack 1.0.0-alpha.134 → 1.0.0-alpha.135
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/send/EnterAmount.tsx +106 -83
- package/src/send/SendEnterAmount.test.tsx +27 -0
package/package.json
CHANGED
package/src/send/EnterAmount.tsx
CHANGED
|
@@ -10,7 +10,7 @@ import BackButton from 'src/components/BackButton'
|
|
|
10
10
|
import { BottomSheetModalRefType } from 'src/components/BottomSheet'
|
|
11
11
|
import Button, { BtnSizes } from 'src/components/Button'
|
|
12
12
|
import FeeInfoBottomSheet from 'src/components/FeeInfoBottomSheet'
|
|
13
|
-
import { FilterChip } from 'src/components/FilterChipsCarousel'
|
|
13
|
+
import { FilterChip, isNetworkChip } from 'src/components/FilterChipsCarousel'
|
|
14
14
|
import InLineNotification, { NotificationVariant } from 'src/components/InLineNotification'
|
|
15
15
|
import KeyboardAwareScrollView from 'src/components/KeyboardAwareScrollView'
|
|
16
16
|
import { ReviewDetailsItem } from 'src/components/ReviewTransaction'
|
|
@@ -34,6 +34,7 @@ import { Spacing } from 'src/styles/styles'
|
|
|
34
34
|
import { feeCurrenciesSelector } from 'src/tokens/selectors'
|
|
35
35
|
import { TokenBalance } from 'src/tokens/slice'
|
|
36
36
|
import { PreparedTransactionsResult } from 'src/viem/prepareTransactions'
|
|
37
|
+
import networkConfig from 'src/web3/networkConfig'
|
|
37
38
|
|
|
38
39
|
export interface ProceedArgs {
|
|
39
40
|
tokenAmount: BigNumber
|
|
@@ -113,9 +114,20 @@ export default function EnterAmount({
|
|
|
113
114
|
}: Props) {
|
|
114
115
|
const { t } = useTranslation()
|
|
115
116
|
const insets = useSafeAreaInsets()
|
|
116
|
-
const [token, setToken] = useState<TokenBalance>(() =>
|
|
117
|
+
const [token, setToken] = useState<TokenBalance | undefined>(() => {
|
|
118
|
+
if (defaultToken) return defaultToken
|
|
119
|
+
const activeFilters = filterChips?.filter((chip) => chip.isSelected) ?? []
|
|
120
|
+
const selectableTokens = tokens.filter((t) =>
|
|
121
|
+
activeFilters.every((filter) =>
|
|
122
|
+
isNetworkChip(filter) ? filter.filterFn(t, filter.selectedNetworkIds) : filter.filterFn(t)
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
return selectableTokens[0]
|
|
126
|
+
})
|
|
117
127
|
const [selectedPercentage, setSelectedPercentage] = useState<number | null>(null)
|
|
118
|
-
const feeCurrencies = useSelector((state) =>
|
|
128
|
+
const feeCurrencies = useSelector((state) =>
|
|
129
|
+
feeCurrenciesSelector(state, token?.networkId ?? networkConfig.defaultNetworkId)
|
|
130
|
+
)
|
|
119
131
|
const networkFee = useNetworkFee(prepareTransactionsResult)
|
|
120
132
|
const localCurrencySymbol = useSelector(getLocalCurrencySymbol) ?? LocalCurrencySymbol.USD
|
|
121
133
|
|
|
@@ -142,6 +154,8 @@ export default function EnterAmount({
|
|
|
142
154
|
useEffect(() => {
|
|
143
155
|
onClearPreparedTransactions()
|
|
144
156
|
|
|
157
|
+
if (!token) return
|
|
158
|
+
|
|
145
159
|
const canRefresh =
|
|
146
160
|
processedAmounts.token.bignum &&
|
|
147
161
|
processedAmounts.token.bignum.gt(0) &&
|
|
@@ -158,9 +172,9 @@ export default function EnterAmount({
|
|
|
158
172
|
const onOpenTokenPicker = () => {
|
|
159
173
|
tokenBottomSheetRef.current?.snapToIndex(0)
|
|
160
174
|
AppAnalytics.track(SendEvents.token_dropdown_opened, {
|
|
161
|
-
currentTokenId: token
|
|
162
|
-
currentTokenAddress: token
|
|
163
|
-
currentNetworkId: token
|
|
175
|
+
currentTokenId: token?.tokenId ?? '',
|
|
176
|
+
currentTokenAddress: token?.address ?? null,
|
|
177
|
+
currentNetworkId: token?.networkId ?? null,
|
|
164
178
|
})
|
|
165
179
|
}
|
|
166
180
|
|
|
@@ -174,6 +188,7 @@ export default function EnterAmount({
|
|
|
174
188
|
}
|
|
175
189
|
|
|
176
190
|
const onSelectPercentageAmount = (percentage: number) => {
|
|
191
|
+
if (!token) return
|
|
177
192
|
handleSelectPercentageAmount(percentage)
|
|
178
193
|
setSelectedPercentage(percentage)
|
|
179
194
|
|
|
@@ -187,6 +202,7 @@ export default function EnterAmount({
|
|
|
187
202
|
}
|
|
188
203
|
|
|
189
204
|
const showLowerAmountError =
|
|
205
|
+
token &&
|
|
190
206
|
processedAmounts.token.bignum &&
|
|
191
207
|
!processedAmounts.token.bignum.lte(token.balance) &&
|
|
192
208
|
!disableBalanceCheck
|
|
@@ -205,6 +221,7 @@ export default function EnterAmount({
|
|
|
205
221
|
prepareTransactionsResult.transactions.length > 0
|
|
206
222
|
|
|
207
223
|
const disabled =
|
|
224
|
+
!token ||
|
|
208
225
|
disableProceed ||
|
|
209
226
|
(disableBalanceCheck ? !!processedAmounts.token.bignum?.isZero() : !transactionIsPossible)
|
|
210
227
|
|
|
@@ -236,89 +253,95 @@ export default function EnterAmount({
|
|
|
236
253
|
onOpenTokenPicker={tokenSelectionDisabled ? undefined : onOpenTokenPicker}
|
|
237
254
|
/>
|
|
238
255
|
|
|
239
|
-
{
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
256
|
+
{token &&
|
|
257
|
+
prepareTransactionsResult?.type !== 'not-enough-balance-for-gas' &&
|
|
258
|
+
!!networkFee && (
|
|
259
|
+
<View style={styles.feeContainer}>
|
|
260
|
+
<ReviewDetailsItem
|
|
261
|
+
approx
|
|
262
|
+
testID="SendEnterAmount/NetworkFee"
|
|
263
|
+
type="token-amount"
|
|
264
|
+
label={t('networkFee')}
|
|
265
|
+
tokenAmount={networkFee.amount}
|
|
266
|
+
localAmount={networkFee.localAmount}
|
|
267
|
+
tokenInfo={networkFee.token}
|
|
268
|
+
localCurrencySymbol={localCurrencySymbol}
|
|
269
|
+
onInfoPress={() => feeInfoBottomSheetRef.current?.snapToIndex(0)}
|
|
270
|
+
/>
|
|
252
271
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
272
|
+
<FeeInfoBottomSheet forwardedRef={feeInfoBottomSheetRef} networkFee={networkFee} />
|
|
273
|
+
</View>
|
|
274
|
+
)}
|
|
256
275
|
</View>
|
|
257
276
|
|
|
258
|
-
{
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
277
|
+
{token && (
|
|
278
|
+
<>
|
|
279
|
+
{showLowerAmountError && (
|
|
280
|
+
<InLineNotification
|
|
281
|
+
variant={NotificationVariant.Warning}
|
|
282
|
+
title={t('sendEnterAmountScreen.insufficientBalanceWarning.title', {
|
|
283
|
+
tokenSymbol: token.symbol,
|
|
284
|
+
})}
|
|
285
|
+
description={t('sendEnterAmountScreen.insufficientBalanceWarning.description', {
|
|
286
|
+
tokenSymbol: token.symbol,
|
|
287
|
+
})}
|
|
288
|
+
style={styles.warning}
|
|
289
|
+
testID="SendEnterAmount/NotEnoughBalanceWarning"
|
|
290
|
+
/>
|
|
291
|
+
)}
|
|
292
|
+
{showMaxAmountWarning && (
|
|
293
|
+
<InLineNotification
|
|
294
|
+
variant={NotificationVariant.Warning}
|
|
295
|
+
title={t('sendEnterAmountScreen.maxAmountWarning.title')}
|
|
296
|
+
description={t('sendEnterAmountScreen.maxAmountWarning.description', {
|
|
297
|
+
feeTokenSymbol: prepareTransactionsResult.feeCurrency.symbol,
|
|
298
|
+
})}
|
|
299
|
+
style={styles.warning}
|
|
300
|
+
testID="SendEnterAmount/MaxAmountWarning"
|
|
301
|
+
/>
|
|
302
|
+
)}
|
|
303
|
+
{showNotEnoughBalanceForGasWarning && (
|
|
304
|
+
<InLineNotification
|
|
305
|
+
variant={NotificationVariant.Warning}
|
|
306
|
+
title={t('sendEnterAmountScreen.notEnoughBalanceForGasWarning.title', {
|
|
307
|
+
feeTokenSymbol: prepareTransactionsResult.feeCurrencies[0].symbol,
|
|
308
|
+
})}
|
|
309
|
+
description={t('sendEnterAmountScreen.notEnoughBalanceForGasWarning.description', {
|
|
310
|
+
feeTokenSymbol: prepareTransactionsResult.feeCurrencies[0].symbol,
|
|
311
|
+
})}
|
|
312
|
+
style={styles.warning}
|
|
313
|
+
testID="SendEnterAmount/NotEnoughForGasWarning"
|
|
314
|
+
/>
|
|
315
|
+
)}
|
|
316
|
+
{prepareTransactionError && (
|
|
317
|
+
<InLineNotification
|
|
318
|
+
variant={NotificationVariant.Error}
|
|
319
|
+
title={t('sendEnterAmountScreen.prepareTransactionError.title')}
|
|
320
|
+
description={t('sendEnterAmountScreen.prepareTransactionError.description')}
|
|
321
|
+
style={styles.warning}
|
|
322
|
+
testID="SendEnterAmount/PrepareTransactionError"
|
|
323
|
+
/>
|
|
324
|
+
)}
|
|
304
325
|
|
|
305
|
-
|
|
326
|
+
{children}
|
|
306
327
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
328
|
+
<EnterAmountOptions
|
|
329
|
+
onPressAmount={onSelectPercentageAmount}
|
|
330
|
+
selectedAmount={selectedPercentage}
|
|
331
|
+
testID="SendEnterAmount/AmountOptions"
|
|
332
|
+
/>
|
|
312
333
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
334
|
+
<ProceedComponent
|
|
335
|
+
tokenAmount={processedAmounts.token.bignum}
|
|
336
|
+
localAmount={processedAmounts.local.bignum}
|
|
337
|
+
token={token}
|
|
338
|
+
amountEnteredIn={amountType}
|
|
339
|
+
onPressProceed={onPressProceed}
|
|
340
|
+
disabled={disabled}
|
|
341
|
+
showLoading={prepareTransactionsLoading}
|
|
342
|
+
/>
|
|
343
|
+
</>
|
|
344
|
+
)}
|
|
322
345
|
</KeyboardAwareScrollView>
|
|
323
346
|
<TokenBottomSheet
|
|
324
347
|
forwardedRef={tokenBottomSheetRef}
|
|
@@ -308,6 +308,33 @@ describe('SendEnterAmount', () => {
|
|
|
308
308
|
expect(queryByText('sendEnterAmountScreen.miniPayFilterChip')).toBeFalsy()
|
|
309
309
|
})
|
|
310
310
|
|
|
311
|
+
it('should not select a default token when isMiniPayRecipient is true and user has no MiniPay tokens', () => {
|
|
312
|
+
jest.mocked(getDynamicConfigParams).mockReturnValue({
|
|
313
|
+
miniPayTokenIds: ['celo-alfajores:0xNOT_HELD_BY_USER'],
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
const { getByText, queryByTestId, getByTestId } = render(
|
|
317
|
+
<Provider store={store}>
|
|
318
|
+
<MockedNavigator
|
|
319
|
+
component={SendEnterAmount}
|
|
320
|
+
params={{ ...params, isMiniPayRecipient: true }}
|
|
321
|
+
/>
|
|
322
|
+
</Provider>
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
// "Select token" placeholder is rendered in place of the selected token
|
|
326
|
+
expect(getByText('tokenEnterAmount.selectToken')).toBeTruthy()
|
|
327
|
+
// Amount input, percentage options, and Review button are not rendered
|
|
328
|
+
expect(queryByTestId('SendEnterAmount/TokenAmountInput')).toBeNull()
|
|
329
|
+
expect(queryByTestId('SendEnterAmount/AmountOptions')).toBeNull()
|
|
330
|
+
expect(queryByTestId('SendEnterAmount/ReviewButton')).toBeNull()
|
|
331
|
+
// MiniPay filter chip is still present (inside the token picker)
|
|
332
|
+
expect(getByText('sendEnterAmountScreen.miniPayFilterChip')).toBeTruthy()
|
|
333
|
+
// Tapping the token row opens the picker
|
|
334
|
+
fireEvent.press(getByTestId('SendEnterAmount/TokenSelect'))
|
|
335
|
+
expect(getByTestId('TokenBottomSheet')).toBeTruthy()
|
|
336
|
+
})
|
|
337
|
+
|
|
311
338
|
it('should include isMiniPayRecipient in send_amount_continue analytics', async () => {
|
|
312
339
|
jest.mocked(usePrepareSendTransactions).mockReturnValue({
|
|
313
340
|
prepareTransactionsResult: mockPrepareTransactionsResultPossible,
|