-
Notifications
You must be signed in to change notification settings - Fork 96
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(TokenEnterAmount): add new component to Swap flow #6247
base: main
Are you sure you want to change the base?
Conversation
src/swap/SwapScreenV2.tsx
Outdated
/> | ||
</View> | ||
|
||
<View> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need this <View>
wrapper?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bakoushin I think it's indeed redundant, will remove!
if ( | ||
!quote || | ||
quote.preparedTransactions.type !== 'need-decrease-spend-amount-for-gas' | ||
) | ||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why we need this condition? it seems to lead to a confusing ux.
if i correctly understand its behavior:
- the warning is displayed
- but the CTA press does nothing
why it does nothing? maybe we shoudn't display the warning in the first place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bakoushin As I understand - it's purely for type narrowing. It shouldn't ever evaluate to true
as warnings.showDecreaseSpendForGasWarning
directly contradicts it. But with this condition quote.preparedTransactions
is evaluated to PreparedTransactionsNeedDecreaseSpendAmountForGas
and doesn't need type casting with as
(even thought the actual warnings.showDecreaseSpendForGasWarning
check already ensures the type is right but typescript cannot determine it as it considers it a "different variable" 🤷 )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, yes! it makes sense, thanks! maybe we can add the // Should never happen
comment here -- up to your judjement.
i noticed they are often used in our code base to mark those type guards and allow to just skip them when reading without thinking too much. at least, that's how it works for me 😅
src/swap/SwapScreenV2.tsx
Outdated
feeCurrencies, | ||
})} | ||
style={styles.warning} | ||
onPressCta={onPressLearnMoreFees} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
either the cta label is missing or this handler is redundant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bakoushin you're right! It was like that initially so I assume that it was accidentally left out from clean up.
</View> | ||
</View> | ||
|
||
<View> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need this <View>
wrapper?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bakoushin Yes. Per design, UK disclaimer has to be right above the button and this View
is a direct child of ScrollView
component with styles.contentContainer
which has justifyContent: 'space-between'
. Without this view disclaimer and button will be evenly separated from other blocks (inputs and warnings) across the whole height of the screen instead of sticking together.
src/swap/SwapScreenV2.tsx
Outdated
contentContainerStyle={styles.contentContainer} | ||
keyboardShouldPersistTaps="handled" | ||
> | ||
<View style={{ display: 'flex', justifyContent: 'space-between', flexGrow: 1 }}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is the reason of inlining styles vs including them in the StyleSheet
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and do we need that View
at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- It's just me not doing my due diligence with the styles cleanup after making layout changes. Will move this to a separate class!
- We do need it as it separates block with inputs and warnings from the block with the disclaimer and button which ensures the first block to stay at the very top and the second one - at the very bottom.
src/swap/SwapScreenV2.tsx
Outdated
keyboardShouldPersistTaps="handled" | ||
> | ||
<View style={{ display: 'flex', justifyContent: 'space-between', flexGrow: 1 }}> | ||
<View style={{ flexShrink: 0 }}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need this style?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bakoushin it's indeed redundant, will remove!
src/swap/SwapScreenV2.tsx
Outdated
} | ||
|
||
if (fromToken?.tokenId === selectedToken.tokenId) { | ||
setFromToken(toToken) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need to set "from" token in this handler?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please ignore, got it 😅
src/swap/SwapScreenV2.tsx
Outdated
// if in "from" we select the same token as in "to" then just swap | ||
if (toToken?.tokenId === selectedToken.tokenId) { | ||
setFromToken(toToken) | ||
setToToken(fromToken) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need to set "to" token in this handler?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please ignore, got it 😅
src/swap/SwapScreenV2.tsx
Outdated
AppAnalytics.track(SwapEvents.swap_screen_select_token, { fieldType: Field.FROM }) | ||
// use requestAnimationFrame so that the bottom sheet open animation is done | ||
// after the selectingField value is updated, so that the title of the | ||
// bottom sheet (which depends on selectingField) does not change on the | ||
// screen | ||
requestAnimationFrame(() => tokenBottomSheetFromRef.current?.snapToIndex(0)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- shall we consistenly use the
hadndle
prefix? - perhaps we can extract this code to a separate function e.g.
handleOpenTokenPicker(fieldType: Field)
to emphasize that hanlding is mostly identical
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bakoushin hard agree on both!
|
||
if (!fromToken || !toToken) { | ||
// Should never happen | ||
Logger.error(TAG, 'fromToken or toToken not found') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if that is a type guard (as "should never happen" comment suggests), do we need to log anything?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bakoushin this log was present there from the start. I would keep it just in case somehow in the future we actually hit it for any miraculous reason (even though it should be impossible but who knows 🤷 )
// clearQuote, | ||
// replaceAmountTo, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shall we remove it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or uncomment? 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bakoushin I'll add a TODO comment for this one. This useEffect
initially lacked some dependencies which contradicts the rules of hooks but if I include all used variables/functions - it causes unnecessary re-runs which breaks a bunch of tests. So in order to make this optimization more clear - I'd prefer to make it in a separate PR, especially considering that currently the flow works as intended (just not following the rules of hooks).
So I've just left those commented there to not forget that they should also be acknowledged once I get to the point of optimizing it so I'll add a comment explaining that.
Epic work! 🎉 Left few nits/questions |
📸 Snapshot TestBase build not foundNo build was found for the base commit 8891d00. This is required to generate a snapshot diff for your pull request. It's possible that you created a branch off the base commit before all of the CI steps have finished processing, e.g. the one that uploads a build to our system. If that's the case, no problem! Just wait and this will eventually resolve. 🛸 Powered by Emerge Tools |
src/components/TokenEnterAmount.tsx
Outdated
@@ -201,9 +215,11 @@ export function useEnterAmount(props: { | |||
displayAmount: getDisplayLocalAmount(parsedLocalAmount, localCurrencySymbol), | |||
}, | |||
} | |||
}, [amount, amountType, localCurrencySymbol]) | |||
}, [amount, amountType, localCurrencySymbol, props.token]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not directly related to this PR, but i'm trying to better understand the logic behind the inclusion/exclusion some variables to the dependency list.
for instance, we included the localCurrencySymbol
, but not usdToLocalRate
. yeah, it is highly unlikely that the rate could suddenly change while this component is rendered. but what is the reason for choosing one over another? it seems equally unlikely that the currency symbol will suddenly change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bakoushin that's just again my inattentiveness! Everything used in the scope should be included in the deps list. Will fix this now!
@@ -2823,5 +2823,6 @@ | |||
"availableBalance": "Available: <0></0>", | |||
"selectToken": "Select token", | |||
"fiatPriceUnavailable": "Price unavailable" | |||
} | |||
}, | |||
"on": "on" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i guess the translation of the word "on" is highly dependent on context. perhaps we can use some template to provide it? kind of like this:
"tokenDescription": "{{tokenName}} on {{tokenNetwork}}"
and, with that, shall we include this item in the tokenEnterAmount
group above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need to keep the "on"?
@@ -283,6 +285,9 @@ export default function BeforeDepositBottomSheet({ | |||
const { t } = useTranslation() | |||
|
|||
const { availableShortcutIds } = pool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure if those files should appear in the diff
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bakoushin oops, that's a merge going wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bakoushin this one's resolved!
@@ -127,7 +127,7 @@ describe(PointsHistoryBottomSheet, () => { | |||
).toBeTruthy() | |||
expect(tree.getByText('points.history.cards.createWallet.subtitle')).toBeTruthy() | |||
|
|||
expect(tree.getByText('March')).toBeTruthy() | |||
expect(tree.getByText('March', { exact: false })).toBeTruthy() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perhaps this change is worth its own (yet tiny) PR, so other team members could benefit from the fix before this epic PR is merged.
also, it will provide more context as to why it is fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bakoushin addressed in this PR: #6392
0130a21
to
9c6886d
Compare
src/swap/SwapScreenV2.tsx
Outdated
[Field.FROM]: processedAmountsFrom.token.bignum | ||
? processedAmountsFrom.token.bignum.toString() | ||
: '', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
supernit: perhaps we can make use of a nullish coalescing operator and save 2 lines here? 😅
processedAmountsFrom.token.bignum?.toString() ?? ''
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bakoushin it's even gonna be 4 lines cause it has to be done for both FROM and TO 😄
src/swap/SwapScreenV2.tsx
Outdated
let newSwitchedToNetwork: typeof switchedToNetworkId | null = null | ||
|
||
switch (true) { | ||
// If were selecting a field that was already selected in the other input then switch inputs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like typo: "we're"
src/swap/SwapScreenV2.tsx
Outdated
if (!fromToken) { | ||
// Should never happen | ||
return | ||
} | ||
AppAnalytics.track(SwapEvents.swap_screen_percentage_selected, { | ||
tokenSymbol: fromToken.symbol, | ||
tokenId: fromToken.tokenId, | ||
tokenNetworkId: fromToken.networkId, | ||
percentage, | ||
}) | ||
} | ||
|
||
function onPressLearnMore() { | ||
AppAnalytics.track(SwapEvents.swap_learn_more) | ||
navigate(Screens.WebViewScreen, { uri: links.swapLearnMore }) | ||
} | ||
|
||
function onPressLearnMoreFees() { | ||
AppAnalytics.track(SwapEvents.swap_gas_fees_learn_more) | ||
navigate(Screens.WebViewScreen, { uri: links.transactionFeesLearnMore }) | ||
} | ||
|
||
return ( | ||
<SafeAreaView style={styles.safeAreaContainer} testID="SwapScreen"> | ||
<CustomHeader |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stylistic nit: most of the handlers above start with handle-
, but these two start with on-
. it would be nice to have a consistent naming (my preference is to keep using handle-
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bakoushin fixed!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀
Final PR for new Enter Amount component. This page implements a 2nd version of SwapScreen that uses new Enter Amount component. It is hidden behind the feature flag to mitigate the risks of such a big rework.
SwapScreenV2.test.tsx
file is an exact copy of the existingSwapScreen.test.tsx
. It seems like a huge addition (2k lines) BUT it is a 99% copy-paste just because the new flow is implemented as a new component. The only changes in that file aretestID
props and some translations excerpts. To make life A LOT easier in reviewing this specific file, I suggest doing the following in VSCode to only see the changed lines:SwapScreen.test.tsx
and click "Select for Compare"SwapScreenV2.test.tsx
and click "Compare with Selected"Details of the implementation for clarity:
SwapScreen.test.tsx
.useState
and it would be a mess to keep multipleuseState
s and Redux slice in sync - all the other fields from the slice were moved to the correspondinguseState
s.useMemo
)useEffect
sTest plan
Simulator.Screen.Recording.-.iPhone.15.Pro.Max.-.2024-12-19.at.14.56.55.mp4
Related issues
Relates to RET-1208
Backwards compatibility
Yes
Network scalability
If a new NetworkId and/or Network are added in the future, the changes in this PR will: