From 33cb4f6f06803c6079d200163327fbf441ae506c Mon Sep 17 00:00:00 2001 From: Hugo Pointcheval Date: Thu, 29 Dec 2022 17:04:26 +0100 Subject: [PATCH] refactor(authentication)!: use mixins, and remove use of onSignUpSuccess --- .../sign_in/cubit/base_sign_in_cubit.dart | 97 ++++++++ .../cubit/mixin/sign_in_anonymously.dart | 66 ++++++ .../mixin/sign_in_with_email_password.dart | 139 +++++++++++ .../cubit/mixin/sign_in_with_google.dart | 65 +++++ .../features/sign_in/cubit/sign_in_cubit.dart | 222 +++--------------- .../sign_up/cubit/base_sign_up_cubit.dart | 101 ++++++++ .../mixin/sign_up_with_email_password.dart | 137 +++++++++++ .../features/sign_up/cubit/sign_up_cubit.dart | 162 +------------ .../lib/wyatt_authentication_bloc.dart | 2 + 9 files changed, 646 insertions(+), 345 deletions(-) create mode 100644 packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/base_sign_in_cubit.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_anonymously.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_email_password.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_google.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/base_sign_up_cubit.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/mixin/sign_up_with_email_password.dart diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/base_sign_in_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/base_sign_in_cubit.dart new file mode 100644 index 00000000..b1446b36 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/base_sign_in_cubit.dart @@ -0,0 +1,97 @@ +// Copyright (C) 2022 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +part of 'sign_in_cubit.dart'; + +abstract class BaseSignInCubit extends FormDataCubit { + BaseSignInCubit({ + required this.authenticationRepository, + }) : super( + SignInState( + form: authenticationRepository.formRepository + .accessForm(AuthFormName.signInForm), + ), + ); + final AuthenticationRepository authenticationRepository; + FormRepository get formRepository => authenticationRepository.formRepository; + + @override + String get formName => AuthFormName.signInForm; + + @override + FutureOr dataChanged( + String key, + FormInputValidator dirtyValue, + ) { + final form = formRepository.accessForm(formName).clone(); + + try { + form.updateValidator(key, dirtyValue); + formRepository.updateForm(form); + } catch (e) { + rethrow; + } + + emit( + SignInState(form: form, status: form.validate()), + ); + } + + @override + FutureOr reset() { + final form = state.form.reset(); + formRepository.updateForm(form); + emit( + SignInState(form: form, status: form.validate()), + ); + } + + @override + FutureOr update( + WyattForm form, { + SetOperation operation = SetOperation.replace, + }) { + final WyattForm current = formRepository.accessForm(formName).clone(); + final WyattForm newForm = operation.operation.call(current, form); + formRepository.updateForm(newForm); + + emit( + SignInState(form: newForm, status: newForm.validate()), + ); + } + + @override + FutureOr validate() { + final WyattForm form = formRepository.accessForm(formName); + emit( + SignInState(form: form, status: form.validate()), + ); + } + + @override + FutureOr submit() async { + final WyattForm form = formRepository.accessForm(formName); + const error = '`submit()` is not implemented for BaseSignUpCubit, ' + 'please use `signUpWithEmailAndPassword()`.'; + emit( + SignInState( + form: form, + errorMessage: error, + status: FormStatus.submissionFailure, + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_anonymously.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_anonymously.dart new file mode 100644 index 00000000..486ed946 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_anonymously.dart @@ -0,0 +1,66 @@ +// Copyright (C) 2022 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'dart:async'; + +import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; +import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/sign_in_cubit.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +mixin SignInAnonymously on BaseSignInCubit { + FutureOrResult onSignInAnonymously( + Result result, + WyattForm form, + ); + + FutureOr signInAnonymously() async { + if (state.status.isSubmissionInProgress) { + return; + } + + final form = formRepository.accessForm(formName); + emit(SignInState(form: form, status: FormStatus.submissionInProgress)); + + final result = await authenticationRepository.signInAnonymously(); + + // Here custom code + final callbackResponse = await onSignInAnonymously(result, form); + if (callbackResponse.isErr) { + final error = callbackResponse.err!; + emit( + SignInState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ); + } + + emit( + result.fold( + (value) => + SignInState(form: form, status: FormStatus.submissionSuccess), + (error) => SignInState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_email_password.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_email_password.dart new file mode 100644 index 00000000..9a1d66e3 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_email_password.dart @@ -0,0 +1,139 @@ +// Copyright (C) 2022 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'dart:async'; + +import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; +import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/sign_in_cubit.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +mixin SignInWithEmailPassword on BaseSignInCubit { + FutureOrResult onSignInWithEmailAndPassword( + Result result, + WyattForm form, + ); + + void emailChanged(String value) { + final emailValidatorType = formRepository + .accessForm(formName) + .validatorOf(AuthFormField.email) + .runtimeType; + assert( + emailValidatorType == Email, + 'Use emailCustomChanged(...) with validator $emailValidatorType', + ); + + final Email email = Email.dirty(value); + dataChanged(AuthFormField.email, email); + } + + void passwordChanged(String value) { + final passwordValidatorType = formRepository + .accessForm(formName) + .validatorOf(AuthFormField.password) + .runtimeType; + assert( + passwordValidatorType == Password, + 'Use passwordCustomChanged(...) with validator $passwordValidatorType', + ); + final Password password = Password.dirty(value); + dataChanged(AuthFormField.password, password); + } + + /// Same as [emailChanged] but with a custom [Validator]. + /// + /// Sort of short hand for [dataChanged]. + void emailCustomChanged< + Validator extends FormInputValidator>( + Validator validator, + ) { + dataChanged(AuthFormField.email, validator); + } + + /// Same as [passwordChanged] but with a custom [Validator]. + /// + /// Sort of short hand for [dataChanged]. + void passwordCustomChanged< + Validator extends FormInputValidator>( + Validator validator, + ) { + dataChanged(AuthFormField.password, validator); + } + + FutureOr signInWithEmailAndPassword() async { + if (state.status.isSubmissionInProgress) { + return; + } + + if (!state.status.isValidated) { + return; + } + + final form = formRepository.accessForm(formName); + emit( + SignInState( + form: form, + status: FormStatus.submissionInProgress, + ), + ); + + final email = form.valueOf(AuthFormField.email); + final password = form.valueOf(AuthFormField.password); + + if (email.isNullOrEmpty || password.isNullOrEmpty) { + emit( + SignInState( + form: form, + errorMessage: 'An error occured while retrieving data from the form.', + status: FormStatus.submissionFailure, + ), + ); + } + + final result = await authenticationRepository.signInWithEmailAndPassword( + email: email!, + password: password!, + ); + + // Here custom code + final callbackResponse = await onSignInWithEmailAndPassword(result, form); + if (callbackResponse.isErr) { + final error = callbackResponse.err!; + emit( + SignInState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ); + } + + emit( + result.fold( + (value) => + SignInState(form: form, status: FormStatus.submissionSuccess), + (error) => SignInState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_google.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_google.dart new file mode 100644 index 00000000..b625534a --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_google.dart @@ -0,0 +1,65 @@ +// Copyright (C) 2022 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'dart:async'; + +import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; +import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/sign_in_cubit.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +mixin SignInWithGoogle on BaseSignInCubit { + FutureOrResult onSignInWithGoogle( + Result result, + WyattForm form, + ); + + FutureOr signInWithGoogle() async { + if (state.status.isSubmissionInProgress) { + return; + } + final form = formRepository.accessForm(formName); + emit(SignInState(form: form, status: FormStatus.submissionInProgress)); + + final result = await authenticationRepository.signInWithGoogle(); + + // Here custom code + final callbackResponse = await onSignInWithGoogle(result, form); + if (callbackResponse.isErr) { + final error = callbackResponse.err!; + emit( + SignInState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ); + } + + emit( + result.fold( + (value) => + SignInState(form: form, status: FormStatus.submissionSuccess), + (error) => SignInState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_cubit.dart index 5c7e460c..3d171f9d 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_cubit.dart @@ -14,213 +14,45 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . + import 'dart:async'; +import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/mixin/sign_in_anonymously.dart'; +import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/mixin/sign_in_with_email_password.dart'; +import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/mixin/sign_in_with_google.dart'; import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; +part 'base_sign_in_cubit.dart'; part 'sign_in_state.dart'; -class SignInCubit extends FormDataCubit { - SignInCubit({ - required this.authenticationRepository, - }) : super( - SignInState( - form: authenticationRepository.formRepository - .accessForm(AuthFormName.signInForm), - ), - ); - final AuthenticationRepository authenticationRepository; - FormRepository get formRepository => authenticationRepository.formRepository; +class SignInCubit extends BaseSignInCubit + with + SignInAnonymously, + SignInWithEmailPassword, + SignInWithGoogle { + SignInCubit({required super.authenticationRepository}); @override - String get formName => AuthFormName.signInForm; - - void emailChanged(String value) { - final emailValidatorType = formRepository - .accessForm(formName) - .validatorOf(AuthFormField.email) - .runtimeType; - assert( - emailValidatorType == Email, - 'Use emailCustomChanged(...) with validator $emailValidatorType', - ); - - final Email email = Email.dirty(value); - dataChanged(AuthFormField.email, email); - } - - void passwordChanged(String value) { - final passwordValidatorType = formRepository - .accessForm(formName) - .validatorOf(AuthFormField.password) - .runtimeType; - assert( - passwordValidatorType == Password, - 'Use passwordCustomChanged(...) with validator $passwordValidatorType', - ); - final Password password = Password.dirty(value); - dataChanged(AuthFormField.password, password); - } - - /// Same as [emailChanged] but with a custom [Validator]. - /// - /// Sort of short hand for [dataChanged]. - void emailCustomChanged< - Validator extends FormInputValidator>( - Validator validator, - ) { - dataChanged(AuthFormField.email, validator); - } - - /// Same as [passwordChanged] but with a custom [Validator]. - /// - /// Sort of short hand for [dataChanged]. - void passwordCustomChanged< - Validator extends FormInputValidator>( - Validator validator, - ) { - dataChanged(AuthFormField.password, validator); - } + FutureOrResult onSignInAnonymously( + Result result, + WyattForm form, + ) => + const Ok(null); @override - FutureOr dataChanged( - String key, - FormInputValidator dirtyValue, - ) { - final form = formRepository.accessForm(formName).clone(); - - try { - form.updateValidator(key, dirtyValue); - formRepository.updateForm(form); - } catch (e) { - rethrow; - } - - emit( - state.copyWith(form: form, status: form.validate()), - ); - } + FutureOrResult onSignInWithEmailAndPassword( + Result result, + WyattForm form, + ) => + const Ok(null); @override - FutureOr reset() { - final form = state.form.reset(); - formRepository.updateForm(form); - emit( - state.copyWith(form: form, status: form.validate()), - ); - } - - @override - FutureOr submit() async { - throw UnimplementedError('`submit()` is not implemented for SignInCubit, ' - 'please use `signInWithEmailAndPassword()` or `signInAnonymously()`'); - } - - @override - FutureOr update( - WyattForm form, { - SetOperation operation = SetOperation.replace, - }) { - final WyattForm current = formRepository.accessForm(formName).clone(); - final WyattForm newForm = operation.operation.call(current, form); - formRepository.updateForm(newForm); - - emit( - state.copyWith( - form: newForm, - status: newForm.validate(), - ), - ); - } - - @override - FutureOr validate() { - emit( - state.copyWith( - status: formRepository.accessForm(formName).validate(), - ), - ); - } - - FutureOr signInWithEmailAndPassword() async { - if (state.status.isSubmissionInProgress) { - return; - } - - if (!state.status.isValidated) { - return; - } - - emit(state.copyWith(status: FormStatus.submissionInProgress)); - - final form = formRepository.accessForm(formName); - final email = form.valueOf(AuthFormField.email); - final password = form.valueOf(AuthFormField.password); - - if (email.isNullOrEmpty || password.isNullOrEmpty) { - emit( - state.copyWith( - errorMessage: 'An error occured while retrieving data from the form.', - status: FormStatus.submissionFailure, - ), - ); - } - - final uid = await authenticationRepository.signInWithEmailAndPassword( - email: email!, - password: password!, - ); - - emit( - uid.fold( - (value) => state.copyWith(status: FormStatus.submissionSuccess), - (error) => state.copyWith( - errorMessage: error.message, - status: FormStatus.submissionFailure, - ), - ), - ); - } - - FutureOr signInAnonymously() async { - if (state.status.isSubmissionInProgress) { - return; - } - - emit(state.copyWith(status: FormStatus.submissionInProgress)); - - final uid = await authenticationRepository.signInAnonymously(); - - emit( - uid.fold( - (value) => state.copyWith(status: FormStatus.submissionSuccess), - (error) => state.copyWith( - errorMessage: error.message, - status: FormStatus.submissionFailure, - ), - ), - ); - } - - FutureOr signInWithGoogle() async { - if (state.status.isSubmissionInProgress) { - return; - } - // TODO(wyatt): maybe emit new state (to not carry an old errorMessage) - emit(state.copyWith(status: FormStatus.submissionInProgress)); - - final uid = await authenticationRepository.signInWithGoogle(); - - emit( - uid.fold( - (value) => state.copyWith(status: FormStatus.submissionSuccess), - (error) => state.copyWith( - errorMessage: error.message, - status: FormStatus.submissionFailure, - ), - ), - ); - } + FutureOrResult onSignInWithGoogle( + Result result, + WyattForm form, + ) => + const Ok(null); } diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/base_sign_up_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/base_sign_up_cubit.dart new file mode 100644 index 00000000..9aaad484 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/base_sign_up_cubit.dart @@ -0,0 +1,101 @@ +// Copyright (C) 2022 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +part of 'sign_up_cubit.dart'; + +abstract class BaseSignUpCubit extends FormDataCubit { + BaseSignUpCubit({ + required this.authenticationRepository, + }) : super( + SignUpState( + form: authenticationRepository.formRepository + .accessForm(AuthFormName.signUpForm), + ), + ); + final AuthenticationRepository authenticationRepository; + FormRepository get formRepository => authenticationRepository.formRepository; + + @override + String get formName => AuthFormName.signUpForm; + + @override + FutureOr dataChanged( + String key, + FormInputValidator dirtyValue, + ) { + final form = formRepository.accessForm(formName).clone(); + + try { + form.updateValidator(key, dirtyValue); + formRepository.updateForm(form); + } catch (e) { + rethrow; + } + + emit( + SignUpState(form: form, status: form.validate()), + ); + } + + @override + FutureOr reset() { + final form = state.form.reset(); + formRepository.updateForm(form); + emit( + SignUpState(form: form, status: form.validate()), + ); + } + + @override + FutureOr update( + WyattForm form, { + SetOperation operation = SetOperation.replace, + }) { + final WyattForm current = formRepository.accessForm(formName).clone(); + final WyattForm newForm = operation.operation.call(current, form); + formRepository.updateForm(newForm); + + emit( + SignUpState( + form: newForm, + status: newForm.validate(), + ), + ); + } + + @override + FutureOr validate() { + final WyattForm form = formRepository.accessForm(formName); + emit( + SignUpState(form: form, status: form.validate()), + ); + } + + @override + FutureOr submit() async { + final WyattForm form = formRepository.accessForm(formName); + const error = '`submit()` is not implemented for BaseSignUpCubit, ' + 'please use `signUpWithEmailAndPassword()`.'; + emit( + SignUpState( + form: form, + errorMessage: error, + status: FormStatus.submissionFailure, + ), + ); + throw UnimplementedError(error); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/mixin/sign_up_with_email_password.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/mixin/sign_up_with_email_password.dart new file mode 100644 index 00000000..6952a01c --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/mixin/sign_up_with_email_password.dart @@ -0,0 +1,137 @@ +// Copyright (C) 2022 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'dart:async'; + +import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; +import 'package:wyatt_authentication_bloc/src/features/sign_up/cubit/sign_up_cubit.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +mixin SignUpWithEmailPassword on BaseSignUpCubit { + FutureOrResult onSignUpWithEmailAndPassword( + Result result, + WyattForm form, + ); + + void emailChanged(String value) { + final emailValidatorType = formRepository + .accessForm(formName) + .validatorOf(AuthFormField.email) + .runtimeType; + assert( + emailValidatorType == Email, + 'Use emailCustomChanged(...) with validator $emailValidatorType', + ); + + final Email email = Email.dirty(value); + dataChanged(AuthFormField.email, email); + } + + void passwordChanged(String value) { + final passwordValidatorType = formRepository + .accessForm(formName) + .validatorOf(AuthFormField.password) + .runtimeType; + assert( + passwordValidatorType == Password, + 'Use passwordCustomChanged(...) with validator $passwordValidatorType', + ); + final Password password = Password.dirty(value); + dataChanged(AuthFormField.password, password); + } + + /// Same as [emailChanged] but with a custom [Validator]. + /// + /// Sort of short hand for [dataChanged]. + void emailCustomChanged< + Validator extends FormInputValidator>( + Validator validator, + ) { + dataChanged(AuthFormField.email, validator); + } + + /// Same as [passwordChanged] but with a custom [Validator]. + /// + /// Sort of short hand for [dataChanged]. + void passwordCustomChanged< + Validator extends FormInputValidator>( + Validator validator, + ) { + dataChanged(AuthFormField.password, validator); + } + + FutureOr signUpWithEmailPassword() async { + if (!state.status.isValidated) { + return; + } + + final form = formRepository.accessForm(formName); + emit(SignUpState(form: form, status: FormStatus.submissionInProgress)); + + final email = form.valueOf(AuthFormField.email); + final password = form.valueOf(AuthFormField.password); + + if (email.isNullOrEmpty || password.isNullOrEmpty) { + emit( + SignUpState( + form: form, + errorMessage: 'An error occured while retrieving data from the form.', + status: FormStatus.submissionFailure, + ), + ); + } + + final result = await authenticationRepository.signUp( + email: email!, + password: password!, + ); + + // Here custom code on sign up + final callbackResponse = await onSignUpWithEmailAndPassword(result, form); + if (callbackResponse.isErr) { + final error = callbackResponse.err!; + emit( + SignUpState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ); + } + + await authenticationRepository.signInWithEmailAndPassword( + email: email, + password: password, + ); + + emit( + result.fold( + (value) => SignUpState( + form: form, + status: FormStatus.submissionSuccess, + ), + (error) => SignUpState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_cubit.dart index 8d41b000..df2766ac 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_cubit.dart @@ -16,164 +16,26 @@ import 'dart:async'; +import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart'; import 'package:wyatt_authentication_bloc/src/core/constants/form_name.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart'; +import 'package:wyatt_authentication_bloc/src/features/sign_up/cubit/mixin/sign_up_with_email_password.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; +part 'base_sign_up_cubit.dart'; part 'sign_up_state.dart'; -class SignUpCubit extends FormDataCubit { - SignUpCubit({ - required this.authenticationRepository, - }) : super( - SignUpState( - form: authenticationRepository.formRepository - .accessForm(AuthFormName.signUpForm), - ), - ); - final AuthenticationRepository authenticationRepository; - FormRepository get formRepository => authenticationRepository.formRepository; +class SignUpCubit extends BaseSignUpCubit + with SignUpWithEmailPassword { + SignUpCubit({required super.authenticationRepository}); @override - String get formName => AuthFormName.signUpForm; - - void emailChanged(String value) { - final emailValidatorType = formRepository - .accessForm(formName) - .validatorOf(AuthFormField.email) - .runtimeType; - assert( - emailValidatorType == Email, - 'Use emailCustomChanged(...) with validator $emailValidatorType', - ); - - final Email email = Email.dirty(value); - dataChanged(AuthFormField.email, email); - } - - void passwordChanged(String value) { - final passwordValidatorType = formRepository - .accessForm(formName) - .validatorOf(AuthFormField.password) - .runtimeType; - assert( - passwordValidatorType == Password, - 'Use passwordCustomChanged(...) with validator $passwordValidatorType', - ); - final Password password = Password.dirty(value); - dataChanged(AuthFormField.password, password); - } - - /// Same as [emailChanged] but with a custom [Validator]. - /// - /// Sort of short hand for [dataChanged]. - void emailCustomChanged< - Validator extends FormInputValidator>( - Validator validator, - ) { - dataChanged(AuthFormField.email, validator); - } - - /// Same as [passwordChanged] but with a custom [Validator]. - /// - /// Sort of short hand for [dataChanged]. - void passwordCustomChanged< - Validator extends FormInputValidator>( - Validator validator, - ) { - dataChanged(AuthFormField.password, validator); - } - - @override - FutureOr dataChanged( - String key, - FormInputValidator dirtyValue, - ) { - final form = formRepository.accessForm(formName).clone(); - - try { - form.updateValidator(key, dirtyValue); - formRepository.updateForm(form); - } catch (e) { - rethrow; - } - - emit( - state.copyWith(form: form, status: form.validate()), - ); - } - - @override - FutureOr reset() { - final form = state.form.reset(); - formRepository.updateForm(form); - emit( - state.copyWith(form: form, status: form.validate()), - ); - } - - @override - FutureOr submit() async { - if (!state.status.isValidated) { - return; - } - - emit(state.copyWith(status: FormStatus.submissionInProgress)); - - final form = formRepository.accessForm(formName); - final email = form.valueOf(AuthFormField.email); - final password = form.valueOf(AuthFormField.password); - - if (email.isNullOrEmpty || password.isNullOrEmpty) { - emit( - state.copyWith( - errorMessage: 'An error occured while retrieving data from the form.', - status: FormStatus.submissionFailure, - ), - ); - } - - final uid = await authenticationRepository.signUp( - email: email!, - password: password!, - ); - - emit( - uid.fold( - (value) => state.copyWith(status: FormStatus.submissionSuccess), - (error) => state.copyWith( - errorMessage: error.message, - status: FormStatus.submissionFailure, - ), - ), - ); - } - - @override - FutureOr update( - WyattForm form, { - SetOperation operation = SetOperation.replace, - }) { - final WyattForm current = formRepository.accessForm(formName).clone(); - final WyattForm newForm = operation.operation.call(current, form); - formRepository.updateForm(newForm); - - emit( - state.copyWith( - form: newForm, - status: newForm.validate(), - ), - ); - } - - @override - FutureOr validate() { - emit( - state.copyWith( - status: formRepository.accessForm(formName).validate(), - ), - ); - } + FutureOrResult onSignUpWithEmailAndPassword( + Result result, + WyattForm form, + ) => + const Ok(null); } diff --git a/packages/wyatt_authentication_bloc/lib/wyatt_authentication_bloc.dart b/packages/wyatt_authentication_bloc/lib/wyatt_authentication_bloc.dart index a010cfa4..d853a49b 100644 --- a/packages/wyatt_authentication_bloc/lib/wyatt_authentication_bloc.dart +++ b/packages/wyatt_authentication_bloc/lib/wyatt_authentication_bloc.dart @@ -17,7 +17,9 @@ /// An authentication library for BLoC. library wyatt_authentication_bloc; +/// {@nodoc} export 'package:firebase_auth/firebase_auth.dart'; +/// {@nodoc} export 'package:google_sign_in/google_sign_in.dart'; export 'src/src.dart';