fix(router): mount screens with /* splat so nested <Routes> match

Each screen's index.tsx exports a <Routes>-wrapper component (Auth,
Portfolio, Send, Receive — pattern from the screen Blues). When
mounted under a non-splat route (`path: "portfolio"`), the inner
<Routes> sees an empty relative path and matches nothing — so the
AppShell renders, the navbar paints, but the body is blank.

Switching to splat (`path: "portfolio/*"`) forwards the remainder
of the URL to each screen's nested router, which can then match
its own index + sub-routes.

Also adds the missing /auth route — Foundation never mounted it so
first-time users could not reach Welcome / Create / Import / SetPIN /
Unlock. Now reachable at /auth/{welcome,create,confirm,import,pin,unlock}.
This commit is contained in:
Hanzo AI
2026-04-30 16:46:31 -07:00
parent 402462d77f
commit 1e14edb7f2
+18 -11
View File
@@ -3,13 +3,19 @@
* bundle is the AppShell + auth state only. Screen Blues fill the
* `./screens/{name}/index.tsx` files; their changes don't ripple here.
*
* `/` redirects to `/portfolio` — the canonical landing page per
* SCREENS.md §1.
* Each screen's `index.tsx` exports a `<Routes>` block (nested router
* pattern) so Foundation must mount with `path: "<name>/*"` (splat)
* to forward sub-paths to the screen's inner Routes.
*
* `/` redirects to `/portfolio` for unlocked users; first-time users
* land at `/auth` (Welcome → Create / Import flow) — the wallet's auth
* gate is enforced by the Welcome screen + auth store, not the router.
*/
import { lazy, Suspense } from "react"
import { createBrowserRouter, Navigate, type RouteObject } from "react-router-dom"
import { AppShell } from "./components/AppShell"
const Auth = lazy(() => import("./screens/auth"))
const Portfolio = lazy(() => import("./screens/portfolio"))
const Send = lazy(() => import("./screens/send"))
const Receive = lazy(() => import("./screens/receive"))
@@ -37,15 +43,16 @@ function ScreenFallback(): React.JSX.Element {
const SCREEN_ROUTES: RouteObject[] = [
{ index: true, element: <Navigate to="/portfolio" replace /> },
{ path: "portfolio", element: <Portfolio /> },
{ path: "send", element: <Send /> },
{ path: "receive", element: <Receive /> },
{ path: "swap", element: <Swap /> },
{ path: "bridge", element: <Bridge /> },
{ path: "stake", element: <Stake /> },
{ path: "dapps", element: <DApps /> },
{ path: "confidential", element: <Confidential /> },
{ path: "settings", element: <Settings /> },
{ path: "auth/*", element: <Auth /> },
{ path: "portfolio/*", element: <Portfolio /> },
{ path: "send/*", element: <Send /> },
{ path: "receive/*", element: <Receive /> },
{ path: "swap/*", element: <Swap /> },
{ path: "bridge/*", element: <Bridge /> },
{ path: "stake/*", element: <Stake /> },
{ path: "dapps/*", element: <DApps /> },
{ path: "confidential/*", element: <Confidential /> },
{ path: "settings/*", element: <Settings /> },
{ path: "*", element: <Navigate to="/portfolio" replace /> },
]