fix(ui): resolve yacht owner names server-side, real user in topbar
Yachts list page rendered each row's Current Owner via OwnerLink, which
fired its own /api/v1/clients/{id} or /companies/{id} fetch — N+1 round-
trips per page load (12+ for the harbor-royale fixture). Worse, until
those fetches resolved each cell showed "Client c68da7..." style raw IDs.
Fix: listYachts now resolves the polymorphic currentOwnerName in two
batched in-array queries after the page query (mirrors the listClients
yachtCount/companyCount pattern), and OwnerLink accepts an optional
preloadedName prop that suppresses the per-row fetch when supplied.
Topbar: show real user name + avatar initial from session/profile, and
expand the My-Account dropdown header to include the user's email.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -23,9 +23,10 @@ import type { Port } from '@/lib/db/schema/ports';
|
||||
|
||||
interface TopbarProps {
|
||||
ports: Port[];
|
||||
user?: { name: string; email: string };
|
||||
}
|
||||
|
||||
export function Topbar({ ports }: TopbarProps) {
|
||||
export function Topbar({ ports, user }: TopbarProps) {
|
||||
const router = useRouter();
|
||||
const currentPortSlug = useUIStore((s) => s.currentPortSlug);
|
||||
const darkMode = useUIStore((s) => s.darkMode);
|
||||
@@ -95,13 +96,18 @@ export function Topbar({ ports }: TopbarProps) {
|
||||
<Avatar className="w-7 h-7">
|
||||
<AvatarImage src={undefined} />
|
||||
<AvatarFallback className="bg-brand text-white text-xs font-semibold">
|
||||
U
|
||||
{(user?.name ?? 'U').slice(0, 1).toUpperCase()}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-52">
|
||||
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
||||
<DropdownMenuContent align="end" className="w-56">
|
||||
<DropdownMenuLabel>
|
||||
<div className="font-medium">{user?.name ?? 'My Account'}</div>
|
||||
{user?.email && (
|
||||
<div className="text-xs text-muted-foreground font-normal">{user.email}</div>
|
||||
)}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
|
||||
<DropdownMenuItem onClick={() => router.push(`${base}/settings/profile` as any)}>
|
||||
|
||||
Reference in New Issue
Block a user