fix: Sync avatar to account sidebar

- Fetch avatar settings in AccountLayout on mount
- Display custom avatar or gravatar in sidebar
- Dispatch woonoow:avatar-updated event on upload/remove
- Listen for event in AccountLayout for real-time sync
This commit is contained in:
Dwindi Ramadhana
2026-01-05 00:31:16 +07:00
parent 86dca3e9c2
commit 663e6c13e6
2 changed files with 41 additions and 4 deletions

View File

@@ -90,6 +90,9 @@ export default function AccountDetails() {
current_avatar: result.avatar_url,
} : null);
// Dispatch event to sync sidebar avatar
window.dispatchEvent(new CustomEvent('woonoow:avatar-updated', { detail: { avatar_url: result.avatar_url } }));
toast.success('Avatar uploaded successfully');
} catch (error: any) {
console.error('Upload avatar error:', error);
@@ -115,6 +118,10 @@ export default function AccountDetails() {
...prev,
current_avatar: null,
} : null);
// Dispatch event to sync sidebar avatar (will fall back to gravatar)
window.dispatchEvent(new CustomEvent('woonoow:avatar-updated', { detail: { avatar_url: null } }));
toast.success('Avatar removed');
} catch (error: any) {
console.error('Remove avatar error:', error);

View File

@@ -1,7 +1,8 @@
import React, { ReactNode, useState } from 'react';
import React, { ReactNode, useState, useEffect } from 'react';
import { Link, useLocation } from 'react-router-dom';
import { LayoutDashboard, ShoppingBag, Download, MapPin, Heart, User, LogOut } from 'lucide-react';
import { useModules } from '@/hooks/useModules';
import { api } from '@/lib/api/client';
import {
AlertDialog,
AlertDialogAction,
@@ -24,6 +25,27 @@ export function AccountLayout({ children }: AccountLayoutProps) {
const { isEnabled } = useModules();
const wishlistEnabled = (window as any).woonoowCustomer?.settings?.wishlist_enabled !== false;
const [isLoggingOut, setIsLoggingOut] = useState(false);
const [avatarUrl, setAvatarUrl] = useState<string | null>(null);
// Fetch avatar settings
useEffect(() => {
const fetchAvatar = async () => {
try {
const data = await api.get<{ current_avatar: string | null; gravatar_url: string }>('/account/avatar-settings');
setAvatarUrl(data.current_avatar || data.gravatar_url);
} catch (error) {
console.error('Failed to fetch avatar:', error);
}
};
fetchAvatar();
// Listen for avatar updates
const handleAvatarUpdate = (e: CustomEvent) => {
setAvatarUrl(e.detail?.avatar_url || null);
};
window.addEventListener('woonoow:avatar-updated' as any, handleAvatarUpdate);
return () => window.removeEventListener('woonoow:avatar-updated' as any, handleAvatarUpdate);
}, []);
const allMenuItems = [
{ id: 'dashboard', label: 'Dashboard', path: '/my-account', icon: LayoutDashboard },
@@ -106,9 +128,17 @@ export function AccountLayout({ children }: AccountLayoutProps) {
<aside className="bg-white rounded-lg border p-4">
<div className="mb-6">
<div className="flex items-center gap-3 pb-4 border-b">
{avatarUrl ? (
<img
src={avatarUrl}
alt={user?.display_name || 'User'}
className="w-12 h-12 rounded-full object-cover"
/>
) : (
<div className="w-12 h-12 rounded-full bg-gray-200 flex items-center justify-center">
<User className="w-6 h-6 text-gray-600" />
</div>
)}
<div>
<p className="font-semibold">{user?.display_name || 'User'}</p>
<p className="text-sm text-gray-500">{user?.email}</p>