'use client'; import { createContext, useContext, useState, useEffect, ReactNode, useCallback } from 'react'; import { api } from '@/lib/api'; import { API_BASE } from '@/lib/api'; interface User { id: string; email?: string; } interface AuthContextType { user: User | null; loading: boolean; cartCount: number; isSeller: boolean; sellerChecked: boolean; unreadMessages: number; login: (email: string, password: string) => Promise<{ success: boolean; error?: string }>; signup: (email: string, password: string) => Promise<{ success: boolean; error?: string }>; logout: () => Promise; refreshCartCount: () => Promise; refreshUnreadMessages: () => Promise; } const AuthContext = createContext({ user: null, loading: true, cartCount: 0, isSeller: false, sellerChecked: false, unreadMessages: 0, login: async () => ({ success: false }), signup: async () => ({ success: false }), logout: async () => {}, refreshCartCount: async () => {}, refreshUnreadMessages: async () => {}, }); export function AuthProvider({ children }: { children: ReactNode }) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const [cartCount, setCartCount] = useState(0); const [isSeller, setIsSeller] = useState(false); const [sellerChecked, setSellerChecked] = useState(false); const [unreadMessages, setUnreadMessages] = useState(0); const refreshCartCount = useCallback(async () => { if (!user) { setCartCount(0); return; } try { const result = await api.cart.count(); if (result.success) { setCartCount(result.count || 0); } } catch {} }, [user]); // Fetch unread message count for the messenger badge. // Functional: only runs when logged in. Counts conversations that have a // lastMessage as "unread" since we don't have read receipts yet. const refreshUnreadMessages = useCallback(async () => { if (!user) { setUnreadMessages(0); return; } try { const resp = await fetch(`${API_BASE}/api/messenger`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ op: 'list' }), }); const data = await resp.json(); if (data.success && Array.isArray(data.conversations)) { const withMessages = data.conversations.filter((c: any) => c.lastMessage && c.lastMessage.trim()); setUnreadMessages(withMessages.length); } } catch {} }, [user]); useEffect(() => { (async () => { try { const result = await api.auth.session(); if (result.success && result.user) { setUser(result.user); } } catch { // Not logged in } finally { setLoading(false); } })(); }, []); // Check seller status ONCE when user is set (not on every page load). // The result is cached in the AuthProvider state, so MobileNav and // other components can read it synchronously without flicker. useEffect(() => { if (!user) { setIsSeller(false); setSellerChecked(true); return; } let cancelled = false; (async () => { try { const resp = await fetch(`${API_BASE}/api/seller-profile`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ op: 'get' }), }); if (resp.ok) { const data = await resp.json(); if (!cancelled && data.success && data.seller) { setIsSeller(true); } } } catch {} if (!cancelled) setSellerChecked(true); })(); return () => { cancelled = true; }; }, [user]); useEffect(() => { if (user) refreshCartCount(); }, [user, refreshCartCount]); // Fetch unread messages when user changes (login/logout) useEffect(() => { refreshUnreadMessages(); }, [user, refreshUnreadMessages]); // Poll for new messages every 30 seconds when logged in (so the badge stays fresh) useEffect(() => { if (!user) return; const interval = setInterval(refreshUnreadMessages, 60000); return () => clearInterval(interval); }, [user, refreshUnreadMessages]); const login = async (email: string, password: string) => { const result = await api.auth.login(email, password); if (result.success && result.user) { setUser(result.user); return { success: true }; } return { success: false, error: result.error }; }; const signup = async (email: string, password: string) => { const result = await api.auth.signup(email, password); if (result.success && result.user) { // Check if the signup returned a session_id (auto-login). // If not (email confirmation required), auto-login with the same credentials // to create a real session. This is necessary because Supabase's signup // endpoint doesn't return a session when email confirmation is enabled, // even with mailer_autoconfirm=true. if (!result.session_id) { const loginResult = await api.auth.login(email, password); if (loginResult.success && loginResult.user) { setUser(loginResult.user); return { success: true }; } // If auto-login fails, still return success (account was created) // but the user will need to log in manually. setUser(result.user); return { success: true }; } setUser(result.user); return { success: true }; } return { success: false, error: result.error }; }; const logout = async () => { await api.auth.logout(); setUser(null); setCartCount(0); setUnreadMessages(0); setIsSeller(false); setSellerChecked(true); }; return ( {children} ); } export function useAuth() { return useContext(AuthContext); }