Skip to content
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

feat(warning): Add generic gas fee warning component #6385

Open
wants to merge 41 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
6aa745d
feat(warning): Add generic gas fee warning component
finnian0826 Dec 18, 2024
fdd9e6f
add in description and cta label
finnian0826 Dec 23, 2024
03940c0
implement, update unit tests
finnian0826 Dec 23, 2024
e0cb9ff
fix hook issue
finnian0826 Dec 23, 2024
9a13634
remove extra hook
finnian0826 Dec 23, 2024
08d5cfe
add unit tests
finnian0826 Dec 30, 2024
8df26f8
cleanup
finnian0826 Dec 30, 2024
5a252c9
cleanup
finnian0826 Dec 30, 2024
0108485
reduce amoutn when gas token
finnian0826 Dec 31, 2024
e317b85
clean up analytics property
finnian0826 Dec 31, 2024
ef17d0b
Merge branch 'main' into finnian0826/act-1482
finnian0826 Dec 31, 2024
654409a
fix merge
finnian0826 Dec 31, 2024
7a33d2b
feedback pt. 1
finnian0826 Dec 31, 2024
0c6c76d
update property
finnian0826 Dec 31, 2024
3f9a16d
update strings
finnian0826 Dec 31, 2024
425c77e
update tests
finnian0826 Dec 31, 2024
1224eec
clean up
finnian0826 Dec 31, 2024
d2ba333
feedback and fix tests
finnian0826 Jan 2, 2025
51df96f
Merge branch 'main' into finnian0826/act-1482
finnian0826 Jan 2, 2025
1795348
rename analytics
finnian0826 Jan 2, 2025
21005b7
feedback
finnian0826 Jan 2, 2025
8b3a671
use string literal
finnian0826 Jan 2, 2025
85dc50a
remove superfluous tests
finnian0826 Jan 2, 2025
9b9c466
move cta function
finnian0826 Jan 3, 2025
ae7755c
fix test
finnian0826 Jan 3, 2025
a9345c9
clean up and add analytics
finnian0826 Jan 6, 2025
e7b011b
Merge branch 'main' into finnian0826/act-1482
finnian0826 Jan 6, 2025
d6b4c16
remove unnecessary test ID prefix
finnian0826 Jan 6, 2025
37215a5
fix translation key with context
finnian0826 Jan 6, 2025
c34fbe6
feedback pt. 1
finnian0826 Jan 7, 2025
0459e45
feedback pt. 2
finnian0826 Jan 7, 2025
d2e29b4
clean up testing code
finnian0826 Jan 7, 2025
b8f45d6
Merge branch 'main' into finnian0826/act-1482
finnian0826 Jan 7, 2025
33ce118
fix unit test
finnian0826 Jan 7, 2025
2272935
fix lint
finnian0826 Jan 7, 2025
9393e98
fix issue with useMemo
finnian0826 Jan 7, 2025
81a166d
feedback
finnian0826 Jan 8, 2025
4dc6531
don't put extra space for description if null
finnian0826 Jan 8, 2025
ec8c5d5
use boolean
finnian0826 Jan 8, 2025
d120e47
feedback
finnian0826 Jan 9, 2025
d560a1a
Merge branch 'main' into finnian0826/act-1482
finnian0826 Jan 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions locales/base/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2823,5 +2823,26 @@
"availableBalance": "Available: <0></0>",
"selectToken": "Select token",
"fiatPriceUnavailable": "Price unavailable"
},
"gasFeeWarning": {
"title": "You need more {{tokenSymbol}} for gas fees",
"descriptionMaxAmount": "Add {{tokenSymbol}} for gas fees or lower the amount you're {{action}}",
"descriptionNotEnoughGas": "Adjust the amount you're {{action}} or add {{tokenSymbol}} to continue",
"titleDapp": "You have an insufficient gas token balance",
"descriptionDapp": "Add {{tokenSymbol}} to complete this transaction",
"cta": "Buy {{tokenSymbol}}",
"ctaGasToken": "{{verb}} smaller amount",
"actions": {
"sending": "sending",
"swapping": "swapping",
"depositing": "depositing",
"withdrawing": "withdrawing"
},
"verb": {
MuckT marked this conversation as resolved.
Show resolved Hide resolved
"send": "Send",
"swap": "Swap",
"deposit": "Deposit",
"withdraw": "Withdraw"
}
}
}
2 changes: 2 additions & 0 deletions src/analytics/Events.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export enum AppEvents {
in_app_review_error = 'in_app_review_error',

handle_deeplink = 'handle_deeplink',

show_gas_fee_warning = 'show_gas_fee_warning',
}

export enum HomeEvents {
Expand Down
6 changes: 6 additions & 0 deletions src/analytics/Properties.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import {
} from 'src/analytics/types'
import { ErrorMessages } from 'src/app/ErrorMessages'
import { AddAssetsActionType } from 'src/components/AddAssetsBottomSheet'
import { GasFeeWarningFlow } from 'src/components/GasFeeWarning'
import { TokenPickerOrigin } from 'src/components/TokenBottomSheet'
import { DappSection } from 'src/dapps/types'
import { BeforeDepositActionName, EarnActiveMode, SerializableRewardsInfo } from 'src/earn/types'
Expand Down Expand Up @@ -152,6 +153,11 @@ interface AppEventsProperties {
fullPath: string | null
query: string | null
}
[AppEvents.show_gas_fee_warning]: {
flow: GasFeeWarningFlow
errorType: 'need-decrease-spend-amount-for-gas' | 'not-enough-balance-for-gas'
tokenNeeded: string
MuckT marked this conversation as resolved.
Show resolved Hide resolved
}
}

interface HomeEventsProperties {
Expand Down
1 change: 1 addition & 0 deletions src/analytics/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export const eventDocs: Record<AnalyticsEventType, string> = {
[AppEvents.in_app_review_impression]: `User sees an in-app review request`,
[AppEvents.in_app_review_error]: `Error while attempting to display in-app review`,
[AppEvents.handle_deeplink]: `When a deeplink that leads into the app is detected and handled`,
[AppEvents.show_gas_fee_warning]: `When the gas fee warning is shown to the user`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[AppEvents.show_gas_fee_warning]: `When the gas fee warning is shown to the user`,
[AppEvents.gas_fee_warning_impression]: `When the gas fee warning is shown to the user`,

?

[HomeEvents.account_circle_tapped]: `When the account circle used in the tab navigation is tapped`,
[HomeEvents.profile_address_copy]: `When a user copies their wallet address from the profile screen`,
[HomeEvents.notification_scroll]: ``,
Expand Down
161 changes: 161 additions & 0 deletions src/components/GasFeeWarning.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { fireEvent, render } from '@testing-library/react-native'
import BigNumber from 'bignumber.js'
import React from 'react'
import { Provider } from 'react-redux'
import AppAnalytics from 'src/analytics/AppAnalytics'
import { AppEvents } from 'src/analytics/Events'
import GasFeeWarning, { GasFeeWarningFlow } from 'src/components/GasFeeWarning'
import {
PreparedTransactionsNeedDecreaseSpendAmountForGas,
PreparedTransactionsNotEnoughBalanceForGas,
PreparedTransactionsPossible,
} from 'src/viem/prepareTransactions'
import { createMockStore } from 'test/utils'
import { mockArbEthTokenId, mockCeloTokenId, mockTokenBalances } from 'test/values'

const mockPreparedTransactionPossible: PreparedTransactionsPossible = {
type: 'possible' as const,
transactions: [],
feeCurrency: {
...mockTokenBalances[mockArbEthTokenId],
isNative: true,
balance: new BigNumber(10),
priceUsd: new BigNumber(1),
lastKnownPriceUsd: new BigNumber(1),
},
}

const mockPreparedTransactionNotEnoughCelo: PreparedTransactionsNotEnoughBalanceForGas = {
type: 'not-enough-balance-for-gas' as const,
feeCurrencies: [
{
...mockTokenBalances[mockCeloTokenId],
isNative: true,
balance: new BigNumber(0),
priceUsd: new BigNumber(1500),
lastKnownPriceUsd: new BigNumber(1500),
},
],
}

const mockPreparedTransactionNeedDecreaseCelo: PreparedTransactionsNeedDecreaseSpendAmountForGas = {
type: 'need-decrease-spend-amount-for-gas' as const,
feeCurrency: {
...mockTokenBalances[mockCeloTokenId],
isNative: true,
balance: new BigNumber(0),
priceUsd: new BigNumber(1500),
lastKnownPriceUsd: new BigNumber(1500),
},
maxGasFeeInDecimal: new BigNumber(1),
estimatedGasFeeInDecimal: new BigNumber(1),
decreasedSpendAmount: new BigNumber(1),
}

const mockPreparedTransactionNotEnoughEth: PreparedTransactionsNotEnoughBalanceForGas = {
type: 'not-enough-balance-for-gas' as const,
feeCurrencies: [
{
...mockTokenBalances[mockArbEthTokenId],
isNative: true,
balance: new BigNumber(0),
priceUsd: new BigNumber(1500),
lastKnownPriceUsd: new BigNumber(1500),
},
],
}

const mockPreparedTransactionNeedDecreaseEth: PreparedTransactionsNeedDecreaseSpendAmountForGas = {
type: 'need-decrease-spend-amount-for-gas' as const,
feeCurrency: {
...mockTokenBalances[mockArbEthTokenId],
isNative: true,
balance: new BigNumber(0),
priceUsd: new BigNumber(1500),
lastKnownPriceUsd: new BigNumber(1500),
},
maxGasFeeInDecimal: new BigNumber(1),
estimatedGasFeeInDecimal: new BigNumber(1),
decreasedSpendAmount: new BigNumber(1),
}

describe('GasFeeWarning', () => {
beforeEach(() => {
jest.clearAllMocks()
})
it('should return null if prepareTransactionsResult is undefined', () => {
const store = createMockStore()
const { queryByTestId } = render(
<Provider store={store}>
<GasFeeWarning flow={GasFeeWarningFlow.Send} testIdPrefix={'test'} />
</Provider>
)
expect(queryByTestId('test/GasFeeWarning')).toBeNull()
})
it('should return null if prepareTransactionsResult.type is possible', () => {
const store = createMockStore()
const { queryByTestId } = render(
<Provider store={store}>
<GasFeeWarning
flow={GasFeeWarningFlow.Send}
testIdPrefix={'test'}
prepareTransactionsResult={mockPreparedTransactionPossible}
/>
</Provider>
)
expect(queryByTestId('test/GasFeeWarning')).toBeNull()
})
it.each`
scenario | flow | prepareTransactionsResult | feeCurrencySymbol | title | description | ctaLabel
${'sending max amount of CELO'} | ${GasFeeWarningFlow.Send} | ${mockPreparedTransactionNeedDecreaseCelo} | ${'CELO'} | ${'gasFeeWarning.title, {"tokenSymbol":"CELO"}'} | ${'gasFeeWarning.descriptionMaxAmount, {"action":"gasFeeWarning.actions.sending","tokenSymbol":"CELO"}'} | ${'gasFeeWarning.ctaGasToken, {"verb":"gasFeeWarning.verb.send"}'}
${'sending max amount of ETH'} | ${GasFeeWarningFlow.Send} | ${mockPreparedTransactionNeedDecreaseEth} | ${'ETH'} | ${'gasFeeWarning.title, {"tokenSymbol":"ETH"}'} | ${'gasFeeWarning.descriptionMaxAmount, {"action":"gasFeeWarning.actions.sending","tokenSymbol":"ETH"}'} | ${'gasFeeWarning.ctaGasToken, {"verb":"gasFeeWarning.verb.send"}'}
${'sending with insufficient CELO'} | ${GasFeeWarningFlow.Send} | ${mockPreparedTransactionNotEnoughCelo} | ${'CELO'} | ${'gasFeeWarning.title, {"tokenSymbol":"CELO"}'} | ${'gasFeeWarning.descriptionNotEnoughGas, {"action":"gasFeeWarning.actions.sending","tokenSymbol":"CELO"}'} | ${'gasFeeWarning.cta, {"tokenSymbol":"CELO"}'}
${'sending with insufficient ETH'} | ${GasFeeWarningFlow.Send} | ${mockPreparedTransactionNotEnoughEth} | ${'ETH'} | ${'gasFeeWarning.title, {"tokenSymbol":"ETH"}'} | ${'gasFeeWarning.descriptionNotEnoughGas, {"action":"gasFeeWarning.actions.sending","tokenSymbol":"ETH"}'} | ${'gasFeeWarning.cta, {"tokenSymbol":"ETH"}'}
${'swapping max amount of CELO'} | ${GasFeeWarningFlow.Swap} | ${mockPreparedTransactionNeedDecreaseCelo} | ${'CELO'} | ${'gasFeeWarning.title, {"tokenSymbol":"CELO"}'} | ${'gasFeeWarning.descriptionMaxAmount, {"action":"gasFeeWarning.actions.swapping","tokenSymbol":"CELO"}'} | ${'gasFeeWarning.ctaGasToken, {"verb":"gasFeeWarning.verb.swap"}'}
${'swapping max amount of ETH'} | ${GasFeeWarningFlow.Swap} | ${mockPreparedTransactionNeedDecreaseEth} | ${'ETH'} | ${'gasFeeWarning.title, {"tokenSymbol":"ETH"}'} | ${'gasFeeWarning.descriptionMaxAmount, {"action":"gasFeeWarning.actions.swapping","tokenSymbol":"ETH"}'} | ${'gasFeeWarning.ctaGasToken, {"verb":"gasFeeWarning.verb.swap"}'}
${'swapping with insufficient CELO'} | ${GasFeeWarningFlow.Swap} | ${mockPreparedTransactionNotEnoughCelo} | ${'CELO'} | ${'gasFeeWarning.title, {"tokenSymbol":"CELO"}'} | ${'gasFeeWarning.descriptionNotEnoughGas, {"action":"gasFeeWarning.actions.swapping","tokenSymbol":"CELO"}'} | ${'gasFeeWarning.cta, {"tokenSymbol":"CELO"}'}
${'swapping with insufficient ETH'} | ${GasFeeWarningFlow.Swap} | ${mockPreparedTransactionNotEnoughEth} | ${'ETH'} | ${'gasFeeWarning.title, {"tokenSymbol":"ETH"}'} | ${'gasFeeWarning.descriptionNotEnoughGas, {"action":"gasFeeWarning.actions.swapping","tokenSymbol":"ETH"}'} | ${'gasFeeWarning.cta, {"tokenSymbol":"ETH"}'}
${'withdrawing max amount of CELO'} | ${GasFeeWarningFlow.Withdraw} | ${mockPreparedTransactionNeedDecreaseCelo} | ${'CELO'} | ${'gasFeeWarning.title, {"tokenSymbol":"CELO"}'} | ${'gasFeeWarning.descriptionMaxAmount, {"action":"gasFeeWarning.actions.withdrawing","tokenSymbol":"CELO"}'} | ${'gasFeeWarning.ctaGasToken, {"verb":"gasFeeWarning.verb.withdraw"}'}
${'withdrawing max amount of ETH'} | ${GasFeeWarningFlow.Withdraw} | ${mockPreparedTransactionNeedDecreaseEth} | ${'ETH'} | ${'gasFeeWarning.title, {"tokenSymbol":"ETH"}'} | ${'gasFeeWarning.descriptionMaxAmount, {"action":"gasFeeWarning.actions.withdrawing","tokenSymbol":"ETH"}'} | ${'gasFeeWarning.ctaGasToken, {"verb":"gasFeeWarning.verb.withdraw"}'}
${'withdrawing with insufficient CELO'} | ${GasFeeWarningFlow.Withdraw} | ${mockPreparedTransactionNotEnoughCelo} | ${'CELO'} | ${'gasFeeWarning.title, {"tokenSymbol":"CELO"}'} | ${'gasFeeWarning.descriptionNotEnoughGas, {"action":"gasFeeWarning.actions.withdrawing","tokenSymbol":"CELO"}'} | ${'gasFeeWarning.cta, {"tokenSymbol":"CELO"}'}
${'withdrawing with insufficient ETH'} | ${GasFeeWarningFlow.Withdraw} | ${mockPreparedTransactionNotEnoughEth} | ${'ETH'} | ${'gasFeeWarning.title, {"tokenSymbol":"ETH"}'} | ${'gasFeeWarning.descriptionNotEnoughGas, {"action":"gasFeeWarning.actions.withdrawing","tokenSymbol":"ETH"}'} | ${'gasFeeWarning.cta, {"tokenSymbol":"ETH"}'}
${'depositing max amount of CELO'} | ${GasFeeWarningFlow.Deposit} | ${mockPreparedTransactionNeedDecreaseCelo} | ${'CELO'} | ${'gasFeeWarning.title, {"tokenSymbol":"CELO"}'} | ${'gasFeeWarning.descriptionMaxAmount, {"action":"gasFeeWarning.actions.depositing","tokenSymbol":"CELO"}'} | ${'gasFeeWarning.ctaGasToken, {"verb":"gasFeeWarning.verb.deposit"}'}
${'depositing max amount of ETH'} | ${GasFeeWarningFlow.Deposit} | ${mockPreparedTransactionNeedDecreaseEth} | ${'ETH'} | ${'gasFeeWarning.title, {"tokenSymbol":"ETH"}'} | ${'gasFeeWarning.descriptionMaxAmount, {"action":"gasFeeWarning.actions.depositing","tokenSymbol":"ETH"}'} | ${'gasFeeWarning.ctaGasToken, {"verb":"gasFeeWarning.verb.deposit"}'}
${'depositing with insufficient CELO'} | ${GasFeeWarningFlow.Deposit} | ${mockPreparedTransactionNotEnoughCelo} | ${'CELO'} | ${'gasFeeWarning.title, {"tokenSymbol":"CELO"}'} | ${'gasFeeWarning.descriptionNotEnoughGas, {"action":"gasFeeWarning.actions.depositing","tokenSymbol":"CELO"}'} | ${'gasFeeWarning.cta, {"tokenSymbol":"CELO"}'}
${'depositing with insufficient ETH'} | ${GasFeeWarningFlow.Deposit} | ${mockPreparedTransactionNotEnoughEth} | ${'ETH'} | ${'gasFeeWarning.title, {"tokenSymbol":"ETH"}'} | ${'gasFeeWarning.descriptionNotEnoughGas, {"action":"gasFeeWarning.actions.depositing","tokenSymbol":"ETH"}'} | ${'gasFeeWarning.cta, {"tokenSymbol":"ETH"}'}
${'dapp transaction with max amount of CELO'} | ${GasFeeWarningFlow.Dapp} | ${mockPreparedTransactionNeedDecreaseCelo} | ${'CELO'} | ${'gasFeeWarning.titleDapp'} | ${'gasFeeWarning.descriptionDapp, {"tokenSymbol":"CELO"}'} | ${undefined}
${'dapp transaction with max amount of ETH'} | ${GasFeeWarningFlow.Dapp} | ${mockPreparedTransactionNeedDecreaseEth} | ${'ETH'} | ${'gasFeeWarning.titleDapp'} | ${'gasFeeWarning.descriptionDapp, {"tokenSymbol":"ETH"}'} | ${undefined}
${'dapp transaction with insufficient CELO'} | ${GasFeeWarningFlow.Dapp} | ${mockPreparedTransactionNotEnoughCelo} | ${'CELO'} | ${'gasFeeWarning.titleDapp'} | ${'gasFeeWarning.descriptionDapp, {"tokenSymbol":"CELO"}'} | ${undefined}
${'dapp transaction with insufficient ETH'} | ${GasFeeWarningFlow.Dapp} | ${mockPreparedTransactionNotEnoughEth} | ${'ETH'} | ${'gasFeeWarning.titleDapp'} | ${'gasFeeWarning.descriptionDapp, {"tokenSymbol":"ETH"}'} | ${undefined}
MuckT marked this conversation as resolved.
Show resolved Hide resolved
`(
'renders error correctly when $scenario',
({ flow, prepareTransactionsResult, feeCurrencySymbol, title, description, ctaLabel }) => {
const store = createMockStore()
const onPressCta = jest.fn()
const { getByTestId, getByText } = render(
<Provider store={store}>
<GasFeeWarning
flow={flow}
testIdPrefix={'test'}
prepareTransactionsResult={prepareTransactionsResult}
onPressCta={ctaLabel ? onPressCta : undefined}
/>
</Provider>
)
expect(getByTestId('test/GasFeeWarning')).toBeTruthy()
expect(AppAnalytics.track).toHaveBeenCalledTimes(1)
expect(AppAnalytics.track).toHaveBeenCalledWith(AppEvents.show_gas_fee_warning, {
flow,
errorType: prepareTransactionsResult.type,
tokenNeeded: feeCurrencySymbol,
})
expect(getByText(title)).toBeTruthy()
expect(getByText(description)).toBeTruthy()
if (ctaLabel) {
fireEvent.press(getByText(ctaLabel))
}
expect(ctaLabel ? getByText(ctaLabel) : true).toBeTruthy()
expect(onPressCta).toHaveBeenCalledTimes(ctaLabel ? 1 : 0)
}
)
})
111 changes: 111 additions & 0 deletions src/components/GasFeeWarning.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import React, { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { StyleSheet } from 'react-native'
import AppAnalytics from 'src/analytics/AppAnalytics'
import { AppEvents } from 'src/analytics/Events'
import InLineNotification, { NotificationVariant } from 'src/components/InLineNotification'
import { Spacing } from 'src/styles/styles'
import { PreparedTransactionsResult } from 'src/viem/prepareTransactions'

export enum GasFeeWarningFlow {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you consider string literals over enum for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no but I can change it to that, in Valora should we prefer string literals over enums? Or what is the convention?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think we have a defined convention, but we did talk about this in an eng sync and I think we've been favoring literals over enums recently

Send = 'Send',
Swap = 'Swap',
Deposit = 'Deposit',
Withdraw = 'Withdraw',
Dapp = 'Dapp',
}

function GasFeeWarning({
prepareTransactionsResult,
flow,
onPressCta,
testIdPrefix,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this required in order to disambiguate warnings? We should never have more than one of these warnings at once, no? Or is this just to add additional context to the test ID?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was just to add additional context to the test ID to make it clearer in tests, but you're right there should never be more than one at once so it is not needed. I can remove if that would be cleaner.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed in d6b4c16

}: {
prepareTransactionsResult?: PreparedTransactionsResult
flow: GasFeeWarningFlow
onPressCta?: () => void
testIdPrefix?: string
}) {
const { t } = useTranslation()

const flowToActionString = {
[GasFeeWarningFlow.Send]: t('gasFeeWarning.actions.sending'),
[GasFeeWarningFlow.Swap]: t('gasFeeWarning.actions.swapping'),
[GasFeeWarningFlow.Deposit]: t('gasFeeWarning.actions.depositing'),
[GasFeeWarningFlow.Withdraw]: t('gasFeeWarning.actions.withdrawing'),
[GasFeeWarningFlow.Dapp]: undefined,
}

const flowToVerbString = {
[GasFeeWarningFlow.Send]: t('gasFeeWarning.verb.send'),
[GasFeeWarningFlow.Swap]: t('gasFeeWarning.verb.swap'),
[GasFeeWarningFlow.Deposit]: t('gasFeeWarning.verb.deposit'),
[GasFeeWarningFlow.Withdraw]: t('gasFeeWarning.verb.withdraw'),
[GasFeeWarningFlow.Dapp]: undefined,
}

useEffect(() => {
if (prepareTransactionsResult && prepareTransactionsResult.type !== 'possible') {
AppAnalytics.track(AppEvents.show_gas_fee_warning, {
flow,
errorType: prepareTransactionsResult.type,
tokenNeeded: feeCurrencySymbol,
})
}
}, [prepareTransactionsResult])

if (!prepareTransactionsResult || prepareTransactionsResult.type === 'possible') {
return null
MuckT marked this conversation as resolved.
Show resolved Hide resolved
}

const feeCurrencySymbol =
prepareTransactionsResult.type === 'not-enough-balance-for-gas'
? prepareTransactionsResult.feeCurrencies[0].symbol
Copy link
Contributor Author

@finnian0826 finnian0826 Dec 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the designs, it seems like it leans towards hardcoding this to be CELO or ETH (this is cases 2-4), however in all of the use cases currently it is done like this (using prepareTransactionsResult.feeCurrencies[0]). I think it is easier to keep it this way for two reasons:

  • ETH tokenId is not available in NetworkConfig, and would be needed for CTA (in order to prefill in CICO flow), so would need to be added for all networks, increasing amount of hardcoded things
  • The CTA is implemented in the component that uses this warning, so the implementer would have to get the hardcoded tokenId based on the network of the prepared transaction, rather than just looking at the first feeCurrencies.

I can add in the ETH tokenId's if we want but wanted to check first about doing it this way instead.

: prepareTransactionsResult.feeCurrency.symbol

const title =
flow === GasFeeWarningFlow.Dapp
? t('gasFeeWarning.titleDapp')
: t('gasFeeWarning.title', { tokenSymbol: feeCurrencySymbol })
const description =
flow === GasFeeWarningFlow.Dapp
? t('gasFeeWarning.descriptionDapp', { tokenSymbol: feeCurrencySymbol })
: prepareTransactionsResult.type === 'not-enough-balance-for-gas'
? t('gasFeeWarning.descriptionNotEnoughGas', {
action: flowToActionString[flow],
tokenSymbol: feeCurrencySymbol,
})
: t('gasFeeWarning.descriptionMaxAmount', {
action: flowToActionString[flow],
tokenSymbol: feeCurrencySymbol,
})
const ctaLabel =
flow === GasFeeWarningFlow.Dapp
? undefined
: prepareTransactionsResult.type === 'not-enough-balance-for-gas'
? t('gasFeeWarning.cta', { tokenSymbol: feeCurrencySymbol })
: t('gasFeeWarning.ctaGasToken', {
verb: flowToVerbString[flow],
})
return (
<InLineNotification
variant={NotificationVariant.Warning}
title={title}
description={description}
ctaLabel={ctaLabel}
onPressCta={onPressCta}
style={styles.warning}
testID={`${testIdPrefix}/GasFeeWarning`}
/>
)
}

const styles = StyleSheet.create({
warning: {
marginTop: Spacing.Regular16,
paddingHorizontal: Spacing.Regular16,
borderRadius: 16,
},
})

export default GasFeeWarning
10 changes: 3 additions & 7 deletions src/earn/EarnEnterAmount.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -917,7 +917,7 @@ describe('EarnEnterAmount', () => {
})
})

it('should track analytics and navigate correctly when tapping cta to add gas', async () => {
it('should show gas warning error when prepareTransactionsResult is type not-enough-balance-for-gas, and tapping cta behaves as expected', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we also add a test for the need-decrease-spend-amount-for-gas? since the cta action for that is set by EarnEnterAmount

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new unit test added in 81a166d

jest.mocked(usePrepareEnterAmountTransactionsCallback).mockReturnValue({
prepareTransactionsResult: {
prepareTransactionsResult: mockPreparedTransactionNotEnough,
Expand All @@ -934,12 +934,8 @@ describe('EarnEnterAmount', () => {
</Provider>
)

await waitFor(() => expect(getByTestId('EarnEnterAmount/NotEnoughForGasWarning')).toBeTruthy())
fireEvent.press(
getByText(
'earnFlow.enterAmount.notEnoughBalanceForGasWarning.noGasCta, {"feeTokenSymbol":"ETH","network":"Arbitrum Sepolia"}'
)
)
await waitFor(() => expect(getByTestId('EarnEnterAmount/GasFeeWarning')).toBeTruthy())
fireEvent.press(getByText('gasFeeWarning.cta, {"tokenSymbol":"ETH"}'))
expect(AppAnalytics.track).toHaveBeenCalledWith(EarnEvents.earn_deposit_add_gas_press, {
gasTokenId: mockArbEthTokenId,
networkId: NetworkId['arbitrum-sepolia'],
Expand Down
Loading
Loading