2025-03-06 16:34:50 -05:00
|
|
|
// lib/hooks/useProfile.ts
|
2025-03-21 22:21:45 -04:00
|
|
|
import { useState, useEffect, useRef } from 'react';
|
2025-03-06 16:34:50 -05:00
|
|
|
import { NDKUser, NDKUserProfile } from '@nostr-dev-kit/ndk-mobile';
|
|
|
|
import { useNDK } from './useNDK';
|
|
|
|
|
|
|
|
export function useProfile(pubkey: string | undefined) {
|
|
|
|
const { ndk } = useNDK();
|
|
|
|
const [profile, setProfile] = useState<NDKUserProfile | null>(null);
|
|
|
|
const [user, setUser] = useState<NDKUser | null>(null);
|
|
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
const [error, setError] = useState<Error | null>(null);
|
|
|
|
|
2025-03-21 22:21:45 -04:00
|
|
|
// Reference to track if component is mounted
|
|
|
|
const isMountedRef = useRef(true);
|
|
|
|
|
|
|
|
// Reset mounted ref when component unmounts
|
|
|
|
useEffect(() => {
|
|
|
|
isMountedRef.current = true;
|
|
|
|
return () => {
|
|
|
|
isMountedRef.current = false;
|
|
|
|
};
|
|
|
|
}, []);
|
|
|
|
|
2025-03-06 16:34:50 -05:00
|
|
|
useEffect(() => {
|
|
|
|
if (!ndk || !pubkey) {
|
|
|
|
setIsLoading(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-03-21 22:21:45 -04:00
|
|
|
let isEffectActive = true;
|
|
|
|
|
2025-03-06 16:34:50 -05:00
|
|
|
const fetchProfile = async () => {
|
|
|
|
try {
|
|
|
|
setIsLoading(true);
|
|
|
|
setError(null);
|
|
|
|
|
|
|
|
// Create NDK user
|
|
|
|
const ndkUser = ndk.getUser({ pubkey });
|
|
|
|
|
|
|
|
// Fetch profile
|
|
|
|
await ndkUser.fetchProfile();
|
|
|
|
|
|
|
|
// Normalize profile data, similar to your current implementation
|
|
|
|
if (ndkUser.profile) {
|
|
|
|
// Ensure image property exists (some clients use picture instead)
|
|
|
|
if (!ndkUser.profile.image && (ndkUser.profile as any).picture) {
|
|
|
|
ndkUser.profile.image = (ndkUser.profile as any).picture;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-21 22:21:45 -04:00
|
|
|
// Only update state if component is still mounted and effect is active
|
|
|
|
if (isMountedRef.current && isEffectActive) {
|
|
|
|
setUser(ndkUser);
|
|
|
|
setProfile(ndkUser.profile || null);
|
|
|
|
setIsLoading(false);
|
|
|
|
}
|
2025-03-06 16:34:50 -05:00
|
|
|
} catch (err) {
|
|
|
|
console.error('Error fetching profile:', err);
|
2025-03-21 22:21:45 -04:00
|
|
|
// Only update state if component is still mounted and effect is active
|
|
|
|
if (isMountedRef.current && isEffectActive) {
|
|
|
|
setError(err instanceof Error ? err : new Error('Failed to fetch profile'));
|
|
|
|
setIsLoading(false);
|
|
|
|
}
|
2025-03-06 16:34:50 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
fetchProfile();
|
2025-03-21 22:21:45 -04:00
|
|
|
|
|
|
|
// Cleanup function to prevent state updates if the effect is cleaned up
|
|
|
|
return () => {
|
|
|
|
isEffectActive = false;
|
|
|
|
};
|
2025-03-06 16:34:50 -05:00
|
|
|
}, [ndk, pubkey]);
|
|
|
|
|
|
|
|
const refreshProfile = async () => {
|
2025-03-21 22:21:45 -04:00
|
|
|
if (!ndk || !pubkey || !isMountedRef.current) return;
|
2025-03-06 16:34:50 -05:00
|
|
|
|
|
|
|
try {
|
|
|
|
setIsLoading(true);
|
|
|
|
setError(null);
|
|
|
|
|
|
|
|
const ndkUser = ndk.getUser({ pubkey });
|
|
|
|
await ndkUser.fetchProfile();
|
|
|
|
|
2025-03-21 22:21:45 -04:00
|
|
|
// Only update state if component is still mounted
|
|
|
|
if (isMountedRef.current) {
|
|
|
|
setUser(ndkUser);
|
|
|
|
setProfile(ndkUser.profile || null);
|
|
|
|
}
|
2025-03-06 16:34:50 -05:00
|
|
|
} catch (err) {
|
2025-03-21 22:21:45 -04:00
|
|
|
if (isMountedRef.current) {
|
|
|
|
setError(err instanceof Error ? err : new Error('Failed to refresh profile'));
|
|
|
|
}
|
2025-03-06 16:34:50 -05:00
|
|
|
} finally {
|
2025-03-21 22:21:45 -04:00
|
|
|
if (isMountedRef.current) {
|
|
|
|
setIsLoading(false);
|
|
|
|
}
|
2025-03-06 16:34:50 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
return {
|
|
|
|
profile,
|
|
|
|
user,
|
|
|
|
isLoading,
|
|
|
|
error,
|
|
|
|
refreshProfile
|
|
|
|
};
|
|
|
|
}
|