🎯

page-and-route

🎯Skill

from onekeyhq/app-monorepo

VibeIndex|
What it does

page-and-route skill from onekeyhq/app-monorepo

πŸ“¦

Part of

onekeyhq/app-monorepo(31 items)

page-and-route

Installation

πŸ“‹ No install commands found in docs. Showing default command. Check GitHub for actual instructions.
Quick InstallInstall with npx
npx skills add onekeyhq/app-monorepo --skill page-and-route
12Installs
2,277
-
Last UpdatedJan 26, 2026

Skill Details

SKILL.md

Helps create and configure pages and routes in the OneKey app-monorepo. Use when creating new pages, configuring routes, setting up deep links, handling QR codes, or understanding navigation patterns. Page, route, navigation, deep link, universal link, QR code, modal, tab, onboarding.

Overview

# Page and Route Skill

This skill helps create and configure pages and routes in the OneKey app-monorepo.

---

⚠️ WARNING: Page Deletion Policy

DO NOT DELETE PAGES unless you have confirmed there are NO external links to the page.

External links include:

  • Deep links / Universal links
  • QR code handlers
  • Banner click handlers
  • Web URLs shared externally
  • Third-party integrations
  • Marketing materials / Documentation

If you need to remove a page's functionality:

Instead of deleting the route, keep the route registered and modify the page component:

```typescript

import { Page } from '@onekeyhq/components';

/**

* @deprecated This page has been deprecated since v5.0.0

*

* New location: packages/kit/src/views/NewFeature/pages/NewPage.tsx

* New route: EModalRoutes.NewFeatureModal -> ENewFeatureRoutes.NewPage

*

* This page is kept for backward compatibility with external deep links.

* DO NOT DELETE - external links may still reference this route.

*/

function DeprecatedPage() {

return (

shouldRedirect={() => true} // Always redirect

onRedirected={() => {

// Navigate to replacement page or home

navigation.switchTab(ETabRoutes.Home);

// Or show a toast explaining the change

Toast.info({ title: 'This feature has been moved' });

}}

>

{null} // Render nothing

);

}

export default DeprecatedPage;

```

This approach ensures:

  • Users accessing via old deep links are gracefully redirected
  • No broken links or blank screens
  • Analytics can track deprecated route access
  • Backward compatibility is maintained

---

Page Types

The page types are defined in packages/components/src/hocs/PageType/pageType.ts:

| Type | Description | Animation Behavior |

|------|-------------|-------------------|

| modal | Modal route pages | iOS: First page slides from bottom, subsequent pages slide from right. Android: No animation. Web/Desktop/Extension/iPad: Same as iOS but displays as floating popup |

| stack | Tab route pages (will be renamed from "stack") | On small screens, first page shows in bottom tab bar; on large screens, tab shows in sidebar. Subsequent pages slide from right. Android: No animation |

| fullScreen | Full screen overlay (deprecated) | Layer is lower than modal, avoid adding new pages |

| onboarding | OnboardingV2 full screen pages | Full screen overlay on all platforms, layer is below modal |

Creating Routes

1. Modal Route

Modal routes are configured in packages/kit/src/routes/Modal/router.tsx.

Example: Creating a NotificationsModal route

#### Step 1: Define Route Enum and Param Types

Create route file packages/shared/src/routes/notifications.ts:

```typescript

export enum EModalNotificationsRoutes {

NotificationList = 'NotificationList',

NotificationIntroduction = 'NotificationIntroduction',

}

export type IModalNotificationsParamList = {

[EModalNotificationsRoutes.NotificationList]: undefined;

[EModalNotificationsRoutes.NotificationIntroduction]: undefined;

};

```

#### Step 2: Add to EModalRoutes Enum

In packages/shared/src/routes/modal.ts:

```typescript

export enum EModalRoutes {

// ... existing routes

NotificationsModal = 'NotificationsModal',

}

export type IModalParamList = {

// ... existing types

[EModalRoutes.NotificationsModal]: IModalNotificationsParamList;

};

```

#### Step 3: Create Router Configuration

Create packages/kit/src/views/Notifications/router/index.ts:

```typescript

import type { IModalFlowNavigatorConfig } from '@onekeyhq/components';

import { LazyLoadPage } from '@onekeyhq/kit/src/components/LazyLoadPage';

import type { IModalNotificationsParamList } from '@onekeyhq/shared/src/routes/notifications';

import { EModalNotificationsRoutes } from '@onekeyhq/shared/src/routes/notifications';

const NotificationList = LazyLoadPage(

() => import('@onekeyhq/kit/src/views/Notifications/pages/NotificationList'),

);

const NotificationIntroduction = LazyLoadPage(

() => import('@onekeyhq/kit/src/views/Notifications/pages/NotificationIntroduction'),

);

export const ModalNotificationsRouter: IModalFlowNavigatorConfig<

EModalNotificationsRoutes,

IModalNotificationsParamList

>[] = [

{

name: EModalNotificationsRoutes.NotificationList,

component: NotificationList,

},

{

name: EModalNotificationsRoutes.NotificationIntroduction,

component: NotificationIntroduction,

},

];

```

#### Step 4: Register in Modal Router

In packages/kit/src/routes/Modal/router.tsx:

```typescript

import { ModalNotificationsRouter } from '../../views/Notifications/router';

const router: IModalRootNavigatorConfig[] = [

// ... existing routes

{

name: EModalRoutes.NotificationsModal,

children: ModalNotificationsRouter,

},

];

```

#### Step 5: Create Page Component

Create packages/kit/src/views/Notifications/pages/NotificationList.tsx:

```typescript

import { Page } from '@onekeyhq/components';

function NotificationList() {

return (

{/ Page content /}

);

}

export default NotificationList;

```

2. Onboarding Route

Onboarding routes are configured in packages/kit/src/views/Onboardingv2/router/index.tsx.

Example: Creating AddExistingWallet page

#### Step 1: Define Route Enum

In packages/shared/src/routes/onboarding.ts:

```typescript

export enum EOnboardingPagesV2 {

GetStarted = 'GetStarted',

AddExistingWallet = 'AddExistingWallet',

// ... more pages

}

```

#### Step 2: Add to Router

In packages/kit/src/views/Onboardingv2/router/index.tsx:

```typescript

const AddExistingWallet = LazyLoadPage(

() => import('../pages/AddExistingWallet'),

undefined,

false,

,

);

export const OnboardingRouterV2: IModalFlowNavigatorConfig<

EOnboardingPagesV2,

IOnboardingParamListV2

>[] = [

// ... other routes

{

name: EOnboardingPagesV2.AddExistingWallet,

component: AddExistingWallet,

options: hiddenHeaderOptions,

},

];

```

3. Tab Route

Tab routes are configured in packages/kit/src/routes/Tab/router.ts.

Example: Creating Market tab with sub-pages

#### Step 1: Define Route Enum and Params

In packages/shared/src/routes/tabMarket.ts:

```typescript

export enum ETabMarketRoutes {

TabMarket = 'TabMarket',

MarketDetail = 'MarketDetail',

MarketDetailV2 = 'MarketDetailV2',

MarketNativeDetail = 'MarketNativeDetail',

MarketBannerDetail = 'MarketBannerDetail',

}

export type ITabMarketParamList = {

[ETabMarketRoutes.TabMarket]: { from?: EEnterWay } | undefined;

[ETabMarketRoutes.MarketDetail]: { token: string };

[ETabMarketRoutes.MarketDetailV2]: {

tokenAddress: string;

network: string;

isNative?: boolean;

};

// ... more params

};

```

#### Step 2: Create Sub-Router

Create packages/kit/src/routes/Tab/Marktet/router.ts:

```typescript

import type { ITabSubNavigatorConfig } from '@onekeyhq/components';

import { ETabMarketRoutes } from '@onekeyhq/shared/src/routes';

import { LazyLoadRootTabPage, LazyLoadPage } from '../../../components/LazyLoadPage';

const MarketHome = LazyLoadRootTabPage(() => import('../../../views/Market/MarketHome'));

const MarketDetail = LazyLoadPage(() => import('../../../views/Market/MarketDetail'));

export const marketRouters: ITabSubNavigatorConfig[] = [

{

rewrite: '/',

name: ETabMarketRoutes.TabMarket,

headerShown: !platformEnv.isNative,

component: MarketHome,

},

{

name: ETabMarketRoutes.MarketDetail,

component: MarketDetail,

rewrite: '/tokens/:token',

},

];

```

#### Step 3: Register in Tab Router

In packages/kit/src/routes/Tab/router.ts:

```typescript

import { marketRouters } from './Marktet/router';

export const useTabRouterConfig = () => {

return useMemo(() => {

const tabs = [

{

name: ETabRoutes.Market,

tabBarIcon: (focused?: boolean) =>

focused ? 'ChartTrendingUp2Solid' : 'ChartTrendingUp2Outline',

translationId: ETranslations.global_market,

rewrite: '/market',

exact: true,

children: marketRouters,

// Control visibility per platform

hiddenIcon: platformEnv.isNative, // Hide on mobile

},

// ... other tabs

];

return tabs;

}, []);

};

```

Tab Configuration Options:

  • hiddenIcon: Hide tab icon on certain platforms
  • hideOnTabBar: Hide from tab bar but keep route accessible
  • inMoreAction: Show in "More" menu instead of main tab bar
  • freezeOnBlur: Keep tab state when switching tabs

Configuring Page Paths

⚠️ WARNING: Route Paths Must Be Unique

Route paths MUST NOT be duplicated. Each route path must be unique across the entire application.

If duplicate paths are detected, the application will throw an error at startup:

```

Found conflicting screens with the same pattern. The pattern '/market/tokens/.'

resolves to both 'Main > Market > MarketDetail' and 'Main > Market > MarketDetailV2'.

Patterns must be unique and cannot resolve to more than one screen.

```

Common causes of duplicate paths:

  • Two routes using the same rewrite value
  • Forgetting to update path when copying route configuration
  • Child routes with identical path segments

How to avoid:

  • Always use unique rewrite values for each route
  • When adding similar routes, differentiate paths (e.g., /token/:network vs /token/:network/:tokenAddress)
  • Run the app locally to verify no path conflicts before committing

URL Path Configuration

Route paths are calculated in packages/kit/src/routes/config/index.ts via resolveScreens.

#### resolveScreens Function

```typescript

interface IScreenRouterConfig {

name: string; // Route name (used as default path segment)

rewrite?: string; // Override path segment

exact?: boolean; // If true, ignores parent paths and uses only rewrite

children?: IScreenRouterConfig[];

}

// resolveScreens transforms route config into path config

const resolveScreens = (routes: IScreenRouterConfig[]) =>

routes.reduce((prev, route) => {

prev[route.name] = {

path: route.rewrite ? route.rewrite : route.name, // Use rewrite or name as path

exact: !!route.exact,

};

if (route.children) {

prev[route.name].screens = resolveScreens(route.children); // Recursive for children

}

return prev;

}, {});

```

How it works:

  1. Each route's name becomes its key in the config
  2. The path is either rewrite value (if provided) or name
  3. exact flag determines if parent paths are included
  4. Children routes are processed recursively

#### Path Calculation Rules

Rule 1: Default path accumulation

Without any configuration, paths accumulate based on route hierarchy:

```

Route: Main -> Market -> MarketDetail

Path: /Main/Market/MarketDetail

```

Rule 2: rewrite replaces current segment only

```typescript

// Tab router config

{

name: ETabRoutes.Market,

rewrite: '/market', // Replaces 'Market' with 'market'

children: marketRouters,

}

// Result: /Main/market/... (only current segment changed)

```

Rule 3: exact: true truncates all parent paths

```typescript

{

name: EModalRoutes.SettingModal,

children: ModalSettingStack,

rewrite: '/settings',

exact: true, // Ignores /Modal prefix

}

// Without exact: /Modal/settings/...

// With exact: /settings/...

```

Rule 4: Path params with /:param syntax

```typescript

// In marketRouters

{

name: ETabMarketRoutes.MarketDetail,

component: MarketDetail,

rewrite: '/tokens/:token', // :token is a path parameter

}

// Result path pattern: /market/tokens/:token

// Actual URL example: /market/tokens/bitcoin

```

#### Complete Examples

Example 1: Tab Route with rewrite + exact

```typescript

// Tab router (packages/kit/src/routes/Tab/router.ts)

{

name: ETabRoutes.Market,

rewrite: '/market',

exact: true, // Path starts from /market, not /Main/Market

children: marketRouters,

}

// Sub-router (packages/kit/src/routes/Tab/Marktet/router.ts)

export const marketRouters = [

{

name: ETabMarketRoutes.TabMarket,

rewrite: '/', // Root of /market

component: MarketHome,

},

{

name: ETabMarketRoutes.MarketDetail,

rewrite: '/tokens/:token',

component: MarketDetail,

},

];

// Resulting paths:

// TabMarket: /market/

// MarketDetail: /market/tokens/:token (e.g., /market/tokens/bitcoin)

```

Example 2: Modal Route with exact

```typescript

// Modal router (packages/kit/src/routes/Modal/router.tsx)

{

name: EModalRoutes.SettingModal,

children: ModalSettingStack,

rewrite: '/settings',

exact: true,

}

// Resulting path: /settings/... (not /Modal/settings/...)

```

Example 3: Onboarding Route

```typescript

// Onboarding router config

{

name: EOnboardingV2Routes.OnboardingV2,

rewrite: '/onboarding',

exact: true,

children: OnboardingRouterV2,

}

// Sub-routes

{

name: EOnboardingPagesV2.GetStarted,

rewrite: '/get-started',

component: GetStarted,

}

// Resulting path: /onboarding/get-started

```

Example 4: Native token detail (no tokenAddress in path)

```typescript

{

name: ETabMarketRoutes.MarketNativeDetail,

component: MarketDetailV2,

rewrite: '/token/:network', // Only network, no token address

}

// URL example: /market/token/eth

```

Example 5: Non-native token detail (with tokenAddress)

```typescript

{

name: ETabMarketRoutes.MarketDetailV2,

component: MarketDetailV2,

rewrite: '/token/:network/:tokenAddress',

}

// URL example: /market/token/eth/0x1234...

```

#### Path Calculation in buildAllowList

The pagePath template function in routeUtils.ts calculates full paths:

```typescript

function pagePath(_: TemplateStringsArray, ...screenNames: string[]): string {

const path = screenNames.reduce((prev, screenName) => {

const screen = screenConfig[screenName];

const paths = screen.path.split('/:');

const rawPath = removeExtraSlash(paths[0]);

const screenPath = paths.length > 1 ? ${rawPath}/. : rawPath;

// If exact, use only current path; otherwise, accumulate

return screen.exact ? screenPath : addPath(prev, screenPath);

}, '');

return /${path};

}

// Usage:

pagePath${ERootRoutes.Main}${ETabRoutes.Market}${ETabMarketRoutes.MarketDetail}

// Result: /market/tokens/. (the /. indicates path params follow)

```

URL Allow List (Browser Display)

By default, routes don't display in the browser URL bar. To enable URL display, configure in packages/shared/src/utils/routeUtils.ts:

```typescript

export const buildAllowList = (screens, perpDisabled, perpTabShowWeb) => {

const rules = {

// Show URL with parameters

[pagePath${ERootRoutes.Main}${ETabRoutes.Market}${ETabMarketRoutes.MarketDetailV2}]: {

showUrl: true, // Enable URL display

showParams: true, // Show query parameters

},

// Show URL without parameters

[pagePath${ERootRoutes.Main}${ETabRoutes.Swap}${ETabSwapRoutes.TabSwap}]: {

showUrl: true,

showParams: false, // Hide query parameters

},

};

return rules;

};

```

Note: When adding new pages that need browser URL display, configure them in buildAllowList.

Platform-Specific Routing: Web vs Extension

The routing implementation differs between web/native platforms and browser extension:

#### Web/Native: Standard Path Routing

File: packages/kit/src/routes/config/getStateFromPath.ts

```typescript

// Simply re-exports from React Navigation

export { getStateFromPath } from '@react-navigation/core';

```

URL format: https://app.onekey.so/market/tokens/bitcoin

#### Extension: Hash Routing

File: packages/kit/src/routes/config/getStateFromPath.ext.ts

The extension uses a custom implementation copied from @react-navigation/core with hash routing modifications. The file is marked with // ---CHANGED Begin---- and // ---CHANGED end---- comments to indicate customizations.

Why custom implementation is needed:

  • Browser extensions load from local HTML files (e.g., ui-expand-tab.html)
  • Standard path routing doesn't work with extension URL scheme
  • Hash routing allows navigation without page reload

Key customizations in getStateFromPath.ext.ts:

```typescript

// 1. Store initial pathname for later use (line 98-100)

// ---CHANGED Begin----: initial path from url

let initialPath: string | undefined = globalThis.location.pathname;

// ---CHANGED end----

// 2. Extract path from hash instead of pathname (line 107-109)

export function getStateFromPath(

path: string,

options?: Options

): ResultState | undefined {

// ---CHANGED Begin----: support hash router

path = globalThis.location.hash.split('#').pop() || '/';

// ---CHANGED end----

// ... rest of function

}

// 3. Rewrite initial path for focused route (line 731-736)

// In createNestedStateObject function:

route = findFocusedRoute(state) as ParsedRoute;

// ---CHANGED Begin----: rewrite hash path to initial path

if (initialPath) {

route.path = initialPath;

initialPath = undefined;

}

// ---CHANGED end----

```

URL format returned (in index.ts line 139):

```typescript

return ${extHtmlFileUrl}#${newPath};

// Example: /ui-expand-tab.html#/market/tokens/bitcoin

```

URL format comparison:

| Platform | URL Format |

|----------|------------|

| Web | https://app.onekey.so/market/tokens/bitcoin |

| Extension | chrome-extension://xxx/ui-expand-tab.html#/market/tokens/bitcoin |

Important notes for extension routing:

  1. The # symbol separates the HTML file from the route path
  2. Windows Chrome has specific requirements (line 131-137 in index.ts):

```typescript

// /ui-expand-tab.html/#/ NOT working for Windows Chrome

// /ui-expand-tab.html#/ works fine

```

  1. When developing extension-specific routes, test on both Mac and Windows Chrome

#### Extension Routing Modifications Summary

The getStateFromPath.ext.ts file contains 4 key modifications from the original @react-navigation/core implementation:

| # | Location | Modification | Functional Impact |

|---|----------|--------------|-------------------|

| 1 | Lines 33-37 | Import changes | Uses OneKeyLocalError instead of native Error; imports utilities from @react-navigation/core |

| 2 | Lines 98-100 | let initialPath = globalThis.location.pathname | Stores HTML file path (e.g., /ui-expand-tab.html) for later use in route state |

| 3 | Lines 107-109 | path = globalThis.location.hash.split('#').pop() | Core change: Extracts route path from URL hash instead of using passed parameter |

| 4 | Lines 731-736 | Rewrite route.path with initialPath | Sets focused route's path to initial HTML file path for proper state management |

Why these modifications are necessary:

  • Browser extensions run from local HTML files, not a web server
  • Standard path routing (/market/tokens/btc) doesn't work with chrome-extension:// URLs
  • Hash routing (#/market/tokens/btc) allows client-side navigation without server requests
  • The initial path storage ensures the extension knows its base HTML file location

#### Route Path Output by Platform

In packages/kit/src/routes/config/index.ts, the getPathFromState function handles platform differences:

```typescript

getPathFromState(state, options) {

// ... calculate path ...

if (platformEnv.isExtension) {

// Extension: return hash-based URL

if (newPath === '/' && globalThis.location.href.endsWith('#/')) {

return extHtmlFileUrl; // e.g., /ui-expand-tab.html

}

return ${extHtmlFileUrl}#${newPath}; // e.g., /ui-expand-tab.html#/market

}

// Web/Desktop: return standard path

return newPath; // e.g., /market

}

```

Page Lifecycle

The Page component supports lifecycle callbacks defined in packages/components/src/layouts/Page/type.ts:

```typescript

interface IPageLifeCycle {

onMounted?: () => void; // Called after page transition completes

onUnmounted?: () => void; // Called after page unmount transition completes

onCancel?: () => void; // Called when page closed without confirm

onConfirm?: () => void; // Called when page closed with confirm

onClose?: (extra?: { flag?: string }) => void; // Called on any close

onRedirected?: () => void; // Called after redirect completes

shouldRedirect?: () => boolean; // Return true to redirect immediately

}

```

Usage in Page Component:

```typescript

import { Page } from '@onekeyhq/components';

function MyPage() {

return (

onMounted={() => console.log('Page mounted')}

onUnmounted={() => console.log('Page unmounted')}

shouldRedirect={() => !hasPermission}

onRedirected={() => navigation.navigate('Login')}

>

{/ content /}

);

}

```

Use Cases:

| Callback | Use Case |

|----------|----------|

| onMounted | Load data, start animations, track page views |

| onUnmounted | Cleanup resources, cancel requests |

| onClose | Save draft, confirm unsaved changes |

| onCancel | Track cancel actions, cleanup form state |

| onConfirm | Track confirm actions, submit data |

| shouldRedirect | Auth guards, permission checks |

| onRedirected | Navigate to login, show toast |

Redirect Pattern:

```typescript

shouldRedirect={() => {

// Return true to immediately go back and trigger onRedirected

return !isUserAuthenticated;

}}

onRedirected={() => {

// Called after going back, navigate to appropriate screen

navigation.pushModal(EModalRoutes.OnboardingModal, {

screen: EOnboardingPages.Login,

});

}}

>

```

Deep Link / Universal Link Configuration

Configure in packages/kit/src/routes/config/deeplink/index.ts:

Example: Adding invite_share deep link

#### Step 1: Define Deep Link Path

In packages/shared/src/consts/deeplinkConsts.tsx:

```typescript

export enum EOneKeyDeepLinkPath {

url_account = 'url_account',

market_detail = 'market_detail',

invite_share = 'invite_share', // Add new path

}

export type IEOneKeyDeepLinkParams = {

[EOneKeyDeepLinkPath.invite_share]: {

utm_source: string;

code: string;

};

};

```

#### Step 2: Handle Deep Link

In packages/kit/src/routes/config/deeplink/index.ts:

```typescript

async function processDeepLinkUrlAccount(params, times = 0) {

const { parsedUrl } = params;

const { hostname, queryParams, scheme, path } = parsedUrl;

if (scheme === ONEKEY_APP_DEEP_LINK || scheme === ONEKEY_APP_DEEP_LINK_NAME) {

switch (hostname ?? path?.slice(1)) {

case EOneKeyDeepLinkPath.invite_share: {

const { utm_source: utmSource, code } = queryParams as IEOneKeyDeepLinkParams[EOneKeyDeepLinkPath.invite_share];

if (navigation) {

navigation.switchTab(ETabRoutes.ReferFriends, {

screen: ETabReferFriendsRoutes.TabReferAFriend,

params: { utmSource, code },

});

}

break;

}

}

}

}

```

Deep Link Format:

  • onekey-wallet://invite_share?utm_source=twitter&code=ABC123
  • https://app.onekey.so/wc/connect/wc?uri=... (Universal Link)

QR Code / Banner Click Navigation

Configure QR code handlers for scanning and banner clicks.

Example: MARKET_DETAIL handler

#### Step 1: Define Handler Type

In packages/shared/types/qrCode.ts:

```typescript

export enum EQRCodeHandlerType {

MARKET_DETAIL = 'MARKET_DETAIL',

// ... other types

}

export enum EQRCodeHandlerNames {

marketDetail = 'marketDetail',

// ... other names

}

export const PARSE_HANDLER_NAMES = {

all: [

EQRCodeHandlerNames.marketDetail,

// ... other handlers

],

};

```

#### Step 2: Create Handler

Create packages/kit-bg/src/services/ServiceScanQRCode/utils/parseQRCode/handlers/marketDetail.ts:

```typescript

import { WEB_APP_URL, WEB_APP_URL_DEV, WEB_APP_URL_SHORT } from '@onekeyhq/shared/src/config/appConfig';

import { EQRCodeHandlerType } from '@onekeyhq/shared/types/qrCode';

import type { IMarketDetailValue, IQRCodeHandler } from '../type';

const marketDetail: IQRCodeHandler = async (value, options) => {

const urlValue = options?.urlResult;

if (urlValue?.data?.urlParamList) {

const origin = urlValue?.data?.origin;

// Check if URL matches OneKey web app

if (

[WEB_APP_URL, WEB_APP_URL_DEV, WEB_APP_URL_SHORT].includes(origin) &&

urlValue?.data?.pathname.startsWith('/market/tokens/')

) {

const coinGeckoId = urlValue?.data?.pathname.split('/market/tokens/').pop();

return {

type: EQRCodeHandlerType.MARKET_DETAIL,

data: { origin, coinGeckoId },

};

}

}

return null;

};

export default marketDetail;

```

#### Step 3: Register Handler

In packages/kit-bg/src/services/ServiceScanQRCode/utils/parseQRCode/handlers/index.ts:

```typescript

import marketDetail from './marketDetail';

export const PARSE_HANDLERS = {

[EQRCodeHandlerNames.marketDetail]: marketDetail,

// ... other handlers

};

```

#### Step 4: Handle Result in UI

In packages/kit/src/views/ScanQrCode/hooks/useParseQRCode.tsx:

```typescript

const parse = useCallback(async (value, params) => {

const result = await backgroundApiProxy.serviceScanQRCode.parse(value, options);

switch (result.type) {

case EQRCodeHandlerType.MARKET_DETAIL: {

const { coinGeckoId } = result.data as IMarketDetailValue;

if (coinGeckoId) {

await closeScanPage();

void marketNavigation.pushDetailPageFromDeeplink(navigation, { coinGeckoId });

}

break;

}

}

}, [navigation]);

```

Navigation Methods

```typescript

// Push modal

navigation.pushModal(EModalRoutes.NotificationsModal, {

screen: EModalNotificationsRoutes.NotificationList,

params: { / page params / },

});

// Switch tab

navigation.switchTab(ETabRoutes.Market);

// Navigate within tab

navigation.navigate(ERootRoutes.Main, {

screen: ETabRoutes.Market,

params: {

screen: ETabMarketRoutes.MarketDetail,

params: { token: 'bitcoin' },

},

}, {

pop: true,

});

// Go back

navigation.goBack();

```

⚠️ IMPORTANT: Always Use `pop: true` with `navigation.navigate`

When using navigation.navigate, ALWAYS include the pop: true option to ensure proper navigation stack management:

```typescript

// βœ… Correct - with pop: true

navigation.navigate(ERootRoutes.Main, undefined, {

pop: true,

});

navigation.navigate(ERootRoutes.Main, {

screen: ETabRoutes.Market,

params: {

screen: ETabMarketRoutes.MarketDetail,

params: { token: 'bitcoin' },

},

}, {

pop: true,

});

// ❌ Wrong - missing pop: true

navigation.navigate(ERootRoutes.Main, {

screen: ETabRoutes.Market,

});

```

Why pop: true is required:

  • Prevents navigation stack from growing indefinitely
  • Ensures proper back button behavior
  • Avoids memory leaks from accumulated screens
  • Maintains consistent navigation state across platforms

Files Reference

| Purpose | Location |

|---------|----------|

| Page type enum | packages/components/src/hocs/PageType/pageType.ts |

| Modal routes | packages/kit/src/routes/Modal/router.tsx |

| Tab routes | packages/kit/src/routes/Tab/router.ts |

| Onboarding routes | packages/kit/src/views/Onboardingv2/router/index.tsx |

| Route enums | packages/shared/src/routes/ |

| URL allow list | packages/shared/src/utils/routeUtils.ts |

| Route config (linking) | packages/kit/src/routes/config/index.ts |

| Web/Native path parser | packages/kit/src/routes/config/getStateFromPath.ts |

| Extension path parser | packages/kit/src/routes/config/getStateFromPath.ext.ts |

| Deep link config | packages/kit/src/routes/config/deeplink/index.ts |

| Deep link consts | packages/shared/src/consts/deeplinkConsts.tsx |

| QR handlers | packages/kit-bg/src/services/ServiceScanQRCode/utils/parseQRCode/handlers/ |

| Page component | packages/components/src/layouts/Page/index.tsx |

| Page lifecycle | packages/components/src/layouts/Page/hooks.ts |