import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:formz/formz.dart'; import 'package:equatable/equatable.dart'; import '../../data/auth_repository.dart'; import '../../data/models/signup_request.dart'; import '../../data/models/auth_response.dart'; class Username extends FormzInput { const Username.pure() : super.pure(''); const Username.dirty([super.value = '']) : super.dirty(); @override String? validator(String value) { if (value.isEmpty) return 'Username is required'; if (value.length < 3) return 'Username must be at least 3 characters'; if (value.length > 30) return 'Username must be at most 30 characters'; return null; } } class Email extends FormzInput { const Email.pure() : super.pure(''); const Email.dirty([super.value = '']) : super.dirty(); static final _regex = RegExp(r'^[\w.-]+@[\w.-]+\.\w+$'); @override String? validator(String value) { if (value.isEmpty) return 'Email is required'; if (!_regex.hasMatch(value)) return 'Invalid email format'; return null; } } class Password extends FormzInput { const Password.pure() : super.pure(''); const Password.dirty([super.value = '']) : super.dirty(); @override String? validator(String value) { if (value.isEmpty) return 'Password is required'; if (value.length < 6) return 'Password must be at least 6 characters'; return null; } } class VerificationCode extends FormzInput { const VerificationCode.pure() : super.pure(''); const VerificationCode.dirty([super.value = '']) : super.dirty(); @override String? validator(String value) { if (value.isEmpty) return 'Code is required'; if (!RegExp(r'^\d{6}$').hasMatch(value)) return 'Code must be 6 digits'; return null; } } class RegisterState extends Equatable { final Username username; final Email email; final Password password; final VerificationCode verificationCode; final FormzSubmissionStatus status; final String? errorMessage; final String? pendingEmail; final bool codeSent; const RegisterState({ this.username = const Username.pure(), this.email = const Email.pure(), this.password = const Password.pure(), this.verificationCode = const VerificationCode.pure(), this.status = FormzSubmissionStatus.initial, this.errorMessage, this.pendingEmail, this.codeSent = false, }); bool get isStep1Valid => username.isValid && email.isValid && password.isValid; bool get isStep2Valid => verificationCode.isValid; RegisterState copyWith({ Username? username, Email? email, Password? password, VerificationCode? verificationCode, FormzSubmissionStatus? status, String? errorMessage, String? pendingEmail, bool? codeSent, }) { return RegisterState( username: username ?? this.username, email: email ?? this.email, password: password ?? this.password, verificationCode: verificationCode ?? this.verificationCode, status: status ?? this.status, errorMessage: errorMessage, pendingEmail: pendingEmail ?? this.pendingEmail, codeSent: codeSent ?? this.codeSent, ); } @override List get props => [ username, email, password, verificationCode, status, errorMessage, pendingEmail, codeSent, ]; } class RegisterCubit extends Cubit { final AuthRepository _repository; RegisterCubit(this._repository) : super(const RegisterState()); void usernameChanged(String value) { emit(state.copyWith(username: Username.dirty(value))); } void emailChanged(String value) { emit(state.copyWith(email: Email.dirty(value))); } void passwordChanged(String value) { emit(state.copyWith(password: Password.dirty(value))); } void verificationCodeChanged(String value) { emit(state.copyWith(verificationCode: VerificationCode.dirty(value))); } Future submitStep1() async { if (!state.isStep1Valid) return false; emit(state.copyWith(status: FormzSubmissionStatus.inProgress)); try { final response = await _repository.signupStart( SignupStartRequest( username: state.username.value, email: state.email.value, password: state.password.value, ), ); emit( state.copyWith( status: FormzSubmissionStatus.success, pendingEmail: response.email, codeSent: true, ), ); return true; } catch (e) { emit( state.copyWith( status: FormzSubmissionStatus.failure, errorMessage: e.toString(), ), ); return false; } } Future submitStep2() async { if (!state.isStep2Valid || state.pendingEmail == null) return null; emit(state.copyWith(status: FormzSubmissionStatus.inProgress)); try { final response = await _repository.signupVerify( SignupVerifyRequest( email: state.pendingEmail!, token: state.verificationCode.value, ), ); emit(state.copyWith(status: FormzSubmissionStatus.success)); return response; } catch (e) { emit( state.copyWith( status: FormzSubmissionStatus.failure, errorMessage: e.toString(), ), ); return null; } } Future resendCode() async { if (state.pendingEmail == null) return; try { await _repository.signupResend( SignupResendRequest(email: state.pendingEmail!), ); emit(state.copyWith(codeSent: true)); } catch (e) { emit(state.copyWith(errorMessage: e.toString())); } } }