Skip to content

refactor(ui): show pill navbar only on root pages - #474

Merged
bordalix merged 15 commits into
masterfrom
wt-navbar-root-only-20260325
Apr 2, 2026
Merged

bordalix merged 15 commits into
masterfrom
wt-navbar-root-only-20260325

Conversation

@sahilc0

@sahilc0 sahilc0 commented Mar 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Show navbar only on Wallet home, Apps home, and Settings menu — sub-pages (Send, Receive, Settings options, etc.) no longer show the navbar
  • Hide navbar on unlock and loading screens — the page === screen guard ensures the navbar is hidden whenever the rendered page is overridden (unlock, loading hold)
  • Add "Sounds good" button to success screens — since the navbar is hidden on sub-pages, Send/Receive/Notes success screens now have a primary action button to navigate back to wallet home
  • Accessibility: inert on hidden navbar — when the navbar is hidden, it's removed from the accessibility tree and tab order
  • Spring animation (Framer Motion) for navbar show/hide transitions — bounces down on exit, springs back up on enter
  • Remove all manual padding workarounds — footer clearance CSS, conditional 4rem padding in ButtonsOnBottom, manual pill-navbar-clearance padding in Delegates.tsx
  • Bonus: cherry-picked VITE_DEV_NSEC auto-init feature (separate commit) for faster local dev iteration

Why

The pill navbar was a fixed overlay (position: fixed, portaled to document.body) that required every component with bottom-positioned elements to manually account for its height. This was brittle — three CSS variables, automatic padding on IonContent, margin on IonFooter, conditional padding in ButtonsOnBottom, and manual padding in Delegates.tsx.

Since all action buttons exist on sub-pages and never on root pages, hiding the navbar on sub-pages eliminates the conflict entirely.

The navbar was also appearing on the Unlock screen because the visibility check used screen from NavigationContext (which could still be Pages.Wallet) instead of the actual rendered page. Adding page === screen as a guard fixes this.

Success screens (send, receive, notes) became dead ends after hiding the navbar on sub-pages — no navbar, no back button, no way out. Added a "Sounds good" ButtonsOnBottom button on each that navigates back to wallet home, following the same pattern as Init/Success.tsx.

Note for reviewers

The isSettingsRoot check in App.tsx couples navbar visibility to OptionsContext.option. This means if someone refactors Settings sub-navigation, they need to be aware it affects navbar visibility. Worth considering whether this should live in the navigation system instead (e.g., expose isRootPage from NavigationContext). @pietro909 thoughts?

Test plan

  • Wallet home: navbar visible, content scrolls with fade effect
  • Tap Send/Receive: navbar bounces out, action buttons at bottom work (especially Skip on Receive)
  • Go back: navbar springs back in
  • Apps home: navbar visible, tap any app → navbar hides
  • Settings menu: navbar visible, tap any option → navbar hides, buttons at correct position
  • Back to Wallet/Apps: navbar reappears with spring animation
  • Unlock screen: navbar NOT visible
  • Loading screen: navbar NOT visible
  • Send success: "Sounds good" button visible, tapping it returns to wallet home
  • Receive success: "Sounds good" button visible, tapping it returns to wallet home
  • Notes success: "Sounds good" button visible, tapping it returns to wallet home
  • Dark mode: navbar styling correct
  • Safe area: bottom spacing correct on notch devices

Summary by CodeRabbit

  • Style

    • Navbar now appears conditionally based on current screen/menu, with smoother, reduced‑motion–respecting animations; pill-navbar becomes non‑interactive when hidden. Adjusted bottom spacing in the delegates view for consistent layout.
  • New Features

    • Added a consistent "Sounds good" bottom action on multiple success flows to return users to the wallet.
  • Tests

    • Added tests validating navbar visibility across auth and navigation states and updated test helpers.

sahilc0 added 2 commits March 25, 2026 13:56
When VITE_DEV_NSEC is set in .env.local, automatically initializes the
wallet on dev server startup, bypassing onboarding and unlock screens.
The pill navbar was a fixed overlay requiring manual padding on every
component with bottom-positioned elements. Since all action buttons
live on sub-pages (Send, Receive, Settings options), hiding the navbar
on sub-pages eliminates the conflict entirely.

- Show navbar only on Wallet home, Apps home, and Settings menu
- Hide with spring animation (Framer Motion) on sub-page navigation
- Remove footer clearance CSS hacks and manual padding workarounds
  in ButtonsOnBottom and Delegates
- Disable pointer-events on hidden navbar to prevent click blocking

Files: App.tsx, PillNavbarOverlay.tsx, ButtonsOnBottom.tsx,
       Delegates.tsx, index.css, ionic.css
@sahilc0
sahilc0 requested review from bordalix and pietro909 March 25, 2026 12:59
@coderabbitai

coderabbitai Bot commented Mar 25, 2026 •

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

App now computes navbar visibility from current screen and Settings option, passes a new visible prop to PillNavbarOverlay which animates show/hide via framer-motion; CSS updated to disable interactions when hidden; tests and mocks updated; multiple Wallet success screens gain a bottom "Sounds good" button navigating to Wallet.

Changes

Cohort / File(s) Summary
App / Navbar wiring
src/App.tsx
Read option from OptionsContext; added isSettingsRoot and showNavbar; apply has-pill-navbar based on showNavbar; pass visible={showNavbar} to PillNavbarOverlay.
Pill navbar component
src/components/PillNavbarOverlay.tsx
Added required visible: boolean prop; replaced static wrapper with motion.div; animate opacity/y by visible; respect useReducedMotion(); apply inert and pill-navbar-layer--hidden when hidden.
Styles
src/index.css, src/ionic.css
Added rule to disable pointer-events for .pill-navbar when parent has pill-navbar-layer--hidden; removed ion-footer.buttons-on-bottom margin-bottom rule tied to has-pill-navbar.
Screens — spacing & buttons
src/screens/Settings/Delegates.tsx, src/screens/Wallet/Receive/Amount.tsx, src/screens/Wallet/Receive/Success.tsx, src/screens/Wallet/Send/Success.tsx, src/screens/Wallet/Notes/Success.tsx
Delegates: replaced bottom padding calc with fixed 24px. Wallet success screens: added ButtonsOnBottom containing a "Sounds good" button wired to navigate to Pages.Wallet.
Tests / mocks
src/test/App.test.tsx, src/test/screens/mocks.ts
Updated IonApp test mock to accept className; extended renderApp helper to accept screen/tab/option; added env/matchMedia/test setup helper; added Navbar visibility tests asserting presence/absence of has-pill-navbar; expanded mockOptionsContextValue.

Sequence Diagram

sequenceDiagram
    participant App as App.tsx
    participant Overlay as PillNavbarOverlay
    participant Motion as Framer Motion

    App->>App: compute isSettingsRoot & showNavbar (screen + option)
    App->>Overlay: render with visible = showNavbar

    alt visible = true
        Overlay->>Motion: animate to { opacity: 1, y: 0 }
        Motion-->>Overlay: mount visible layer
        Overlay->>Overlay: ensure interactive (no inert / pointer-events active)
    else visible = false
        Overlay->>Motion: animate to { opacity: 0, y: 24 }
        Motion-->>Overlay: collapsed/hidden
        Overlay->>Overlay: apply inert and pill-navbar-layer--hidden (disable pointer-events)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • pietro909
  • bordalix
  • Kukks
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor(ui): show pill navbar only on root pages' accurately and clearly summarizes the main change - restricting navbar visibility to root pages only.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch wt-navbar-root-only-20260325

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Mar 25, 2026 •

Copy link
Copy Markdown

Deploying wallet-bitcoin with  Cloudflare Pages  Cloudflare Pages

Latest commit: 9d9119d
Status: ✅  Deploy successful!
Preview URL: https://3e4dffe3.wallet-bitcoin.pages.dev
Branch Preview URL: https://wt-navbar-root-only-20260325.wallet-bitcoin.pages.dev

View logs

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Mar 25, 2026 •

Copy link
Copy Markdown

Deploying wallet-mutinynet with  Cloudflare Pages  Cloudflare Pages

Latest commit: 9d9119d
Status: ✅  Deploy successful!
Preview URL: https://bd8c7722.arkade-wallet.pages.dev
Branch Preview URL: https://wt-navbar-root-only-20260325.arkade-wallet.pages.dev

View logs

sahilc0 added 2 commits March 25, 2026 14:03
- Keep master's authState/unlockWallet additions in App.tsx and wallet.tsx
- Keep master's .scroll-fade opt-in selector for scroll mask
- Remove footer clearance rule (our change) that master re-added
@ghost

ghost commented Mar 25, 2026

Copy link
Copy Markdown

🔍 Arkana PR Review — wallet#474

refactor(ui): show pill navbar only on root pages by @sahilc0

Overview

Clean refactor that conditionally hides the pill navbar on sub-pages, replacing fragile manual padding workarounds with a simple visibility flag + spring animation. +22/-9 — tight and focused.

✅ What Looks Good

  • Solid approach: Hiding navbar on sub-pages where action buttons live eliminates the conflict entirely — much better than fighting CSS layering.
  • useReducedMotion respect — good accessibility practice with the Framer Motion transitions.
  • pointer-events: none on hidden state — prevents ghost taps during exit animation.
  • Cleanup of manual padding in Delegates.tsx, ionic.css, and ButtonsOnBottom — less special-casing = fewer future bugs.

⚠️ Items to Consider

  1. isSettingsRoot coupling (as noted in PR): The option === SettingsOptions.Menu check in App.tsx couples navbar visibility to OptionsContext. The PR body already flags this — worth resolving before merge or at minimum tracking as a follow-up issue. A NavigationContext.isRootPage approach would be more robust.

  2. Animation on initial mount: initial={false} on the motion.div skips the entry animation on first render. This is correct for the common case (app loads on Wallet home), but if the app deep-links directly to a sub-page and then navigates back to a root page, verify the navbar animates in correctly rather than appearing instantly.

  3. CSS class toggle vs. animation state: The pill-navbar-layer--hidden class is applied immediately, but the Framer Motion animate runs over duration: 0.5. There is a brief window where pointer-events: none is set but the element is still partially visible/interactive. Consider syncing pointer-events to onAnimationComplete instead, or accepting the current tradeoff (minor).

  4. Safe area on notch devices: The test plan mentions this — since pill-navbar-clearance CSS variable removal changes the bottom spacing model, this needs careful testing on iOS Safari with home indicator.

Security

No security concerns — UI-only change, no data handling.

Verdict

Clean, well-scoped refactor. The isSettingsRoot coupling is the main thing to resolve (even as a tracked TODO). Otherwise looks good to merge.

sahilc0 added 2 commits March 26, 2026 13:45
The navbar visibility check used `screen` from NavigationContext, which
lags behind the actual rendered page. When the app is locked, `screen`
stays as Pages.Wallet while `page` is overridden to Pages.Unlock,
causing the navbar to appear on the unlock screen.

Add `page === screen` guard so the navbar hides whenever the rendered
page is overridden (unlock, loading). Also add `inert` to the hidden
navbar overlay for accessibility, and stub VITE_DEV_NSEC in tests to
prevent env-dependent flakiness.
@ghost

ghost commented Mar 26, 2026

Copy link
Copy Markdown

Iterative review — 36e846e + 2fe4100 (fix navbar on unlock/loading + test formatting)

Good improvement. The key change in App.tsx:

const isSettingsRoot = screen === Pages.Settings && option === SettingsOptions.Menu
const showNavbar = page === screen && (screen === Pages.Wallet || screen === Pages.Apps || isSettingsRoot)

The page === screen guard is the critical fix — when the rendered page is overridden (unlock screen, loading hold), the navbar correctly hides even if the navigation context still has Tabs.Wallet set. This was a real UX bug where the navbar would flash on lock/loading screens.

New tests cover all three cases (unlock, loading, authenticated root) — solid coverage.

Minor: the PillNavbarOverlay now accepts visible and uses Framer Motion spring animation with inert for a11y. Clean approach — inert removes it from tab order when hidden, and useReducedMotion respects user preferences.

LGTM ✅

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (1)
src/test/App.test.tsx (1)

193-235: LGTM!

The new test suite provides solid coverage of the navbar visibility logic:

  • Tests the page !== screen guard (unlock overrides wallet screen).
  • Tests the loading hold scenario.
  • Tests the happy path for authenticated users on root pages.

Consider adding tests for Apps and Settings root pages if not covered elsewhere, to ensure parity with the Wallet root test.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/test/App.test.tsx` around lines 193 - 235, Add two new tests mirroring
the Wallet root test to cover Apps and Settings roots: use renderApp with
authState: 'authenticated' and initialized: true and set screen/tab to
Pages.Apps/Tabs.Apps and Pages.Settings/Tabs.Settings respectively; then await
screen.findByTestId('ion-app') and assert ionApp.className contains
'has-pill-navbar'. Place them alongside the existing Navbar visibility tests and
reuse the same test setup (beforeEach stubbing detectJSCapabilities, matchMedia,
vi.stubEnv) so renderApp, Pages, and Tabs symbols are referenced exactly as in
the current suite.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/test/App.test.tsx`:
- Around line 193-235: Add two new tests mirroring the Wallet root test to cover
Apps and Settings roots: use renderApp with authState: 'authenticated' and
initialized: true and set screen/tab to Pages.Apps/Tabs.Apps and
Pages.Settings/Tabs.Settings respectively; then await
screen.findByTestId('ion-app') and assert ionApp.className contains
'has-pill-navbar'. Place them alongside the existing Navbar visibility tests and
reuse the same test setup (beforeEach stubbing detectJSCapabilities, matchMedia,
vi.stubEnv) so renderApp, Pages, and Tabs symbols are referenced exactly as in
the current suite.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e8c4b040-9af2-4fe7-a4b1-f929222d99a2

📥 Commits

Reviewing files that changed from the base of the PR and between cf486c7 and 2fe4100.

📒 Files selected for processing (5)
  • src/App.tsx
  • src/components/PillNavbarOverlay.tsx
  • src/index.css
  • src/ionic.css
  • src/test/App.test.tsx
💤 Files with no reviewable changes (1)
  • src/ionic.css
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/PillNavbarOverlay.tsx

With the navbar hidden on sub-pages, payment success screens
(send, receive, notes) were dead ends with no way to navigate home.
Adds a ButtonsOnBottom "Sounds good" button that navigates to wallet.
@ghost

ghost commented Mar 26, 2026

Copy link
Copy Markdown

Iterative review — 9018fcb1 (add "Sounds good" button to success screens)

Straightforward fix for the dead-end problem: Send, Receive, and Notes success screens now have a ButtonsOnBottom → Button that calls navigate(Pages.Wallet). Same pattern as Init/Success.tsx.

Consistent across all three screens, correct imports. No concerns — this was the expected follow-up from hiding the navbar on sub-pages.

LGTM ✅

sahilc0 added 2 commits March 31, 2026 15:29
Addresses CodeRabbit nitpick — adds navbar visibility tests for
Apps root and Settings menu to match the existing Wallet root test.
@ghost

ghost commented Mar 31, 2026

Copy link
Copy Markdown

🔍 Arkana PR Review

PR: refactor(ui): show pill navbar only on root pages

Overall Assessment

Well-structured refactor that eliminates a fragile layout pattern (manual padding workarounds for the fixed navbar). The core logic change — hiding navbar on sub-pages using page === screen — is simple and correct. Good test coverage added.

Observations

1. page === screen guard ✅
This is the key insight: when the rendered page differs from screen (due to unlock/loading override), the navbar hides. Clean and catches edge cases like the unlock screen showing a navbar over the password prompt.

2. isSettingsRoot coupling
As noted in the PR description, isSettingsRoot depends on OptionsContext.option. This means settings sub-navigation refactors must account for navbar visibility. The suggestion to expose isRootPage from NavigationContext is worth considering for future-proofing, but the current approach works fine for the existing navigation structure.

3. "Sounds good" button on success screens ✅
Necessary addition since success screens become dead-ends without the navbar. The pattern matches Init/Success.tsx. All three screens (Send, Receive, Notes) consistently use navigate(Pages.Wallet).

4. inert attribute on hidden navbar ✅
Properly removes hidden navbar from accessibility tree and tab order. The pill-navbar-layer--hidden class with pointer-events: none is belt-and-suspenders with inert — good defensive approach.

5. Spring animation
{ type: 'spring', duration: 0.5, bounce: 0.25 } gives a subtle bounce. The prefersReduced check with { duration: 0 } is correct for accessibility.

6. Removed padding workarounds ✅
Removing ion-footer.buttons-on-bottom margin, pill-navbar-clearance in Delegates, and the conditional has-pill-navbar class is the real win here. Every one of those was a maintenance trap.

7. Tests ✅
Good coverage: unlock screen, loading hold, wallet root, apps root, and settings menu all tested for navbar visibility. The mock setup properly passes screen, tab, and option through to exercise the showNavbar logic.

8. Minor: VITE_DEV_NSEC cherry-pick
The separate commit for dev auto-init is also in PR #485. If both merge, the second will conflict. Coordinate merge order or rebase whichever lands second.

Security

No security concerns — UI layout changes only.

Verdict

Looks good. No blocking issues. The isRootPage refactor suggestion from the author is valid but can be done as a follow-up.

@ghost

ghost commented Mar 31, 2026

Copy link
Copy Markdown

🔍 Iterative Review — commits 9234c98..eff74d1

Changes since last review: 2 commits — expanded test coverage for navbar visibility.

Added two new test cases covering Apps root and Settings root (with SettingsOptions.Menu) navbar visibility. The renderApp helper now accepts an option prop, and mockOptionsContextValue includes a default option: SettingsOptions.Menu — matches the real default so existing tests remain valid.

Good coverage additions. The Settings test correctly verifies that option === SettingsOptions.Menu triggers the navbar, which is the coupling point the PR description flagged for future refactors. No issues.

@bordalix

bordalix commented Apr 1, 2026

Copy link
Copy Markdown
Collaborator

@sahilc0 fix merge conflicts

@ghost

ghost commented Apr 1, 2026

Copy link
Copy Markdown

Review of new commit (eff74d1..2e2938f — bordalix)

src/screens/Wallet/Receive/Amount.tsx — Adds "Sounds good" ButtonsOnBottom button to the faucet success screen, navigating back to wallet home.

Follows the same pattern established by the earlier commits for send/receive/notes success screens. Consistent and necessary — without it, the faucet success screen was a dead end after the navbar-hiding change.

LGTM.

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (3)
src/test/screens/mocks.ts (1)

117-120: Mock is incomplete but functional due to as any cast.

The mockOptionsContextValue only provides 2 of the 6 fields required by OptionsContextProps (direction, options, goBack, and validOptions are missing per src/providers/options.tsx:130-146). This works because consumers cast with as any, but it could cause runtime errors if tests ever access the missing fields.

Consider completing the mock for robustness:

♻️ Suggested complete mock
 export const mockOptionsContextValue = {
+  direction: 'forward' as const,
   option: SettingsOptions.Menu,
+  options: [],
+  goBack: () => {},
   setOption: () => {},
+  validOptions: () => [],
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/test/screens/mocks.ts` around lines 117 - 120, The mock
mockOptionsContextValue is missing several fields from OptionsContextProps
(direction, options, goBack, validOptions) which are currently masked by an as
any cast; update mockOptionsContextValue to include all required keys with
sensible defaults (e.g., direction: a default string, options: an array, goBack:
a noop, validOptions: a function returning true) so tests don't rely on any, and
remove any as any casts in tests/consumers so the mock type-checks against
OptionsContextProps; reference the OptionsContextProps type and the
mockOptionsContextValue constant when making the change.
src/test/App.test.tsx (2)

219-260: Good coverage but missing negative test for Settings sub-pages.

The tests cover the positive cases well. However, there's no test verifying that the navbar is hidden on Settings sub-pages (when option !== SettingsOptions.Menu). Per the logic in src/App.tsx:251, isSettingsRoot requires option === SettingsOptions.Menu.

🧪 Suggested test for Settings sub-page
   it('shows navbar on settings menu when authenticated and initialized', async () => {
     // ... existing test
   })
+
+  it('hides navbar on settings sub-page when authenticated and initialized', async () => {
+    renderApp({
+      authState: 'authenticated',
+      initialized: true,
+      screen: Pages.Settings,
+      tab: Tabs.Settings,
+      option: SettingsOptions.Password, // or any non-Menu option
+    })
+
+    const ionApp = await screen.findByTestId('ion-app')
+    expect(ionApp.className).not.toContain('has-pill-navbar')
+  })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/test/App.test.tsx` around lines 219 - 260, Add a negative test that
verifies the navbar is hidden for Settings sub-pages by rendering via renderApp
with authState: 'authenticated', initialized: true, screen: Pages.Settings, tab:
Tabs.Settings and option set to a non-root value (e.g., SettingsOptions.Profile
or any value !== SettingsOptions.Menu) and then assert that the ion-app test
id's className does NOT contain 'has-pill-navbar'; this mirrors the existing
positive Settings root test but uses SettingsOptions != Menu to exercise the
isSettingsRoot branch.

198-217: Consider extracting shared setup to reduce duplication.

The beforeEach/afterEach blocks here duplicate the setup from the "App startup routing" suite (lines 116-135). This could be extracted to a shared helper or module-level setup.

♻️ Suggested refactor to deduplicate setup
+function setupTestEnvironment() {
+  sessionStorage.clear()
+  window.matchMedia = vi.fn().mockImplementation((query: string) => ({
+    matches: false,
+    media: query,
+    onchange: null,
+    addListener: vi.fn(),
+    removeListener: vi.fn(),
+    addEventListener: vi.fn(),
+    removeEventListener: vi.fn(),
+    dispatchEvent: vi.fn(),
+  }))
+  vi.mocked(detectJSCapabilities).mockResolvedValue({ isSupported: true })
+  vi.stubEnv('VITE_DEV_NSEC', '')
+}
+
 describe('App startup routing', () => {
   beforeEach(() => {
-    sessionStorage.clear()
-    window.matchMedia = vi.fn().mockImplementation((query: string) => ({
-      matches: false,
-      media: query,
-      onchange: null,
-      addListener: vi.fn(),
-      removeListener: vi.fn(),
-      addEventListener: vi.fn(),
-      removeEventListener: vi.fn(),
-      dispatchEvent: vi.fn(),
-    }))
-    vi.mocked(detectJSCapabilities).mockResolvedValue({ isSupported: true })
-    vi.stubEnv('VITE_DEV_NSEC', '')
+    setupTestEnvironment()
   })
   // ...
 })

 describe('Navbar visibility', () => {
   beforeEach(() => {
-    sessionStorage.clear()
-    window.matchMedia = vi.fn().mockImplementation((query: string) => ({
-      matches: false,
-      media: query,
-      onchange: null,
-      addListener: vi.fn(),
-      removeListener: vi.fn(),
-      addEventListener: vi.fn(),
-      removeEventListener: vi.fn(),
-      dispatchEvent: vi.fn(),
-    }))
-    vi.mocked(detectJSCapabilities).mockResolvedValue({ isSupported: true })
-    vi.stubEnv('VITE_DEV_NSEC', '')
+    setupTestEnvironment()
   })
   // ...
 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/test/App.test.tsx` around lines 198 - 217, The beforeEach/afterEach setup
in the 'Navbar visibility' suite duplicates initialization from the 'App startup
routing' suite; extract the shared setup into a single helper or module-level
beforeEach to avoid duplication: create a shared setup function (e.g.,
initTestEnv or setupAppTest) that performs sessionStorage.clear(), stubs
window.matchMedia, mocks detectJSCapabilities, and sets
vi.stubEnv('VITE_DEV_NSEC', ''), then call that helper from both suites and move
vi.unstubAllEnvs() into a shared afterEach or module-level teardown to keep
cleanup consistent; update references to detectJSCapabilities,
window.matchMedia, sessionStorage.clear, vi.stubEnv and vi.unstubAllEnvs
accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/test/App.test.tsx`:
- Around line 219-260: Add a negative test that verifies the navbar is hidden
for Settings sub-pages by rendering via renderApp with authState:
'authenticated', initialized: true, screen: Pages.Settings, tab: Tabs.Settings
and option set to a non-root value (e.g., SettingsOptions.Profile or any value
!== SettingsOptions.Menu) and then assert that the ion-app test id's className
does NOT contain 'has-pill-navbar'; this mirrors the existing positive Settings
root test but uses SettingsOptions != Menu to exercise the isSettingsRoot
branch.
- Around line 198-217: The beforeEach/afterEach setup in the 'Navbar visibility'
suite duplicates initialization from the 'App startup routing' suite; extract
the shared setup into a single helper or module-level beforeEach to avoid
duplication: create a shared setup function (e.g., initTestEnv or setupAppTest)
that performs sessionStorage.clear(), stubs window.matchMedia, mocks
detectJSCapabilities, and sets vi.stubEnv('VITE_DEV_NSEC', ''), then call that
helper from both suites and move vi.unstubAllEnvs() into a shared afterEach or
module-level teardown to keep cleanup consistent; update references to
detectJSCapabilities, window.matchMedia, sessionStorage.clear, vi.stubEnv and
vi.unstubAllEnvs accordingly.

In `@src/test/screens/mocks.ts`:
- Around line 117-120: The mock mockOptionsContextValue is missing several
fields from OptionsContextProps (direction, options, goBack, validOptions) which
are currently masked by an as any cast; update mockOptionsContextValue to
include all required keys with sensible defaults (e.g., direction: a default
string, options: an array, goBack: a noop, validOptions: a function returning
true) so tests don't rely on any, and remove any as any casts in tests/consumers
so the mock type-checks against OptionsContextProps; reference the
OptionsContextProps type and the mockOptionsContextValue constant when making
the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d50166b7-5131-4ff3-b11a-c87af961f77a

📥 Commits

Reviewing files that changed from the base of the PR and between 9018fcb and 2e2938f.

📒 Files selected for processing (3)
  • src/screens/Wallet/Receive/Amount.tsx
  • src/test/App.test.tsx
  • src/test/screens/mocks.ts

Resolve merge conflicts after merging master into navbar branch:
- App.tsx: keep `option` from OptionsContext (navbar visibility) +
  `dataReady`/`loadError` from master (boot animation)
- App.tsx: integrate boot animation logic with navbar show/hide
- Tests: fix loading assertions (LoadingLogo no longer renders
  visible gitCommit text), add dataReady to mock, extract shared
  test setup, add negative test for settings sub-pages,
  complete mockOptionsContextValue with all required fields
@sahilc0

sahilc0 commented Apr 1, 2026

Copy link
Copy Markdown
Contributor Author

Merge conflicts resolved and pushed. Also addressed CodeRabbit feedback:

  • Extracted shared test setup (setupTestEnvironment) to reduce duplication between test suites
  • Added negative test for settings sub-pages (verifies navbar hides when option !== SettingsOptions.Menu)
  • Completed mockOptionsContextValue with all required fields (direction, options, goBack, validOptions)
  • Fixed loading hold test to work with the new LoadingLogo component (which replaced the old Loading screen)
  • Added dataReady to test mock to account for master's new shouldHoldOnLoading condition

@bordalix merge conflicts fixed ^

@ghost

ghost commented Apr 1, 2026

Copy link
Copy Markdown

Review — merge commit 62067cf (conflict resolution with master)

Clean merge. The navbar visibility logic is properly preserved alongside master's new boot animation (LoadingLogo, dataReady, loadError, BootError).

Key observations on the conflict resolution:

  1. shouldHoldOnLoading expanded correctly — now gates on !dataReady in addition to !initialized, and adds isInInitFlow guard to avoid blocking the Connect component during wallet creation/restore. This is correct — dataReady is the new "wallet data fully loaded" signal from master.

  2. Boot animation suppresses navbar — !bootAnimActive guard on PillNavbarOverlay mount prevents the navbar from flashing during the loading→wallet transition. Good call.

  3. Test adaptations are solid — setupTestEnvironment() extraction reduces duplication, dataReady: initialized in the mock is the right default, and the new settings sub-page negative test adds useful coverage.

  4. Mock completeness — mockOptionsContextValue and mockWalletContextValue now include all required fields (direction, goBack, validOptions, loadError, dismissLoadError), preventing type errors in test renders.

No issues found. The merge preserves both feature branches correctly.

@ghost

ghost commented Apr 2, 2026

Copy link
Copy Markdown

Followup review — 5266c438, 165f5c4c (bordalix test fixes)

Clean adaptation of e2e tests to the new navbar behavior:

  • utils.ts: pay() now clicks "Sounds good" after send success, waitForPaymentReceived() does the same after receive — correct, since the navbar is gone on success screens and tests need explicit navigation back.
  • send.test.ts: Removes redundant tab-wallet clicks (unnecessary now that "Sounds good" navigates home) and replaces them with the new button. Removes some assertions that relied on being on the wallet page automatically.
  • lock.test.ts / nostr.test.ts / swap.test.ts: Adds Go back clicks where the navbar no longer provides navigation from sub-pages. Correct — settings password page and boltz app detail page are sub-pages now.
  • receive.test.ts: Assertion changed from success text to transaction amount on wallet home — makes sense since waitForPaymentReceived now auto-navigates via "Sounds good".
  • restore.test.ts: Reorders assertions and adjusts for the new flow. The waitForSelector on - 2,303 SATS replaces waiting for success text, consistent with the utils change.

No issues. These are mechanical test adjustments that correctly follow the UI changes from the parent commits.

@ghost

ghost commented Apr 2, 2026

Copy link
Copy Markdown

🔍 Automated Review Update (2026-04-02)

New commits since last review: test fixes by @bordalix + merge with master. Core navbar refactor logic unchanged.

Changes reviewed (165f5c4 → 9d9119d)

  • fix test / more test fixes — bordalix fixing test assertions after master merge
  • Merge commit resolving conflicts with master (picks up #506, #507, #510)

Previous review findings still apply

The original review covered:

  • ✅ showNavbar logic in App.tsx — clean, guards page === screen correctly
  • ✅ PillNavbarOverlay — inert for a11y, pointer-events: none when hidden, reduced-motion respected
  • ✅ Success screen "Sounds good" buttons — consistent pattern across Send/Receive/Notes/Faucet
  • ✅ Removed footer clearance CSS hacks — no more manual padding workarounds
  • ⚠️ Coupling note (still relevant): isSettingsRoot check couples navbar visibility to OptionsContext.option. PR description correctly flags this for awareness.

Test coverage

Tests updated appropriately — navbar visibility tests cover Wallet root, Apps root, Settings menu (shown), Settings sub-page (hidden), unlock screen (hidden), and loading hold (hidden). E2E tests updated to use "Sounds good" navigation and explicit back-button clicks where navbar is now hidden.

No security concerns. LGTM — ready for human approval. 👍

@bordalix
bordalix merged commit 0bca0ae into master Apr 2, 2026
5 checks passed
@bordalix
bordalix deleted the wt-navbar-root-only-20260325 branch May 18, 2026 16:12
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