feat(quick-260630-gbh-01): header avatar display with initial fallback
- AuthUser store: add optional hasAvatar? field - Header: populate hasAvatar from fetchCurrentUser() result - Header avatar button: shows <img src='/api-proxy/users/me/avatar'> when hasAvatar=true with onError fallback to initial span - Plain <img> tag used (same-origin /api-proxy rewrite, no next/image remote config needed)
This commit is contained in:
@@ -31,6 +31,7 @@ export function Header() {
|
||||
displayName: u.displayName,
|
||||
role: u.role,
|
||||
tenantId: u.tenantId,
|
||||
hasAvatar: u.hasAvatar,
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -53,6 +54,8 @@ export function Header() {
|
||||
return () => document.removeEventListener('mousedown', handleClickOutside);
|
||||
}, [dropdownOpen]);
|
||||
|
||||
const [avatarError, setAvatarError] = useState(false);
|
||||
|
||||
const userInitial = user
|
||||
? (user.displayName ?? user.username).charAt(0).toUpperCase()
|
||||
: '?';
|
||||
@@ -104,10 +107,19 @@ export function Header() {
|
||||
<div className="relative" ref={dropdownRef}>
|
||||
<button
|
||||
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||
className="h-8 w-8 rounded-full bg-primary flex items-center justify-center text-xs font-medium text-primary-foreground hover:opacity-90 transition-opacity"
|
||||
className="h-8 w-8 rounded-full overflow-hidden bg-primary flex items-center justify-center text-xs font-medium text-primary-foreground hover:opacity-90 transition-opacity"
|
||||
aria-label={tHeader('userMenu')}
|
||||
>
|
||||
{userInitial}
|
||||
{user?.hasAvatar && !avatarError ? (
|
||||
<img
|
||||
src="/api-proxy/users/me/avatar"
|
||||
alt=""
|
||||
className="h-8 w-8 rounded-full object-cover"
|
||||
onError={() => setAvatarError(true)}
|
||||
/>
|
||||
) : (
|
||||
<span>{userInitial}</span>
|
||||
)}
|
||||
</button>
|
||||
|
||||
{/* Dropdown menu */}
|
||||
|
||||
@@ -6,6 +6,7 @@ export interface AuthUser {
|
||||
displayName: string | null;
|
||||
role: 'SUPER_ADMIN' | 'ADMIN' | 'USER';
|
||||
tenantId: string;
|
||||
hasAvatar?: boolean;
|
||||
}
|
||||
|
||||
interface AuthState {
|
||||
|
||||
Reference in New Issue
Block a user