import { useState, useEffect, useRef } from 'react' import { useAuth } from '@/components/AuthProvider' import { supabase } from '@/lib/supabase' export interface UserProfile { id: string email: string | null full_name: string | null avatar_url: string | null created_at: string updated_at: string welcome_tour_completed?: boolean welcome_tour_completed_at?: string | null welcome_tour_started_at?: string | null welcome_tour_current_step?: number welcome_tour_steps_viewed?: number[] welcome_tour_completion_type?: 'completed' | 'skipped' | 'abandoned' | null welcome_tour_selected_plan?: string | null welcome_tour_selected_billing?: 'month' | 'year' | null welcome_tour_total_time_seconds?: number welcome_tour_video_watched?: boolean welcome_tour_version?: string } // Cache profile data across component re-renders let profileCache: { userId: string; data: UserProfile | null; timestamp: number } | null = null; let ongoingRequest: { userId: string; promise: Promise } | null = null; const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes export function useProfile() { const { user } = useAuth() const [profile, setProfile] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const hasFetched = useRef(false) useEffect(() => { if (!user?.id) { setProfile(null) setLoading(false) hasFetched.current = false return } // Check cache first const now = Date.now() if (profileCache && profileCache.userId === user.id && (now - profileCache.timestamp) < CACHE_DURATION) { setProfile(profileCache.data) setLoading(false) hasFetched.current = true return } // Only fetch if we haven't fetched for this user yet if (!hasFetched.current) { fetchProfile() } }, [user?.id]) const fetchProfile = async (): Promise => { if (!user?.id) return null // Check if there's already an ongoing request for this user if (ongoingRequest && ongoingRequest.userId === user.id) { try { const result = await ongoingRequest.promise if (result) { setProfile(result) } hasFetched.current = true setLoading(false) return result } catch (err) { setError(err instanceof Error ? err.message : 'Failed to fetch profile') setLoading(false) return null } } // Create new request promise const requestPromise = (async (): Promise => { const { data, error } = await supabase .from('profiles') .select('*') .eq('id', user.id) .single() if (error) { if (error.code === 'PGRST116') { // No profile found, create one from auth metadata const profileData = { id: user.id, email: user.email, full_name: user.user_metadata?.full_name || user.user_metadata?.name || '', avatar_url: user.user_metadata?.avatar_url || user.user_metadata?.picture || null, } const { data: newProfile, error: createError } = await supabase .from('profiles') .insert(profileData) .select() .single() if (createError) throw createError return newProfile } else { throw error } } return data })() // Store the ongoing request ongoingRequest = { userId: user.id, promise: requestPromise } try { setLoading(true) setError(null) const result = await requestPromise // Update cache profileCache = { userId: user.id, data: result, timestamp: Date.now() } setProfile(result) hasFetched.current = true return result } catch (err) { console.error('Error fetching profile:', err) setError(err instanceof Error ? err.message : 'Failed to fetch profile') return null } finally { setLoading(false) // Clear ongoing request ongoingRequest = null } } const updateProfile = async (updates: Partial>) => { if (!user?.id || !profile) return try { const { data, error } = await supabase .from('profiles') .update({ ...updates, updated_at: new Date().toISOString() }) .eq('id', user.id) .select() .single() if (error) throw error // Update cache profileCache = { userId: user.id, data: data, timestamp: Date.now() } setProfile(data) return data } catch (err) { console.error('Error updating profile:', err) throw err } } // Force refresh and clear cache - now returns a Promise const refetch = async (): Promise => { if (!user?.id) return null // Clear cache and force fresh fetch profileCache = null hasFetched.current = false ongoingRequest = null // Fetch fresh profile data const result = await fetchProfile() return result } return { profile, loading, error, updateProfile, refetch } }