import React, { createContext, useContext, useState, useEffect, ReactNode, } from 'react'; import { User } from '../types'; import { databaseService } from '../services/database'; import { authService } from '../services/auth/auth.service'; const SESSION_KEY = 'medication_app_session'; interface UserContextType { user: User | null; isLoading: boolean; login: (email: string, password: string) => Promise; register: ( email: string, password: string, username?: string ) => Promise; loginWithOAuth: ( provider: 'google' | 'github', userData: { email: string; username: string; avatar?: string } ) => Promise; changePassword: ( currentPassword: string, newPassword: string ) => Promise; logout: () => void; updateUser: ( updatedUser: Omit & { _rev: string } ) => Promise; } const UserContext = createContext(undefined); export const UserProvider: React.FC<{ children: ReactNode }> = ({ children, }) => { const [user, setUser] = useState(null); const [isLoading, setIsLoading] = useState(true); useEffect(() => { try { const sessionUser = localStorage.getItem(SESSION_KEY); if (sessionUser) { setUser(JSON.parse(sessionUser)); } } catch { // silent fail } finally { setIsLoading(false); } }, []); useEffect(() => { if (user) { localStorage.setItem(SESSION_KEY, JSON.stringify(user)); } else { localStorage.removeItem(SESSION_KEY); } }, [user]); const login = async (email: string, password: string): Promise => { try { // Use auth service for password-based login const result = await authService.login({ email, password }); console.warn('Login result received:', result); console.warn('User from login:', result.user); console.warn('User _id:', result.user._id); // Update last login time const updatedUser = { ...result.user, lastLoginAt: new Date() }; await databaseService.updateUser(updatedUser); console.warn('Updated user with last login:', updatedUser); // Store access token for subsequent API calls. localStorage.setItem('access_token', result.accessToken); // Set the user from the login result setUser(updatedUser); console.warn('User set in context'); return true; } catch (error) { console.error('Login error:', error); return false; } }; const register = async ( email: string, password: string, username?: string ): Promise => { try { await authService.register(email, password, username); // Don't auto-login after registration, require email verification return true; } catch (error) { console.error('Registration error:', error); return false; } }; const loginWithOAuth = async ( provider: 'google' | 'github', userData: { email: string; username: string; avatar?: string } ): Promise => { try { const result = await authService.loginWithOAuth(provider, userData); console.warn('OAuth login result received:', result); console.warn('OAuth user:', result.user); console.warn('OAuth user _id:', result.user._id); // Update last login time const updatedUser = { ...result.user, lastLoginAt: new Date() }; await databaseService.updateUser(updatedUser); console.warn('Updated OAuth user with last login:', updatedUser); localStorage.setItem('access_token', result.accessToken); setUser(updatedUser); console.warn('OAuth user set in context'); return true; } catch (error) { console.error('OAuth login error:', error); return false; } }; const changePassword = async ( currentPassword: string, newPassword: string ): Promise => { try { if (!user) { throw new Error('No user logged in'); } await authService.changePassword(user._id, currentPassword, newPassword); return true; } catch (error) { console.error('Password change error:', error); return false; } }; const logout = () => { setUser(null); }; const updateUser = async (updatedUser: User) => { try { const savedUser = await databaseService.updateUser(updatedUser); setUser(savedUser); } catch (error) { console.error('Failed to update user', error); // Optionally revert state or show error } }; if (isLoading) { return (
); } return ( {children} ); }; export const useUser = (): UserContextType => { const context = useContext(UserContext); if (context === undefined) { throw new Error('useUser must be used within a UserProvider'); } return context; }; // Dummy icon for loading screen const PillIcon: React.FC> = props => ( );