/// Business Logic Component for managing authentication state. /// /// The [AuthBloc] handles authentication-related events and manages the /// authentication state throughout the application. It coordinates with /// the [AuthRepository] to perform authentication operations and emits /// appropriate states based on the results. /// /// Supported authentication methods: /// - Email and password authentication /// - Google Sign-In /// - Apple Sign-In /// - Password reset functionality /// /// This bloc handles the following events: /// - [AuthCheckRequested]: Verifies current authentication status /// - [AuthSignInRequested]: Processes email/password sign-in /// - [AuthSignUpRequested]: Processes user registration /// - [AuthGoogleSignInRequested]: Processes Google authentication /// - [AuthAppleSignInRequested]: Processes Apple authentication /// - [AuthSignOutRequested]: Processes user sign-out /// - [AuthPasswordResetRequested]: Processes password reset requests library; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../repositories/auth_repository.dart'; import 'auth_event.dart'; import 'auth_state.dart'; /// BLoC for managing authentication state and operations. class AuthBloc extends Bloc { /// Repository for authentication operations. final AuthRepository _authRepository; /// Creates an [AuthBloc] with the provided [authRepository]. /// /// The bloc starts in the [AuthInitial] state and registers event handlers /// for all supported authentication events. AuthBloc({required AuthRepository authRepository}) : _authRepository = authRepository, super(AuthInitial()) { on(_onAuthCheckRequested); on(_onSignInRequested); on(_onSignUpRequested); on(_onGoogleSignInRequested); on(_onGoogleSignUpRequested); on(_onAppleSignInRequested); on(_onAppleSignUpRequested); on(_onSignOutRequested); on(_onPasswordResetRequested); } /// Handles [AuthCheckRequested] events. /// /// Checks if a user is currently authenticated and emits the appropriate state. /// If a user is found, attempts to fetch user data from Firestore. Future _onAuthCheckRequested( AuthCheckRequested event, Emitter emit, ) async { emit(AuthLoading()); try { final currentUser = _authRepository.currentUser; if (currentUser != null) { // Fetch user data from Firestore final user = await _authRepository.getUserFromFirestore( currentUser.uid, ); if (user != null) { emit(AuthAuthenticated(user: user)); } else { emit(AuthUnauthenticated()); } } else { emit(AuthUnauthenticated()); } } catch (e) { emit(AuthError(message: e.toString().replaceAll('Exception: ', ''))); } } /// Handles [AuthSignInRequested] events. /// /// Attempts to sign in a user with the provided email and password. /// Emits [AuthAuthenticated] on success or [AuthError] on failure. Future _onSignInRequested( AuthSignInRequested event, Emitter emit, ) async { emit(AuthLoading()); try { final user = await _authRepository.signInWithEmailAndPassword( email: event.email, password: event.password, ); if (user != null) { emit(AuthAuthenticated(user: user)); } else { emit(const AuthError(message: 'Invalid email or password')); } } catch (e) { emit(AuthError(message: e.toString().replaceAll('Exception: ', ''))); } } /// Handles [AuthSignUpRequested] events. /// /// Attempts to create a new user account with the provided information. /// Emits [AuthAuthenticated] on success or [AuthError] on failure. Future _onSignUpRequested( AuthSignUpRequested event, Emitter emit, ) async { emit(AuthLoading()); try { final user = await _authRepository.signUpWithEmailAndPassword( email: event.email, password: event.password, nom: event.nom, prenom: event.prenom, phoneNumber: event.phoneNumber, ); if (user != null) { emit(AuthAuthenticated(user: user)); } else { emit(const AuthError(message: 'Failed to create account')); } } catch (e) { emit(AuthError(message: e.toString().replaceAll('Exception: ', ''))); } } /// Handles [AuthGoogleSignInRequested] events. /// /// Attempts to sign in the user using Google authentication. /// Emits [AuthAuthenticated] on success or [AuthError] on failure. Future _onGoogleSignInRequested( AuthGoogleSignInRequested event, Emitter emit, ) async { emit(AuthLoading()); try { final user = await _authRepository.signInWithGoogle(); if (user != null) { emit(AuthAuthenticated(user: user)); } else { emit( const AuthError( message: 'Utilisateur n\'est pas encore inscrit avec Google, veuillez créer un compte avec Google', ), ); } } catch (e) { emit(AuthError(message: e.toString().replaceAll('Exception: ', ''))); } } Future _onGoogleSignUpRequested( AuthGoogleSignUpRequested event, Emitter emit, ) async { // This method can be implemented if needed for Google sign-up specific logic. emit(AuthLoading()); try { final user = await _authRepository.signUpWithGoogle( event.phoneNumber, event.name, event.firstname, ); if (user != null) { emit(AuthAuthenticated(user: user)); } else { emit(const AuthError(message: 'Failed to create account with Google')); } } catch (e) { emit(AuthError(message: e.toString().replaceAll('Exception: ', ''))); } } Future _onAppleSignUpRequested( AuthAppleSignUpRequested event, Emitter emit, ) async { // This method can be implemented if needed for Apple sign-up specific logic. emit(AuthLoading()); try { final user = await _authRepository.signUpWithApple( event.phoneNumber, event.name, event.firstname, ); if (user != null) { emit(AuthAuthenticated(user: user)); } else { emit(const AuthError(message: 'Failed to create account with Apple')); } } catch (e) { emit(AuthError(message: e.toString().replaceAll('Exception: ', ''))); } } /// Handles [AuthAppleSignInRequested] events. /// /// Attempts to sign in the user using Apple authentication. /// Emits [AuthAuthenticated] on success or [AuthError] on failure. Future _onAppleSignInRequested( AuthAppleSignInRequested event, Emitter emit, ) async { emit(AuthLoading()); try { final user = await _authRepository.signInWithApple(); if (user != null) { emit(AuthAuthenticated(user: user)); } else { emit( const AuthError( message: 'Utilisateur n\'est pas encore inscrit avec Apple, veuillez créer un compte avec Apple', ), ); } } catch (e) { emit(AuthError(message: e.toString().replaceAll('Exception: ', ''))); } } /// Handles [AuthSignOutRequested] events. /// /// Signs out the current user and emits [AuthUnauthenticated]. Future _onSignOutRequested( AuthSignOutRequested event, Emitter emit, ) async { await _authRepository.signOut(); emit(AuthUnauthenticated()); } /// Handles [AuthPasswordResetRequested] events. /// /// Sends a password reset email to the specified email address. /// Emits [AuthPasswordResetSent] on success or [AuthError] on failure. Future _onPasswordResetRequested( AuthPasswordResetRequested event, Emitter emit, ) async { try { await _authRepository.resetPassword(event.email); emit(AuthPasswordResetSent(email: event.email)); } catch (e) { emit(AuthError(message: e.toString().replaceAll('Exception: ', ''))); } } }