'use client'; import { createContext, useContext, useState, useEffect, useRef, useCallback } from 'react'; import { useSession } from 'next-auth/react'; import { agentsService } from '@/services/agents.service'; import { usersService } from '@/services/users.service'; import { uploadService } from '@/services/upload.service'; import { notificationsApiService } from '@/services/notifications-api.service'; interface HeaderData { profileImage: string | null; profileName: string | null; profileTitle: string | null; avatarLoaded: boolean; setAvatarLoaded: (loaded: boolean) => void; notificationCount: number; } const HeaderContext = createContext({ profileImage: null, profileName: null, profileTitle: null, avatarLoaded: false, setAvatarLoaded: () => {}, notificationCount: 0, }); export function useHeaderData() { return useContext(HeaderContext); } export function HeaderProvider({ children }: { children: React.ReactNode }) { const { data: session, status } = useSession(); const [profileImage, setProfileImage] = useState(null); const [profileName, setProfileName] = useState(null); const [profileTitle, setProfileTitle] = useState(null); const [avatarLoaded, setAvatarLoaded] = useState(false); const [notificationCount, setNotificationCount] = useState(0); const lastAvatarKeyRef = useRef(null); const hasFetchedRef = useRef(false); const fetchProfileData = useCallback(async (forceRefresh = false) => { try { const role = (session?.user as any)?.role; let avatar: string | null = null; let name: string | null = null; let title: string | null = null; if (role === 'AGENT') { const profile = await agentsService.getMyProfile(); avatar = profile.avatar; name = profile.firstName ? `${profile.firstName} ${profile.lastName || ''}`.trim() : null; title = profile.agentType?.name || 'Real Estate Agent'; } else if (role === 'USER') { const profile = await usersService.getMyProfile(); avatar = profile.avatar; name = profile.firstName ? `${profile.firstName} ${profile.lastName || ''}`.trim() : null; title = 'Member'; } if (name) setProfileName(name); if (title) setProfileTitle(title); if (avatar && (avatar !== lastAvatarKeyRef.current || forceRefresh)) { lastAvatarKeyRef.current = avatar; setAvatarLoaded(false); try { const avatarUrl = await uploadService.getPresignedDownloadUrl(avatar); setProfileImage(avatarUrl); } catch { setProfileImage(avatar); } } } catch (err) { console.error('Failed to fetch profile data:', err); } }, [session]); // Fetch once on auth useEffect(() => { if (status === 'authenticated' && session?.user && !hasFetchedRef.current) { hasFetchedRef.current = true; fetchProfileData(); } if (status === 'unauthenticated') { hasFetchedRef.current = false; setProfileImage(null); setProfileName(null); setProfileTitle(null); setAvatarLoaded(false); lastAvatarKeyRef.current = null; } }, [status, session, fetchProfileData]); // Listen for profile-updated events useEffect(() => { const handleProfileUpdate = () => { lastAvatarKeyRef.current = null; fetchProfileData(true); }; window.addEventListener('profile-updated', handleProfileUpdate); return () => window.removeEventListener('profile-updated', handleProfileUpdate); }, [fetchProfileData]); // Notification count polling useEffect(() => { if (status !== 'authenticated') return; const fetchCount = async () => { try { const count = await notificationsApiService.getUnreadCount(); setNotificationCount(count); } catch { // Silently fail } }; fetchCount(); const interval = setInterval(fetchCount, 30000); const handleNotification = () => fetchCount(); window.addEventListener('notification-received', handleNotification); return () => { clearInterval(interval); window.removeEventListener('notification-received', handleNotification); }; }, [status]); return ( {children} ); }