Improve auth performance: cache profile, remove double fetch, reduce timeout
- Seed currentUser from localStorage instantly on load (no loading flash) - Remove getSession() duplicate — onAuthStateChange handles everything - Fetch fresh profile in background while cached version shows immediately - Reduce fallback timeout from 5s to 2s - Explicit Supabase client auth options for reliability Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+28
-15
@@ -3,36 +3,49 @@ import { supabase } from '../lib/supabase';
|
|||||||
|
|
||||||
const AuthContext = createContext(null);
|
const AuthContext = createContext(null);
|
||||||
|
|
||||||
|
const PROFILE_CACHE_KEY = 'fourge_profile';
|
||||||
|
|
||||||
export function AuthProvider({ children }) {
|
export function AuthProvider({ children }) {
|
||||||
const [currentUser, setCurrentUser] = useState(null);
|
const [currentUser, setCurrentUser] = useState(() => {
|
||||||
|
// Seed from cache instantly — no loading flash for returning users
|
||||||
|
try {
|
||||||
|
const cached = localStorage.getItem(PROFILE_CACHE_KEY);
|
||||||
|
return cached ? JSON.parse(cached) : null;
|
||||||
|
} catch { return null; }
|
||||||
|
});
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
const fetchProfile = async (authUser) => {
|
const fetchAndCacheProfile = async (authUser) => {
|
||||||
const { data } = await supabase
|
const { data } = await supabase
|
||||||
.from('profiles')
|
.from('profiles')
|
||||||
.select('*, company:companies(id, name, phone, address)')
|
.select('*, company:companies(id, name, phone, address)')
|
||||||
.eq('id', authUser.id)
|
.eq('id', authUser.id)
|
||||||
.single();
|
.single();
|
||||||
if (data) setCurrentUser({ ...data, email: authUser.email });
|
if (data) {
|
||||||
|
const profile = { ...data, email: authUser.email };
|
||||||
|
setCurrentUser(profile);
|
||||||
|
localStorage.setItem(PROFILE_CACHE_KEY, JSON.stringify(profile));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const timeout = setTimeout(() => setLoading(false), 5000);
|
// Fallback — stop blocking after 2s max
|
||||||
|
const timeout = setTimeout(() => setLoading(false), 2000);
|
||||||
supabase.auth.getSession().then(async ({ data: { session } }) => {
|
let resolved = false;
|
||||||
if (session?.user) await fetchProfile(session.user);
|
|
||||||
clearTimeout(timeout);
|
|
||||||
setLoading(false);
|
|
||||||
}).catch(() => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
setLoading(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
const { data: { subscription } } = supabase.auth.onAuthStateChange(async (event, session) => {
|
const { data: { subscription } } = supabase.auth.onAuthStateChange(async (event, session) => {
|
||||||
if (session?.user) {
|
if (session?.user) {
|
||||||
await fetchProfile(session.user);
|
// Fetch fresh profile in background (cache already seeded above)
|
||||||
|
fetchAndCacheProfile(session.user);
|
||||||
} else {
|
} else {
|
||||||
setCurrentUser(null);
|
setCurrentUser(null);
|
||||||
|
localStorage.removeItem(PROFILE_CACHE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!resolved) {
|
||||||
|
resolved = true;
|
||||||
|
clearTimeout(timeout);
|
||||||
|
setLoading(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -55,7 +68,6 @@ export function AuthProvider({ children }) {
|
|||||||
options: { data: { name, role: 'client' } },
|
options: { data: { name, role: 'client' } },
|
||||||
});
|
});
|
||||||
if (error) return { error: error.message };
|
if (error) return { error: error.message };
|
||||||
// Auto sign-in immediately after signup (no email confirmation required)
|
|
||||||
const { error: loginError } = await supabase.auth.signInWithPassword({ email, password });
|
const { error: loginError } = await supabase.auth.signInWithPassword({ email, password });
|
||||||
if (loginError) return { error: loginError.message };
|
if (loginError) return { error: loginError.message };
|
||||||
return {};
|
return {};
|
||||||
@@ -64,6 +76,7 @@ export function AuthProvider({ children }) {
|
|||||||
const logout = async () => {
|
const logout = async () => {
|
||||||
await supabase.auth.signOut();
|
await supabase.auth.signOut();
|
||||||
setCurrentUser(null);
|
setCurrentUser(null);
|
||||||
|
localStorage.removeItem(PROFILE_CACHE_KEY);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (loading) return (
|
if (loading) return (
|
||||||
|
|||||||
+7
-1
@@ -5,4 +5,10 @@ const key = import.meta.env.VITE_SUPABASE_ANON_KEY;
|
|||||||
|
|
||||||
if (!url || !key) throw new Error('Missing Supabase environment variables. Check VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY.');
|
if (!url || !key) throw new Error('Missing Supabase environment variables. Check VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY.');
|
||||||
|
|
||||||
export const supabase = createClient(url, key);
|
export const supabase = createClient(url, key, {
|
||||||
|
auth: {
|
||||||
|
persistSession: true,
|
||||||
|
autoRefreshToken: true,
|
||||||
|
detectSessionInUrl: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user