From 50886d97b3ee81b9422bedf0f6291fa1d99e0d2a Mon Sep 17 00:00:00 2001 From: Hugo Pointcheval Date: Mon, 6 Feb 2023 21:23:22 +0100 Subject: [PATCH] feat(authentication): add account edit cubit --- .../lib/src/core/constants/form_field.dart | 2 + .../lib/src/core/constants/form_name.dart | 2 + .../lib/src/core/utils/forms.dart | 96 +++++++++++++ ...hentication_firebase_data_source_impl.dart | 12 +- .../authentication_repository_impl.dart | 52 +++---- .../cubit/base_edit_account_cubit.dart | 100 +++++++++++++ .../cubit/edit_account_cubit.dart | 51 +++++++ .../cubit/edit_account_state.dart | 48 +++++++ .../edit_account/cubit/mixin/edit_email.dart | 131 ++++++++++++++++++ .../cubit/mixin/edit_password.dart | 130 +++++++++++++++++ .../features/edit_account/edit_account.dart | 20 +++ .../listener/edit_account_listener.dart | 69 +++++++++ .../lib/src/features/features.dart | 1 + .../sign_in/cubit/base_sign_in_cubit.dart | 2 +- 14 files changed, 678 insertions(+), 38 deletions(-) create mode 100644 packages/wyatt_authentication_bloc/lib/src/core/utils/forms.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/base_edit_account_cubit.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/edit_account_cubit.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/edit_account_state.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_email.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_password.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/features/edit_account/edit_account.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/features/edit_account/listener/edit_account_listener.dart diff --git a/packages/wyatt_authentication_bloc/lib/src/core/constants/form_field.dart b/packages/wyatt_authentication_bloc/lib/src/core/constants/form_field.dart index aa1ed36a..bbfc22e8 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/constants/form_field.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/constants/form_field.dart @@ -20,4 +20,6 @@ abstract class AuthFormField { static const email = 'wyattEmailField'; /// Password field: `wyattPasswordField` static const password = 'wyattPasswordField'; + /// Confirm Password field: `wyattConfirmPasswordField` + static const confirmPassword = 'wyattConfirmPasswordField'; } diff --git a/packages/wyatt_authentication_bloc/lib/src/core/constants/form_name.dart b/packages/wyatt_authentication_bloc/lib/src/core/constants/form_name.dart index 3eca89e0..16f58cf0 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/constants/form_name.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/constants/form_name.dart @@ -22,4 +22,6 @@ abstract class AuthFormName { static const String signInForm = 'wyattSignInForm'; /// Password reset form: `wyattPasswordResetForm` static const String passwordResetForm = 'wyattPasswordResetForm'; + /// Edit account form: `wyattEditAccountForm` + static const String editAccountForm = 'wyattEditAccountForm'; } diff --git a/packages/wyatt_authentication_bloc/lib/src/core/utils/forms.dart b/packages/wyatt_authentication_bloc/lib/src/core/utils/forms.dart new file mode 100644 index 00000000..f8f8bf17 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/core/utils/forms.dart @@ -0,0 +1,96 @@ +// Copyright (C) 2023 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 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; + +abstract class Forms { + static WyattForm buildSignInForm( + FormInputValidator? customEmailValidator, + FormInputValidator? customPasswordValidator, + ) => + WyattFormImpl( + [ + FormInput( + AuthFormField.email, + customEmailValidator ?? const Email.pure(), + ), + FormInput( + AuthFormField.password, + customPasswordValidator ?? const Password.pure(), + ) + ], + name: AuthFormName.signInForm, + ); + + static WyattForm buildSignUpForm( + FormInputValidator? customEmailValidator, + FormInputValidator? customPasswordValidator, + // ignore: strict_raw_type + List? extraSignUpInputs, + ) => + WyattFormImpl( + [ + FormInput( + AuthFormField.email, + customEmailValidator ?? const Email.pure(), + ), + FormInput( + AuthFormField.password, + customPasswordValidator ?? const Password.pure(), + ), + ...extraSignUpInputs ?? [] + ], + name: AuthFormName.signUpForm, + ); + + static WyattForm buildPasswordResetForm( + FormInputValidator? customEmailValidator, + ) => + WyattFormImpl( + [ + FormInput( + AuthFormField.email, + customEmailValidator ?? const Email.pure(), + ), + ], + name: AuthFormName.passwordResetForm, + ); + + static WyattForm buildEditAccountForm( + FormInputValidator? customEmailValidator, + FormInputValidator? customPasswordValidator, + // ignore: strict_raw_type + List? extraEditAccountInputs, + ) => + WyattFormImpl( + [ + FormInput( + AuthFormField.email, + customEmailValidator ?? const Email.pure(), + metadata: const FormInputMetadata(isRequired: false), + ), + FormInput( + AuthFormField.password, + customPasswordValidator ?? const Password.pure(), + metadata: const FormInputMetadata(isRequired: false), + ), + ...extraEditAccountInputs ?? [] + ], + validationStrategy: const OnlyRequiredInputValidator(), + name: AuthFormName.editAccountForm, + ); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart index 2d75d36a..b2c9d4f2 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart @@ -254,7 +254,11 @@ class AuthenticationFirebaseDataSourceImpl Future updateEmail({required String email}) async { try { await _firebaseAuth.currentUser!.updateEmail(email); - final account = AccountModel.fromFirebaseUser(_firebaseAuth.currentUser); + final jwt = await _firebaseAuth.currentUser!.getIdToken(true); + final account = AccountModel.fromFirebaseUser( + _firebaseAuth.currentUser, + accessToken: jwt, + ); return account; } on FirebaseAuthException catch (e) { @@ -269,7 +273,11 @@ class AuthenticationFirebaseDataSourceImpl Future updatePassword({required String password}) async { try { await _firebaseAuth.currentUser!.updatePassword(password); - final account = AccountModel.fromFirebaseUser(_firebaseAuth.currentUser); + final jwt = await _firebaseAuth.currentUser!.getIdToken(true); + final account = AccountModel.fromFirebaseUser( + _firebaseAuth.currentUser, + accessToken: jwt, + ); return account; } on FirebaseAuthException catch (e) { diff --git a/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart index 2c25e1bc..4d3a3f4e 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart @@ -15,8 +15,7 @@ // along with this program. If not, see . 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/core/utils/forms.dart'; import 'package:wyatt_authentication_bloc/src/domain/data_sources/remote/authentication_remote_data_source.dart'; import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; import 'package:wyatt_authentication_bloc/src/domain/entities/session_wrapper.dart'; @@ -31,6 +30,8 @@ class AuthenticationRepositoryImpl FormRepository? formRepository, // ignore: strict_raw_type List? extraSignUpInputs, + // ignore: strict_raw_type + List? extraEditAccountInputs, FormInputValidator? customEmailValidator, FormInputValidator? customPasswordValidator, }) { @@ -41,45 +42,26 @@ class AuthenticationRepositoryImpl } _formRepository ..registerForm( - WyattFormImpl( - [ - FormInput( - AuthFormField.email, - customEmailValidator ?? const Email.pure(), - ), - FormInput( - AuthFormField.password, - customPasswordValidator ?? const Password.pure(), - ) - ], - name: AuthFormName.signInForm, + Forms.buildSignUpForm( + customEmailValidator, + customPasswordValidator, + extraSignUpInputs, ), ) ..registerForm( - WyattFormImpl( - [ - FormInput( - AuthFormField.email, - customEmailValidator ?? const Email.pure(), - ), - FormInput( - AuthFormField.password, - customPasswordValidator ?? const Password.pure(), - ), - ...extraSignUpInputs ?? [] - ], - name: AuthFormName.signUpForm, + Forms.buildSignInForm( + customEmailValidator, + customPasswordValidator, ), ) ..registerForm( - WyattFormImpl( - [ - FormInput( - AuthFormField.email, - customEmailValidator ?? const Email.pure(), - ), - ], - name: AuthFormName.passwordResetForm, + Forms.buildPasswordResetForm(customEmailValidator), + ) + ..registerForm( + Forms.buildEditAccountForm( + customEmailValidator, + customPasswordValidator, + extraEditAccountInputs, ), ); } diff --git a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/base_edit_account_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/base_edit_account_cubit.dart new file mode 100644 index 00000000..3d6ba12d --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/base_edit_account_cubit.dart @@ -0,0 +1,100 @@ +// Copyright (C) 2023 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 'edit_account_cubit.dart'; + +/// Abstract edit account cubit useful for implementing a cubit with fine +/// granularity by adding only the required mixins. +abstract class BaseEditAccountCubit + extends FormDataCubit { + BaseEditAccountCubit({ + required this.authenticationRepository, + }) : super( + EditAccountState( + 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( + EditAccountState(form: form, status: form.validate()), + ); + } + + @override + FutureOr reset() { + final form = state.form.reset(); + formRepository.updateForm(form); + emit( + EditAccountState(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( + EditAccountState(form: newForm, status: newForm.validate()), + ); + } + + @override + FutureOr validate() { + final WyattForm form = formRepository.accessForm(formName); + emit( + EditAccountState(form: form, status: form.validate()), + ); + } + + @override + FutureOr submit() async { + final WyattForm form = formRepository.accessForm(formName); + const error = '`submit()` is not implemented for BaseEditAccountCubit, ' + 'please use `updateEmail()` or `updatePassword()`.'; + emit( + EditAccountState( + form: form, + errorMessage: error, + status: FormStatus.submissionFailure, + ), + ); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/edit_account_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/edit_account_cubit.dart new file mode 100644 index 00000000..b3fcc2b2 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/edit_account_cubit.dart @@ -0,0 +1,51 @@ +// Copyright (C) 2023 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/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/edit_account/edit_account.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +part 'base_edit_account_cubit.dart'; +part 'edit_account_state.dart'; + +/// Fully featured edit account cubit. +/// +/// Sufficient in most cases. (Where fine granularity is not required.) +class EditAccountCubit extends BaseEditAccountCubit + with UpdateEmail, UpdatePassword { + EditAccountCubit({required super.authenticationRepository}); + + @override + FutureOrResult onEmailUpdated( + Result result, + WyattForm form, + ) => + const Ok(null); + + @override + FutureOrResult onPasswordUpdated( + Result result, + WyattForm form, + ) => + const Ok(null); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/edit_account_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/edit_account_state.dart new file mode 100644 index 00000000..0c8fbfba --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/edit_account_state.dart @@ -0,0 +1,48 @@ +// Copyright (C) 2023 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 'edit_account_cubit.dart'; + +/// Edit account cubit state to manage the form. +class EditAccountState extends FormDataState { + const EditAccountState({ + required super.form, + super.status = FormStatus.pure, + super.errorMessage, + }); + FormInputValidator get email => + form.validatorOf(AuthFormField.email); + FormInputValidator get password => + form.validatorOf(AuthFormField.password); + + EditAccountState copyWith({ + WyattForm? form, + FormStatus? status, + String? errorMessage, + }) => + EditAccountState( + form: form ?? this.form, + status: status ?? this.status, + errorMessage: errorMessage ?? this.errorMessage, + ); + + @override + List get props => [email, password, status]; + + @override + String toString() => 'EditAccountState(status: ${status.name} ' + '${(errorMessage != null) ? " [$errorMessage]" : ""}, $form)'; +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_email.dart b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_email.dart new file mode 100644 index 00000000..47aecb30 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_email.dart @@ -0,0 +1,131 @@ +// Copyright (C) 2023 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/core/utils/custom_routine.dart'; +import 'package:wyatt_authentication_bloc/src/domain/domain.dart'; +import 'package:wyatt_authentication_bloc/src/features/edit_account/cubit/edit_account_cubit.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +/// Edit account mixin. +/// +/// Allows the user to edit his email +/// +/// Gives access to the `updateEmail` method and +/// `onEmailUpdated` callback. +mixin UpdateEmail on BaseEditAccountCubit { + /// This callback is triggered when user updates his email + FutureOrResult onEmailUpdated( + 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); + } + + /// 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); + } + + /// {@macro update_email} + FutureOr updateEmail() async { + if (state.status.isSubmissionInProgress) { + return; + } + + if (!state.status.isValidated) { + return; + } + + final form = formRepository.accessForm(formName); + emit( + EditAccountState( + form: form, + status: FormStatus.submissionInProgress, + ), + ); + + final email = form.valueOf(AuthFormField.email); + + if (email.isNullOrEmpty) { + emit( + EditAccountState( + form: form, + errorMessage: 'An error occured while retrieving data from the form.', + status: FormStatus.submissionFailure, + ), + ); + } + + return CustomRoutine( + routine: () => authenticationRepository.updateEmail( + email: email!, + ), + attachedLogic: (routineResult) => onEmailUpdated( + routineResult, + form, + ), + onError: (error) { + emit( + EditAccountState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ); + addError(error); + }, + onSuccess: (account, data) { + authenticationRepository.addSession( + SessionWrapper( + event: UpdatedEvent(account: account), + session: Session( + account: account, + data: data, + ), + ), + ); + emit( + EditAccountState( + form: form, + status: FormStatus.submissionSuccess, + ), + ); + }, + ).call(); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_password.dart b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_password.dart new file mode 100644 index 00000000..3b270800 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_password.dart @@ -0,0 +1,130 @@ +// Copyright (C) 2023 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/core/utils/custom_routine.dart'; +import 'package:wyatt_authentication_bloc/src/domain/domain.dart'; +import 'package:wyatt_authentication_bloc/src/features/edit_account/cubit/edit_account_cubit.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +/// Edit account mixin. +/// +/// Allows the user to edit his password +/// +/// Gives access to the `updatePassword` method and +/// `onPasswordUpdated` callback. +mixin UpdatePassword on BaseEditAccountCubit { + /// This callback is triggered when a user edits his password. + FutureOrResult onPasswordUpdated( + Result result, + WyattForm form, + ); + + 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 [passwordChanged] but with a custom [Validator]. + /// + /// Sort of short hand for [dataChanged]. + void passwordCustomChanged< + Validator extends FormInputValidator>( + Validator validator, + ) { + dataChanged(AuthFormField.password, validator); + } + + /// {@macro update_password} + FutureOr updatePassword() async { + if (state.status.isSubmissionInProgress) { + return; + } + + if (!state.status.isValidated) { + return; + } + + final form = formRepository.accessForm(formName); + emit( + EditAccountState( + form: form, + status: FormStatus.submissionInProgress, + ), + ); + + final password = form.valueOf(AuthFormField.password); + + if (password.isNullOrEmpty) { + emit( + EditAccountState( + form: form, + errorMessage: 'An error occured while retrieving data from the form.', + status: FormStatus.submissionFailure, + ), + ); + } + + return CustomRoutine( + routine: () => authenticationRepository.updatePassword( + password: password!, + ), + attachedLogic: (routineResult) => onPasswordUpdated( + routineResult, + form, + ), + onError: (error) { + emit( + EditAccountState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ); + addError(error); + }, + onSuccess: (account, data) { + authenticationRepository.addSession( + SessionWrapper( + event: SignedInEvent(account: account), + session: Session( + account: account, + data: data, + ), + ), + ); + emit( + EditAccountState( + form: form, + status: FormStatus.submissionSuccess, + ), + ); + }, + ).call(); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/edit_account.dart b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/edit_account.dart new file mode 100644 index 00000000..1040179f --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/edit_account.dart @@ -0,0 +1,20 @@ +// Copyright (C) 2023 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 . + +export 'cubit/edit_account_cubit.dart'; +export 'cubit/mixin/edit_email.dart'; +export 'cubit/mixin/edit_password.dart'; +export 'listener/edit_account_listener.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/listener/edit_account_listener.dart b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/listener/edit_account_listener.dart new file mode 100644 index 00000000..62134eb5 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/listener/edit_account_listener.dart @@ -0,0 +1,69 @@ +// Copyright (C) 2023 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 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wyatt_authentication_bloc/src/features/edit_account/cubit/edit_account_cubit.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; + +/// Widget that listens and builds a child based on the state of +/// the edit account cubit +class EditAccountListener extends StatelessWidget { + const EditAccountListener({ + required this.child, + this.onProgress, + this.onSuccess, + this.onError, + this.customBuilder, + super.key, + }); + + final void Function(BuildContext context)? onProgress; + final void Function(BuildContext context)? onSuccess; + final void Function( + BuildContext context, + FormStatus status, + String? errorMessage, + )? onError; + final void Function(BuildContext context, EditAccountState state)? + customBuilder; + final Widget child; + + @override + Widget build(BuildContext context) => + BlocListener, EditAccountState>( + listener: (context, state) { + if (customBuilder != null) { + return customBuilder!(context, state); + } + + if (onSuccess != null && + state.status == FormStatus.submissionSuccess) { + return onSuccess!(context); + } + if (onProgress != null && + state.status == FormStatus.submissionInProgress) { + return onProgress!(context); + } + if (onError != null && + (state.status == FormStatus.submissionCanceled || + state.status == FormStatus.submissionFailure)) { + return onError!(context, state.status, state.errorMessage); + } + }, + child: child, + ); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/features/features.dart b/packages/wyatt_authentication_bloc/lib/src/features/features.dart index 435d4d30..cbdaf015 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/features.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/features.dart @@ -15,6 +15,7 @@ // along with this program. If not, see . export 'authentication/authentication.dart'; +export 'edit_account/edit_account.dart'; export 'email_verification/email_verification.dart'; export 'password_reset/password_reset.dart'; export 'sign_in/sign_in.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 index 636a2786..bc55b6a8 100644 --- 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 @@ -86,7 +86,7 @@ abstract class BaseSignInCubit extends FormDataCubit { @override FutureOr submit() async { final WyattForm form = formRepository.accessForm(formName); - const error = '`submit()` is not implemented for BaseSignUpCubit, ' + const error = '`submit()` is not implemented for BaseSignInCubit, ' 'please use `signUpWithEmailAndPassword()`.'; emit( SignInState(