Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions apps/wallet/src/ui/app/components/NavigationStackProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) 2026 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { createContext, useContext, useEffect, useState, type ReactNode } from 'react';
import { useLocation, useNavigationType } from 'react-router-dom';
import { NAVBAR_ITEM_PATHS } from './navigation';

export const HOME_PATH = NAVBAR_ITEM_PATHS.home;

export const TAB_BAR_PATHS = new Set<string>(
Object.values(NAVBAR_ITEM_PATHS).filter((p) => p !== HOME_PATH),
);

const NavigationDepthContext = createContext<number>(0);

export function NavigationStackProvider({ children }: { children: ReactNode }) {
const [depth, setDepth] = useState(0);
const location = useLocation();
const navigationType = useNavigationType();

useEffect(() => {
const hasMenuParam = new URLSearchParams(location.search).has('menu');
const isHome =
!hasMenuParam &&
(location.pathname === HOME_PATH || location.pathname.startsWith(HOME_PATH + '/'));
const isTabBar = !hasMenuParam && TAB_BAR_PATHS.has(location.pathname);

if (isHome) {
setDepth(0);
} else if (isTabBar) {
setDepth(1);
} else if (navigationType === 'PUSH') {
setDepth((prev) => prev + 1);
} else if (navigationType === 'POP') {
setDepth((prev) => Math.max(0, prev - 1));
}
}, [location.key, navigationType]);

return (
<NavigationDepthContext.Provider value={depth}>{children}</NavigationDepthContext.Provider>
);
}

export function useNavigationDepth(): number {
return useContext(NavigationDepthContext);
}
6 changes: 3 additions & 3 deletions apps/wallet/src/ui/app/components/Overlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { ReactNode } from 'react';
import { Header } from '@iota/apps-ui-kit';
import { Portal } from '../shared/Portal';
import { useNavigate } from 'react-router-dom';
import { useNavigationDepth } from './NavigationStackProvider';

interface OverlayProps {
title?: string;
Expand All @@ -17,7 +18,6 @@ interface OverlayProps {
setShowModal?: (showModal: boolean) => void;
background?: 'bg-iota-neutral-100 dark:bg-iota-neutral-6';
titleCentered?: boolean;
showBackButton?: boolean;
onBack?: () => void;
hideCloseIcon?: boolean;
headerAction?: ReactNode;
Expand All @@ -30,7 +30,6 @@ export function Overlay({
closeOverlay,
setShowModal,
titleCentered = true,
showBackButton,
onBack,
headerAction,
hideCloseIcon,
Expand All @@ -43,6 +42,7 @@ export function Overlay({
[closeOverlay, setShowModal],
);
const navigate = useNavigate();
const depth = useNavigationDepth();
const handleBack = useCallback(() => {
if (onBack) {
onBack();
Expand All @@ -56,7 +56,7 @@ export function Overlay({
{title && (
<div className="relative w-full">
<Header
onBack={showBackButton ? handleBack : undefined}
onBack={depth >= 1 ? handleBack : undefined}
title={title}
onClose={!hideCloseIcon ? closeModal : undefined}
titleCentered={titleCentered}
Expand Down
28 changes: 15 additions & 13 deletions apps/wallet/src/ui/app/components/PageTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,43 @@
import { Header } from '@iota/apps-ui-kit';
import { useCallback } from 'react';
import type { ReactNode } from 'react';
import { useNavigate } from 'react-router-dom';
import { useLocation, useNavigate } from 'react-router-dom';
import { HOME_PATH, TAB_BAR_PATHS, useNavigationDepth } from './NavigationStackProvider';

interface PageTemplateProps {
title?: string;
children: ReactNode;
onClose?: () => void;
isTitleCentered?: boolean;
showBackButton?: boolean;
onBack?: () => void;
}

export function PageTemplate({
title,
children,
onClose,
isTitleCentered,
showBackButton,
onBack,
}: PageTemplateProps) {
export function PageTemplate({ title, children, isTitleCentered, onBack }: PageTemplateProps) {
const navigate = useNavigate();
const location = useLocation();
const depth = useNavigationDepth();

const handleBack = useCallback(() => {
if (onBack) {
onBack();
} else if (TAB_BAR_PATHS.has(location.pathname)) {
navigate(HOME_PATH, { replace: true });
} else {
navigate(-1);
}
}, [onBack, navigate, location.pathname]);

const handleClose = useCallback(() => {
navigate(HOME_PATH, { replace: true });
}, [navigate]);

return (
<div className="flex h-full w-full flex-col">
{title && (
<Header
titleCentered={isTitleCentered}
title={title}
onBack={showBackButton ? handleBack : undefined}
onClose={onClose}
onBack={depth >= 1 ? handleBack : undefined}
onClose={depth >= 2 ? handleClose : undefined}
/>
)}
<div className="w-full flex-1 overflow-y-auto overflow-x-hidden bg-iota-neutral-100 p-md dark:bg-iota-neutral-6">
Expand Down
1 change: 1 addition & 0 deletions apps/wallet/src/ui/app/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from './DAppInfoCard';
export * from './DAppPermissionList';
export * from './HideShowDisplayBox';
export * from './Overlay';
export { NavigationStackProvider } from './NavigationStackProvider';
export * from './PageTemplate';
export * from './SectionHeader';
export * from './SummaryCard';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function ConnectedAppsCard() {
const { connectedApps, loading } = useConnectedApps();

return (
<PageTemplate title="Connected Apps" isTitleCentered showBackButton>
<PageTemplate title="Connected Apps" isTitleCentered>
<Loading loading={loading}>
<div
className={cn('flex flex-1 flex-col gap-md', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ export function AutoLockAccounts() {
showModal={true}
title="Auto Lock Profile"
closeOverlay={() => navigate('/tokens')}
showBackButton
>
<Loading loading={autoLock.isPending}>
<Form className="flex h-full flex-col" form={form} onSubmit={handleSave}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useNavigate } from 'react-router-dom';
export function NetworkSettings() {
const navigate = useNavigate();
return (
<Overlay showModal title="Network" closeOverlay={() => navigate('/tokens')} showBackButton>
<Overlay showModal title="Network" closeOverlay={() => navigate('/tokens')}>
<NetworkSelector />
</Overlay>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function ThemeSettings() {
ampli.changedTheme({ theme: value });
}
return (
<Overlay showModal title="Theme" closeOverlay={() => navigate('/tokens')} showBackButton>
<Overlay showModal title="Theme" closeOverlay={() => navigate('/tokens')}>
<div className="flex w-full flex-col">
{THEME_ENTRIES.map(([label, value]) => (
<div className="px-md" key={value}>
Expand Down
29 changes: 12 additions & 17 deletions apps/wallet/src/ui/app/components/navigation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,30 @@ type NavbarItemWithPath = NavbarItemWithId & {
path: string;
};

export const NAVBAR_ITEM_PATHS = {
home: '/tokens',
assets: '/nfts',
apps: '/apps',
activity: '/transactions',
} as const;

export function Navigation() {
const navigate = useNavigate();
const location = useLocation();

const NAVBAR_ITEMS: NavbarItemWithPath[] = [
{ id: 'home', icon: <Home />, path: '/tokens' },
{
id: 'assets',
icon: <Assets />,
path: '/nfts',
},
{
id: 'apps',
icon: <Apps />,
path: '/apps',
},
{
id: 'activity',
icon: <Activity />,
path: '/transactions',
},
{ id: 'home', icon: <Home />, path: NAVBAR_ITEM_PATHS.home },
{ id: 'assets', icon: <Assets />, path: NAVBAR_ITEM_PATHS.assets },
{ id: 'apps', icon: <Apps />, path: NAVBAR_ITEM_PATHS.apps },
{ id: 'activity', icon: <Activity />, path: NAVBAR_ITEM_PATHS.activity },
];

const activeId = NAVBAR_ITEMS.find((item) => location.pathname.startsWith(item.path))?.id || '';

function handleItemClick(id: string) {
const item = NAVBAR_ITEMS.find((item) => item.id === id);
if (item && !item.isDisabled) {
navigate(item.path);
navigate(item.path, { replace: true });
}
}

Expand Down
8 changes: 1 addition & 7 deletions apps/wallet/src/ui/app/pages/accounts/AddAccountPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,7 @@ export function AddAccountPage() {
}

return (
<PageTemplate
title="Add Profile"
isTitleCentered
onClose={() => navigate('/')}
showBackButton
onBack={() => navigate('/')}
>
<PageTemplate title="Add Profile" isTitleCentered>
<div className="flex h-full w-full flex-col">
<div className="flex w-full flex-1 flex-col pb-md--rs text-center">
<img
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ export function CreateNewPasskey() {
<PageTemplate
title="Create Passkey Account"
isTitleCentered
showBackButton
onBack={() => navigate('/accounts/import-existing')}
>
<Form
Expand Down
2 changes: 0 additions & 2 deletions apps/wallet/src/ui/app/pages/accounts/CreateNewWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ export function CreateNewWallet() {
<PageTemplate
title="Create a new wallet"
isTitleCentered
onClose={() => navigate('/')}
showBackButton
onBack={() => navigate('/accounts/add-account')}
>
<div className="flex h-full w-full flex-col">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,6 @@ export function ImportExistingWallet() {
<PageTemplate
title="Import a wallet"
isTitleCentered
onClose={() => navigate('/')}
showBackButton
onBack={() => navigate('/accounts/add-account')}
>
<div className="flex h-full w-full flex-col">
Expand Down
2 changes: 1 addition & 1 deletion apps/wallet/src/ui/app/pages/accounts/ImportKeystone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export function ImportKeystone() {
const disableFinish = step.type === 'select-accounts' && step.selectedAccounts.size === 0;

return (
<PageTemplate title="Import Keystone" isTitleCentered showBackButton>
<PageTemplate title="Import Keystone" isTitleCentered>
<div className="flex h-full w-full flex-col items-center">
<div className="w-full grow">
<div className="flex h-full flex-col justify-between gap-1">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export function ImportPasskeyPage() {
<PageTemplate
title="Import Passkey Account"
isTitleCentered
showBackButton
onBack={() => navigate('/accounts/import-existing')}
>
{accountID ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function ImportPassphrasePage() {

const BUTTON_ICON_CLASSES = 'w-5 h-5 text-iota-neutral-10 dark:text-iota-neutral-92';
return (
<PageTemplate title="Import Mnemonic" isTitleCentered showBackButton>
<PageTemplate title="Import Mnemonic" isTitleCentered>
<div className="flex h-full flex-col gap-md">
<div className="flex w-full flex-col items-end">
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function ImportPrivateKeyPage() {
}

return (
<PageTemplate title="Import Private Key" isTitleCentered showBackButton>
<PageTemplate title="Import Private Key" isTitleCentered>
<div className="flex h-full w-full flex-col items-center ">
<div className="w-full grow">
<ImportPrivateKeyForm onSubmit={handleOnSubmit} />
Expand Down
2 changes: 1 addition & 1 deletion apps/wallet/src/ui/app/pages/accounts/ImportSeedPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function ImportSeedPage() {
}

return (
<PageTemplate title="Import Seed" isTitleCentered showBackButton>
<PageTemplate title="Import Seed" isTitleCentered>
<div className="flex h-full w-full flex-col items-center ">
<div className="w-full grow">
<ImportSeedForm onSubmit={handleOnSubmit} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,7 @@ export function ProtectAccountPage() {
}

return (
<PageTemplate
title="Create Password"
isTitleCentered
showBackButton
onClose={() => navigate(-1)}
>
<PageTemplate title="Create Password" isTitleCentered>
<Loading loading={showVerifyPasswordView === null}>
{showVerifyPasswordView ? (
<VerifyPasswordModal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export function ManageAccountsPage() {
<Overlay
showModal
title="Manage Accounts"
showBackButton
titleCentered={false}
hideCloseIcon
headerAction={
Expand Down
5 changes: 2 additions & 3 deletions apps/wallet/src/ui/app/pages/home/kiosk-details/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,11 @@ import {
} from '_components';
import { useGetKioskContents, Collapsible } from '@iota/core';
import { formatAddress } from '@iota/iota-sdk/utils';
import { Link, useSearchParams, useNavigate } from 'react-router-dom';
import { Link, useSearchParams } from 'react-router-dom';
import cl from 'clsx';
import { KeyValueInfo } from '@iota/apps-ui-kit';

export function KioskDetailsPage() {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const kioskId = searchParams.get('kioskId');
const accountAddress = useActiveAddress();
Expand All @@ -31,7 +30,7 @@ export function KioskDetailsPage() {
}

return (
<PageTemplate title="Kiosk" isTitleCentered onClose={() => navigate(-1)}>
<PageTemplate title="Kiosk" isTitleCentered>
<div
className={cl('flex h-full flex-1 flex-col flex-nowrap gap-5', {
'items-center': isPending,
Expand Down
7 changes: 1 addition & 6 deletions apps/wallet/src/ui/app/pages/home/nft-details/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,7 @@ export function NFTDetailsPage() {
}

return (
<PageTemplate
title="Visual Asset"
isTitleCentered
onClose={() => navigate(-1)}
showBackButton
>
<PageTemplate title="Visual Asset" isTitleCentered>
<div
className={cl('flex h-full flex-1 flex-col flex-nowrap gap-5', {
'items-center': isPending,
Expand Down
1 change: 0 additions & 1 deletion apps/wallet/src/ui/app/pages/home/nft-transfer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export function NftTransferPage() {
title="Send NFT"
closeOverlay={() => navigate('/nfts')}
onBack={() => navigate('/nfts')}
showBackButton
>
<Loading loading={isPending}>
<div className="flex h-full w-full flex-col gap-md">
Expand Down
Loading
Loading