Skip to content

feat(home): add global wallet navigation and branding#2227

Open
webguru-hypha wants to merge 2 commits into
mainfrom
home-screen-main-pr-2225
Open

feat(home): add global wallet navigation and branding#2227
webguru-hypha wants to merge 2 commits into
mainfrom
home-screen-main-pr-2225

Conversation

@webguru-hypha

@webguru-hypha webguru-hypha commented May 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add a global My Wallet entry and dedicated wallet page in the top navigation
  • render the root ecosystem logo / home branding through a connected top bar
  • keep the home navigation aligned with the updated menu structure

Test plan

  • pnpm run format:fix
  • pnpm --filter web check-types

Made with Cursor

Summary by CodeRabbit

  • New Features
    • Added a new "My Wallet" section accessible from the navigation menu on both mobile and desktop views.
    • The My Wallet page displays three tabs: Wallet, Transactions, and Rewards for viewing and managing user assets and transaction history.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@webguru-hypha, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 50 minutes and 20 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4d8e5d97-8af6-4a08-bee0-09fc170615d1

📥 Commits

Reviewing files that changed from the base of the PR and between 0d78883 and 8da4464.

📒 Files selected for processing (3)
  • apps/web/src/app/[lang]/my-wallet/page.tsx
  • apps/web/src/app/layout.tsx
  • apps/web/src/components/my-wallet-tabs.tsx

Walkthrough

This PR introduces a new My Wallet page and component, enabling users to view wallet assets, transaction history, and pending rewards in a tabbed interface. The layout is updated with translated navigation labels and menu items linking to the new wallet page on both mobile and desktop.

Changes

My Wallet Feature

Layer / File(s) Summary
MyWalletTabs component implementation
apps/web/src/components/my-wallet-tabs.tsx
Client component with three tab panels for Wallet, Transactions, and Rewards. Uses useAuthentication and useMe hooks to verify user sign-in status and fetch person data. Renders sign-in prompts or loading states, then displays UserAssetsSection, UserTransactionsSection, and PendingRewardsSection with computed basePath derived from lang and person.slug.
My Wallet page route
apps/web/src/app/[lang]/my-wallet/page.tsx
Async page component that awaits locale params from Next.js dynamic routing, extracts lang, and renders a Container with "My Wallet" heading and MyWalletTabs component.
Navigation menu wiring and translations
apps/web/src/app/layout.tsx
Adds navMyWalletLabel initialized from Navigation translations, then inserts myWallet nav item linking to /${locale}/my-wallet in both mobile and desktop ConnectedButtonProfile navItems arrays.

Sequence Diagram

sequenceDiagram
  participant User
  participant MyWalletTabs
  participant useAuthentication
  participant useMe
  participant TabSections
  User->>MyWalletTabs: render(lang)
  MyWalletTabs->>useAuthentication: check if signed in
  MyWalletTabs->>useMe: fetch person data
  alt Not authenticated or missing slug
    MyWalletTabs-->>User: show sign-in prompt
  else Loading
    MyWalletTabs-->>User: show Loading...
  else Loaded and authenticated
    MyWalletTabs->>TabSections: render UserAssetsSection, UserTransactionsSection, PendingRewardsSection
    TabSections-->>User: render tabs with wallet content
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • hypha-dao/hypha-web#2068: Modifies apps/web/src/app/layout.tsx header/menu composition, including changes to MenuTop wiring and header nav items that may interact with the navigation changes in this PR.
  • hypha-dao/hypha-web#697: Modifies the top-menu navigation navItems to add/remove wallet-related entries; this PR adds a myWallet menu item linking to the new wallet page.

Suggested reviewers

  • plitzenberger
  • sergey3bv
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title follows conventional commits format but the scope 'home' does not match the actual changes, which are primarily related to the 'web' app and wallet feature. Update the title to use 'feat(web): add global wallet navigation' or similar to accurately reflect that changes are in the web app, not the home package.
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 (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 home-screen-main-pr-2225

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.

@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.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/src/app/`[lang]/my-wallet/page.tsx:
- Around line 9-19: The page heading is hardcoded; import getTranslations from
"next-intl/server" at the top, call it inside MyWalletPage with the locale from
props.params (e.g., const t = getTranslations(lang)), and replace the hardcoded
<h1> text with a translated key like t('myWallet.title'); keep
MyWalletTabs(lang={lang}) as-is and ensure the translation key exists in the
my-wallet namespace/messages.

In `@apps/web/src/app/layout.tsx`:
- Around line 179-182: The tNav('myWallet') call references a missing
translation key; add a "myWallet" entry under the "Navigation" namespace in each
locale file so tNav can resolve it: update packages/i18n/src/messages/en.json,
de.json, es.json, fr.json and pt.json to include "Navigation": { "myWallet":
"<appropriate translated string>" } (use the English text in en.json and correct
translations in the other files) so the navigation label renders correctly in
Layout (tNav usage).

In `@apps/web/src/components/connected-menu-top.tsx`:
- Around line 172-186: The MenuTop consumer is passing logoNode but MenuTopProps
and MenuTop implementation don't accept or render it, which causes no logo when
useReplacementLogoNode is true; update the MenuTop API by adding logoNode?:
ReactNode to the MenuTopProps type and modify the MenuTop component (the MenuTop
function/JSX) to conditionally render the provided logoNode in place of the
default <Logo> when logoNode exists (respecting existing logoHref / hrefTarget
behavior), ensuring prop names (logoNode, logoHref, hrefTarget) are used
consistently and exported in the MenuTop signature so the custom ecosystem logo
supplied by connected-menu-top.tsx will render.
- Around line 55-92: The two useSWR calls (for activeSpace and
organisationSpaces) duplicate the same inline fetch logic; extract a shared
generic fetcher function (e.g., apiJsonNoCacheFetcher<T>(url: string,
contextLabel?: string): Promise<T | null | T[]>) that sets Accept header, uses
cache: 'no-store', checks response.ok, logs a contextual warning (use the
contextLabel like '[ConnectedMenuTop] activeSpace' / '[ConnectedMenuTop]
organisationSpaces'), and returns the parsed JSON cast to T (or a safe default
like null or [] as appropriate). Replace the inline async fetchers in the useSWR
for activeSpace and organisationSpaces with calls to this shared fetcher,
preserving the return type casts and the same null/empty-array fallback
behavior.
- Around line 8-12: The import is failing because getRootSpace is not exported
from `@hypha-platform/epics`; remove getRootSpace from the named import (leave
getDhoSpaceSlugFromPathname and isSafeImageUrl) and either (a) add a local
utility function getRootSpace inside connected-menu-top.tsx with the same
behavior used by this component, or (b) import getRootSpace from the correct
module that actually exports it if one exists; then update all usages of
getRootSpace in this file to reference the new local helper or the corrected
import and run the build to verify the error is resolved.

In `@apps/web/src/components/my-wallet-tabs.tsx`:
- Around line 18-33: Replace all hardcoded user-facing strings in the
MyWalletTabs component with next-intl translation lookups using the provided
lang prop; specifically, import and call the translator (e.g., useTranslations
or intl) in MyWalletTabs and replace "Loading..." with t('loading') (or an
equivalent key), "Sign in to view your wallet." with t('signInToViewWallet'),
and the tab labels "Wallet", "Transactions", "Rewards" with t('tabs.wallet'),
t('tabs.transactions'), t('tabs.rewards') respectively; ensure keys are added to
the relevant locale files and keep the component's logic (isLoading,
isAuthenticated, person?.slug, activeTab, setActiveTab) unchanged while swapping
literal strings for t(...) calls.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0b9a0e4f-2c85-43b3-9cb8-162810f79250

📥 Commits

Reviewing files that changed from the base of the PR and between 15be14f and 5fbab6f.

📒 Files selected for processing (4)
  • apps/web/src/app/[lang]/my-wallet/page.tsx
  • apps/web/src/app/layout.tsx
  • apps/web/src/components/connected-menu-top.tsx
  • apps/web/src/components/my-wallet-tabs.tsx

Comment on lines +9 to +19
export default async function MyWalletPage(props: PageProps) {
const { lang } = await props.params;

return (
<Container className="flex w-full flex-col gap-4 py-4">
<h1 className="text-7 font-semibold tracking-tight text-foreground">
My Wallet
</h1>
<MyWalletTabs lang={lang} />
</Container>
);

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Hardcoded "My Wallet" page heading — use getTranslations

The <h1> text is a hardcoded user-facing string. In a Server Component the fix uses getTranslations from next-intl/server.

✏️ Proposed fix
+import { getTranslations } from 'next-intl/server';
 import { Locale } from '@hypha-platform/i18n';
 import { Container } from '@hypha-platform/ui';
 import { MyWalletTabs } from '@web/components/my-wallet-tabs';
 
 type PageProps = {
   params: Promise<{ lang: Locale }>;
 };
 
 export default async function MyWalletPage(props: PageProps) {
   const { lang } = await props.params;
+  const t = await getTranslations('MyWallet');
 
   return (
     <Container className="flex w-full flex-col gap-4 py-4">
-      <h1 className="text-7 font-semibold tracking-tight text-foreground">
-        My Wallet
-      </h1>
+      <h1 className="text-7 font-semibold tracking-tight text-foreground">
+        {t('pageTitle')}
+      </h1>
       <MyWalletTabs lang={lang} />
     </Container>
   );
 }

As per coding guidelines: "next-intl integration for i18n (no hardcoded user-facing strings)".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export default async function MyWalletPage(props: PageProps) {
const { lang } = await props.params;
return (
<Container className="flex w-full flex-col gap-4 py-4">
<h1 className="text-7 font-semibold tracking-tight text-foreground">
My Wallet
</h1>
<MyWalletTabs lang={lang} />
</Container>
);
import { getTranslations } from 'next-intl/server';
import { Locale } from '@hypha-platform/i18n';
import { Container } from '@hypha-platform/ui';
import { MyWalletTabs } from '@web/components/my-wallet-tabs';
type PageProps = {
params: Promise<{ lang: Locale }>;
};
export default async function MyWalletPage(props: PageProps) {
const { lang } = await props.params;
const t = await getTranslations('MyWallet');
return (
<Container className="flex w-full flex-col gap-4 py-4">
<h1 className="text-7 font-semibold tracking-tight text-foreground">
{t('pageTitle')}
</h1>
<MyWalletTabs lang={lang} />
</Container>
);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/app/`[lang]/my-wallet/page.tsx around lines 9 - 19, The page
heading is hardcoded; import getTranslations from "next-intl/server" at the top,
call it inside MyWalletPage with the locale from props.params (e.g., const t =
getTranslations(lang)), and replace the hardcoded <h1> text with a translated
key like t('myWallet.title'); keep MyWalletTabs(lang={lang}) as-is and ensure
the translation key exists in the my-wallet namespace/messages.

Comment thread apps/web/src/app/layout.tsx Outdated
Comment on lines +179 to +182
{
label: tNav('myWallet'),
href: `/${locale}/my-wallet`,
},

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.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for 'myWallet' key in all Navigation translation files
rg -n '"myWallet"' --type json

Repository: hypha-dao/hypha-web

Length of output: 45


🏁 Script executed:

# Find translation file locations
fd -e json -e ts -e tsx | grep -i -E '(i18n|intl|locale|translation|message|lang)' | head -20

Repository: hypha-dao/hypha-web

Length of output: 843


🏁 Script executed:

# Check the structure of navigation-related translations
fd -type f \( -name '*nav*' -o -name '*menu*' \) | grep -E '\.(json|ts|tsx)$'

Repository: hypha-dao/hypha-web

Length of output: 234


🏁 Script executed:

# Look for where tNav is defined and how translations are loaded
rg -n "tNav\s*=" --type typescript --type tsx -A 3

Repository: hypha-dao/hypha-web

Length of output: 98


🏁 Script executed:

# Check for any reference to 'myWallet' in the codebase (case-insensitive)
rg -i "myWallet" --type json --type typescript --type tsx -C 2

Repository: hypha-dao/hypha-web

Length of output: 98


🏁 Script executed:

# Search for myWallet in the translation JSON files
grep -r "myWallet" packages/i18n/src/messages/

Repository: hypha-dao/hypha-web

Length of output: 45


🏁 Script executed:

# Check the English translation file structure
cat packages/i18n/src/messages/en.json | head -100

Repository: hypha-dao/hypha-web

Length of output: 4253


🏁 Script executed:

# Check the navigation configuration
cat packages/i18n/src/navigation.ts

Repository: hypha-dao/hypha-web

Length of output: 258


🏁 Script executed:

# Check if myWallet appears anywhere in the en.json file
grep -i "wallet" packages/i18n/src/messages/en.json

Repository: hypha-dao/hypha-web

Length of output: 4175


🏁 Script executed:

# Get the complete Navigation section from en.json
jq '.Navigation' packages/i18n/src/messages/en.json

Repository: hypha-dao/hypha-web

Length of output: 640


🏁 Script executed:

# Check if myWallet is defined elsewhere in the codebase
rg -i "myWallet" --type json

Repository: hypha-dao/hypha-web

Length of output: 45


🏁 Script executed:

# Also check if the layout.tsx file actually exists and has the line we're checking
grep -n "myWallet" apps/web/src/app/layout.tsx

Repository: hypha-dao/hypha-web

Length of output: 126


Add myWallet translation key to the Navigation namespace in all translation files

The tNav('myWallet') call at line 180 references a translation key that doesn't exist in packages/i18n/src/messages/{en,de,es,fr,pt}.json. This will either throw an error or fall back to displaying the raw key string. Add the translation key to the Navigation section of all locale files.

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

In `@apps/web/src/app/layout.tsx` around lines 179 - 182, The tNav('myWallet')
call references a missing translation key; add a "myWallet" entry under the
"Navigation" namespace in each locale file so tNav can resolve it: update
packages/i18n/src/messages/en.json, de.json, es.json, fr.json and pt.json to
include "Navigation": { "myWallet": "<appropriate translated string>" } (use the
English text in en.json and correct translations in the other files) so the
navigation label renders correctly in Layout (tNav usage).

Comment thread apps/web/src/components/connected-menu-top.tsx
Comment on lines +55 to +92
const { data: activeSpace, isLoading: isLoadingActiveSpace } =
useSWR<Space | null>(
activeSpaceSlug ? `/api/v1/spaces/${activeSpaceSlug}` : null,
async (url: string) => {
const response = await fetch(url, {
headers: { Accept: 'application/json' },
cache: 'no-store',
});
if (!response.ok) {
console.warn('[ConnectedMenuTop] spaces fetch failed', {
status: response.status,
url,
});
return null;
}
return (await response.json()) as Space;
},
);
const {
data: organisationSpaces = [],
isLoading: isLoadingOrganisationSpaces,
} = useSWR<Space[]>(
activeSpaceSlug ? `/api/v1/spaces/${activeSpaceSlug}/organisation` : null,
async (url: string) => {
const response = await fetch(url, {
headers: { Accept: 'application/json' },
cache: 'no-store',
});
if (!response.ok) {
console.warn('[ConnectedMenuTop] organisation spaces fetch failed', {
status: response.status,
url,
});
return [];
}
return (await response.json()) as Space[];
},
);

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 | 🔵 Trivial | ⚡ Quick win

Duplicate inline SWR fetchers — extract a shared helper

The two useSWR calls (Lines 55–72 and 73–92) share identical fetch logic: set Accept header, use cache: 'no-store', check response.ok, warn on failure, and cast the result. Extract a single generic fetcher to avoid divergence.

♻️ Proposed refactor
+async function jsonFetcher<T>(url: string, fallback: T): Promise<T> {
+  const response = await fetch(url, {
+    headers: { Accept: 'application/json' },
+    cache: 'no-store',
+  });
+  if (!response.ok) {
+    console.warn('[ConnectedMenuTop] fetch failed', { status: response.status, url });
+    return fallback;
+  }
+  return (await response.json()) as T;
+}
+
 const { data: activeSpace, isLoading: isLoadingActiveSpace } =
   useSWR<Space | null>(
     activeSpaceSlug ? `/api/v1/spaces/${activeSpaceSlug}` : null,
-    async (url: string) => {
-      const response = await fetch(url, {
-        headers: { Accept: 'application/json' },
-        cache: 'no-store',
-      });
-      if (!response.ok) {
-        console.warn('[ConnectedMenuTop] spaces fetch failed', {
-          status: response.status,
-          url,
-        });
-        return null;
-      }
-      return (await response.json()) as Space;
-    },
+    (url: string) => jsonFetcher<Space | null>(url, null),
   );

 const { data: organisationSpaces = [], isLoading: isLoadingOrganisationSpaces } =
   useSWR<Space[]>(
     activeSpaceSlug ? `/api/v1/spaces/${activeSpaceSlug}/organisation` : null,
-    async (url: string) => {
-      const response = await fetch(url, {
-        headers: { Accept: 'application/json' },
-        cache: 'no-store',
-      });
-      if (!response.ok) {
-        console.warn('[ConnectedMenuTop] organisation spaces fetch failed', {
-          status: response.status,
-          url,
-        });
-        return [];
-      }
-      return (await response.json()) as Space[];
-    },
+    (url: string) => jsonFetcher<Space[]>(url, []),
   );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/connected-menu-top.tsx` around lines 55 - 92, The two
useSWR calls (for activeSpace and organisationSpaces) duplicate the same inline
fetch logic; extract a shared generic fetcher function (e.g.,
apiJsonNoCacheFetcher<T>(url: string, contextLabel?: string): Promise<T | null |
T[]>) that sets Accept header, uses cache: 'no-store', checks response.ok, logs
a contextual warning (use the contextLabel like '[ConnectedMenuTop] activeSpace'
/ '[ConnectedMenuTop] organisationSpaces'), and returns the parsed JSON cast to
T (or a safe default like null or [] as appropriate). Replace the inline async
fetchers in the useSWR for activeSpace and organisationSpaces with calls to this
shared fetcher, preserving the return type casts and the same null/empty-array
fallback behavior.

Comment thread apps/web/src/components/connected-menu-top.tsx
Comment on lines +18 to +33
export function MyWalletTabs({ lang }: MyWalletTabsProps) {
const [activeTab, setActiveTab] = React.useState('wallet');
const { isAuthenticated } = useAuthentication();
const { person, isLoading } = useMe();

if (isLoading) {
return <div className="py-4 text-sm text-muted-foreground">Loading...</div>;
}

if (!isAuthenticated || !person?.slug) {
return (
<div className="py-4 text-sm text-muted-foreground">
Sign in to view your wallet.
</div>
);
}

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Hardcoded user-facing strings — must use next-intl

Every visible string is hardcoded instead of going through next-intl. Per the apps/web/** coding guidelines, there must be no hardcoded user-facing strings.

Affected strings:

  • Line 24: "Loading..."
  • Line 30: "Sign in to view your wallet."
  • Lines 46, 49, 52: "Wallet", "Transactions", "Rewards"
✏️ Proposed fix
+import { useTranslations } from 'next-intl';
 
 export function MyWalletTabs({ lang }: MyWalletTabsProps) {
   const [activeTab, setActiveTab] = React.useState('wallet');
   const { isAuthenticated } = useAuthentication();
   const { person, isLoading } = useMe();
+  const t = useTranslations('MyWallet');
 
   if (isLoading) {
-    return <div className="py-4 text-sm text-muted-foreground">Loading...</div>;
+    return <div className="py-4 text-sm text-muted-foreground">{t('loading')}</div>;
   }
 
   if (!isAuthenticated || !person?.slug) {
     return (
       <div className="py-4 text-sm text-muted-foreground">
-        Sign in to view your wallet.
+        {t('signInPrompt')}
       </div>
     );
   }
   // ...
           <TabsTrigger value="wallet" variant="switch">
-            Wallet
+            {t('tabWallet')}
           </TabsTrigger>
           <TabsTrigger value="transactions" variant="switch">
-            Transactions
+            {t('tabTransactions')}
           </TabsTrigger>
           <TabsTrigger value="rewards" variant="switch">
-            Rewards
+            {t('tabRewards')}
           </TabsTrigger>

As per coding guidelines: "next-intl integration for i18n (no hardcoded user-facing strings)".

Also applies to: 43-54

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

In `@apps/web/src/components/my-wallet-tabs.tsx` around lines 18 - 33, Replace all
hardcoded user-facing strings in the MyWalletTabs component with next-intl
translation lookups using the provided lang prop; specifically, import and call
the translator (e.g., useTranslations or intl) in MyWalletTabs and replace
"Loading..." with t('loading') (or an equivalent key), "Sign in to view your
wallet." with t('signInToViewWallet'), and the tab labels "Wallet",
"Transactions", "Rewards" with t('tabs.wallet'), t('tabs.transactions'),
t('tabs.rewards') respectively; ensure keys are added to the relevant locale
files and keep the component's logic (isLoading, isAuthenticated, person?.slug,
activeTab, setActiveTab) unchanged while swapping literal strings for t(...)
calls.

webguru-hypha pushed a commit that referenced this pull request May 22, 2026
Replace the missing getRootSpace dependency with a local root-space resolver and restore MenuTop logoNode support so connected-menu-top compiles against current UI exports.

@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.

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (2)
apps/web/src/components/connected-menu-top.tsx (2)

154-158: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't gate the new connected branding behind aiChatEnabled.

This condition turns the new root-space logo path off on every space route whenever AI chat is disabled, so the branding added by this PR disappears in the default flag state. Either make this unconditional for space routes or introduce a dedicated branding flag instead of reusing the AI chat one. As per coding guidelines, "AI chat, Human chat, Coherence, and Space Memory are gated flags — off by default".

🤖 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 `@apps/web/src/components/connected-menu-top.tsx` around lines 154 - 158,
Summary: The connected branding is incorrectly gated by aiChatEnabled causing
the root-space logo to be hidden when AI chat is off. Fix: remove aiChatEnabled
from the gating logic so the new branding path is active on space routes
regardless of the AI chat flag—change suppressDefaultLogo to depend only on
isSpaceRoute and keep canRenderSpaceLogoNode using rootSpace,
isLoadingActiveSpace, and isLoadingOrganisationSpaces; alternatively if you
prefer a feature flag, introduce a dedicated enableConnectedBranding boolean and
use that instead of aiChatEnabled in suppressDefaultLogo.

187-189: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use rootTitle for the text fallback.

When a space has no custom logo image, this renders the same generic label for every DHO, so the branding context is lost exactly on the fallback path. Showing rootTitle first keeps the menu identifiable.

💡 Suggested fix
           <span className="relative truncate">
-            {tNavigation('ecosystemLogo')}
+            {rootTitle || tNavigation('ecosystemLogo')}
           </span>
🤖 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 `@apps/web/src/components/connected-menu-top.tsx` around lines 187 - 189,
Replace the generic fallback text so the menu shows the space branding: in the
component that renders the span (connected-menu-top, where
tNavigation('ecosystemLogo') is used), render rootTitle first and fall back to
tNavigation('ecosystemLogo') if rootTitle is falsy (e.g. use rootTitle ||
tNavigation('ecosystemLogo')). Update the span content accordingly so the UI
shows the specific rootTitle when no custom logo image exists.
🤖 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 `@apps/web/src/components/connected-menu-top.tsx`:
- Around line 53-62: The helper currently walks up parents using current.parent
or organisationById.get(current.parentId) and then returns the last seen current
even when a parent lookup failed; change the traversal so that if current.parent
is falsy and current.parentId is a number but
organisationById.get(current.parentId) returns undefined (i.e., nextParent is
unresolved), the function returns null instead of falling back to the child;
update the traversal in the block that computes nextParent (the variables
current, nextParent, organisationById, parentId) to detect this incomplete chain
and return null, and adjust the function signature/consumer handling if
necessary to accept a nullable return.

---

Outside diff comments:
In `@apps/web/src/components/connected-menu-top.tsx`:
- Around line 154-158: Summary: The connected branding is incorrectly gated by
aiChatEnabled causing the root-space logo to be hidden when AI chat is off. Fix:
remove aiChatEnabled from the gating logic so the new branding path is active on
space routes regardless of the AI chat flag—change suppressDefaultLogo to depend
only on isSpaceRoute and keep canRenderSpaceLogoNode using rootSpace,
isLoadingActiveSpace, and isLoadingOrganisationSpaces; alternatively if you
prefer a feature flag, introduce a dedicated enableConnectedBranding boolean and
use that instead of aiChatEnabled in suppressDefaultLogo.
- Around line 187-189: Replace the generic fallback text so the menu shows the
space branding: in the component that renders the span (connected-menu-top,
where tNavigation('ecosystemLogo') is used), render rootTitle first and fall
back to tNavigation('ecosystemLogo') if rootTitle is falsy (e.g. use rootTitle
|| tNavigation('ecosystemLogo')). Update the span content accordingly so the UI
shows the specific rootTitle when no custom logo image exists.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1366ae62-acb0-4f8f-b7e1-ec4c144c1fa6

📥 Commits

Reviewing files that changed from the base of the PR and between 5fbab6f and 0d78883.

📒 Files selected for processing (2)
  • apps/web/src/components/connected-menu-top.tsx
  • packages/ui/src/organisms/menu-top.tsx

Comment thread apps/web/src/components/connected-menu-top.tsx Outdated
@github-actions

github-actions Bot commented May 22, 2026

Copy link
Copy Markdown

🔗 Custom preview URL: https://pr-2227.preview-app.hypha.earth

Add the global wallet entry and root ecosystem branding in the top bar
so the home navigation reflects the new home-screen experience.
@webguru-hypha webguru-hypha force-pushed the home-screen-main-pr-2225 branch from 22a37a2 to 53a5850 Compare May 27, 2026 17:19
Stack toolbar controls and action buttons on narrow viewports, use a
wallet-specific single-column token grid until 720px, and tighten
asset card text wrapping for small screens.

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

1 participant