Skip to content

Commit 838e866

Browse files
committed
fix(ui): wrap DropdownMenuLabel + items in DropdownMenuGroup
Base UI (shadcn v3) requires MenuGroupRootContext — DropdownMenuLabel + child items must live inside <Menu.Group>. Wrap all three callsites: - apps/web/src/components/app/notification-bell.tsx (header) - apps/web/src/components/app/app-sidebar.tsx (account menu) - apps/admin/src/app/[locale]/users/_user-actions-menu.tsx
1 parent ee044f4 commit 838e866

3 files changed

Lines changed: 85 additions & 73 deletions

File tree

apps/admin/src/app/[locale]/users/_user-actions-menu.tsx

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
import {
1313
DropdownMenu,
1414
DropdownMenuContent,
15+
DropdownMenuGroup,
1516
DropdownMenuItem,
1617
DropdownMenuLabel,
1718
DropdownMenuSeparator,
@@ -114,44 +115,49 @@ export function UserActionsMenu({ row, currentUserId }: Props) {
114115
}
115116
/>
116117
<DropdownMenuContent align="end" className="w-56">
117-
<DropdownMenuLabel className="truncate">
118-
{row.name ?? row.email}
119-
</DropdownMenuLabel>
120-
<DropdownMenuSeparator />
121-
{isAdmin ? (
122-
<DropdownMenuItem onClick={onDemote} disabled={pending || isSelf}>
123-
<ShieldOff className="mr-2 h-4 w-4" />
124-
Demote to user
125-
</DropdownMenuItem>
126-
) : (
127-
<DropdownMenuItem onClick={onPromote} disabled={pending}>
128-
<ShieldUser className="mr-2 h-4 w-4" />
129-
Promote to admin
130-
</DropdownMenuItem>
131-
)}
132-
<DropdownMenuItem
133-
onClick={onImpersonate}
134-
disabled={pending || isSelf}
135-
>
136-
<UserCog className="mr-2 h-4 w-4" />
137-
Impersonate
138-
</DropdownMenuItem>
139-
<DropdownMenuSeparator />
140-
{row.banned ? (
141-
<DropdownMenuItem onClick={onUnban} disabled={pending}>
142-
<CheckCircle2 className="mr-2 h-4 w-4" />
143-
Unban
144-
</DropdownMenuItem>
145-
) : (
118+
<DropdownMenuGroup>
119+
<DropdownMenuLabel className="truncate">
120+
{row.name ?? row.email}
121+
</DropdownMenuLabel>
122+
<DropdownMenuSeparator />
123+
{isAdmin ? (
124+
<DropdownMenuItem
125+
onClick={onDemote}
126+
disabled={pending || isSelf}
127+
>
128+
<ShieldOff className="mr-2 h-4 w-4" />
129+
Demote to user
130+
</DropdownMenuItem>
131+
) : (
132+
<DropdownMenuItem onClick={onPromote} disabled={pending}>
133+
<ShieldUser className="mr-2 h-4 w-4" />
134+
Promote to admin
135+
</DropdownMenuItem>
136+
)}
146137
<DropdownMenuItem
147-
onClick={() => setBanOpen(true)}
138+
onClick={onImpersonate}
148139
disabled={pending || isSelf}
149-
className="text-destructive focus:text-destructive"
150140
>
151-
<Ban className="mr-2 h-4 w-4" />
152-
Ban…
141+
<UserCog className="mr-2 h-4 w-4" />
142+
Impersonate
153143
</DropdownMenuItem>
154-
)}
144+
<DropdownMenuSeparator />
145+
{row.banned ? (
146+
<DropdownMenuItem onClick={onUnban} disabled={pending}>
147+
<CheckCircle2 className="mr-2 h-4 w-4" />
148+
Unban
149+
</DropdownMenuItem>
150+
) : (
151+
<DropdownMenuItem
152+
onClick={() => setBanOpen(true)}
153+
disabled={pending || isSelf}
154+
className="text-destructive focus:text-destructive"
155+
>
156+
<Ban className="mr-2 h-4 w-4" />
157+
Ban…
158+
</DropdownMenuItem>
159+
)}
160+
</DropdownMenuGroup>
155161
</DropdownMenuContent>
156162
</DropdownMenu>
157163

apps/web/src/components/app/app-sidebar.tsx

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Avatar, AvatarFallback } from "@starter-saas/ui/components/avatar";
44
import {
55
DropdownMenu,
66
DropdownMenuContent,
7+
DropdownMenuGroup,
78
DropdownMenuItem,
89
DropdownMenuLabel,
910
DropdownMenuSeparator,
@@ -146,30 +147,32 @@ export function AppSidebar() {
146147
</div>
147148
</DropdownMenuTrigger>
148149
<DropdownMenuContent side="top" align="end" className="w-56">
149-
<DropdownMenuLabel>My account</DropdownMenuLabel>
150-
<DropdownMenuSeparator />
151-
<DropdownMenuItem
152-
onClick={() => router.push("/dashboard/settings")}
153-
>
154-
<Settings className="mr-2 h-4 w-4" />
155-
Settings
156-
</DropdownMenuItem>
157-
<DropdownMenuItem
158-
onClick={() => router.push("/dashboard/billing")}
159-
>
160-
<CreditCard className="mr-2 h-4 w-4" />
161-
Billing
162-
</DropdownMenuItem>
163-
<DropdownMenuSeparator />
164-
<DropdownMenuItem
165-
onClick={async () => {
166-
await authClient.signOut();
167-
window.location.href = "/sign-in";
168-
}}
169-
>
170-
<LogOut className="mr-2 h-4 w-4" />
171-
Sign out
172-
</DropdownMenuItem>
150+
<DropdownMenuGroup>
151+
<DropdownMenuLabel>My account</DropdownMenuLabel>
152+
<DropdownMenuSeparator />
153+
<DropdownMenuItem
154+
onClick={() => router.push("/dashboard/settings")}
155+
>
156+
<Settings className="mr-2 h-4 w-4" />
157+
Settings
158+
</DropdownMenuItem>
159+
<DropdownMenuItem
160+
onClick={() => router.push("/dashboard/billing")}
161+
>
162+
<CreditCard className="mr-2 h-4 w-4" />
163+
Billing
164+
</DropdownMenuItem>
165+
<DropdownMenuSeparator />
166+
<DropdownMenuItem
167+
onClick={async () => {
168+
await authClient.signOut();
169+
window.location.href = "/sign-in";
170+
}}
171+
>
172+
<LogOut className="mr-2 h-4 w-4" />
173+
Sign out
174+
</DropdownMenuItem>
175+
</DropdownMenuGroup>
173176
</DropdownMenuContent>
174177
</DropdownMenu>
175178
</SidebarMenuItem>

apps/web/src/components/app/notification-bell.tsx

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Button } from "@starter-saas/ui/components/button";
55
import {
66
DropdownMenu,
77
DropdownMenuContent,
8+
DropdownMenuGroup,
89
DropdownMenuLabel,
910
DropdownMenuSeparator,
1011
DropdownMenuTrigger,
@@ -102,21 +103,23 @@ export function NotificationBell() {
102103
}
103104
/>
104105
<DropdownMenuContent align="end" className="w-80">
105-
<div className="flex items-center justify-between gap-2 px-1">
106-
<DropdownMenuLabel className="font-semibold">
107-
Notifications
108-
</DropdownMenuLabel>
109-
{unread > 0 ? (
110-
<Button
111-
variant="ghost"
112-
size="sm"
113-
className="h-7 gap-1 text-xs"
114-
onClick={markAllRead}
115-
>
116-
<CheckCheck className="h-3 w-3" /> Mark all read
117-
</Button>
118-
) : null}
119-
</div>
106+
<DropdownMenuGroup>
107+
<div className="flex items-center justify-between gap-2 px-1">
108+
<DropdownMenuLabel className="font-semibold">
109+
Notifications
110+
</DropdownMenuLabel>
111+
{unread > 0 ? (
112+
<Button
113+
variant="ghost"
114+
size="sm"
115+
className="h-7 gap-1 text-xs"
116+
onClick={markAllRead}
117+
>
118+
<CheckCheck className="h-3 w-3" /> Mark all read
119+
</Button>
120+
) : null}
121+
</div>
122+
</DropdownMenuGroup>
120123
<DropdownMenuSeparator />
121124

122125
{rows === null ? (

0 commit comments

Comments
 (0)