Skip to content

refactor(stake): use native stack navigators for Stake routes#30220

Open
weitingsun wants to merge 4 commits into
mainfrom
wsun/stake-native-stack-update
Open

refactor(stake): use native stack navigators for Stake routes#30220
weitingsun wants to merge 4 commits into
mainfrom
wsun/stake-native-stack-update

Conversation

@weitingsun
Copy link
Copy Markdown
Contributor

@weitingsun weitingsun commented May 14, 2026

Description

Migrates the Stake screen and modal navigators from @react-navigation/stack to @react-navigation/native-stack(POC), and replaces getStakingNavbar + useEffect(setOptions(...)) with an in-screen HeaderStandard on three Stake flows.

Why: Setting headers via useEffect + setOptions on native stack causes a visible flicker on first paint (the default native header renders, then is replaced); for these screens we now configure headerShown: false at the route level and render the header in-screen with HeaderStandard, which eliminates the flicker.

What changed

  1. Stake/routes/index.tsx:
  • createStackNavigator → createNativeStackNavigator for both StakeScreenStack and StakeModalStack.
  • Modal stack switched to clearNativeStackNavigatorOptions + transparentModalScreenOptions (native-stack equivalents of the prior preset).
  • screenOptions.headerShadowVisible: false.
  • headerShown: false on STAKE, STAKE_CONFIRMATION, UNSTAKE_CONFIRMATION, EARNINGS_HISTORY.
  1. StakeConfirmationView, UnstakeConfirmationView, StakeEarningsHistoryView: replaced legacy header setup with HeaderStandard; back button preserves the existing analytics events (STAKE_CONFIRMATION_BACK_CLICKED, UNSTAKE_CONFIRMATION_BACK_CLICKED) via useAnalytics.
    Note I am leaving migration EarnWithDrawInputView.tsx out on purpose because this navbar has more logic so it's better for the team to do the migration

  2. UnstakeConfirmationView.styles.ts: mainContainer height: '100%' → flex: 1 so the footer (Cancel / Continue) lays out correctly under the new flex parent + HeaderStandard.

  3. EarnInputView: removed the now-redundant useEffect(() => navigation.setOptions({ headerShown: false })) (the route owns it).

  4. Tests: navigation mocks now include goBack; StakeEarningsHistoryView.test.tsx was rewritten to assert on the rendered header title instead of setOptions / getStakingNavbar (which the screen no longer calls).

Android test build: https://github.com/MetaMask/metamask-mobile/actions/runs/25891826048

Changelog

CHANGELOG entry:null

Related issues

Fixes:

Manual testing steps

Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]

Screenshots/Recordings

Please note that some of these flows are not representing what app is behaving right now. I hardcoded some of the screens to see the navigation behaviours

Before

Stake before 1 stake after 2 stake confirmation before

After

stake after 1 stake after 2 stake confirmation after

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
    • Ideally on a mid-range device; emulator is acceptable
  • I've tested with a power user scenario
    • Use these power-user SRPs to import wallets with many accounts and tokens
  • I've instrumented key operations with Sentry traces for production performance metrics

For performance guidelines and tooling, see the Performance Guide.

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Medium Risk
Navigation stack implementation and header rendering for core staking flows are changed, which could impact screen transitions, header visibility, and back-navigation/analytics if misconfigured. Changes are localized to Stake/Earn staking screens with updated tests covering the new back behavior.

Overview
Stake navigation is migrated from @react-navigation/stack to @react-navigation/native-stack, including modal presentation options via clearNativeStackNavigatorOptions + transparentModalScreenOptions and default headerShadowVisible: false.

Three Stake screens (StakeConfirmationView, UnstakeConfirmationView, StakeEarningsHistoryView) now render HeaderStandard in-screen with route-level headerShown: false, moving back-button analytics tracking into explicit onBack handlers (and adding test IDs for back buttons). EarnInputView removes a redundant navigation.setOptions({ headerShown: false }), and UnstakeConfirmationView layout is adjusted (height: '100%'flex: 1) to fit the new header structure.

Tests are updated to stop asserting on setOptions/getStakingNavbar and instead validate rendered header titles plus goBack + analytics event tracking on back presses.

Reviewed by Cursor Bugbot for commit d5e6dcc. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions
Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamaskbotv2 metamaskbotv2 Bot added the team-mobile-platform Mobile Platform team label May 14, 2026
@weitingsun weitingsun marked this pull request as ready for review May 14, 2026 23:30
@weitingsun weitingsun requested a review from a team as a code owner May 14, 2026 23:30
name={Routes.STAKING.STAKE}
component={EarnInputView}
options={{ headerShown: false }}
/>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

UNSTAKE route gets header flicker after native stack migration

Medium Severity

The UNSTAKE route's component (EarnWithdrawInputView) still configures its header via useEffect + navigation.setOptions(getStakingNavbar(...)). Migrating the navigator from createStackNavigator to createNativeStackNavigator introduces the exact visible header flicker the PR describes and fixes for other screens. The UNSTAKE route lacks headerShown: false and an in-screen HeaderStandard, so the default native header renders first, then gets replaced on the next frame by the JS-configured header.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f194b46. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I am leaving this out on purpose because EarnWithdrawInputView seems to be doing more with their navbar so I am leaving this to the team to migrate over to HeaderStandard

Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a2c1345. Configure here.

@weitingsun weitingsun self-assigned this May 15, 2026
@github-project-automation github-project-automation Bot moved this to Needs dev review in PR review queue May 15, 2026
@github-actions
Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeStake, SmokeConfirmations
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: medium
  • AI Confidence: 90%
click to see 🤖 AI reasoning details

E2E Test Selection:
The changes are focused on the Stake/Earn/Unstake UI flows:

  1. Navigation stack migration (routes/index.tsx): Migrated from createStackNavigator to createNativeStackNavigator for both the main Stack and ModalStack. This is a significant navigation change that affects screen transitions, header rendering, and modal presentation (transparentModal). The clearNativeStackNavigatorOptions and transparentModalScreenOptions replace the old options.

  2. Header refactoring (StakeConfirmationView, UnstakeConfirmationView, StakeEarningsHistoryView): Replaced the old getStakingNavbar + useEffect pattern with the new HeaderStandard component from @metamask/design-system-react-native. This changes how headers are rendered in these views.

  3. EarnInputView: Removed redundant useEffect that set headerShown: false since this is now handled at the navigator level.

  4. Style fix (UnstakeConfirmationView.styles.ts): Changed height: '100%' to flex: 1 for proper layout behavior.

SmokeStake is selected because these changes directly affect the stake entry, stake confirmation, unstake confirmation, and earnings history views - the core staking flows.

SmokeConfirmations is selected per the SmokeStake tag description: "When selecting SmokeStake, also select SmokeConfirmations (transaction confirmations are part of the flow)." The StakeConfirmationView and UnstakeConfirmationView are confirmation screens that are part of the staking flow.

No other tags are needed as the changes are scoped to the Stake/Earn UI components and don't touch shared navigation infrastructure, browser, accounts, network, or other feature areas.

Performance Test Selection:
The migration from createStackNavigator to createNativeStackNavigator is generally a performance improvement (native stack is more performant), not a regression. The header component changes are UI-only refactors. No performance test tags are warranted for these changes.

View GitHub Actions results

@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown
Contributor

@Matt561 Matt561 left a comment

Choose a reason for hiding this comment

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

@weitingsun When testing, the withdrawal screen (staking and lending) renders with iOS' "glass" buttons in the header.

Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size-M team-mobile-platform Mobile Platform team

Projects

Status: Needs dev review

Development

Successfully merging this pull request may close these issues.

2 participants