Skip to content

frontend: move insurance into marketplace#4113

Open
strmci wants to merge 2 commits into
BitBoxSwiss:masterfrom
strmci:move_insurance_to_marketplace
Open

frontend: move insurance into marketplace#4113
strmci wants to merge 2 commits into
BitBoxSwiss:masterfrom
strmci:move_insurance_to_marketplace

Conversation

@strmci
Copy link
Copy Markdown
Collaborator

@strmci strmci commented May 6, 2026

Route Bitsurance through the marketplace layout and add the Insure tab.Move Bitsurance entry points to
/market/bitsurance, update navigationentry points, and keep the single-account auto-connect flow.

Also preserve account-code marketplace tab paths, clean stale no-account routing, and cover the new tab/path
helpers in tests.

@strmci
Copy link
Copy Markdown
Collaborator Author

strmci commented May 6, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This pull request moves Bitsurance screens under /market/bitsurance and serves them via a new MarketplaceLayout with outlet context. Market navigation helpers and an "Insure" tab are added. Bitsurance pages are simplified from guided wrappers to View-based layouts and their internal routes updated to /market/bitsurance/*. Bitsurance entries were removed from the sidebar and settings; bottom-nav/back-navigation rules, tests, localization (generic.insure), and the changelog were updated accordingly.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
frontends/web/src/routes/bitsurance/bitsurance.tsx (1)

44-57: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Always clear scanLoading on lookup failures.

If bitsuranceLookup() fails here, the function returns before resetting scanLoading, which leaves the detect CTA permanently disabled for the rest of the session.

🔧 Suggested fix
   const detect = async (redirectToDashboard: boolean) => {
     setScanLoading(true);
     setScanDone(false);
     setInsuredAccounts([]);
-    const response = await bitsuranceLookup();
-    if (!response.success) {
-      alertUser(response.errorMessage);
-      return;
-    }
-    const insuredAccountsCodes = response.bitsuranceAccounts.map(account => account.status ? account.code : null);
-    const insured = accounts.filter(({ code }) => insuredAccountsCodes.includes(code));
-    setInsuredAccounts(insured);
-    setScanDone(true);
-    setScanLoading(false);
-    if (insured.length && redirectToDashboard) {
-      navigate('/market/bitsurance/dashboard');
+    try {
+      const response = await bitsuranceLookup();
+      if (!response.success) {
+        alertUser(response.errorMessage);
+        return;
+      }
+      const insuredAccountsCodes = response.bitsuranceAccounts.map(account => account.status ? account.code : null);
+      const insured = accounts.filter(({ code }) => insuredAccountsCodes.includes(code));
+      setInsuredAccounts(insured);
+      setScanDone(true);
+      if (insured.length && redirectToDashboard) {
+        navigate('/market/bitsurance/dashboard');
+      }
+    } finally {
+      setScanLoading(false);
     }
   };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontends/web/src/routes/bitsurance/bitsurance.tsx` around lines 44 - 57, The
detect function currently returns early on bitsuranceLookup() failure without
resetting scanLoading, leaving the CTA disabled; update detect to ensure
setScanLoading(false) is always called on error paths (including after
alertUser(response.errorMessage) and any other early returns), e.g., call
setScanLoading(false) before returning or use a try/finally around the
bitsuranceLookup() flow so setScanLoading(false) runs regardless; refer to the
detect function, bitsuranceLookup, setScanLoading and setScanDone to apply the
fix.
frontends/web/src/components/sidebar/sidebar.tsx (1)

95-153: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Handle account-scoped market routes in the sidebar active check.

This predicate only matches /market..., so the Marketplace entry stays inactive on preserved account-scoped paths like /account/:code/market/....

🔧 Suggested fix
-  const userInSpecificAccountMarketPage = pathname.startsWith('/market');
+  const userInSpecificAccountMarketPage =
+    pathname.startsWith('/market')
+    || /^\/account\/[^/]+\/market(?:\/|$)/.test(pathname);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontends/web/src/components/sidebar/sidebar.tsx` around lines 95 - 153, The
sidebar currently sets userInSpecificAccountMarketPage =
pathname.startsWith('/market'), which misses account-scoped market routes like
/account/:code/market; update the predicate used by
userInSpecificAccountMarketPage (and the NavLink market active check) to detect
both top-level and account-scoped market paths — e.g., replace the startsWith
check with a broader match (pathname.startsWith('/market') ||
pathname.includes('/market') or a regex like
/(^\/market|\/account\/[^/]+\/market)/) and ensure the NavLink className for the
market entry uses this updated variable to mark the link active.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontends/web/src/routes/bitsurance/dashboard.tsx`:
- Around line 117-123: The Button's title prop is using the wrong translation
key (t('account.exportTransactions')) causing an unrelated tooltip; update the
title to use the bitsurance-related translation (e.g., set
title={t('bitsurance.dashboard.button')} or another appropriate bitsurance key)
on the Button component (the JSX around Button with className={style.button},
primary, onClick={() => navigate('/market/bitsurance/account')} and children
{t('bitsurance.dashboard.button')}) so the hover text matches the "Insure a new
account" CTA.

In `@frontends/web/src/routes/bitsurance/widget.tsx`:
- Around line 145-156: Replace the hardcoded iframe title "Bitsurance" with a
translated string: import and call useTranslation() in the widget component
(frontends/web/src/routes/bitsurance/widget.tsx), then replace
title="Bitsurance" with title={t('bitsurance.widgetTitle')} (or your chosen
translation key) and add the key to your i18n resource files; ensure iframeRef,
onIframeLoad, height and iframeURL usage remain unchanged.

In `@frontends/web/src/routes/router.tsx`:
- Around line 334-346: The nested Route with path="bitsurance" under the parent
Route path="bitsurance" creates a dead /bitsurance/bitsurance route; update the
child route inside the outer Route (the one rendering BitsuranceRedirect) to
either be removed or changed to a catch-all by replacing the child Route
path="bitsurance" with path="*" so it will match any legacy /bitsurance/...
paths and render BitsuranceRedirect; locate the Routes referencing
path="bitsurance" and the BitsuranceRedirect element to apply the fix.

---

Outside diff comments:
In `@frontends/web/src/components/sidebar/sidebar.tsx`:
- Around line 95-153: The sidebar currently sets userInSpecificAccountMarketPage
= pathname.startsWith('/market'), which misses account-scoped market routes like
/account/:code/market; update the predicate used by
userInSpecificAccountMarketPage (and the NavLink market active check) to detect
both top-level and account-scoped market paths — e.g., replace the startsWith
check with a broader match (pathname.startsWith('/market') ||
pathname.includes('/market') or a regex like
/(^\/market|\/account\/[^/]+\/market)/) and ensure the NavLink className for the
market entry uses this updated variable to mark the link active.

In `@frontends/web/src/routes/bitsurance/bitsurance.tsx`:
- Around line 44-57: The detect function currently returns early on
bitsuranceLookup() failure without resetting scanLoading, leaving the CTA
disabled; update detect to ensure setScanLoading(false) is always called on
error paths (including after alertUser(response.errorMessage) and any other
early returns), e.g., call setScanLoading(false) before returning or use a
try/finally around the bitsuranceLookup() flow so setScanLoading(false) runs
regardless; refer to the detect function, bitsuranceLookup, setScanLoading and
setScanDone to apply the fix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c20af321-9a3b-40c2-8e63-18820a32918b

📥 Commits

Reviewing files that changed from the base of the PR and between 0c3adf2 and 0a4f4b8.

📒 Files selected for processing (20)
  • frontends/web/src/app.tsx
  • frontends/web/src/components/bottom-navigation/bottom-navigation.tsx
  • frontends/web/src/components/bottom-navigation/utils.ts
  • frontends/web/src/components/sidebar/sidebar.tsx
  • frontends/web/src/contexts/BackNavigationContext.tsx
  • frontends/web/src/locales/en/app.json
  • frontends/web/src/routes/account/components/insuredtag.tsx
  • frontends/web/src/routes/bitsurance/account.tsx
  • frontends/web/src/routes/bitsurance/bitsurance.tsx
  • frontends/web/src/routes/bitsurance/dashboard.tsx
  • frontends/web/src/routes/bitsurance/widget.module.css
  • frontends/web/src/routes/bitsurance/widget.tsx
  • frontends/web/src/routes/market/components/marketplace-navigation.tsx
  • frontends/web/src/routes/market/components/markettab.module.css
  • frontends/web/src/routes/market/components/markettab.test.tsx
  • frontends/web/src/routes/market/components/markettab.tsx
  • frontends/web/src/routes/market/market.tsx
  • frontends/web/src/routes/market/marketplace-layout.tsx
  • frontends/web/src/routes/router.tsx
  • frontends/web/src/routes/settings/more.tsx
💤 Files with no reviewable changes (2)
  • frontends/web/src/app.tsx
  • frontends/web/src/routes/bitsurance/widget.module.css

Comment thread frontends/web/src/routes/bitsurance/dashboard.tsx Outdated
Comment thread frontends/web/src/routes/bitsurance/widget.tsx
Comment thread frontends/web/src/routes/router.tsx Outdated
@strmci strmci force-pushed the move_insurance_to_marketplace branch from 0a4f4b8 to 03f2bdb Compare May 6, 2026 13:56
@BitBoxSwiss BitBoxSwiss deleted a comment from coderabbitai Bot May 6, 2026
@strmci strmci force-pushed the move_insurance_to_marketplace branch 5 times, most recently from a318c9e to 42e71f8 Compare May 7, 2026 12:40
@strmci strmci requested a review from thisconnect May 7, 2026 12:50
@strmci strmci marked this pull request as ready for review May 7, 2026 12:50
@strmci strmci requested a review from a team as a code owner May 7, 2026 12:50
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontends/web/src/routes/router.tsx (1)

291-319: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add legacy /bitsurance route redirects or update PR description.

The PR objective states "redirect legacy /bitsurance routes accordingly", but the current router contains no redirects for legacy paths like /bitsurance, /bitsurance/dashboard, /bitsurance/account/:code, or /bitsurance/widget/:code. These paths will now fail to match any route, breaking external links and user bookmarks.

Either:

  1. Add a redirect subtree at the root /bitsurance path that maps these legacy routes to their new /market/bitsurance/* counterparts, or
  2. Update the PR description to reflect that legacy URLs are intentionally no longer supported.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontends/web/src/routes/router.tsx` around lines 291 - 319, The router is
missing legacy redirects for /bitsurance/* so external links break; add a
root-level Route subtree that matches legacy paths (e.g., path="bitsurance" with
nested routes for index, dashboard, account/:code, widget/:code) and redirect
them to their new counterparts under /market/bitsurance (use the same target
routes used in the Market subtree such as the index -> /market/bitsurance,
dashboard -> /market/bitsurance/dashboard, account/:code ->
/market/bitsurance/account/:code, widget/:code ->
/market/bitsurance/widget/:code) so existing bookmarks resolve to the new
components (the new Market bitsurance routes reference Bitsurance,
BitsuranceAccountEl, BitsuranceWidgetEl, BitsuranceDashboard and
MarketplaceLayoutEl); alternatively update the PR description to state legacy
URLs are intentionally removed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontends/web/src/components/sidebar/sidebar.tsx`:
- Line 95: The variable userInSpecificAccountMarketPage no longer matches its
predicate pathname.startsWith('/market'); rename it (e.g., inMarketSection) or
inline the condition where used to improve clarity—update all occurrences of
userInSpecificAccountMarketPage (including the second usage block within the
same file) to the new name or replace with pathname.startsWith('/market') so
references like the assignment and any conditionals or JSX checks remain
consistent.

In `@frontends/web/src/routes/bitsurance/account.tsx`:
- Around line 90-114: The JSX return wraps a single <View> in an unnecessary
fragment (<>...</>); remove the fragment tokens so the component returns the
<View> directly (keep the existing <ViewContent>, conditional rendering of
btcAccounts, GroupedAccountSelector props like disabled, selected,
onChange={handleChangeAccount}, onProceed={handleProceed}, and the
t('bitsuranceAccount.noAccount') branch unchanged). Ensure
parentheses/whitespace remain correct around the returned <View>.

In `@frontends/web/src/routes/bitsurance/bitsurance.tsx`:
- Around line 86-143: The top-level fragment wrapping the single <View> in the
Bitsurance component is unnecessary; remove the <> and </> so the render returns
the <View fullscreen={false}> element directly (update the return in
bitsurance.tsx to return <View>... without the surrounding fragment), keeping
all inner children and props unchanged.

In `@frontends/web/src/routes/bitsurance/dashboard.tsx`:
- Around line 105-197: The JSX fragment wrapping the single <View> is
unnecessary; remove the outer <>...</> so the component returns the <View>
directly (update the return in the render of this file: remove the fragment
tokens surrounding the View element), ensuring the remaining structure and
import usage of View, ViewContent and children stay intact.

In `@frontends/web/src/routes/market/marketplace-layout.tsx`:
- Around line 78-82: The Header currently always uses t('generic.buySell'),
causing Bitsurance pages to show the wrong title; update the title prop in
marketplace-layout's JSX (the Header component usage) to conditionally choose
t('generic.insure') when the page is a Bitsurance route (use the existing
pathname check, isBitsurance flag, or activeTab) and fall back to
t('generic.buySell') otherwise, ensuring the translation hook
useTranslation()/t() is used and keeping the existing HideAmountsButton
rendering unchanged.

---

Outside diff comments:
In `@frontends/web/src/routes/router.tsx`:
- Around line 291-319: The router is missing legacy redirects for /bitsurance/*
so external links break; add a root-level Route subtree that matches legacy
paths (e.g., path="bitsurance" with nested routes for index, dashboard,
account/:code, widget/:code) and redirect them to their new counterparts under
/market/bitsurance (use the same target routes used in the Market subtree such
as the index -> /market/bitsurance, dashboard -> /market/bitsurance/dashboard,
account/:code -> /market/bitsurance/account/:code, widget/:code ->
/market/bitsurance/widget/:code) so existing bookmarks resolve to the new
components (the new Market bitsurance routes reference Bitsurance,
BitsuranceAccountEl, BitsuranceWidgetEl, BitsuranceDashboard and
MarketplaceLayoutEl); alternatively update the PR description to state legacy
URLs are intentionally removed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5e9759fe-e298-4b56-b496-1909e709ab2c

📥 Commits

Reviewing files that changed from the base of the PR and between 0a4f4b8 and 42e71f8.

📒 Files selected for processing (21)
  • CHANGELOG.md
  • frontends/web/src/app.tsx
  • frontends/web/src/components/bottom-navigation/bottom-navigation.tsx
  • frontends/web/src/components/bottom-navigation/utils.ts
  • frontends/web/src/components/sidebar/sidebar.tsx
  • frontends/web/src/contexts/BackNavigationContext.tsx
  • frontends/web/src/locales/en/app.json
  • frontends/web/src/routes/account/components/insuredtag.tsx
  • frontends/web/src/routes/bitsurance/account.tsx
  • frontends/web/src/routes/bitsurance/bitsurance.tsx
  • frontends/web/src/routes/bitsurance/dashboard.tsx
  • frontends/web/src/routes/bitsurance/widget.module.css
  • frontends/web/src/routes/bitsurance/widget.tsx
  • frontends/web/src/routes/market/components/marketplace-navigation.tsx
  • frontends/web/src/routes/market/components/markettab.module.css
  • frontends/web/src/routes/market/components/markettab.test.tsx
  • frontends/web/src/routes/market/components/markettab.tsx
  • frontends/web/src/routes/market/market.tsx
  • frontends/web/src/routes/market/marketplace-layout.tsx
  • frontends/web/src/routes/router.tsx
  • frontends/web/src/routes/settings/more.tsx
💤 Files with no reviewable changes (2)
  • frontends/web/src/app.tsx
  • frontends/web/src/routes/bitsurance/widget.module.css


const accountsByKeystore = getAccountsByKeystore(accounts);
const userInSpecificAccountMarketPage = (pathname.startsWith('/market'));
const userInSpecificAccountMarketPage = pathname.startsWith('/market');
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 7, 2026

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | 💤 Low value

Optional: rename userInSpecificAccountMarketPage.

Now that the predicate is just pathname.startsWith('/market'), the variable's name (which implied a per-account market context) no longer reflects what it checks. Consider renaming to inMarketSection or inlining the condition.

♻️ Proposed rename
-  const userInSpecificAccountMarketPage = pathname.startsWith('/market');
+  const inMarketSection = pathname.startsWith('/market');
@@
-                className={({ isActive }) => isActive || userInSpecificAccountMarketPage ? style.sidebarActive : ''}
+                className={({ isActive }) => isActive || inMarketSection ? style.sidebarActive : ''}

Also applies to: 151-169

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontends/web/src/components/sidebar/sidebar.tsx` at line 95, The variable
userInSpecificAccountMarketPage no longer matches its predicate
pathname.startsWith('/market'); rename it (e.g., inMarketSection) or inline the
condition where used to improve clarity—update all occurrences of
userInSpecificAccountMarketPage (including the second usage block within the
same file) to the new name or replace with pathname.startsWith('/market') so
references like the assignment and any conditionals or JSX checks remain
consistent.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

would be great to use simple naming, to reduce mental overhead, inMarket or inMarketSection 👍

const inMarket = ...

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@thisconnect, agreed — inMarket keeps it concise. Here's the updated diff:

-  const userInSpecificAccountMarketPage = pathname.startsWith('/market');
+  const inMarket = pathname.startsWith('/market');
@@
-                className={({ isActive }) => isActive || userInSpecificAccountMarketPage ? style.sidebarActive : ''}
+                className={({ isActive }) => isActive || inMarket ? style.sidebarActive : ''}

🧠 Learnings used
Learnt from: thisconnect
Repo: BitBoxSwiss/bitbox-wallet-app PR: 4102
File: frontends/web/src/components/infobutton/infobutton.tsx:6-6
Timestamp: 2026-05-05T13:22:38.824Z
Learning: In this repository’s web frontend, accessibility (screen reader support and meaningful ARIA semantics such as aria-labels/roles) is intentionally deferred until an active accessibility effort starts. During code reviews, do not raise or require missing ARIA attributes, roles, or screen-reader support as issues in TSX changes; wait to enforce these concerns once accessibility work is underway.

Learnt from: thisconnect
Repo: BitBoxSwiss/bitbox-wallet-app PR: 3916
File: frontends/web/src/components/banners/offline-error.tsx:16-17
Timestamp: 2026-05-14T09:39:14.878Z
Learning: In BitBoxSwiss/bitbox-wallet-app, treat `TConfig.backend` and `TConfig.backend.proxy` as required (non-optional) because they are typed as such in `frontends/web/src/api/config.ts`. Only the top-level `config` value from `ConfigContext` may be `undefined` (`TConfig | undefined`). During review, avoid recommending or introducing optional chaining like `config?.backend?.` or `config?.backend?.proxy`—if you need to handle absence, guard on `config` itself (or earlier null-check) and then access `backend`/`proxy` directly.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

renamed to inMarketSection

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment thread frontends/web/src/routes/bitsurance/account.tsx
Comment thread frontends/web/src/routes/bitsurance/bitsurance.tsx
Comment thread frontends/web/src/routes/bitsurance/dashboard.tsx Outdated
Comment thread frontends/web/src/routes/market/marketplace-layout.tsx
@strmci strmci force-pushed the move_insurance_to_marketplace branch from 42e71f8 to 9160192 Compare May 8, 2026 09:52
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontends/web/src/routes/bitsurance/bitsurance.tsx`:
- Around line 48-52: The bitsuranceLookup result is not being used to stop or
redirect before navigation: update the logic around bitsuranceLookup(),
alertUser(), and detect(false) so that you only call
navigate('/market/bitsurance/account') when the lookup succeeded and the account
actually needs onboarding; if response.success is false, return early (no
navigation) after calling alertUser(response.errorMessage); if the response
indicates the account is already insured, either short-circuit to the
appropriate account view or show the "already insured" UI instead of proceeding
to the insure flow. Adjust both the initial lookup block (bitsuranceLookup,
alertUser, detect(false)) and the later navigation block that currently
unconditionally calls navigate('/market/bitsurance/account') so navigation is
gated by response.success and the lookup's insured status.

In `@frontends/web/src/routes/market/components/markettab.module.css`:
- Around line 1-9: The .navigation rule uses justify-content: center (a no-op
without a flex/grid container) and suggests it was intended to be both a flex
item and a flex container (flex-grow: 0); update the .navigation CSS to make
justify-content effective by adding display: flex (and optionally align-items:
center if vertical centering of the pill buttons is desired) so children are
centered, or remove justify-content if you do not want it to be a container —
edit the .navigation block to add display: flex and align-items: center to
restore the intended centering behavior.

In `@frontends/web/src/routes/market/components/markettab.test.tsx`:
- Line 76: Tests are failing because the i18n mock used by frontends/web tests
does not include translations for 'generic.swap' and 'generic.insure', so t(...)
falls back to the key strings and the queries for button names 'Swap'/'Insure'
fail; open the i18n mock (frontends/web/__mocks__/i18n.ts) and add entries
'generic.swap': 'Swap' and 'generic.insure': 'Insure' to the resources object
used by the mocked t function so the rendered buttons have the expected
accessible names.

In `@frontends/web/src/routes/market/market.tsx`:
- Around line 75-90: The effect currently selects nextAccount but never updates
the URL when the route lacked a valid account code; update it to perform a
replace-navigation to the account-scoped path whenever validRouteAccountCode is
falsy and you choose a non-empty nextAccount: after calling
setMarketAccountCode?.(nextAccount) and setSelectedAccount(nextAccount) in the
useEffect, call your router replace (e.g. history.replace or navigate with {
replace: true }) with getMarketSelectPath(activeTab, nextAccount) so the URL is
normalized into the account-scoped path; guard this navigation behind
validRouteAccountCode being empty and nextAccount !== '' to avoid unnecessary
redirects.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 024b5c9a-1805-4ee9-b76c-816761377a95

📥 Commits

Reviewing files that changed from the base of the PR and between 42e71f8 and 9160192.

📒 Files selected for processing (21)
  • CHANGELOG.md
  • frontends/web/src/app.tsx
  • frontends/web/src/components/bottom-navigation/bottom-navigation.tsx
  • frontends/web/src/components/bottom-navigation/utils.ts
  • frontends/web/src/components/sidebar/sidebar.tsx
  • frontends/web/src/contexts/BackNavigationContext.tsx
  • frontends/web/src/locales/en/app.json
  • frontends/web/src/routes/account/components/insuredtag.tsx
  • frontends/web/src/routes/bitsurance/account.tsx
  • frontends/web/src/routes/bitsurance/bitsurance.tsx
  • frontends/web/src/routes/bitsurance/dashboard.tsx
  • frontends/web/src/routes/bitsurance/widget.module.css
  • frontends/web/src/routes/bitsurance/widget.tsx
  • frontends/web/src/routes/market/components/marketplace-navigation.tsx
  • frontends/web/src/routes/market/components/markettab.module.css
  • frontends/web/src/routes/market/components/markettab.test.tsx
  • frontends/web/src/routes/market/components/markettab.tsx
  • frontends/web/src/routes/market/market.tsx
  • frontends/web/src/routes/market/marketplace-layout.tsx
  • frontends/web/src/routes/router.tsx
  • frontends/web/src/routes/settings/more.tsx
💤 Files with no reviewable changes (2)
  • frontends/web/src/routes/bitsurance/widget.module.css
  • frontends/web/src/app.tsx

Comment thread frontends/web/src/routes/bitsurance/bitsurance.tsx
Comment thread frontends/web/src/routes/market/components/markettab.module.css
Comment thread frontends/web/src/routes/market/components/markettab.test.tsx
Comment thread frontends/web/src/routes/market/market.tsx Outdated
@strmci strmci force-pushed the move_insurance_to_marketplace branch from 9160192 to 2ef541b Compare May 8, 2026 10:09
Route Bitsurance through the marketplace layout and
add the Insure tab.Move Bitsurance entry points to
/market/bitsurance, update navigationentry points, and
keep the single-account auto-connect flow.

Also preserve account-code marketplace tab paths, clean
stale no-account routing, and cover the new tab/path
helpers in tests.
@strmci strmci force-pushed the move_insurance_to_marketplace branch from 2ef541b to 7b7ab45 Compare May 11, 2026 08:28
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
frontends/web/src/routes/market/components/markettab.module.css (1)

1-9: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add display: flex to make justify-content: center effective.

The .navigation rule includes justify-content: center, but without display: flex, this property has no effect. The flex-grow: 0 on line 3 confirms this element is intended to participate in both flex-item and flex-container roles.

🛠️ Proposed fix
 .navigation {
   box-sizing: border-box;
+  display: flex;
   flex-grow: 0;
   justify-content: center;
   margin: 0 auto;
   max-width: var(--content-width);
   padding: 0 var(--space-default);
   width: 100%;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontends/web/src/routes/market/components/markettab.module.css` around lines
1 - 9, The .navigation CSS block is missing display: flex so justify-content:
center has no effect; update the .navigation rule to include display: flex
(keeping existing properties like flex-grow: 0, width, padding, etc.) so it
becomes a flex container and the justify-content center behavior works as
intended.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontends/web/src/routes/market/components/marketplace-navigation.tsx`:
- Line 20: cachedShowSwap is a module-level boolean preserving swap visibility
across remounts; replace it with a proper shared state provider to be safe for
SSR/concurrent renders. Create a SwapVisibilityContext (or use existing global
store like Redux/Zustand) that exposes showSwap and setShowSwap, update
MarketplaceNavigation to read/write via useContext/useStore instead of the
module variable, remove cachedShowSwap, and optionally persist initial value to
localStorage inside the provider if you need cross-session caching.

In `@frontends/web/src/routes/market/marketplace-layout.tsx`:
- Around line 41-72: The pathname checks using startsWith in
marketplace-layout.tsx (variables isBitsurance, isMarketSelect, and
showMarketplaceNavigation) are too permissive; update them to anchor with exact
match or a trailing slash (e.g., replace
pathname.startsWith('/market/bitsurance') with pathname === '/market/bitsurance'
|| pathname.startsWith('/market/bitsurance/')) and do the same for
'/market/select' and the '/market/bitsurance/widget' check so sibling segments
like '/market/bitsurance-foo' no longer match; keep the rest of the logic
(marketAccountCode, outletContext, handleChangeTab) unchanged.

---

Duplicate comments:
In `@frontends/web/src/routes/market/components/markettab.module.css`:
- Around line 1-9: The .navigation CSS block is missing display: flex so
justify-content: center has no effect; update the .navigation rule to include
display: flex (keeping existing properties like flex-grow: 0, width, padding,
etc.) so it becomes a flex container and the justify-content center behavior
works as intended.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 23d82b71-52c4-4f7f-8657-38a0029d0392

📥 Commits

Reviewing files that changed from the base of the PR and between 9160192 and 7b7ab45.

📒 Files selected for processing (22)
  • CHANGELOG.md
  • frontends/web/__mocks__/i18n.ts
  • frontends/web/src/app.tsx
  • frontends/web/src/components/bottom-navigation/bottom-navigation.tsx
  • frontends/web/src/components/bottom-navigation/utils.ts
  • frontends/web/src/components/sidebar/sidebar.tsx
  • frontends/web/src/contexts/BackNavigationContext.tsx
  • frontends/web/src/locales/en/app.json
  • frontends/web/src/routes/account/components/insuredtag.tsx
  • frontends/web/src/routes/bitsurance/account.tsx
  • frontends/web/src/routes/bitsurance/bitsurance.tsx
  • frontends/web/src/routes/bitsurance/dashboard.tsx
  • frontends/web/src/routes/bitsurance/widget.module.css
  • frontends/web/src/routes/bitsurance/widget.tsx
  • frontends/web/src/routes/market/components/marketplace-navigation.tsx
  • frontends/web/src/routes/market/components/markettab.module.css
  • frontends/web/src/routes/market/components/markettab.test.tsx
  • frontends/web/src/routes/market/components/markettab.tsx
  • frontends/web/src/routes/market/market.tsx
  • frontends/web/src/routes/market/marketplace-layout.tsx
  • frontends/web/src/routes/router.tsx
  • frontends/web/src/routes/settings/more.tsx
💤 Files with no reviewable changes (2)
  • frontends/web/src/app.tsx
  • frontends/web/src/routes/bitsurance/widget.module.css

showSwap?: boolean;
};

let cachedShowSwap: boolean | undefined;
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 11, 2026

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | 💤 Low value

Module-level state is acceptable here but consider alternatives in future.

The cachedShowSwap module-level variable preserves swap visibility across component remounts. While this works for a client-side SPA, consider moving this to a context provider or state manager if the app adopts SSR or concurrent rendering in the future.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontends/web/src/routes/market/components/marketplace-navigation.tsx` at
line 20, cachedShowSwap is a module-level boolean preserving swap visibility
across remounts; replace it with a proper shared state provider to be safe for
SSR/concurrent renders. Create a SwapVisibilityContext (or use existing global
store like Redux/Zustand) that exposes showSwap and setShowSwap, update
MarketplaceNavigation to read/write via useContext/useStore instead of the
module variable, remove cachedShowSwap, and optionally persist initial value to
localStorage inside the provider if you need cross-session caching.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This introduced a impure hidden global state, this should be move to the market context, but see my other comment about the current approach of using react-router "outlet".

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@thisconnect, agreed — cachedShowSwap as a module-level variable is global and impure state that survives across component lifecycles (and even multiple app instances in a test environment, which can cause flaky tests). Moving it into the marketplace/market context is the right fix, where it can live as proper reactive state alongside marketAccountCode, regions, etc. in TMarketplaceOutletContext.

Since this refactor seems blocked on or coupled to the broader outlet-vs-context discussion you mentioned in your other comment, would you like me to open a follow-up GitHub issue to track moving cachedShowSwap into the market context once the outlet approach is settled?


🧠 Learnings used
Learnt from: thisconnect
Repo: BitBoxSwiss/bitbox-wallet-app PR: 4038
File: frontends/web/src/routes/settings/components/about/support-link-setting.tsx:7-7
Timestamp: 2026-04-22T18:36:13.978Z
Learning: In files under `frontends/web/src/routes/`, do not flag relative imports within the `src/routes/` directory tree (e.g., `./...` and `../...`). Use the `@/` alias mainly when the import leaves `src/routes/` and targets other `src/` areas (e.g., `@/components`, `@/api`, `@/utils`).

Learnt from: thisconnect
Repo: BitBoxSwiss/bitbox-wallet-app PR: 4102
File: frontends/web/src/components/infobutton/infobutton.tsx:6-6
Timestamp: 2026-05-05T13:22:38.824Z
Learning: In this repository’s web frontend, accessibility (screen reader support and meaningful ARIA semantics such as aria-labels/roles) is intentionally deferred until an active accessibility effort starts. During code reviews, do not raise or require missing ARIA attributes, roles, or screen-reader support as issues in TSX changes; wait to enforce these concerns once accessibility work is underway.

Learnt from: thisconnect
Repo: BitBoxSwiss/bitbox-wallet-app PR: 3916
File: frontends/web/src/components/banners/offline-error.tsx:16-17
Timestamp: 2026-05-14T09:39:14.878Z
Learning: In BitBoxSwiss/bitbox-wallet-app, treat `TConfig.backend` and `TConfig.backend.proxy` as required (non-optional) because they are typed as such in `frontends/web/src/api/config.ts`. Only the top-level `config` value from `ConfigContext` may be `undefined` (`TConfig | undefined`). During review, avoid recommending or introducing optional chaining like `config?.backend?.` or `config?.backend?.proxy`—if you need to handle absence, guard on `config` itself (or earlier null-check) and then access `backend`/`proxy` directly.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We should fix it and not merge as is, so no issue is needed thanks.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧩 Analysis chain

Understood, @thisconnect — let me look at the full content of both files to plan a minimal fix.


🏁 Script executed:

#!/bin/bash
cat frontends/web/src/routes/market/marketplace-layout.tsx
echo "---FILE BOUNDARY---"
cat frontends/web/src/routes/market/components/marketplace-navigation.tsx

Length of output: 5447


@thisconnect, agreed. Here's the minimal fix — lift the swap-status fetch and its cached value into MarketplaceLayout state, so MarketplaceNavigation becomes a pure/stateless forwarder.

  • Move showSwap state and getSwapStatus load to MarketplaceLayout
  • Remove cachedShowSwap module-level var + useLoad/useEffect from MarketplaceNavigation
  • Wire the resolved value down as a prop

🧠 Learnings used
Learnt from: thisconnect
Repo: BitBoxSwiss/bitbox-wallet-app PR: 4038
File: frontends/web/src/routes/settings/components/about/support-link-setting.tsx:7-7
Timestamp: 2026-04-22T18:36:13.978Z
Learning: In files under `frontends/web/src/routes/`, do not flag relative imports within the `src/routes/` directory tree (e.g., `./...` and `../...`). Use the `@/` alias mainly when the import leaves `src/routes/` and targets other `src/` areas (e.g., `@/components`, `@/api`, `@/utils`).

Learnt from: thisconnect
Repo: BitBoxSwiss/bitbox-wallet-app PR: 4102
File: frontends/web/src/components/infobutton/infobutton.tsx:6-6
Timestamp: 2026-05-05T13:22:38.824Z
Learning: In this repository’s web frontend, accessibility (screen reader support and meaningful ARIA semantics such as aria-labels/roles) is intentionally deferred until an active accessibility effort starts. During code reviews, do not raise or require missing ARIA attributes, roles, or screen-reader support as issues in TSX changes; wait to enforce these concerns once accessibility work is underway.

Learnt from: thisconnect
Repo: BitBoxSwiss/bitbox-wallet-app PR: 3916
File: frontends/web/src/components/banners/offline-error.tsx:16-17
Timestamp: 2026-05-14T09:39:14.878Z
Learning: In BitBoxSwiss/bitbox-wallet-app, treat `TConfig.backend` and `TConfig.backend.proxy` as required (non-optional) because they are typed as such in `frontends/web/src/api/config.ts`. Only the top-level `config` value from `ConfigContext` may be `undefined` (`TConfig | undefined`). During review, avoid recommending or introducing optional chaining like `config?.backend?.` or `config?.backend?.proxy`—if you need to handle absence, guard on `config` itself (or earlier null-check) and then access `backend`/`proxy` directly.

  • 📌 Commit the changes to this branch

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

React Router outlet context usage replaced with a market-specific React context, following the staging-spark style.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment thread frontends/web/src/routes/market/marketplace-layout.tsx
Comment thread frontends/web/__mocks__/i18n.ts Outdated
en: {
translation: {
'generic.insure': 'Insure',
'generic.swap': 'Swap',
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is it important to add this here?

Other tests don't mock here, but directly in the test files where needed.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

removed

<div className={style.single}>
<ShieldLight alt={t('sidebar.insurance')} />
</div>
<span className={style.sidebarLabel}>{t('sidebar.insurance')}</span>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

With this PR sidebar.insurance is not used anywhere anymore, please remove.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

removed

<Main>
<GuideWrapper>
<GuidedContent>
<Header title={<h2>{t('bitsuranceAccount.title')}</h2>} />
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

bitsuranceAccount.title is not used in the codebase anymore.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

removed

const { isDarkMode } = useDarkmode();
const [insuredAccounts, setInsuredAccounts] = useState<TAccount[]>([]);
const [redirecting, setRedirecting] = useState(true);
const [redirecting, setRedirecting] = useState(() => accounts.some(({ bitsuranceStatus }) => bitsuranceStatus));
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I wanted to nit that this initialization is a bit hard to read and duplicate with the condition in the next effect.
But GPT mentions you might not need the redirecting state at all.
But should it only check the accounts on component-mount or also if accounts object changes later?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good point, I removed the redirecting state and replaced it with a derived hasBitsuranceAccount value, which is used both for the redirect effect and the render guard.

if (nextAccount) {
setMarketAccountCode?.(nextAccount);
if (!validRouteAccountCode) {
navigate(getMarketSelectPath(activeTab, nextAccount), { replace: true });
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'd find it much clearer to understand what it does if you just use the 1 line template literal and remove getMarketSelectPath.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Removed getMarketSelectPath and used market select URL template strings.

showSwap?: boolean;
};

let cachedShowSwap: boolean | undefined;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This introduced a impure hidden global state, this should be move to the market context, but see my other comment about the current approach of using react-router "outlet".


const handleChangeTab = (tab: TMarketplaceTab) => {
if (tab === 'insure') {
navigate(getInsurancePath(accounts));
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

getInsurancePath is only used here, I find it much harder to follow. Please remove getInsurancePath and just add the 2 lines here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

getInsurancePath removed


const accountsByKeystore = getAccountsByKeystore(accounts);
const userInSpecificAccountMarketPage = (pathname.startsWith('/market'));
const userInSpecificAccountMarketPage = pathname.startsWith('/market');
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

would be great to use simple naming, to reduce mental overhead, inMarket or inMarketSection 👍

const inMarket = ...

setSelectedAccount(nextAccount);
}
}, [accounts, selectedAccount]);
}, [accounts, activeTab, navigate, selectedAccount, setMarketAccountCode, validRouteAccountCode]);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The purpose of this effect before was to: // keep account list in sync and ensure a valid selected account..

Now it also does conditional navigate but is very hard to follow. I can't tell if there was also some bug fixed or why it needs all those dependecies here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I split the effect so each part has a single responsibility (syncing the account list, ensuring a valid selected account, and normalizing the URL) so it's easier to follow.

</View>
</>
);
};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I've reviewed all other changes, but did not yet fully understand this file nor review it fully.

@strmci strmci force-pushed the move_insurance_to_marketplace branch from d326e55 to 0b1d8c4 Compare May 20, 2026 08:43
- remove generic.insure / generic.swap from the shared i18n
  mock and kept translation setup local to the relevant test.
- rename userInSpecificAccountMarketPage to
  inMarketSection.
- remove redirecting state in Bitsurance and derived redirect
  state from hasBitsuranceAccount.
- removed getMarketSelectPath and used explicit market
  select URL template strings.
- remove getInsurancePath and inlined the Bitsurance route
  decision.
- removed unused sidebar.insurance, bitsuranceAccount.title
- replaced hidden global cachedShowSwap with
   market-   scoped React context.
-  replaced React Router outlet context usage with
   a market-specific React context, following the staging-spark
   style.
- simplify market navigation state in market.tsx
@strmci strmci force-pushed the move_insurance_to_marketplace branch from 0b1d8c4 to 3bfc0bb Compare May 20, 2026 09:14
@strmci
Copy link
Copy Markdown
Collaborator Author

strmci commented May 20, 2026

@thisconnect thanks

I addressed your comments in the second commit, PTAL 🙏

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