Skip to content

Multi Account notifications#2046

Merged
prxt6529 merged 5 commits intomainfrom
multi-account-notifications
Mar 4, 2026
Merged

Multi Account notifications#2046
prxt6529 merged 5 commits intomainfrom
multi-account-notifications

Conversation

@prxt6529
Copy link
Copy Markdown
Collaborator

@prxt6529 prxt6529 commented Mar 4, 2026

Summary by CodeRabbit

  • New Features

    • Connected accounts display unread notification badges (numeric, capped at "99+") and a subtle unread dot on other profiles across header, sidebar, dropdowns and user lists.
    • Unread counts update automatically via background polling so indicators stay current.
  • Style

    • Avatar markup and spacing adjusted to accommodate badges and indicators.
    • Navigation and spacer heights tweaked for consistent alignment.

Signed-off-by: prxt6529 <prxt@6529.io>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 4, 2026

📝 Walkthrough

Walkthrough

Adds a new polling hook that computes per-connected-account unread notification counts, exposes a normalized address→count map on SeizeConnectContext, and wires those counts into header, sidebar, connected-accounts, and proxy UI to render per-account badges and an aggregated unread indicator.

Changes

Cohort / File(s) Summary
Context & Hook
components/auth/SeizeConnectContext.tsx, hooks/useConnectedAccountsUnreadNotifications.ts
New hook polls backend (~15s) and returns a lowercased address→count map; SeizeConnectContextType gains connectedAccountUnreadNotifications and provider exposes it (included in memo deps).
Header — main & avatar components
components/header/AppHeader.tsx, components/header/AppSidebarUserInfo.tsx, components/header/AppSidebarConnectedAccounts.tsx
Consume context counts, wrap avatar DOM to support badges/dots, render unread indicators (badge label capped at 99+) with positioning and ARIA attributes.
Connected accounts UI & proxy
components/header/user/connected/HeaderUserConnectedAccounts.tsx, components/header/user/proxy/HeaderUserProxyDropdown.tsx
ConnectedAccountItem adds optional unreadNotificationsCount; proxy dropdown accepts connectedAccountUnreadNotifications prop and augments accounts with per-account counts before rendering.
Sidebar & layout tweaks
components/layout/sidebar/WebSidebarUser.tsx, components/layout/AppLayout.tsx
WebSidebarUser computes hasUnreadOnOtherConnectedProfiles from context and shows an unread dot; AppLayout spacer height adjusted to tw-h-[85px].
Navigation adjustments
components/navigation/BottomNavigation.tsx, components/navigation/NavItem.tsx
BottomNavigation: removed Capacitor padding logic, fixed height tw-h-20 and simplified item alignment; NavItem: button heights changed from tw-h-16 to tw-h-full.
Small UI components & avatars
components/header/user/connected/*, components/header/* (related files)
Multiple avatar blocks refactored to add inner wrappers for badge placement and to preserve existing overlays/fallbacks; unread badge rendering added across related components.

Sequence Diagram(s)

sequenceDiagram
    participant UI as UI Components
    participant Context as SeizeConnectContext
    participant Hook as useConnectedAccountsUnreadNotifications
    participant RQ as ReactQuery
    participant API as Backend API

    UI->>Context: read connectedAccountUnreadNotifications
    Context->>Hook: initialize with storedConnectedAccounts
    Hook->>RQ: create polling queries (interval: 15000ms)
    RQ->>API: fetch unread count per account
    API-->>RQ: return counts
    RQ-->>Hook: aggregated address→count map
    Hook-->>Context: provide counts
    Context-->>UI: deliver counts
    UI->>UI: render badges/dots per account
    Note over RQ,API: refetch on interval, focus, reconnect
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Multi Profile support #2010 — Related SeizeConnectContext and connected-account UI changes that appear connected to per-account state surfaced across header/sidebar components.

Suggested reviewers

  • simo6529
  • ragnep
  • GelatoGenesis

Poem

🐰
I counted pings on wallets near and far,
Tiny indigo dots mark each unread star,
Hooks hum softly, polling day and night,
Avatars gleam with badges in sight,
Hooray — every hop brings unread to light!

🚥 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 'Multi Account notifications' directly describes the primary feature added: support for displaying unread notification counts across multiple connected accounts with visual indicators.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch multi-account-notifications

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: 2

🧹 Nitpick comments (1)
components/navigation/BottomNavigation.tsx (1)

118-121: Use a stable identifier instead of label text for Home offset logic.

Line 119 depends on item.name === "Home", which is brittle if the label changes (copy/i18n). Prefer a stable field like icon or an explicit id.

Suggested refactor
-                item.name === "Home" ? "-tw-translate-y-1" : ""
+                item.icon === "home" ? "-tw-translate-y-1" : ""
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/navigation/BottomNavigation.tsx` around lines 118 - 121, The
current offset logic in BottomNavigation.tsx uses a brittle label check
(item.name === "Home") to apply "-tw-translate-y-1"; replace this with a stable
identifier (e.g., item.id or item.key or item.icon) by updating the conditional
in the className expression to check that stable field instead of item.name, and
ensure the navigation items source (where items are defined) includes and sets
that stable id for the Home entry so the new condition (e.g., item.id === 'home'
or item.icon === 'homeIcon') reliably targets the Home button.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/navigation/BottomNavigation.tsx`:
- Around line 111-112: Replace the hard-coded tw-h-[65px] in the
BottomNavigation component’s container className with a height that adds the iOS
safe area inset (use calc(65px + env(safe-area-inset-bottom, 0px)) or
equivalent) so the nav sits above the gesture area; then update the layout
spacer element used to push page content (the bottom nav spacer in the same
component) to use the identical height formula so content spacing remains in
sync.

In `@hooks/useConnectedAccountsUnreadNotifications.ts`:
- Around line 31-42: The current try/catch in
useConnectedAccountsUnreadNotifications swallows fetch/auth errors and returns
0, which can incorrectly clear unread counts; change the error handling so
failures do not coerce to 0: remove the catch that returns 0 (or rethrow the
caught error) so that errors from commonApiFetch(...) propagate, and keep the
successful path that returns clampUnreadCount(notifications.unread_count);
adjust any callers to handle the thrown error or preserve prior values instead
of relying on a 0 fallback.

---

Nitpick comments:
In `@components/navigation/BottomNavigation.tsx`:
- Around line 118-121: The current offset logic in BottomNavigation.tsx uses a
brittle label check (item.name === "Home") to apply "-tw-translate-y-1"; replace
this with a stable identifier (e.g., item.id or item.key or item.icon) by
updating the conditional in the className expression to check that stable field
instead of item.name, and ensure the navigation items source (where items are
defined) includes and sets that stable id for the Home entry so the new
condition (e.g., item.id === 'home' or item.icon === 'homeIcon') reliably
targets the Home button.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 41bc68df-c800-46d3-861e-6f34ec5801a8

📥 Commits

Reviewing files that changed from the base of the PR and between 03acc1c and 9f99919.

📒 Files selected for processing (10)
  • components/auth/SeizeConnectContext.tsx
  • components/header/AppHeader.tsx
  • components/header/AppSidebarConnectedAccounts.tsx
  • components/header/AppSidebarUserInfo.tsx
  • components/header/user/connected/HeaderUserConnectedAccounts.tsx
  • components/header/user/proxy/HeaderUserProxyDropdown.tsx
  • components/layout/AppLayout.tsx
  • components/layout/sidebar/WebSidebarUser.tsx
  • components/navigation/BottomNavigation.tsx
  • hooks/useConnectedAccountsUnreadNotifications.ts

Comment thread components/navigation/BottomNavigation.tsx Outdated
Comment thread hooks/useConnectedAccountsUnreadNotifications.ts Outdated
Signed-off-by: prxt6529 <prxt@6529.io>
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.

♻️ Duplicate comments (1)
components/navigation/BottomNavigation.tsx (1)

111-112: ⚠️ Potential issue | 🟠 Major

Reintroduce bottom safe-area compensation for iOS gesture areas.

Line 111 still uses a fixed nav height without safe-area-inset-bottom, so tap targets can sit too low on notched devices. Please also keep the spacer in components/layout/AppLayout.tsx synchronized with the same formula.

Suggested fix
-      className={`${hiddenStyle} tw-fixed tw-bottom-0 tw-left-0 tw-z-50 tw-h-20 tw-w-full tw-bg-black tw-shadow-inner tw-transition-[opacity,transform] tw-duration-75 tw-relative before:tw-absolute before:tw-inset-x-0 before:tw-top-0 before:tw-h-px before:tw-bg-iron-900 before:tw-content-['']`}
+      className={`${hiddenStyle} tw-fixed tw-bottom-0 tw-left-0 tw-z-50 tw-h-[calc(5rem+env(safe-area-inset-bottom,0px))] tw-pb-[env(safe-area-inset-bottom,0px)] tw-w-full tw-bg-black tw-shadow-inner tw-transition-[opacity,transform] tw-duration-75 tw-relative before:tw-absolute before:tw-inset-x-0 before:tw-top-0 before:tw-h-px before:tw-bg-iron-900 before:tw-content-['']`}

And keep spacer synced in components/layout/AppLayout.tsx:

-  <div className="tw-h-20 tw-w-full" />
+  <div className="tw-h-[calc(5rem+env(safe-area-inset-bottom,0px))] tw-w-full" />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/navigation/BottomNavigation.tsx` around lines 111 - 112, Bottom
navigation currently uses a fixed height class (tw-h-20) in the BottomNavigation
component causing tap targets to be too low on iOS; change the height to use a
calc that adds the safe-area inset (e.g., calc(5rem +
env(safe-area-inset-bottom))) by replacing the fixed tailwind height with an
inline style or CSS variable so the element respects safe-area-inset-bottom, and
then update the matching spacer in the AppLayout component (the spacer element
in components/layout/AppLayout.tsx) to use the identical calc formula so both
remain synchronized.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@components/navigation/BottomNavigation.tsx`:
- Around line 111-112: Bottom navigation currently uses a fixed height class
(tw-h-20) in the BottomNavigation component causing tap targets to be too low on
iOS; change the height to use a calc that adds the safe-area inset (e.g.,
calc(5rem + env(safe-area-inset-bottom))) by replacing the fixed tailwind height
with an inline style or CSS variable so the element respects
safe-area-inset-bottom, and then update the matching spacer in the AppLayout
component (the spacer element in components/layout/AppLayout.tsx) to use the
identical calc formula so both remain synchronized.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1861ef1b-2b4e-4657-b25d-3e6213514a42

📥 Commits

Reviewing files that changed from the base of the PR and between 9f99919 and 32651ec.

📒 Files selected for processing (3)
  • components/layout/AppLayout.tsx
  • components/navigation/BottomNavigation.tsx
  • components/navigation/NavItem.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/layout/AppLayout.tsx

prxt6529 added 2 commits March 4, 2026 14:24
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
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.

♻️ Duplicate comments (1)
components/navigation/BottomNavigation.tsx (1)

111-112: ⚠️ Potential issue | 🟠 Major

Add safe-area-inset-bottom for iOS notched devices.

The 85px height still doesn't account for iOS home indicator safe area. On devices with a home indicator, the nav may overlap or sit too close to the gesture area, affecting tap targets.

Additionally, per the relevant code snippets in LayoutContext.tsx (lines 280-288), the layout system measures this element's height via getBoundingClientRect(). Without the safe-area extension, the measured height won't include the bottom inset, potentially causing content to be clipped behind the nav on notched devices.

Suggested fix
-      className={`${hiddenStyle} tw-fixed tw-bottom-0 tw-left-0 tw-z-50 tw-h-[85px] tw-w-full tw-bg-black tw-shadow-inner tw-transition-[opacity,transform] tw-duration-75`}
+      className={`${hiddenStyle} tw-fixed tw-bottom-0 tw-left-0 tw-z-50 tw-h-[calc(85px+env(safe-area-inset-bottom,0px))] tw-pb-[env(safe-area-inset-bottom,0px)] tw-w-full tw-bg-black tw-shadow-inner tw-transition-[opacity,transform] tw-duration-75`}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/navigation/BottomNavigation.tsx` around lines 111 - 112,
BottomNavigation's fixed height doesn't include iOS safe-area inset, so update
the component (BottomNavigation.tsx) to account for env(safe-area-inset-bottom):
add the safe-area inset to the element's bottom spacing (e.g., include
padding-bottom using env(safe-area-inset-bottom) /
constant(safe-area-inset-bottom) or a Tailwind utility that applies that
padding) while keeping the visible tap target height (~85px) so
LayoutContext.tsx's getBoundingClientRect() measures include the inset; ensure
the className that currently uses hiddenStyle and tw-h-[85px] is adjusted to
include the bottom-safe-area padding rather than reducing the core 85px height.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@components/navigation/BottomNavigation.tsx`:
- Around line 111-112: BottomNavigation's fixed height doesn't include iOS
safe-area inset, so update the component (BottomNavigation.tsx) to account for
env(safe-area-inset-bottom): add the safe-area inset to the element's bottom
spacing (e.g., include padding-bottom using env(safe-area-inset-bottom) /
constant(safe-area-inset-bottom) or a Tailwind utility that applies that
padding) while keeping the visible tap target height (~85px) so
LayoutContext.tsx's getBoundingClientRect() measures include the inset; ensure
the className that currently uses hiddenStyle and tw-h-[85px] is adjusted to
include the bottom-safe-area padding rather than reducing the core 85px height.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ee4fb896-8d56-45dd-8989-c0fb003314ad

📥 Commits

Reviewing files that changed from the base of the PR and between 32651ec and ec86a84.

📒 Files selected for processing (2)
  • components/layout/AppLayout.tsx
  • components/navigation/BottomNavigation.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/layout/AppLayout.tsx

Signed-off-by: prxt6529 <prxt@6529.io>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Mar 4, 2026

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.

🧹 Nitpick comments (1)
hooks/useConnectedAccountsUnreadNotifications.ts (1)

46-50: Normalize query-key address order to avoid cache churn.

The key currently depends on incoming account order. Reordered-but-identical accounts will produce a new query key, which can drop continuity for cached previousCounts during transient per-account failures.

Proposed refactor
+  const stableAddressKeys = accounts
+    .map((account) => toAddressKey(account.address))
+    .sort();
+
   const queryKey = [
     QueryKey.IDENTITY_NOTIFICATIONS,
     "connected-account-unread-counts",
-    accounts.map((account) => toAddressKey(account.address)),
+    stableAddressKeys,
   ] as const;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/useConnectedAccountsUnreadNotifications.ts` around lines 46 - 50, The
query key generation in useConnectedAccountsUnreadNotifications.ts uses the
accounts array order so QueryKey.IDENTITY_NOTIFICATIONS +
"connected-account-unread-counts" + accounts.map(toAddressKey) can change when
account order changes; normalize by mapping accounts to their toAddressKey
values, sorting that array deterministically (e.g., lexicographically), and use
the sorted address keys in the queryKey so identical sets produce the same key
and avoid cache churn.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@hooks/useConnectedAccountsUnreadNotifications.ts`:
- Around line 46-50: The query key generation in
useConnectedAccountsUnreadNotifications.ts uses the accounts array order so
QueryKey.IDENTITY_NOTIFICATIONS + "connected-account-unread-counts" +
accounts.map(toAddressKey) can change when account order changes; normalize by
mapping accounts to their toAddressKey values, sorting that array
deterministically (e.g., lexicographically), and use the sorted address keys in
the queryKey so identical sets produce the same key and avoid cache churn.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2c93f58b-8623-4ecb-8928-3c06a43e6a8d

📥 Commits

Reviewing files that changed from the base of the PR and between ec86a84 and 31ab529.

📒 Files selected for processing (1)
  • hooks/useConnectedAccountsUnreadNotifications.ts

@prxt6529 prxt6529 merged commit 6b83404 into main Mar 4, 2026
7 checks passed
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