import React, { createContext, useState, useContext, useEffect } from 'react'; import { base44 } from '@/api/base44Client'; import { appParams } from '@/lib/app-params'; import { createAxiosClient } from '@base44/sdk/dist/utils/axios-client'; const AuthContext = createContext(); export const AuthProvider = ({ children }) => { const [user, setUser] = useState(null); const [isAuthenticated, setIsAuthenticated] = useState(false); const [isLoadingAuth, setIsLoadingAuth] = useState(true); const [isLoadingPublicSettings, setIsLoadingPublicSettings] = useState(true); const [authError, setAuthError] = useState(null); const [appPublicSettings, setAppPublicSettings] = useState(null); // Contains only { id, public_settings } useEffect(() => { // checkAppState(); // disable Base44 calls for local running setIsLoadingAuth(false); setIsLoadingPublicSettings(false); }, []); const checkAppState = async () => { try { setIsLoadingPublicSettings(true); setAuthError(null); // First, check app public settings (with token if available) // This will tell us if auth is required, user not registered, etc. const appClient = createAxiosClient({ baseURL: `/api/apps/public`, headers: { 'X-App-Id': appParams.appId }, token: appParams.token, // Include token if available interceptResponses: true }); try { const publicSettings = await appClient.get(`/prod/public-settings/by-id/${appParams.appId}`); setAppPublicSettings(publicSettings); // If we got the app public settings successfully, check if user is authenticated if (appParams.token) { await checkUserAuth(); } else { setIsLoadingAuth(false); setIsAuthenticated(false); } setIsLoadingPublicSettings(false); } catch (appError) { console.error('App state check failed:', appError); // Handle app-level errors if (appError.status === 403 && appError.data?.extra_data?.reason) { const reason = appError.data.extra_data.reason; if (reason === 'auth_required') { setAuthError({ type: 'auth_required', message: 'Authentication required' }); } else if (reason === 'user_not_registered') { setAuthError({ type: 'user_not_registered', message: 'User not registered for this app' }); } else { setAuthError({ type: reason, message: appError.message }); } } else { setAuthError({ type: 'unknown', message: appError.message || 'Failed to load app' }); } setIsLoadingPublicSettings(false); setIsLoadingAuth(false); } } catch (error) { console.error('Unexpected error:', error); setAuthError({ type: 'unknown', message: error.message || 'An unexpected error occurred' }); setIsLoadingPublicSettings(false); setIsLoadingAuth(false); } }; const checkUserAuth = async () => { try { // Now check if the user is authenticated setIsLoadingAuth(true); const currentUser = await base44.auth.me(); setUser(currentUser); setIsAuthenticated(true); setIsLoadingAuth(false); } catch (error) { console.error('User auth check failed:', error); setIsLoadingAuth(false); setIsAuthenticated(false); // If user auth fails, it might be an expired token if (error.status === 401 || error.status === 403) { setAuthError({ type: 'auth_required', message: 'Authentication required' }); } } }; const logout = (shouldRedirect = true) => { setUser(null); setIsAuthenticated(false); if (shouldRedirect) { // Use the SDK's logout method which handles token cleanup and redirect base44.auth.logout(window.location.href); } else { // Just remove the token without redirect base44.auth.logout(); } }; const navigateToLogin = () => { // Use the SDK's redirectToLogin method base44.auth.redirectToLogin(window.location.href); }; return ( {children} ); }; export const useAuth = () => { const context = useContext(AuthContext); if (!context) { throw new Error('useAuth must be used within an AuthProvider'); } return context; };