Skip to content

Conversation

tomasjakl
Copy link
Contributor

@tomasjakl tomasjakl commented Oct 3, 2025

Description

Related Issue

Resolve #21192

πŸ”πŸ–₯️ Suite native android test results: View in Currents

@tomasjakl tomasjakl added the mobile Suite Lite issues and PRs label Oct 3, 2025
@tomasjakl tomasjakl linked an issue Oct 3, 2025 that may be closed by this pull request
@tomasjakl tomasjakl force-pushed the 21192-mobile-swap-refactor-approval-screen-and-wire-it-to-trade-data branch from 922ae03 to 8598d73 Compare October 5, 2025 22:33
@tomasjakl tomasjakl force-pushed the 21192-mobile-swap-refactor-approval-screen-and-wire-it-to-trade-data branch from 8598d73 to b913f78 Compare October 6, 2025 01:58
@tomasjakl tomasjakl marked this pull request as ready for review October 6, 2025 01:59
@tomasjakl tomasjakl requested a review from a team as a code owner October 6, 2025 01:59
@tomasjakl
Copy link
Contributor Author

@coderabbitai review

Copy link

coderabbitai bot commented Oct 6, 2025

βœ… Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

coderabbitai bot commented Oct 6, 2025

Walkthrough

  • Adds new intl message approvalSuccessAlert.
  • Expands approval flow: introduces approval status branching with new status 'needs_increase' and function tokenSupportsIncreasingAllowance.
  • Updates quote selection hook to navigate based on approval status and token allowance capability to Preview, Approval, or Revoke screens.
  • Refactors navigation types: TradingExchangePreview, TradingExchangeApproval, TradingExchangeRevoke now carry params.
  • Updates Approval, Preview, and Revoke screens to consume route params; Approval screen manages approval type and success path to Preview with isApproved flag.
  • Enhances ExchangeApprovalLimitSheet to be controlled via props and select approval type.
  • Adjusts formatting/render logic for amounts and various tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Linked Issues Check ⚠️ Warning The implementation addresses most coding objectives from issue #21192, including the fixed getApprovalStatus logic, navigation to the approval screen on needs_approval, default DexApprovalType, bottomsheet options, and confirmTrade and fetchFeesAndCompose integration, but the preview screen alert text and parameter handling do not match the desktop message or the specified revoke-flow semantics. Adjust the preview screen to display the desktop text β€œYou’ve approved this token, but the limit is too low. Increase it to continue.” and ensure the route parameter clearly reflects a previous revoke scenario.
Description Check ⚠️ Warning The pull request description retains only the template placeholders for the general summary and detailed description without any actual content and omits the required Screenshots section, leaving key template fields unfilled. Please complete the Description section with a detailed summary of your changes and either provide the Screenshots section or remove it if no visuals are necessary.
βœ… Passed checks (3 passed)
Check name Status Explanation
Title Check βœ… Passed The title succinctly describes the primary feature of wiring the approval and revoke screens to trade data and follows the conventional β€œfeat(...)” format without extraneous information.
Out of Scope Changes Check βœ… Passed All changes in this pull request pertain exclusively to wiring the approval and revoke screens to trade data, updating navigation types, messages, hooks, and tests, without any unrelated or out-of-scope modifications.
Docstring Coverage βœ… Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • πŸ“ Generate docstrings
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 21192-mobile-swap-refactor-approval-screen-and-wire-it-to-trade-data

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❀️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
suite-native/module-trading/src/hooks/exchange/__tests__/useExchangeSelectQuote.test.ts (1)

225-225: Consider explicit params for TradingExchangePreview navigation.

The tests pass an empty object {} for TradingExchangePreview params. While technically valid since isApproved is optional, consider being more explicit for clarity:

-expect(mockNavigation.navigate).toHaveBeenCalledWith('TradingExchangePreview', {});
+expect(mockNavigation.navigate).toHaveBeenCalledWith('TradingExchangePreview', { isApproved: false });

This makes the intent clearer and matches the param type definition.

Also applies to: 287-287, 311-311

suite-native/module-trading/src/components/exchange/ExchangeApprovalLimitSheet/__tests__/ExchangeApprovalLimitSheet.comp.test.tsx (1)

101-111: Strengthen the β€œpasses correct props” assertions

These two tests never interact with the sheet – they just confirm that the mocked callback exists, so a regression in the approval-type wiring would still pass. Please drive the component (e.g., press the Unlimited/Limited card) and assert that mockOnApprovalTypeSelect receives 'INFINITE' / 'MINIMAL', and optionally that the selected state updates. This will turn the tests into real safeguards.

πŸ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 8b87f08 and b913f78.

πŸ“’ Files selected for processing (15)
  • suite-native/intl/src/messages.ts (1 hunks)
  • suite-native/module-trading/src/components/exchange/ExchangeApprovalLimitSheet/ExchangeApprovalLimitSheet.tsx (4 hunks)
  • suite-native/module-trading/src/components/exchange/ExchangeApprovalLimitSheet/__tests__/ExchangeApprovalLimitSheet.comp.test.tsx (4 hunks)
  • suite-native/module-trading/src/components/exchange/ExchangePreview/ExchangePreviewView.tsx (2 hunks)
  • suite-native/module-trading/src/hooks/exchange/__tests__/useExchangeSelectQuote.test.ts (3 hunks)
  • suite-native/module-trading/src/hooks/exchange/useExchangeSelectQuote.ts (3 hunks)
  • suite-native/module-trading/src/screens/TradingExchangeApprovalScreen.tsx (5 hunks)
  • suite-native/module-trading/src/screens/TradingExchangePreviewScreen.tsx (3 hunks)
  • suite-native/module-trading/src/screens/TradingExchangeRevokeScreen.tsx (5 hunks)
  • suite-native/module-trading/src/screens/__tests__/TradingExchangeApprovalScreen.comp.test.tsx (2 hunks)
  • suite-native/module-trading/src/screens/__tests__/TradingExchangePreviewScreen.comp.test.tsx (3 hunks)
  • suite-native/module-trading/src/screens/__tests__/TradingExchangeRevokeScreen.comp.test.tsx (2 hunks)
  • suite-native/module-trading/src/utils/general/__tests__/approvalStatusUtils.test.ts (2 hunks)
  • suite-native/module-trading/src/utils/general/approvalStatusUtils.ts (1 hunks)
  • suite-native/navigation/src/navigators.ts (2 hunks)
🧰 Additional context used
🧠 Learnings (5)
πŸ“š Learning: 2025-08-27T09:59:23.527Z
Learnt from: vytick
PR: trezor/trezor-suite#20985
File: suite-native/module-trading/src/screens/TradingExchangePreviewScreen.tsx:92-106
Timestamp: 2025-08-27T09:59:23.527Z
Learning: The TradingExchangePreviewScreen in suite-native/module-trading/src/screens/TradingExchangePreviewScreen.tsx is POC code with intentional technical debt around error handling in flow steps, as it will be heavily reworked in follow-up PRs.

Applied to files:

  • suite-native/module-trading/src/screens/__tests__/TradingExchangeApprovalScreen.comp.test.tsx
  • suite-native/module-trading/src/screens/__tests__/TradingExchangeRevokeScreen.comp.test.tsx
  • suite-native/module-trading/src/hooks/exchange/__tests__/useExchangeSelectQuote.test.ts
  • suite-native/module-trading/src/components/exchange/ExchangePreview/ExchangePreviewView.tsx
  • suite-native/module-trading/src/screens/__tests__/TradingExchangePreviewScreen.comp.test.tsx
  • suite-native/navigation/src/navigators.ts
  • suite-native/module-trading/src/hooks/exchange/useExchangeSelectQuote.ts
  • suite-native/module-trading/src/screens/TradingExchangePreviewScreen.tsx
  • suite-native/module-trading/src/screens/TradingExchangeRevokeScreen.tsx
  • suite-native/module-trading/src/screens/TradingExchangeApprovalScreen.tsx
πŸ“š Learning: 2025-02-04T13:18:21.530Z
Learnt from: jbazant
PR: trezor/trezor-suite#16668
File: suite-native/module-trading/src/components/TradeableAssetsSheet/TradeableAssetsSheet.tsx:0-0
Timestamp: 2025-02-04T13:18:21.530Z
Learning: The mock data arrays in `suite-native/module-trading/src/components/TradeableAssetsSheet/TradeableAssetsSheet.tsx` are intentionally used as visual stubs and will be replaced with real data fetching in future commits.

Applied to files:

  • suite-native/module-trading/src/screens/__tests__/TradingExchangeApprovalScreen.comp.test.tsx
  • suite-native/module-trading/src/screens/__tests__/TradingExchangePreviewScreen.comp.test.tsx
πŸ“š Learning: 2025-02-21T23:00:49.788Z
Learnt from: jbazant
PR: trezor/trezor-suite#17164
File: suite-native/module-trading/src/components/general/TradeableAssetsSheet/__tests__/TradeableAssetListItem.comp.test.tsx:61-75
Timestamp: 2025-02-21T23:00:49.788Z
Learning: The `renderWithStore` utility from `suite-native/test-utils` accepts a `preloadedState` option to set up initial Redux state for tests. The store initialization is asynchronous, so tests should use `findBy*` queries instead of `getBy*` queries.

Applied to files:

  • suite-native/module-trading/src/screens/__tests__/TradingExchangeApprovalScreen.comp.test.tsx
πŸ“š Learning: 2025-09-30T20:12:08.320Z
Learnt from: jbazant
PR: trezor/trezor-suite#22046
File: suite-native/module-trading/src/components/exchange/ExchangePreview/ExchangeFeePickerCard.tsx:13-28
Timestamp: 2025-09-30T20:12:08.320Z
Learning: In suite-native/module-trading, when a parent component like ExchangePreviewView is memoized, child components such as ExchangeFeePickerCard don't need to be memoized as they won't re-render unless the parent re-renders, and adding memo() would only introduce unnecessary overhead.

Applied to files:

  • suite-native/module-trading/src/components/exchange/ExchangePreview/ExchangePreviewView.tsx
πŸ“š Learning: 2025-09-30T20:12:19.587Z
Learnt from: jbazant
PR: trezor/trezor-suite#22046
File: suite-native/module-trading/src/components/exchange/ExchangePreview/ExchangeFromAccountTradePreviewCard.tsx:16-38
Timestamp: 2025-09-30T20:12:19.587Z
Learning: In suite-native/module-trading, when a component like ExchangeFromAccountTradePreviewCard is only used from an already memoized parent component (like ExchangePreviewView), adding React.memo to the child component adds overhead without performance benefit and should be avoided.

Applied to files:

  • suite-native/module-trading/src/components/exchange/ExchangePreview/ExchangePreviewView.tsx
πŸ”‡ Additional comments (12)
suite-native/module-trading/src/screens/__tests__/TradingExchangeApprovalScreen.comp.test.tsx (2)

15-20: LGTM! Mock for useExchangeFlow is well-structured.

The mock provides the necessary confirmTrade and fetchFeesAndCompose functions that the screen under test expects from the exchange flow hook.


56-69: Approve code: quote extracted from route.params TradingExchangeApprovalScreen destructures quote on line 48; no changes needed.

suite-native/intl/src/messages.ts (1)

2318-2318: LGTM! Translation key properly added.

The new approvalSuccessAlert message is correctly placed under moduleTrading.tradingExchangePreviewScreen and provides clear user-facing text for the approval success state.

suite-native/module-trading/src/screens/__tests__/TradingExchangeRevokeScreen.comp.test.tsx (2)

38-51: LGTM! Test properly updated for route-based data flow.

The renderScreen function now correctly passes the route prop with { params: { quote: testQuote } }, aligning with the updated navigation parameter types.


75-80: Correct test update for multiple matching elements.

Using getAllByText and expecting 2 occurrences of "0 USDC" is the proper way to test when the same text appears multiple times on screen (for current limit and new limit).

suite-native/module-trading/src/hooks/exchange/__tests__/useExchangeSelectQuote.test.ts (1)

258-399: Excellent test coverage of approval status navigation paths.

The new test suite thoroughly covers all approval status scenarios:

  • approved β†’ TradingExchangePreview
  • not_needed β†’ TradingExchangePreview
  • needs_approval β†’ TradingExchangeApproval
  • needs_increase with token support β†’ TradingExchangeApproval with shouldIncreaseLimit
  • needs_increase without token support β†’ TradingExchangeRevoke with shouldIncreaseLimit
suite-native/module-trading/src/screens/__tests__/TradingExchangePreviewScreen.comp.test.tsx (1)

56-66: Well-designed test helper with optional parameter.

The renderTradingExchangePreviewScreen helper now accepts an optional isApproved parameter (defaulting to false), making it easy to test both the approval success alert and normal preview flows.

suite-native/module-trading/src/screens/TradingExchangePreviewScreen.tsx (2)

39-43: LGTM! Route params properly extracted.

The component correctly destructures params from the route prop and extracts isApproved. The type system guarantees params exists (as an object with optional isApproved), so the destructuring is safe.


143-155: Approval success alert properly implemented.

The conditional rendering of the approval success alert wrapped in Animated.View is well-structured:

  • Alert only shows when isApproved is truthy
  • Uses proper translation key for the message
  • Success variant provides appropriate visual feedback
  • VStack provides consistent spacing
suite-native/navigation/src/navigators.ts (2)

2-2: LGTM! Required type import added.

The ExchangeTrade import from invity-api is necessary for typing the route params that now carry quote data.


342-353: Navigation param types properly defined.

The updated param types for the trading exchange flow are well-structured:

  • TradingExchangePreview: Simple optional boolean flag for approval success state
  • TradingExchangeApproval: Quote data plus optional flags for limit increase and revoke status
  • TradingExchangeRevoke: Quote data plus optional flag for limit increase

This enables type-safe route-based data flow across the approval/revoke screens.

suite-native/module-trading/src/components/exchange/ExchangeApprovalLimitSheet/ExchangeApprovalLimitSheet.tsx (1)

59-74: Nice token-aware formatting

Great touch splitting into CryptoAmountFormatter vs TokenAmountFormatter; this keeps network and token approvals formatted with the right precision.

}
}, [isVisible, openModal]);
useEffect(
() => (isVisible ? openModal() : closeModal()),
Copy link
Contributor

Choose a reason for hiding this comment

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

This calls openModal when removing from parent, right? Do we want it? Why did the previous version not work?

}

const limitAmount = `200.32 ${coinSymbol}`; //TODO
const limitAmount =
Copy link
Contributor

@vytick vytick Oct 6, 2025

Choose a reason for hiding this comment

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

nit:

Suggested change
const limitAmount =
const limitAmountFormatter =

Copy link
Contributor

Choose a reason for hiding this comment

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

I would avoid unnecessary re-renders for this one. Could we use a useMemo or useCallback here, please?

contractAddress={contractAddress}
isChecked={true}
isChecked={selectedApprovalType === 'INFINITE'}
onChange={() => {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit

Suggested change
onChange={() => {
onChange={() => onApprovalTypeSelect('INFINITE')}

contractAddress={contractAddress}
isChecked={false}
isChecked={selectedApprovalType === 'MINIMAL'}
onChange={() => {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit

Suggested change
onChange={() => {
onChange={() => onApprovalTypeSelect('MINIMAL')}

<ExchangeFeePickerCard quote={quote} isTxnError={isTxnError} />
</VStack>
</ScrollView>
<>
Copy link
Contributor

Choose a reason for hiding this comment

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

Q: are there now correct spaces between children? previously 20pts

export const TradingExchangeApprovalScreen = ({
route: { params },
}: TradingExchangeApprovalScreenProps) => {
const { quote, shouldIncreaseLimit, isRevoked } = params;
Copy link
Contributor

Choose a reason for hiding this comment

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

I am still not sure about passing quote via params, but lets give it a try and refactor later if necessary


if (success) {
// TODO
await fetchFeesAndCompose();
Copy link
Contributor

Choose a reason for hiding this comment

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

This wont be needed here, lets delete so we are not confused later

return 'needs_approval';
};

export const tokenSupportsIncreasingAllowance = (contractAddress?: string): boolean => {
Copy link
Contributor

Choose a reason for hiding this comment

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

This can be easily moved to suite-common/trading from desktop and reused. Please, lets do that, so there is single source of truth for both apps.

return (
<Screen header={<ExchangePreviewScreenHeader />}>
<ExchangePreviewView quote={quote} txnErrorString={txnErrorString} />
<VStack spacing="sp20" paddingVertical="sp20">
Copy link
Contributor

Choose a reason for hiding this comment

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

Please move this into ExchangePreviewView

Copy link
Contributor

@vytick vytick left a comment

Choose a reason for hiding this comment

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

I have tested it and it seems to work as expected. Only a few small changes and it is good to merge πŸ‘

({ isVisible, onDismiss }: ExchangeApprovalLimitSheetProps) => {
const { bottomSheetRef, openModal } = useBottomSheetModal();
({
isVisible,
Copy link
Contributor

Choose a reason for hiding this comment

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

What about moving useBottomSheetModal one level up instead of using isVisible? It feels redundant.. maybe we could change the logic directly in useBottomSheetControls What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

Then you could remove the the useEffect logic below as well

const isIncreasingAllowanceSupported =
tokenSupportsIncreasingAllowance(contractAddress);

if (approvalStatus === 'needs_increase' && isIncreasingAllowanceSupported) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Maybe we can simpify it a bit?

if (approvalStatus === 'needs_increase') {
    const route = isIncreasingAllowanceSupported
        ? TradingStackRoutes.TradingExchangeApproval
        : TradingStackRoutes.TradingExchangeRevoke;

    return navigation.navigate(route, {
        quote: candidateQuote,
        shouldIncreaseLimit: true,
    });
}

// fallback
return navigation.navigate(TradingStackRoutes.TradingExchangeApproval, {
    quote: candidateQuote,
});

variant="info"
/>
{!!shouldIncreaseLimit && (
<Animated.View>
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: we can use AnimatedBox from atoms

<Button
onPress={() => {
// TODO
if (shouldIncreaseLimit) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: could we extract it to a separate function please?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mobile Suite Lite issues and PRs
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Mobile Swap: refactor approval screen and wire it to trade data
3 participants