feat(home): add global wallet navigation and branding#2227
feat(home): add global wallet navigation and branding#2227webguru-hypha wants to merge 88 commits into
Conversation
|
Important Review skippedToo many files! This PR contains 169 files, which is 19 over the limit of 150. To get a review, narrow the scope: Upgrade to a paid plan to raise the limit. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (169)
You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughThis PR adds a new locale-aware My Wallet route with a tabbed wallet interface and wires the page into the app navigation for mobile and desktop menus. ChangesMy Wallet Feature
Estimated code review effort: 2 (Simple) | ~12 minutes Sequence Diagram(s)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
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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
📒 Files selected for processing (4)
apps/web/src/app/[lang]/my-wallet/page.tsxapps/web/src/app/layout.tsxapps/web/src/components/connected-menu-top.tsxapps/web/src/components/my-wallet-tabs.tsx
| 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> | ||
| ); |
There was a problem hiding this comment.
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.
| 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.
| { | ||
| label: tNav('myWallet'), | ||
| href: `/${locale}/my-wallet`, | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check for 'myWallet' key in all Navigation translation files
rg -n '"myWallet"' --type jsonRepository: 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 -20Repository: 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 3Repository: 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 2Repository: 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 -100Repository: hypha-dao/hypha-web
Length of output: 4253
🏁 Script executed:
# Check the navigation configuration
cat packages/i18n/src/navigation.tsRepository: 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.jsonRepository: 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.jsonRepository: hypha-dao/hypha-web
Length of output: 640
🏁 Script executed:
# Check if myWallet is defined elsewhere in the codebase
rg -i "myWallet" --type jsonRepository: 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.tsxRepository: 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).
| 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[]; | ||
| }, | ||
| ); |
There was a problem hiding this comment.
🧹 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.
| 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> | ||
| ); | ||
| } |
There was a problem hiding this comment.
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.
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.
There was a problem hiding this comment.
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 winDon'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 winUse
rootTitlefor 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
rootTitlefirst 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
📒 Files selected for processing (2)
apps/web/src/components/connected-menu-top.tsxpackages/ui/src/organisms/menu-top.tsx
|
🔗 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.
22a37a2 to
53a5850
Compare
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>
Rebase layout onto main's SwrProvider/LocalizedIntlProvider stack while keeping My Wallet nav links. Use getDhoPathDefaultLanding in asset-card. Co-authored-by: Cursor <cursoragent@cursor.com>
…Matrix call links Introduces a full Calendar tab for spaces with FullCalendar UI, scheduled-item CRUD, RRULE recurrence, email/push reminders via OneSignal, and auto-generated Hypha call join links for Matrix-backed calls. Co-authored-by: Cursor <cursoragent@cursor.com>
The reminder notifier imported core/server and was re-exported through actions/index, which pulled server-only code into use-send-notifications. Export it only from notifications/server instead. Co-authored-by: Cursor <cursoragent@cursor.com>
The calendar route and top tab strip were wired up, but the AI left panel section nav was missing the Calendar item between Members and Treasury. Co-authored-by: Cursor <cursoragent@cursor.com>
Harden auth on scheduled-item APIs and server actions, isolate reminder dispatch failures, validate patches against persisted state, tighten reminder queries, and improve calendar UX (locale, all-day handling, HTML escaping). Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Add Booking as a scheduled item type, snap times to 15-minute increments, and keep end in sync when start changes. Co-authored-by: Cursor <cursoragent@cursor.com>
Match proposal form validation UX by placing errors under fields and focusing the first invalid input on submit. Co-authored-by: Cursor <cursoragent@cursor.com>
Move create/edit into ProposalOverlayShell aside routes so outside clicks no longer dismiss the form or discard entered data, matching Signals and proposal flows. Co-authored-by: Cursor <cursoragent@cursor.com>
Address API pagination shape, validation edge cases, reminder dispatch idempotency, client/server boundaries, and calendar UX issues from PR review. Co-authored-by: Cursor <cursoragent@cursor.com>
Fix PaginatedResponse import path, Drizzle returning() usage, recurrence preset narrowing, and Prettier formatting. Co-authored-by: Cursor <cursoragent@cursor.com>
Validate PATCH updates against the merged full record, expand recurrence with local dtstart to preserve wall-clock times, and add calendar tab path helper regression coverage. Co-authored-by: Cursor <cursoragent@cursor.com>
Expand recurring occurrences in the event timezone with floating DTSTART and tzid, stop emitting UTC Z-suffixed rrule inputs to FullCalendar, and fix weekly fallback weekday indexing for strict TypeScript. Co-authored-by: Cursor <cursoragent@cursor.com>
Scroll validation errors within the overlay panel, show a sticky error banner above Save, validate recurrence-until client-side, and surface server error messages instead of failing silently. Co-authored-by: Cursor <cursoragent@cursor.com>
Set datetime-local step to 300 seconds and snap start/end times to five-minute increments (00, 05, 10, …, 55). Co-authored-by: Cursor <cursoragent@cursor.com>
Extend coherences with task fields (status, board, due date, assignees) and space-level workflow config, then replace tag-filter boards with Board, Swimlane, and List views with drag-and-drop. Signal due dates overlay on the calendar tab and scheduled items gain an optional coherence_id link. Co-authored-by: Cursor <cursoragent@cursor.com>
Use Drizzle returning() without column projection, add task field defaults to create-signal form, guard nullable signal slugs, and run Prettier. Co-authored-by: Cursor <cursoragent@cursor.com>
Address review feedback on signal task workflow, calendar linkage, and scheduled-item APIs — including patch semantics, auth, pagination, and reminder dispatch reliability. Co-authored-by: Cursor <cursoragent@cursor.com>
Remove anchorDate/view useEffects that re-triggered gotoDate on every datesSet callback. Drive calendar navigation imperatively from controls and only sync state when the visible range actually changes. Co-authored-by: Cursor <cursoragent@cursor.com>
Swimlane rows now show status columns (mini-Kanban) with drag-and-drop for status and board. Add status, board category, and due date fields to create/edit signal forms with i18n hints clarifying board vs type/tags. Co-authored-by: Cursor <cursoragent@cursor.com>
The create form lives at @aside/[tab]/new-signal, not create-signal. Co-authored-by: Cursor <cursoragent@cursor.com>
Link a configure cog beside the view switcher to space configuration for status and board editing, and return to the signals tab on close or save when opened from that entry point. Co-authored-by: Cursor <cursoragent@cursor.com>
Remove the grid view hero image and use the same left priority color bar as board and list cards for a consistent signal card layout. Co-authored-by: Cursor <cursoragent@cursor.com>
Persist board/swimlane/list/grid selection in the view query param so users can be linked directly to a specific signals layout, including when returning from workflow settings. Co-authored-by: Cursor <cursoragent@cursor.com>
Allow flex children to shrink below long join URLs and stack meeting actions in compact mode so footer buttons and hints stay visible. Co-authored-by: Cursor <cursoragent@cursor.com>
Use inline SVG icons for call, event, meeting, and booking types in month, time grid, and agenda views so narrow cells no longer clip the old accent stripe. Co-authored-by: Cursor <cursoragent@cursor.com>
Remove uppercase styling so Month, Week, Day, and Agenda match the rest of the app. Co-authored-by: Cursor <cursoragent@cursor.com>
Set the prev/today/next control group to h-10 so it matches the adjacent calendar icon without extra wrapper padding. Co-authored-by: Cursor <cursoragent@cursor.com>
Use solid grid lines with vertical day dividers, HH:mm slot labels, and clear Today badges across month, week, day, and agenda views. Co-authored-by: Cursor <cursoragent@cursor.com>
Expand recurring items into concrete occurrences for the visible range so agenda lists weekly calls, sync month/week/day/agenda to the view query param, and remove the header subtitle. Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the workflow cog inline with view tabs, add horizontal scroll for priority filters, and defer side-by-side layout until lg breakpoints.
Move task route DB lookups behind core/server and gate useJwt on isAuthenticated so forms recover after sign-in.
Keep month view only until week/day/agenda are ready, strip view query params, and remove the redundant double border around the calendar card.
Align task PATCH auth with panel delegates, fetch fresh JWTs per update, and harden optimistic overlays so stale refetches cannot revert moves. Co-authored-by: Cursor <cursoragent@cursor.com>
Grid cards already open chat on click, so hide the redundant footer action. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Update the local SWR cache only after task moves and avoid unmounting the board during background revalidation. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Align signal edit/delete auth with panel interaction instead of author-only or Matrix signal-team membership checks. Co-authored-by: Cursor <cursoragent@cursor.com>
Allow creators through panel auth, validate workflow fields only when they change, pass assigneeIds into edit, and surface validation errors in the form. Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the edit-form delete action with soft archive so signals stay recoverable and match the grid card archive behavior. Co-authored-by: Cursor <cursoragent@cursor.com>
…nd cards Show Unarchive in the edit form and card header when a signal is archived, and remove the redundant grid footer unarchive button. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve Matrix IDs server-side by person id so the public members API can stay free of Privy subs, then use the full space roster for team management and @ mentions instead of joined-room members only. Co-authored-by: Cursor <cursoragent@cursor.com>
Replace Matrix room joiners with on-chain members plus validated delegates for Signal Team management, @ mentions, and the chat Members tab. Co-authored-by: Cursor <cursoragent@cursor.com>
Surface loading/error states for Matrix ID lookup, list every on-chain member and delegate in manage UI (not just Matrix-linked rows), and remove the unbounded module-level person-id cache. Co-authored-by: Cursor <cursoragent@cursor.com>
Clear signal/msg URL params and bump the deep-link epoch before leaving coherence mode so the back arrow returns to space chat on the first click. Co-authored-by: Cursor <cursoragent@cursor.com>
Include on-chain membership in delegate SWR cache keys, reuse personRosterDisplayLabel for sorting, and surface aggregated fetch errors to roster consumers. Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
My Walletentry and dedicated wallet page in the top navigationTest plan
pnpm run format:fixpnpm --filter web check-typesMade with Cursor
Summary by CodeRabbit