Initial commit
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
import React, { createContext, useContext, useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { CCUser, CCUserMetadata, authService } from '../services/auth/authService';
|
||||
import { logger } from '../debugConfig';
|
||||
import { supabase } from '../supabaseClient';
|
||||
|
||||
export interface AuthContextType {
|
||||
user: CCUser | null;
|
||||
user_role: string | null;
|
||||
loading: boolean;
|
||||
error: Error | null;
|
||||
signIn: (email: string, password: string) => Promise<void>;
|
||||
signOut: () => Promise<void>;
|
||||
clearError: () => void;
|
||||
}
|
||||
|
||||
export const AuthContext = createContext<AuthContextType>({
|
||||
user: null,
|
||||
user_role: null,
|
||||
loading: true,
|
||||
error: null,
|
||||
signIn: async () => {},
|
||||
signOut: async () => {},
|
||||
clearError: () => {}
|
||||
});
|
||||
|
||||
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
const navigate = useNavigate();
|
||||
const [user, setUser] = useState<CCUser | null>(null);
|
||||
const [user_role, setUserRole] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const loadUser = async () => {
|
||||
try {
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
|
||||
if (user) {
|
||||
const metadata = user.user_metadata as CCUserMetadata;
|
||||
setUser({
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
user_type: metadata.user_type || '',
|
||||
username: metadata.username || '',
|
||||
display_name: metadata.display_name || '',
|
||||
user_db_name: `cc.users.${metadata.user_type}.${metadata.username}`,
|
||||
school_db_name: 'cc.institutes.development.default',
|
||||
created_at: user.created_at,
|
||||
updated_at: user.updated_at
|
||||
});
|
||||
setUserRole(metadata.user_role || null);
|
||||
} else {
|
||||
setUser(null);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('auth-context', '❌ Failed to load user', { error });
|
||||
setError(error instanceof Error ? error : new Error('Failed to load user'));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
loadUser();
|
||||
|
||||
const { data: { subscription } } = supabase.auth.onAuthStateChange(async (event, session) => {
|
||||
if (event === 'SIGNED_IN' && session?.user) {
|
||||
const metadata = session.user.user_metadata as CCUserMetadata;
|
||||
setUser({
|
||||
id: session.user.id,
|
||||
email: session.user.email,
|
||||
user_type: metadata.user_type || '',
|
||||
username: metadata.username || '',
|
||||
display_name: metadata.display_name || '',
|
||||
user_db_name: `cc.users.${metadata.user_type}.${metadata.username}`,
|
||||
school_db_name: 'cc.institutes.development.default',
|
||||
created_at: session.user.created_at,
|
||||
updated_at: session.user.updated_at
|
||||
});
|
||||
} else if (event === 'SIGNED_OUT') {
|
||||
setUser(null);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
subscription.unsubscribe();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const signIn = async (email: string, password: string) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const { data, error: signInError } = await supabase.auth.signInWithPassword({
|
||||
email,
|
||||
password
|
||||
});
|
||||
|
||||
if (signInError) throw signInError;
|
||||
|
||||
if (data.user) {
|
||||
const metadata = data.user.user_metadata as CCUserMetadata;
|
||||
setUser({
|
||||
id: data.user.id,
|
||||
email: data.user.email,
|
||||
user_type: metadata.user_type || '',
|
||||
username: metadata.username || '',
|
||||
display_name: metadata.display_name || '',
|
||||
user_db_name: `cc.users.${metadata.user_type}.${metadata.username}`,
|
||||
school_db_name: 'cc.institutes.development.default',
|
||||
created_at: data.user.created_at,
|
||||
updated_at: data.user.updated_at
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('auth-context', '❌ Sign in failed', { error });
|
||||
setError(error instanceof Error ? error : new Error('Sign in failed'));
|
||||
throw error;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const signOut = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
await authService.logout();
|
||||
setUser(null);
|
||||
navigate('/');
|
||||
} catch (error) {
|
||||
logger.error('auth-context', '❌ Sign out failed', { error });
|
||||
setError(error instanceof Error ? error : new Error('Sign out failed'));
|
||||
throw error;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const clearError = () => setError(null);
|
||||
|
||||
return (
|
||||
<AuthContext.Provider
|
||||
value={{
|
||||
user,
|
||||
user_role,
|
||||
loading,
|
||||
error,
|
||||
signIn,
|
||||
signOut,
|
||||
clearError
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export const useAuth = () => useContext(AuthContext);
|
||||
Reference in New Issue
Block a user