feat: sync profile data with session and implement visibility-based refetching in ProfileSettingsForm

This commit is contained in:
pradeepkumar
2026-04-24 12:56:20 +05:30
parent cecbba7f3e
commit 1dba4e70d5

View File

@@ -87,83 +87,114 @@ export function ProfileSettingsForm({
// Track if initial profile fetch is done to avoid re-showing loading spinner
const hasFetchedRef = useRef(false);
// Fetch profile data on mount based on user role
useEffect(() => {
const fetchProfile = async () => {
try {
// Only show loading spinner on initial fetch, not on session-triggered re-fetches
if (!hasFetchedRef.current) {
setIsLoading(true);
}
const role = (session?.user as any)?.role;
if (role === 'AGENT') {
const profile = await agentsService.getMyProfile();
const profileData = {
firstName: profile.firstName || '',
lastName: profile.lastName || '',
career: profile.headline || profile.agentType?.name || 'Real Estate Agent',
email: profile.email || session?.user?.email || '',
phone: profile.phone || '',
};
setFormData(profileData);
setOriginalData(profileData); // Store original for cancel
if (profile.avatar) {
try {
const presignedUrl = await uploadService.getPresignedDownloadUrl(profile.avatar);
setAvatarUrl(presignedUrl);
} catch {
setAvatarUrl(profile.avatar);
}
}
} else if (role === 'USER') {
const profile = await usersService.getMyProfile();
const profileData = {
firstName: profile.firstName || '',
lastName: profile.lastName || '',
career: '', // Users don't have career/agent type
email: profile.email || session?.user?.email || '',
phone: profile.phone || '',
};
setFormData(profileData);
setOriginalData(profileData); // Store original for cancel
if (profile.avatar) {
try {
const presignedUrl = await uploadService.getPresignedDownloadUrl(profile.avatar);
setAvatarUrl(presignedUrl);
} catch {
setAvatarUrl(profile.avatar);
}
}
}
} catch (err) {
console.error('Failed to fetch profile:', err);
// Use session data as fallback
if (session?.user) {
const nameParts = (session.user?.name || '').split(' ');
setFormData(prev => ({
...prev,
firstName: nameParts[0] || prev.firstName,
lastName: nameParts.slice(1).join(' ') || prev.lastName,
email: session.user?.email || prev.email,
}));
if (session.user.image) {
setAvatarUrl(session.user.image);
}
}
} finally {
setIsLoading(false);
hasFetchedRef.current = true;
const fetchProfile = async () => {
try {
// Only show loading spinner on initial fetch, not on session-triggered re-fetches
if (!hasFetchedRef.current) {
setIsLoading(true);
}
};
const role = (session?.user as any)?.role;
if (role === 'AGENT') {
const profile = await agentsService.getMyProfile();
const profileData = {
firstName: profile.firstName || '',
lastName: profile.lastName || '',
career: profile.headline || profile.agentType?.name || 'Real Estate Agent',
email: profile.email || session?.user?.email || '',
phone: profile.phone || '',
};
setFormData(profileData);
setOriginalData(profileData);
// If backend email diverges from session (email change verified in another tab),
// refresh the next-auth JWT so header/other places also pick up the new address.
if (profile.email && session?.user?.email && profile.email !== session.user.email) {
try {
await updateSession({ user: { email: profile.email } });
} catch {
// updateSession is best-effort
}
}
if (profile.avatar) {
try {
const presignedUrl = await uploadService.getPresignedDownloadUrl(profile.avatar);
setAvatarUrl(presignedUrl);
} catch {
setAvatarUrl(profile.avatar);
}
}
} else if (role === 'USER') {
const profile = await usersService.getMyProfile();
const profileData = {
firstName: profile.firstName || '',
lastName: profile.lastName || '',
career: '',
email: profile.email || session?.user?.email || '',
phone: profile.phone || '',
};
setFormData(profileData);
setOriginalData(profileData);
if (profile.email && session?.user?.email && profile.email !== session.user.email) {
try {
await updateSession({ user: { email: profile.email } });
} catch {
// best-effort
}
}
if (profile.avatar) {
try {
const presignedUrl = await uploadService.getPresignedDownloadUrl(profile.avatar);
setAvatarUrl(presignedUrl);
} catch {
setAvatarUrl(profile.avatar);
}
}
}
} catch (err) {
console.error('Failed to fetch profile:', err);
if (session?.user) {
const nameParts = (session.user?.name || '').split(' ');
setFormData(prev => ({
...prev,
firstName: nameParts[0] || prev.firstName,
lastName: nameParts.slice(1).join(' ') || prev.lastName,
email: session.user?.email || prev.email,
}));
if (session.user.image) {
setAvatarUrl(session.user.image);
}
}
} finally {
setIsLoading(false);
hasFetchedRef.current = true;
}
};
// Initial fetch on mount
useEffect(() => {
if (session) {
// Skip re-fetching on session changes after initial load (e.g. after updateSession in handleSave)
if (hasFetchedRef.current) return;
fetchProfile();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [session]);
// Re-fetch when the tab becomes visible again (e.g. user verified email
// change in another tab and returned). Ensures email/phone/avatar stay in
// sync with the source of truth.
useEffect(() => {
const onVisible = () => {
if (document.visibilityState === 'visible' && session && hasFetchedRef.current) {
fetchProfile();
}
};
document.addEventListener('visibilitychange', onVisible);
return () => document.removeEventListener('visibilitychange', onVisible);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [session]);
const handleChange = (field: string, value: string) => {