"use client"; import { createContext, useContext, useEffect, useState, useCallback, type ReactNode, } from "react"; import { createClient } from "@/lib/supabase/client"; import type { User, Session } from "@supabase/supabase-js"; import type { Profile } from "@/types"; interface AuthContextValue { user: User | null; session: Session | null; profile: Profile | null; loading: boolean; signUp: (email: string, password: string) => Promise<{ error: string | null }>; signIn: (email: string, password: string) => Promise<{ error: string | null }>; signInAnonymously: () => Promise<{ error: string | null }>; signOut: () => Promise; updateProfile: (data: Partial) => Promise<{ error: string | null }>; refreshProfile: () => Promise; } const AuthContext = createContext(null); function mapDbProfile(row: Record): Profile { const loc = row.location as { coordinates?: [number, number] } | null; return { id: row.id as string, username: (row.username as string) ?? null, display_name: (row.display_name as string) ?? null, age: (row.age as number) ?? null, position: (row.position as Profile["position"]) ?? null, bio: (row.bio as string) ?? null, avatar_url: (row.avatar_url as string) ?? null, status: (row.status as Profile["status"]) ?? "offline", is_anonymous: (row.is_anonymous as boolean) ?? true, kinks: (row.kinks as string[]) ?? [], sti_status: (row.sti_status as string) ?? null, on_prep: (row.on_prep as boolean) ?? false, last_active: (row.last_active as string) ?? new Date().toISOString(), lat: loc?.coordinates?.[1] ?? null, lng: loc?.coordinates?.[0] ?? null, city: (row.city as string) ?? null, state: (row.state as string) ?? null, id_verified: (row.id_verified as boolean) ?? false, id_verified_at: (row.id_verified_at as string) ?? null, vanilla_mode: (row.vanilla_mode as boolean) ?? false, created_at: (row.created_at as string) ?? new Date().toISOString(), }; } export function AuthProvider({ children }: { children: ReactNode }) { const supabase = createClient(); const [user, setUser] = useState(null); const [session, setSession] = useState(null); const [profile, setProfile] = useState(null); const [loading, setLoading] = useState(true); const fetchProfile = useCallback( async (userId: string) => { const { data, error } = await supabase .from("profiles") .select("*") .eq("id", userId) .single(); if (!error && data) { setProfile(mapDbProfile(data)); } }, [supabase] ); useEffect(() => { supabase.auth.getSession().then(({ data: { session: s } }) => { setSession(s); setUser(s?.user ?? null); if (s?.user) fetchProfile(s.user.id); setLoading(false); }); const { data: { subscription }, } = supabase.auth.onAuthStateChange((_event, s) => { setSession(s); setUser(s?.user ?? null); if (s?.user) { fetchProfile(s.user.id); } else { setProfile(null); } }); return () => subscription.unsubscribe(); }, [supabase, fetchProfile]); const signUp = async (email: string, password: string) => { const { error } = await supabase.auth.signUp({ email, password, options: { emailRedirectTo: `${window.location.origin}/profile` }, }); return { error: error?.message ?? null }; }; const signIn = async (email: string, password: string) => { const { error } = await supabase.auth.signInWithPassword({ email, password }); return { error: error?.message ?? null }; }; const signInAnonymously = async () => { const { error } = await supabase.auth.signInAnonymously(); return { error: error?.message ?? null }; }; const signOut = async () => { await supabase.auth.signOut(); setProfile(null); }; const updateProfile = async (data: Partial) => { if (!user) return { error: "Not signed in" }; const payload: Record = { updated_at: new Date().toISOString(), last_active: new Date().toISOString(), }; if (data.display_name !== undefined) payload.display_name = data.display_name; if (data.username !== undefined) payload.username = data.username; if (data.age !== undefined) payload.age = data.age; if (data.position !== undefined) payload.position = data.position; if (data.bio !== undefined) payload.bio = data.bio; if (data.kinks !== undefined) payload.kinks = data.kinks; if (data.sti_status !== undefined) payload.sti_status = data.sti_status; if (data.on_prep !== undefined) payload.on_prep = data.on_prep; if (data.is_anonymous !== undefined) payload.is_anonymous = data.is_anonymous; if (data.status !== undefined) payload.status = data.status; if (data.city !== undefined) payload.city = data.city; if (data.state !== undefined) payload.state = data.state; if (data.id_verified !== undefined) payload.id_verified = data.id_verified; if (data.id_verified_at !== undefined) payload.id_verified_at = data.id_verified_at; const { error } = await supabase .from("profiles") .update(payload) .eq("id", user.id); if (error) return { error: error.message }; if (data.lat != null && data.lng != null) { await supabase.rpc("update_profile_location", { p_user_id: user.id, p_lat: data.lat, p_lng: data.lng, }); } await fetchProfile(user.id); return { error: null }; }; const refreshProfile = async () => { if (user) await fetchProfile(user.id); }; return ( {children} ); } export function useAuth() { const ctx = useContext(AuthContext); if (!ctx) throw new Error("useAuth must be used within AuthProvider"); return ctx; }