Skip to content

feat: upgrade React Native to 0.84.1 with native tabs and scan overlay#420

Open
ignaciosantise wants to merge 13 commits intomainfrom
feat/rn-update
Open

feat: upgrade React Native to 0.84.1 with native tabs and scan overlay#420
ignaciosantise wants to merge 13 commits intomainfrom
feat/rn-update

Conversation

@ignaciosantise
Copy link
Collaborator

Summary

  • Upgraded React Native from 0.82.0 to 0.84.1 and React from 19.1.1 to 19.2.3
  • Implemented native bottom tab navigation using react-native-bottom-tabs for Liquid Glass support on iOS 26+
  • iOS uses native UITabBarController with SF Symbols; Android uses Material BottomNavigationView with SVG icon fallback
  • Added postinstall patch to fix React 19.2 dev-mode Proxy introspection crash with valtio
  • Repositioned Modal/Toast for correct z-ordering with native tab view hierarchy
  • Redesigned scan camera view with dark overlay, rounded square cutout, and corner brackets matching Figma

Architecture

graph TD
    A[App.tsx] --> B[NavigationContainer]
    B --> C[RootStackNavigator]
    B --> D[Modal]
    A --> E[Toast]
    C --> F[HomeTabNavigator]
    C --> G[Scan / Logs / SecretPhrase]
    F --> H[Native TabView]
    H -->|iOS| I[UITabBarController + SF Symbols]
    H -->|Android| J[Material BottomNavigationView + SVG Icons]
    I -->|iOS 26+| K[Liquid Glass Effect]
Loading

Key Changes

  • React Native 0.84.1: Bumped reanimated to 4.2.2, worklets to 0.7.4, valtio to 2.3.1
  • Native Tabs: createNativeBottomTabNavigator replaces JS-based bottom tabs
  • Icons: SF Symbols on iOS (wallet.bifold.fill, square.stack.3d.up.fill, gearshape.fill), SVG on Android
  • Android Styling: Material3 theme, bg-primary tab bar, 1px border-primary divider
  • Dev Patch: patch-react-dev.sh wraps addObjectDiffToProperties in try/catch for valtio Proxy compat
  • Scan Screen: Dark overlay with rounded cutout, white corner brackets, close button, instruction text

Test plan

  • Tested on iPhone 16 simulator (iOS 18) — native tab bar renders correctly
  • Test on iOS 26 simulator for Liquid Glass effect
  • Test on Android emulator for Material styling and SVG icons
  • Verify scan screen overlay and QR detection

🤖 Generated with Claude Code

ignaciosantise and others added 9 commits March 18, 2026 12:54
- Upgrade React Native from 0.82.0 to 0.84.1
- Upgrade React from 19.1.1 to 19.2.3
- Integrate react-native-bottom-tabs (1.1.0) + @bottom-tabs/react-navigation (1.1.0) for native platform tab bars
- Use native UITabBarController on iOS (Liquid Glass on iOS 26+) and Material BottomNavigationView on Android
- Use SF Symbols for iOS tab icons (wallet.bifold.fill, square.stack.3d.up.fill, gearshape.fill)
- Keep SVG icons for Android fallback (tab-wallet.svg, tab-connections.svg, tab-settings.svg)
- Add 1px border-primary divider above Android tab bar via sceneStyle borderBottomWidth
- Update Android theme to Material3.DayNight.NoActionBar for native tab bar compatibility
- Fix React 19.2 dev-mode crash with valtio Proxy objects via postinstall patch script (patch-react-dev.sh)
- Move Modal inside NavigationContainer and Toast outside for correct native view hierarchy
- Add hapticFeedbackEnabled for tab press haptic feedback
- Bump react-native-reanimated to ^4.2.2 and react-native-worklets to 0.7.4 for RN 0.84.1 compatibility

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Disable sendDefaultPii in Sentry to prevent auto-attaching IP/headers
- Sanitize symKey from WalletConnect deep link URLs before logging
- Make patch-react-dev.sh cross-platform (BSD/GNU sed) with patch validation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Set scrollEdgeAppearance to opaque to prevent the translucent tab bar
from briefly showing a lighter blur during tab transitions in dark mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Disable translucent tab bar (liquid glass) due to dark mode flash issue
- Convert postinstall sed script to proper yarn patch for react-native
- Restore __DEV__ logging in LogStore (root cause fixed by patch)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sync native iOS color scheme with app theme via Appearance.setColorScheme()
so native UIKit/SwiftUI components (tab bar) respect dark mode during
transitions. Also bump react-navigation and react-native-screens.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use createNativeStackNavigator for native iOS headers with back chevron
on Logs and SecretPhrase screens. Remove @react-navigation/stack which
is no longer imported anywhere.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Make the selected tab pill/circle transparent by overriding
colorSecondaryContainer in the app theme.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rners

Redesign the scan camera view with a dark overlay, rounded square cutout,
white corner brackets, and close button matching the Figma design.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 18, 2026 18:54
@vercel
Copy link

vercel bot commented Mar 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pos-demo Ready Ready Preview, Comment Mar 19, 2026 9:00pm

Request Review

@claude
Copy link

claude bot commented Mar 18, 2026

Claude finished @ignaciosantise's task in 54s —— View job


PR Review: feat/rn-update

  • Gather context and read changed files
  • Analyze code for bugs, security, performance issues
  • Run license compliance subagent
  • Run breaking changes subagent
  • Run data classification subagent
  • Post review findings

🚨 PR Too Large Files: 26 Lines: 3,901 Severity: HIGH Category: maintainability

This PR bundles several independent concerns. Suggested splits:

  • PR 1: RN 0.84.1 + React 19.2.3 upgrade, patch, dependency version bumps (package.json, yarn.lock, Podfile.lock)
  • PR 2: Native bottom tabs migration (HomeTabNavigator, TypesUtil, SVG icons, styles.xml, App.tsx modal/toast reorder)
  • PR 3: Scan screen redesign (Scan/index.tsx, styles.ts, ScannerFrame.tsx)
  • PR 4: Remaining fixes (ERC20BalanceService, SettingsStore, PaymentStore cleanups)

Found 6 issue(s)

Issue 1: Potential crash when no codes scanned

ID: scan-codes-null-crash-a3f1
File: wallets/rn_cli_wallet/src/screens/Scan/index.tsx:41
Severity: HIGH
Category: code_quality

Context:

  • Pattern: codes[0] is accessed unconditionally, then codes[0].value is force-asserted with !
  • Risk: onCodeScanned may be called with an empty array or a code whose value is undefined (malformed QR data)
  • Impact: Unhandled crash / navigation to Connections with undefined URI
  • Trigger: Any QR scan where codes is empty or codes[0].value is undefined

Recommendation:

const onCodeScanned = (codes: Code[]) => {
  const uri = codes[0]?.value;
  if (!uri) return;
  haptics.scanSuccess();
  navigation.navigate('Home', { screen: 'Connections', params: { uri } });
};

Fix this →


Issue 2: Static Dimensions break scan overlay on orientation change / foldables

ID: scan-dimensions-static-module-b7c2
File: wallets/rn_cli_wallet/src/screens/Scan/index.tsx:24 + wallets/rn_cli_wallet/src/screens/Scan/styles.ts:4
Severity: MEDIUM
Category: code_quality

Context:

  • Pattern: screenWidth/screenHeight in index.tsx:24 and scanAreaLeft/scanAreaTop in styles.ts:4 are computed once at module-load time via Dimensions.get('window')
  • Risk: On orientation change, foldable device fold/unfold, or multi-window mode, the SVG overlay cutout and scanFrame position will be misaligned
  • Impact: The dark overlay cutout won't match the scanner frame
  • Trigger: Device rotation or multi-window resize while Scan screen is active

Recommendation: Use useWindowDimensions() inside the component:

import { useWindowDimensions } from 'react-native';

export default function Scan({ navigation }: Props) {
  const { width: screenWidth, height: screenHeight } = useWindowDimensions();
  const scanAreaLeft = (screenWidth - SCAN_AREA_SIZE) / 2;
  const scanAreaTop = (screenHeight - SCAN_AREA_SIZE) / 3;
  // ...
}

Fix this →


Issue 3: RootStackScreenProps type contract change may break screen components

ID: brk-typesutil-rootstack-screenprop-type-b2f4
File: wallets/rn_cli_wallet/src/utils/TypesUtil.ts:79
Severity: MEDIUM
Category: breaking_change

Context:

  • Pattern: RootStackScreenProps changed from StackScreenProps (@react-navigation/stack) to NativeStackScreenProps (@react-navigation/native-stack) — these have different navigation prop shapes
  • Risk: Screen components using Stack-specific navigator APIs (e.g. navigation.push overloads, navigation.reset) could hit TypeScript errors
  • Impact: All screens importing RootStackScreenPropsScan, LogList, SecretPhrase
  • Trigger: TypeScript compilation; runtime is consistent since the navigator itself was also migrated

Recommendation: Audit all screen components using RootStackScreenProps to confirm they compile cleanly. If any used StackNavigationProp-specific APIs, update to NativeStackNavigationProp equivalents.


Issue 4: Unused ClipPath in scan SVG overlay

ID: scan-svg-unused-clippath-d4e8
File: wallets/rn_cli_wallet/src/screens/Scan/index.tsx:87-90
Severity: LOW
Category: code_quality

Context:

  • Pattern: <ClipPath id="overlay"> defined in <Defs> but never referenced via clipPath="url(#overlay)" on any element; ClipPath imported but unused
  • Impact: Dead code; unnecessary import

Recommendation: Remove the <ClipPath> block from <Defs> and remove ClipPath from the react-native-svg import. The fillRule="evenodd" on <Path> already correctly produces the cutout.
Fix this →


Issue 5: ean-13 barcode type causes false positives in QR scanner

ID: scan-codetypes-ean13-false-positive-c1a9
File: wallets/rn_cli_wallet/src/screens/Scan/index.tsx:49
Severity: LOW
Category: code_quality

Context:

  • Pattern: codeTypes: ['qr', 'ean-13'] — retail barcodes included alongside QR
  • Risk: Scanning any product barcode triggers navigation to Connections with a numeric non-WC URI
  • Impact: Confusing UX; handleUriOrPaymentLink called with a non-WalletConnect URI
  • Trigger: Scanning any retail barcode while Scan screen is open

Recommendation: Use codeTypes: ['qr'] only, unless a payment flow specifically requires EAN-13.


Issue 6: react-native-dialog removed from package.json — verify no remaining imports

ID: brk-packagejson-dialog-dep-removed-c9e2
File: wallets/rn_cli_wallet/package.json
Severity: LOW
Category: breaking_change

Context:

  • Pattern: react-native-dialog removed from dependencies
  • Risk: Build failure if any file still imports it
  • Trigger: Build/bundle time

Recommendation: ✅ Already verified — no remaining imports of react-native-dialog found in src/.


Subagent Findings

License Compliance: ✅ No issues — @bottom-tabs/react-navigation and react-native-bottom-tabs are both MIT licensed.

Data Classification: ✅ No issues — sendDefaultPii correctly set to false, symKey redacted in deeplink logs, no hardcoded secrets.

Breaking Changes: Internal breaking changes are coordinated within the PR (Scan styles, stack navigator type). No external API breakage since this is an app, not a library. See issues 3 and 6 above.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Upgrades the wallets/rn_cli_wallet React Native app to RN 0.84.1 / React 19.2.3, introduces native bottom tabs via react-native-bottom-tabs, and updates the Scan UI with a new overlay/frame while adjusting Modal/Toast placement for correct z-ordering.

Changes:

  • Bump RN/React and related ecosystem deps (Reanimated/Worklets/Valtio/React Navigation), plus a Yarn patch for a dev-mode RN renderer issue.
  • Replace JS bottom tabs with native tabs (@bottom-tabs/react-navigation) and update navigation stack types/structure.
  • Redesign the Scan screen overlay + add a reusable ScannerFrame component; move Modal/Toast positioning.

Reviewed changes

Copilot reviewed 19 out of 26 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
yarn.lock Adds a top-level Yarn v1 lockfile header (currently empty).
wallets/rn_cli_wallet/yarn.lock Updates dependency lock entries for RN 0.84.1 + new native tabs deps.
wallets/rn_cli_wallet/package.json Bumps RN/React + related deps; adds native bottom tabs packages; updates resolutions/patches.
wallets/rn_cli_wallet/src/utils/TypesUtil.ts Switches stack screen prop typing to native-stack.
wallets/rn_cli_wallet/src/store/SettingsStore.ts Persists theme mode and applies appearance changes on load/set.
wallets/rn_cli_wallet/src/store/PaymentStore.ts Logging formatting change for “cancelled” path.
wallets/rn_cli_wallet/src/services/ERC20BalanceService.ts Formatting/refactor for ABI/Contract creation and call mapping.
wallets/rn_cli_wallet/src/screens/Settings/index.tsx Minor formatting changes; keeps Logs navigation entry.
wallets/rn_cli_wallet/src/screens/Scan/styles.ts Adds dimension-based scan area constants and new layout styles.
wallets/rn_cli_wallet/src/screens/Scan/index.tsx Implements scan overlay/cutout, close button, instruction text, and uses ScannerFrame.
wallets/rn_cli_wallet/src/screens/LogList/components/LogFilterSheet.tsx Minor formatting + eslint suppression for inline styles.
wallets/rn_cli_wallet/src/screens/App.tsx Moves Modal/Toast placement; redacts symKey in deeplink logs; disables Sentry default PII.
wallets/rn_cli_wallet/src/navigators/RootStackNavigator.tsx Migrates to native-stack; introduces custom header for Home; updates back button display mode.
wallets/rn_cli_wallet/src/navigators/HomeTabNavigator.tsx Migrates to native bottom tabs and switches tab icon strategy per platform.
wallets/rn_cli_wallet/src/modals/PaymentOptionsModal/ResultView.tsx Formatting-only change.
wallets/rn_cli_wallet/src/modals/PaymentOptionsModal/ExpiryWarningView.tsx Formatting-only change.
wallets/rn_cli_wallet/src/lib/TonLib.ts Adds eslint suppression for bitwise operation.
wallets/rn_cli_wallet/src/components/ScannerFrame.tsx New SVG-based scanner corner frame component.
wallets/rn_cli_wallet/src/components/FadeGradient.tsx Formatting-only change.
wallets/rn_cli_wallet/src/assets/icons/tab-wallet.svg New Android tab icon asset.
wallets/rn_cli_wallet/src/assets/icons/tab-settings.svg New Android tab icon asset.
wallets/rn_cli_wallet/src/assets/icons/tab-connections.svg New Android tab icon asset.
wallets/rn_cli_wallet/ios/RNWeb3Wallet.xcodeproj/project.pbxproj Adds compile flags (incl. RCT_REMOVE_LEGACY_ARCH) and Swift explicit modules setting.
wallets/rn_cli_wallet/android/app/src/main/res/values/styles.xml Switches app theme to Material3 and adjusts theme colors.
wallets/rn_cli_wallet/.yarn/patches/react-native-npm-0.84.1-dev-proxy-fix.patch Adds a Yarn patch targeting RN dev renderer behavior.
Comments suppressed due to low confidence (1)

wallets/rn_cli_wallet/src/screens/Scan/index.tsx:46

  • onCodeScanned assumes codes[0] exists and that codes[0].value is non-null (uri!). If the scanner reports an empty array or a code without a value, this will throw or navigate with an invalid URI. Add a guard (e.g., return early when codes.length === 0 or when !codes[0].value).
  const onCodeScanned = (codes: Code[]) => {
    haptics.scanSuccess();
    const uri = codes[0].value;
    navigation.navigate('Home', {
      screen: 'Connections',
      params: { uri: uri! },
    });
  };

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +12 to +25
const tabWalletIcon = Platform.select({
ios: { sfSymbol: 'wallet.bifold.fill' },
default: require('@/assets/icons/tab-wallet.svg'),
});

const SettingsIcon = ({ color }: { color: string }) => (
<SvgSettingsTab height={24} width={24} fill={color} />
);
const tabConnectionsIcon = Platform.select({
ios: { sfSymbol: 'square.stack.3d.up.fill' },
default: require('@/assets/icons/tab-connections.svg'),
});

const NavHeader = () => <Header />;
const tabSettingsIcon = Platform.select({
ios: { sfSymbol: 'gearshape.fill' },
default: require('@/assets/icons/tab-settings.svg'),
});
Comment on lines +56 to +61
headerBackButtonDisplayMode: 'minimal',
headerTintColor: Theme['text-primary'],
headerTitleStyle: {
fontWeight: '400',
},
headerTitleStyle,
cardStyle: {
backgroundColor: Theme['bg-primary'],
}}
Comment on lines +86 to +90
<Defs>
<ClipPath id="overlay">
<Rect x={0} y={0} width={screenWidth} height={screenHeight} />
</ClipPath>
</Defs>
import { Button } from '@/components/Button';
import { ScannerFrame } from '@/components/ScannerFrame';

const { width: screenWidth, height: screenHeight } = Dimensions.get('window');

Choose a reason for hiding this comment

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

🤖 Auto Review Issue: Static Dimensions break scan overlay on orientation change / foldables

Severity: MEDIUM
Category: code_quality
Tool: Claude Auto Review

Context:

  • Pattern: screenWidth/screenHeight in index.tsx:24 and scanAreaLeft/scanAreaTop in styles.ts:4 are computed once at module-load time via Dimensions.get('window')
  • Risk: On orientation change, foldable device fold/unfold, or multi-window mode, the SVG overlay cutout and scanFrame position will be misaligned
  • Impact: The dark overlay cutout won't match the scanner frame
  • Trigger: Device rotation or multi-window resize while Scan screen is active

Recommendation: Use useWindowDimensions() inside the component:

import { useWindowDimensions } from 'react-native';

export default function Scan({ navigation }: Props) {
  const { width: screenWidth, height: screenHeight } = useWindowDimensions();
  const scanAreaLeft = (screenWidth - SCAN_AREA_SIZE) / 2;
  const scanAreaTop = (screenHeight - SCAN_AREA_SIZE) / 3;
  // ...
}

Fix this →

// Define screen props types
export type RootStackScreenProps<T extends keyof RootStackParamList> =
StackScreenProps<RootStackParamList, T>;
NativeStackScreenProps<RootStackParamList, T>;

Choose a reason for hiding this comment

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

🤖 Auto Review Issue: RootStackScreenProps type contract change may break screen components

Severity: MEDIUM
Category: breaking_change
Tool: Claude Auto Review

Context:

  • Pattern: RootStackScreenProps changed from StackScreenProps (@react-navigation/stack) to NativeStackScreenProps (@react-navigation/native-stack) — these have different navigation prop shapes
  • Risk: Screen components using Stack-specific navigator APIs (e.g. navigation.push overloads, navigation.reset) could hit TypeScript errors
  • Impact: All screens importing RootStackScreenPropsScan, LogList, SecretPhrase
  • Trigger: TypeScript compilation; runtime is consistent since the navigator itself was also migrated

Recommendation: Audit all screen components using RootStackScreenProps to confirm they compile cleanly. If any used StackNavigationProp-specific APIs, update to NativeStackNavigationProp equivalents.

height={screenHeight}
>
<Defs>
<ClipPath id="overlay">

Choose a reason for hiding this comment

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

🤖 Auto Review Issue: Unused ClipPath in scan SVG overlay

Severity: LOW
Category: code_quality
Tool: Claude Auto Review

Context:

  • Pattern: <ClipPath id="overlay"> defined in <Defs> but never referenced via clipPath="url(#overlay)" on any element; ClipPath imported but unused
  • Impact: Dead code; unnecessary import

Recommendation: Remove the <ClipPath> block from <Defs> and remove ClipPath from the react-native-svg import. The fillRule="evenodd" on <Path> already correctly produces the cutout.
Fix this →

…vices

Set root view background to match theme so transparent nav bar shows
correct color in dark mode. Use screen dimensions with buffer for scan
overlay SVG to cover full display including navigation bar area.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ariants

Debug builds handled this differently, causing internal/release builds
on Firebase to still show a white navigation bar and extra tab padding.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
React Native 0.84's enableEdgeToEdge() sets isNavigationBarContrastEnforced
to true, causing a white scrim on the nav bar (visible on Xiaomi/HyperOS).
Override it after super.onCreate() to ensure transparent nav bar on all
build variants.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants