examforge / src /AuthContext.tsx
Benjahmin's picture
feat(auth): implement email-password authentication
20ba598
Raw
History Blame Contribute Delete
4.04 kB
import React, { createContext, useContext, useEffect, useState } from 'react';
import { UserProfile } from './types';
import { AuthService } from './services/AuthService';
interface AuthContextType {
user: any | null; // backward compatibility
profile: UserProfile | null;
loading: boolean;
login: (id: string, pin: string) => Promise<void>;
logout: () => Promise<void>;
registerStudent: (data: any) => Promise<UserProfile>;
registerTeacher: (data: any) => Promise<UserProfile>;
}
const AuthContext = createContext<AuthContextType | undefined>(undefined);
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [profile, setProfile] = useState<UserProfile | null>(() => {
const saved = localStorage.getItem('local_user_profile');
try {
return saved ? JSON.parse(saved) : null;
} catch {
return null;
}
});
const [loading, setLoading] = useState(true);
useEffect(() => {
async function checkSession() {
try {
const token = localStorage.getItem('local_user_token');
const headers: Record<string, string> = {};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const response = await fetch('/api/auth/me', { headers });
if (response.ok) {
const profileData = await response.json();
setProfile(profileData);
localStorage.setItem('local_user_profile', JSON.stringify(profileData));
} else {
setProfile(null);
localStorage.removeItem('local_user_profile');
localStorage.removeItem('local_user_token');
}
} catch (err) {
console.warn("Failed to retrieve user session during refresh:", err);
} finally {
setLoading(false);
}
}
checkSession();
}, []);
const login = async (idOrEmail: string, pinOrPassword: string) => {
const isEmail = idOrEmail.includes('@');
const { user: profileData, customToken } = isEmail
? await AuthService.loginWithEmail(idOrEmail, pinOrPassword)
: await AuthService.login(idOrEmail, pinOrPassword);
setProfile(profileData);
localStorage.setItem('local_user_profile', JSON.stringify(profileData));
if (customToken) {
localStorage.setItem('local_user_token', customToken);
}
};
const logout = async () => {
const token = localStorage.getItem('local_user_token');
const headers: Record<string, string> = {};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
await fetch('/api/auth/logout', { method: 'POST', headers }).catch(() => {});
setProfile(null);
localStorage.removeItem('local_user_profile');
localStorage.removeItem('local_user_token');
};
const registerStudent = async (data: any) => {
const { user: profileData, customToken } = data.email && data.password
? await AuthService.registerStudentWithEmail(data)
: await AuthService.registerStudent(data);
setProfile(profileData);
localStorage.setItem('local_user_profile', JSON.stringify(profileData));
if (customToken) {
localStorage.setItem('local_user_token', customToken);
}
return profileData;
};
const registerTeacher = async (data: any) => {
const { user: profileData, customToken } = data.email && data.password
? await AuthService.registerTeacherWithEmail(data)
: await AuthService.registerTeacher(data);
setProfile(profileData);
localStorage.setItem('local_user_profile', JSON.stringify(profileData));
if (customToken) {
localStorage.setItem('local_user_token', customToken);
}
return profileData;
};
return (
<AuthContext.Provider value={{ user: profile, profile, loading, login, logout, registerStudent, registerTeacher }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
}