Files
krow_talent_app/src/lib/AuthContext.jsx
2026-08-24 13:16:15 +05:30

108 lines
3.3 KiB
JavaScript

import React, { createContext, useState, useContext, useEffect } from 'react';
import { base44 } from '@/api/base44Client';
/**
* Auth context.
*
* The single source of truth for "is anyone signed in", and it is not a flag
* this app sets. `checkUserAuth` calls `GET /me`; the server reads its own
* session table and either returns a user or answers 401. Success means there
* is a session, failure means there is not, and there is no third answer this
* code can manufacture.
*
* The context shape is unchanged from the demo's version — `isLoadingAuth`,
* `isLoadingPublicSettings`, `authError`, `navigateToLogin` and the rest — so
* `App.jsx`, `ProtectedRoute` and every consumer stay as they were. What
* changed is where the answer comes from: a real session cookie rather than a
* client that reported the seeded user as permanently signed in.
*/
const AuthContext = createContext(/** @type {any} */ (null));
/** @param {any} props */
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [isLoadingAuth, setIsLoadingAuth] = useState(true);
const [authChecked, setAuthChecked] = useState(false);
const checkUserAuth = async () => {
setIsLoadingAuth(true);
try {
const currentUser = await base44.auth.me();
setUser(currentUser);
setIsAuthenticated(true);
} catch {
// A 401 is the ordinary state of a signed-out visitor, and it is also
// what an expired session looks like on the first request after it
// lapses. Both mean the same thing here.
setUser(null);
setIsAuthenticated(false);
} finally {
setIsLoadingAuth(false);
setAuthChecked(true);
}
};
useEffect(() => {
checkUserAuth();
}, []);
/**
* Signs in.
*
* Resolves to the user on success and throws the API's error otherwise. The
* error's message is already the generic one the server chose — it does not
* say whether the address exists — so callers show it as-is rather than
* writing their own.
*/
const login = async ({ email, password, rememberMe = false }) => {
const currentUser = await base44.auth.login({ email, password, rememberMe });
setUser(currentUser);
setIsAuthenticated(true);
setAuthChecked(true);
return currentUser;
};
const logout = async (redirectTo = '/admin/login') => {
setUser(null);
setIsAuthenticated(false);
// Revokes the session server-side, expires the cookie, then redirects.
await base44.auth.logout(redirectTo);
};
const navigateToLogin = () => {
base44.auth.redirectToLogin();
};
return (
<AuthContext.Provider
value={{
user,
isAuthenticated,
isLoadingAuth,
// No remote app settings to fetch in the demo.
isLoadingPublicSettings: false,
authError: null,
appPublicSettings: null,
authChecked,
login,
logout,
navigateToLogin,
checkUserAuth,
checkAppState: checkUserAuth,
}}
>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
};