92 lines
2.6 KiB
TypeScript
92 lines
2.6 KiB
TypeScript
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
import { FirebaseAuthTypes } from '../firebase';
|
|
import { UserProfile } from '../services/authServices';
|
|
import { useUserProfileStore } from '../stores/userProfileStore';
|
|
import type { ProfileCacheEntry } from '../stores/userProfileStore';
|
|
import { useGlobalLoading } from './useGlobalLoading';
|
|
|
|
interface UseUserProfileReturn {
|
|
profile: UserProfile | null;
|
|
loading: boolean;
|
|
error: string | null;
|
|
refreshProfile: () => Promise<void>;
|
|
}
|
|
|
|
const defaultEntry: ProfileCacheEntry = {
|
|
profile: null,
|
|
loading: false,
|
|
error: null,
|
|
};
|
|
|
|
export const useUserProfile = (user: FirebaseAuthTypes.User | null): UseUserProfileReturn => {
|
|
const uid = user?.uid ?? null;
|
|
const lastUidRef = useRef<string | null>(null);
|
|
|
|
const ensureSubscription = useUserProfileStore((state) => state.ensureSubscription);
|
|
const refreshFromStore = useUserProfileStore((state) => state.refreshProfile);
|
|
const removeProfile = useUserProfileStore((state) => state.removeProfile);
|
|
|
|
const entry = useUserProfileStore(
|
|
useCallback(
|
|
(state) => (uid ? state.profiles[uid] ?? defaultEntry : defaultEntry),
|
|
[uid]
|
|
)
|
|
);
|
|
const { withLoading } = useGlobalLoading();
|
|
|
|
useEffect(() => {
|
|
// Clean up subscription from previous user when switching or logging out
|
|
if (lastUidRef.current && lastUidRef.current !== uid) {
|
|
removeProfile(lastUidRef.current);
|
|
}
|
|
|
|
lastUidRef.current = uid;
|
|
}, [uid, removeProfile]);
|
|
|
|
useEffect(() => {
|
|
if (!uid) {
|
|
return;
|
|
}
|
|
|
|
ensureSubscription(uid);
|
|
}, [uid, ensureSubscription]);
|
|
|
|
const refreshProfile = useCallback(async () => {
|
|
if (!uid) {
|
|
return;
|
|
}
|
|
await withLoading(() => refreshFromStore(uid));
|
|
}, [refreshFromStore, uid, withLoading]);
|
|
|
|
return useMemo(
|
|
() => ({
|
|
profile: entry.profile,
|
|
loading: uid ? entry.loading : false,
|
|
error: uid ? entry.error : null,
|
|
refreshProfile,
|
|
}),
|
|
[entry.error, entry.loading, entry.profile, refreshProfile, uid]
|
|
);
|
|
};
|
|
|
|
// Standalone function to fetch any user's profile (useful for admin features)
|
|
export const fetchUserProfile = async (uid: string, opts?: { force?: boolean }): Promise<UserProfile | null> => {
|
|
if (!uid) {
|
|
return null;
|
|
}
|
|
|
|
const { force = false } = opts ?? {};
|
|
const cached = force ? null : useUserProfileStore.getState().profiles[uid]?.profile;
|
|
|
|
if (cached) {
|
|
return cached;
|
|
}
|
|
|
|
try {
|
|
return await useUserProfileStore.getState().refreshProfile(uid);
|
|
} catch (error) {
|
|
console.error('Error fetching user profile:', error);
|
|
throw error;
|
|
}
|
|
};
|