6177214e-ce7c-49e3-99de-ff9721b26f63 — Commit c3d4023c

AuthorMikkel Thygesen<mikkelet@gmail.com>
Date2026-02-20 01:22:22 +0100
3672: moved profile settings

Changed files

.../.generated/domain/models/address.freezed.dart  | 280 ++++++++++++++++
 .../lib/.generated/domain/models/user.freezed.dart | 358 +++++++++++++++++++++
 .../presentation/app/app_state.freezed.dart        | 277 ----------------
 .../presentation/app/bloc/app_cubit.freezed.dart   | 277 ++++++++++++++++
 .../app/bloc/profile_cubit.freezed.dart            | 301 +++++++++++++++++
 .../bloc/profile_settings_state.freezed.dart       | 277 ++++++++++++++++
 .../profile_settings/profile_settings_route.g.dart |  35 ++
 .../lib/check_in/check_in_repository.dart          |   2 +-
 .../lib/check_out/bloc/check_out_cubit.dart        |   2 +-
 comwell_key_app/lib/comwell_app.dart               |  14 +-
 .../components/get_a_phone_call_section.dart       |   2 +-
 .../lib/contact/cubit/contact_cubit.dart           |   4 +-
 comwell_key_app/lib/database/daos/user_dao.dart    |   2 +-
 comwell_key_app/lib/domain/models/address.dart     |  13 +
 comwell_key_app/lib/domain/models/user.dart        |  35 ++
 .../domain/repositories/profile_repository.dart    |  88 +++++
 .../repositories/profile_settings_repository.dart  |  31 ++
 .../lib/my_booking/cubit/my_booking_cubit.dart     |   2 +-
 .../lib/my_booking/my_booking_repository.dart      |   4 +-
 .../pregistration/cubit/preregistration_cubit.dart |   8 +-
 .../pregistration/cubit/preregistration_state.dart |   3 +-
 .../pregistration/pages/prereg_profile_page.dart   |   2 +-
 .../pregistration/pregistration_repository.dart    |   2 +-
 .../lib/presentation/app/app_cubit.dart            |  33 --
 .../lib/presentation/app/app_event_listener.dart   |   3 +-
 .../lib/presentation/app/app_state.dart            |  14 -
 .../lib/presentation/app/bloc/app_cubit.dart       |  45 +++
 .../lib/presentation/app/bloc/profile_cubit.dart   | 120 +++++++
 .../bloc/booking_details_cubit.dart                |   4 +-
 .../screens/login/bloc/login_cubit.dart            |   2 +-
 .../bloc/profile_settings_cubit.dart               | 116 +++++++
 .../bloc/profile_settings_state.dart               |  17 +
 .../components/address_bottom_sheet.dart           | 186 +++++++++++
 .../components/comwell_text_field.dart             |  74 +++++
 .../components/date_time_picker.dart               | 147 +++++++++
 .../components/delete_profile_dialog_widget.dart   |  89 +++++
 .../components/intl_phone_field.dart               | 154 +++++++++
 .../components/text_field_with_trailing_icon.dart  |  63 ++++
 .../profile_settings/profile_settings_route.dart   |  31 ++
 .../profile_settings/profile_settings_screen.dart  | 212 ++++++++++++
 .../profile/components/card_content_widget.dart    |   2 +-
 .../profile/components/comwell_club_container.dart |   4 +-
 .../comwell_club_signup_bottom_sheet.dart          |  96 +++---
 .../lib/profile/components/error_page_widget.dart  |   2 +-
 .../profile/components/logout_dialog_widget.dart   |   2 +-
 .../profile/components/profile_page_widget.dart    |   2 +-
 .../lib/profile/cubit/profile_cubit.dart           | 120 -------
 .../lib/profile/cubit/profile_state.dart           |  37 ---
 comwell_key_app/lib/profile/profile_page.dart      |   4 +-
 .../lib/profile/profile_repository.dart            |  89 -----
 .../components/address_bottom_sheet.dart           | 173 ----------
 .../components/comwell_text_field.dart             |  74 -----
 .../components/date_time_picker.dart               | 147 ---------
 .../components/delete_profile_dialog_widget.dart   |  89 -----
 .../components/intl_phone_field.dart               | 154 ---------
 .../components/text_field_with_trailing_icon.dart  |  63 ----
 .../cubit/profile_settings_cubit.dart              | 122 -------
 .../cubit/profile_settings_state.dart              |  43 ---
 .../lib/profile_settings/model/address.dart        |  18 --
 .../lib/profile_settings/model/user.dart           | 118 -------
 .../profile_settings/profile_settings_page.dart    | 217 -------------
 .../profile_settings/profile_settings_route.dart   |  10 -
 .../repostiory/profile_settings_repository.dart    |  35 --
 comwell_key_app/lib/routing/app_router.dart        |   4 +-
 .../lib/services/mappers/user_mapper.dart          |  34 +-
 comwell_key_app/lib/utils/address_utils.dart       |   2 +-
 comwell_key_app/lib/utils/locator.dart             |   4 +-
 .../profile_settings_cubit_test.dart               |  95 ++++--
 68 files changed, 3105 insertions(+), 1984 deletions(-)

Diff

diff --git a/comwell_key_app/lib/.generated/domain/models/address.freezed.dart b/comwell_key_app/lib/.generated/domain/models/address.freezed.dart
new file mode 100644
index 00000000..8781dc7d
--- /dev/null
+++ b/comwell_key_app/lib/.generated/domain/models/address.freezed.dart
@@ -0,0 +1,280 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// coverage:ignore-file
+// ignore_for_file: type=lint
+// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
+
+part of '../../../domain/models/address.dart';
+
+// **************************************************************************
+// FreezedGenerator
+// **************************************************************************
+
+// dart format off
+T _$identity<T>(T value) => value;
+/// @nodoc
+mixin _$Address {
+
+ String get street; String get city; String get country; String get zipCode;
+/// Create a copy of Address
+/// with the given fields replaced by the non-null parameter values.
+@JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+$AddressCopyWith<Address> get copyWith => _$AddressCopyWithImpl<Address>(this as Address, _$identity);
+
+
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is Address&&(identical(other.street, street) || other.street == street)&&(identical(other.city, city) || other.city == city)&&(identical(other.country, country) || other.country == country)&&(identical(other.zipCode, zipCode) || other.zipCode == zipCode));
+}
+
+
+@override
+int get hashCode => Object.hash(runtimeType,street,city,country,zipCode);
+
+@override
+String toString() {
+ return 'Address(street: $street, city: $city, country: $country, zipCode: $zipCode)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class $AddressCopyWith<$Res> {
+ factory $AddressCopyWith(Address value, $Res Function(Address) _then) = _$AddressCopyWithImpl;
+@useResult
+$Res call({
+ String street, String city, String country, String zipCode
+});
+
+
+
+
+}
+/// @nodoc
+class _$AddressCopyWithImpl<$Res>
+ implements $AddressCopyWith<$Res> {
+ _$AddressCopyWithImpl(this._self, this._then);
+
+ final Address _self;
+ final $Res Function(Address) _then;
+
+/// Create a copy of Address
+/// with the given fields replaced by the non-null parameter values.
+@pragma('vm:prefer-inline') @override $Res call({Object? street = null,Object? city = null,Object? country = null,Object? zipCode = null,}) {
+ return _then(_self.copyWith(
+street: null == street ? _self.street : street // ignore: cast_nullable_to_non_nullable
+as String,city: null == city ? _self.city : city // ignore: cast_nullable_to_non_nullable
+as String,country: null == country ? _self.country : country // ignore: cast_nullable_to_non_nullable
+as String,zipCode: null == zipCode ? _self.zipCode : zipCode // ignore: cast_nullable_to_non_nullable
+as String,
+ ));
+}
+
+}
+
+
+/// Adds pattern-matching-related methods to [Address].
+extension AddressPatterns on Address {
+/// A variant of `map` that fallback to returning `orElse`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _Address value)? $default,{required TResult orElse(),}){
+final _that = this;
+switch (_that) {
+case _Address() when $default != null:
+return $default(_that);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// Callbacks receives the raw object, upcasted.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case final Subclass2 value:
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _Address value) $default,){
+final _that = this;
+switch (_that) {
+case _Address():
+return $default(_that);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `map` that fallback to returning `null`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _Address value)? $default,){
+final _that = this;
+switch (_that) {
+case _Address() when $default != null:
+return $default(_that);case _:
+ return null;
+
+}
+}
+/// A variant of `when` that fallback to an `orElse` callback.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String street, String city, String country, String zipCode)? $default,{required TResult orElse(),}) {final _that = this;
+switch (_that) {
+case _Address() when $default != null:
+return $default(_that.street,_that.city,_that.country,_that.zipCode);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// As opposed to `map`, this offers destructuring.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case Subclass2(:final field2):
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String street, String city, String country, String zipCode) $default,) {final _that = this;
+switch (_that) {
+case _Address():
+return $default(_that.street,_that.city,_that.country,_that.zipCode);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `when` that fallback to returning `null`
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String street, String city, String country, String zipCode)? $default,) {final _that = this;
+switch (_that) {
+case _Address() when $default != null:
+return $default(_that.street,_that.city,_that.country,_that.zipCode);case _:
+ return null;
+
+}
+}
+
+}
+
+/// @nodoc
+
+
+class _Address implements Address {
+ const _Address({this.street = "", this.city = "", this.country = "", this.zipCode = ""});
+
+
+@override@JsonKey() final String street;
+@override@JsonKey() final String city;
+@override@JsonKey() final String country;
+@override@JsonKey() final String zipCode;
+
+/// Create a copy of Address
+/// with the given fields replaced by the non-null parameter values.
+@override @JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+_$AddressCopyWith<_Address> get copyWith => __$AddressCopyWithImpl<_Address>(this, _$identity);
+
+
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is _Address&&(identical(other.street, street) || other.street == street)&&(identical(other.city, city) || other.city == city)&&(identical(other.country, country) || other.country == country)&&(identical(other.zipCode, zipCode) || other.zipCode == zipCode));
+}
+
+
+@override
+int get hashCode => Object.hash(runtimeType,street,city,country,zipCode);
+
+@override
+String toString() {
+ return 'Address(street: $street, city: $city, country: $country, zipCode: $zipCode)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class _$AddressCopyWith<$Res> implements $AddressCopyWith<$Res> {
+ factory _$AddressCopyWith(_Address value, $Res Function(_Address) _then) = __$AddressCopyWithImpl;
+@override @useResult
+$Res call({
+ String street, String city, String country, String zipCode
+});
+
+
+
+
+}
+/// @nodoc
+class __$AddressCopyWithImpl<$Res>
+ implements _$AddressCopyWith<$Res> {
+ __$AddressCopyWithImpl(this._self, this._then);
+
+ final _Address _self;
+ final $Res Function(_Address) _then;
+
+/// Create a copy of Address
+/// with the given fields replaced by the non-null parameter values.
+@override @pragma('vm:prefer-inline') $Res call({Object? street = null,Object? city = null,Object? country = null,Object? zipCode = null,}) {
+ return _then(_Address(
+street: null == street ? _self.street : street // ignore: cast_nullable_to_non_nullable
+as String,city: null == city ? _self.city : city // ignore: cast_nullable_to_non_nullable
+as String,country: null == country ? _self.country : country // ignore: cast_nullable_to_non_nullable
+as String,zipCode: null == zipCode ? _self.zipCode : zipCode // ignore: cast_nullable_to_non_nullable
+as String,
+ ));
+}
+
+
+}
+
+// dart format on
diff --git a/comwell_key_app/lib/.generated/domain/models/user.freezed.dart b/comwell_key_app/lib/.generated/domain/models/user.freezed.dart
new file mode 100644
index 00000000..123b2609
--- /dev/null
+++ b/comwell_key_app/lib/.generated/domain/models/user.freezed.dart
@@ -0,0 +1,358 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// coverage:ignore-file
+// ignore_for_file: type=lint
+// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
+
+part of '../../../domain/models/user.dart';
+
+// **************************************************************************
+// FreezedGenerator
+// **************************************************************************
+
+// dart format off
+T _$identity<T>(T value) => value;
+/// @nodoc
+mixin _$User {
+
+ String get userId; String get hmsId; String get firstName; String get lastName; String get addressCountry; String get phoneNumber; String get email; String get shopperReference; String get gender; String get companyId; String get companyName; String get symplifyId; String get signUpCampaign; String get signUpSource; String get locale; String get nationality; bool get emailVerified; bool get isClubMember; bool get wasRecentlyCreated; Address get address; int get points; DateTime? get birthDate; DateTime? get createDate; DateTime? get signUpDate;
+/// Create a copy of User
+/// with the given fields replaced by the non-null parameter values.
+@JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+$UserCopyWith<User> get copyWith => _$UserCopyWithImpl<User>(this as User, _$identity);
+
+
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is User&&(identical(other.userId, userId) || other.userId == userId)&&(identical(other.hmsId, hmsId) || other.hmsId == hmsId)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.addressCountry, addressCountry) || other.addressCountry == addressCountry)&&(identical(other.phoneNumber, phoneNumber) || other.phoneNumber == phoneNumber)&&(identical(other.email, email) || other.email == email)&&(identical(other.shopperReference, shopperReference) || other.shopperReference == shopperReference)&&(identical(other.gender, gender) || other.gender == gender)&&(identical(other.companyId, companyId) || other.companyId == companyId)&&(identical(other.companyName, companyName) || other.companyName == companyName)&&(identical(other.symplifyId, symplifyId) || other.symplifyId == symplifyId)&&(identical(other.signUpCampaign, signUpCampaign) || other.signUpCampaign == signUpCampaign)&&(identical(other.signUpSource, signUpSource) || other.signUpSource == signUpSource)&&(identical(other.locale, locale) || other.locale == locale)&&(identical(other.nationality, nationality) || other.nationality == nationality)&&(identical(other.emailVerified, emailVerified) || other.emailVerified == emailVerified)&&(identical(other.isClubMember, isClubMember) || other.isClubMember == isClubMember)&&(identical(other.wasRecentlyCreated, wasRecentlyCreated) || other.wasRecentlyCreated == wasRecentlyCreated)&&(identical(other.address, address) || other.address == address)&&(identical(other.points, points) || other.points == points)&&(identical(other.birthDate, birthDate) || other.birthDate == birthDate)&&(identical(other.createDate, createDate) || other.createDate == createDate)&&(identical(other.signUpDate, signUpDate) || other.signUpDate == signUpDate));
+}
+
+
+@override
+int get hashCode => Object.hashAll([runtimeType,userId,hmsId,firstName,lastName,addressCountry,phoneNumber,email,shopperReference,gender,companyId,companyName,symplifyId,signUpCampaign,signUpSource,locale,nationality,emailVerified,isClubMember,wasRecentlyCreated,address,points,birthDate,createDate,signUpDate]);
+
+@override
+String toString() {
+ return 'User(userId: $userId, hmsId: $hmsId, firstName: $firstName, lastName: $lastName, addressCountry: $addressCountry, phoneNumber: $phoneNumber, email: $email, shopperReference: $shopperReference, gender: $gender, companyId: $companyId, companyName: $companyName, symplifyId: $symplifyId, signUpCampaign: $signUpCampaign, signUpSource: $signUpSource, locale: $locale, nationality: $nationality, emailVerified: $emailVerified, isClubMember: $isClubMember, wasRecentlyCreated: $wasRecentlyCreated, address: $address, points: $points, birthDate: $birthDate, createDate: $createDate, signUpDate: $signUpDate)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class $UserCopyWith<$Res> {
+ factory $UserCopyWith(User value, $Res Function(User) _then) = _$UserCopyWithImpl;
+@useResult
+$Res call({
+ String userId, String hmsId, String firstName, String lastName, String addressCountry, String phoneNumber, String email, String shopperReference, String gender, String companyId, String companyName, String symplifyId, String signUpCampaign, String signUpSource, String locale, String nationality, bool emailVerified, bool isClubMember, bool wasRecentlyCreated, Address address, int points, DateTime? birthDate, DateTime? createDate, DateTime? signUpDate
+});
+
+
+$AddressCopyWith<$Res> get address;
+
+}
+/// @nodoc
+class _$UserCopyWithImpl<$Res>
+ implements $UserCopyWith<$Res> {
+ _$UserCopyWithImpl(this._self, this._then);
+
+ final User _self;
+ final $Res Function(User) _then;
+
+/// Create a copy of User
+/// with the given fields replaced by the non-null parameter values.
+@pragma('vm:prefer-inline') @override $Res call({Object? userId = null,Object? hmsId = null,Object? firstName = null,Object? lastName = null,Object? addressCountry = null,Object? phoneNumber = null,Object? email = null,Object? shopperReference = null,Object? gender = null,Object? companyId = null,Object? companyName = null,Object? symplifyId = null,Object? signUpCampaign = null,Object? signUpSource = null,Object? locale = null,Object? nationality = null,Object? emailVerified = null,Object? isClubMember = null,Object? wasRecentlyCreated = null,Object? address = null,Object? points = null,Object? birthDate = freezed,Object? createDate = freezed,Object? signUpDate = freezed,}) {
+ return _then(_self.copyWith(
+userId: null == userId ? _self.userId : userId // ignore: cast_nullable_to_non_nullable
+as String,hmsId: null == hmsId ? _self.hmsId : hmsId // ignore: cast_nullable_to_non_nullable
+as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable
+as String,lastName: null == lastName ? _self.lastName : lastName // ignore: cast_nullable_to_non_nullable
+as String,addressCountry: null == addressCountry ? _self.addressCountry : addressCountry // ignore: cast_nullable_to_non_nullable
+as String,phoneNumber: null == phoneNumber ? _self.phoneNumber : phoneNumber // ignore: cast_nullable_to_non_nullable
+as String,email: null == email ? _self.email : email // ignore: cast_nullable_to_non_nullable
+as String,shopperReference: null == shopperReference ? _self.shopperReference : shopperReference // ignore: cast_nullable_to_non_nullable
+as String,gender: null == gender ? _self.gender : gender // ignore: cast_nullable_to_non_nullable
+as String,companyId: null == companyId ? _self.companyId : companyId // ignore: cast_nullable_to_non_nullable
+as String,companyName: null == companyName ? _self.companyName : companyName // ignore: cast_nullable_to_non_nullable
+as String,symplifyId: null == symplifyId ? _self.symplifyId : symplifyId // ignore: cast_nullable_to_non_nullable
+as String,signUpCampaign: null == signUpCampaign ? _self.signUpCampaign : signUpCampaign // ignore: cast_nullable_to_non_nullable
+as String,signUpSource: null == signUpSource ? _self.signUpSource : signUpSource // ignore: cast_nullable_to_non_nullable
+as String,locale: null == locale ? _self.locale : locale // ignore: cast_nullable_to_non_nullable
+as String,nationality: null == nationality ? _self.nationality : nationality // ignore: cast_nullable_to_non_nullable
+as String,emailVerified: null == emailVerified ? _self.emailVerified : emailVerified // ignore: cast_nullable_to_non_nullable
+as bool,isClubMember: null == isClubMember ? _self.isClubMember : isClubMember // ignore: cast_nullable_to_non_nullable
+as bool,wasRecentlyCreated: null == wasRecentlyCreated ? _self.wasRecentlyCreated : wasRecentlyCreated // ignore: cast_nullable_to_non_nullable
+as bool,address: null == address ? _self.address : address // ignore: cast_nullable_to_non_nullable
+as Address,points: null == points ? _self.points : points // ignore: cast_nullable_to_non_nullable
+as int,birthDate: freezed == birthDate ? _self.birthDate : birthDate // ignore: cast_nullable_to_non_nullable
+as DateTime?,createDate: freezed == createDate ? _self.createDate : createDate // ignore: cast_nullable_to_non_nullable
+as DateTime?,signUpDate: freezed == signUpDate ? _self.signUpDate : signUpDate // ignore: cast_nullable_to_non_nullable
+as DateTime?,
+ ));
+}
+/// Create a copy of User
+/// with the given fields replaced by the non-null parameter values.
+@override
+@pragma('vm:prefer-inline')
+$AddressCopyWith<$Res> get address {
+
+ return $AddressCopyWith<$Res>(_self.address, (value) {
+ return _then(_self.copyWith(address: value));
+ });
+}
+}
+
+
+/// Adds pattern-matching-related methods to [User].
+extension UserPatterns on User {
+/// A variant of `map` that fallback to returning `orElse`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _User value)? $default,{required TResult orElse(),}){
+final _that = this;
+switch (_that) {
+case _User() when $default != null:
+return $default(_that);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// Callbacks receives the raw object, upcasted.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case final Subclass2 value:
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _User value) $default,){
+final _that = this;
+switch (_that) {
+case _User():
+return $default(_that);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `map` that fallback to returning `null`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _User value)? $default,){
+final _that = this;
+switch (_that) {
+case _User() when $default != null:
+return $default(_that);case _:
+ return null;
+
+}
+}
+/// A variant of `when` that fallback to an `orElse` callback.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String userId, String hmsId, String firstName, String lastName, String addressCountry, String phoneNumber, String email, String shopperReference, String gender, String companyId, String companyName, String symplifyId, String signUpCampaign, String signUpSource, String locale, String nationality, bool emailVerified, bool isClubMember, bool wasRecentlyCreated, Address address, int points, DateTime? birthDate, DateTime? createDate, DateTime? signUpDate)? $default,{required TResult orElse(),}) {final _that = this;
+switch (_that) {
+case _User() when $default != null:
+return $default(_that.userId,_that.hmsId,_that.firstName,_that.lastName,_that.addressCountry,_that.phoneNumber,_that.email,_that.shopperReference,_that.gender,_that.companyId,_that.companyName,_that.symplifyId,_that.signUpCampaign,_that.signUpSource,_that.locale,_that.nationality,_that.emailVerified,_that.isClubMember,_that.wasRecentlyCreated,_that.address,_that.points,_that.birthDate,_that.createDate,_that.signUpDate);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// As opposed to `map`, this offers destructuring.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case Subclass2(:final field2):
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String userId, String hmsId, String firstName, String lastName, String addressCountry, String phoneNumber, String email, String shopperReference, String gender, String companyId, String companyName, String symplifyId, String signUpCampaign, String signUpSource, String locale, String nationality, bool emailVerified, bool isClubMember, bool wasRecentlyCreated, Address address, int points, DateTime? birthDate, DateTime? createDate, DateTime? signUpDate) $default,) {final _that = this;
+switch (_that) {
+case _User():
+return $default(_that.userId,_that.hmsId,_that.firstName,_that.lastName,_that.addressCountry,_that.phoneNumber,_that.email,_that.shopperReference,_that.gender,_that.companyId,_that.companyName,_that.symplifyId,_that.signUpCampaign,_that.signUpSource,_that.locale,_that.nationality,_that.emailVerified,_that.isClubMember,_that.wasRecentlyCreated,_that.address,_that.points,_that.birthDate,_that.createDate,_that.signUpDate);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `when` that fallback to returning `null`
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String userId, String hmsId, String firstName, String lastName, String addressCountry, String phoneNumber, String email, String shopperReference, String gender, String companyId, String companyName, String symplifyId, String signUpCampaign, String signUpSource, String locale, String nationality, bool emailVerified, bool isClubMember, bool wasRecentlyCreated, Address address, int points, DateTime? birthDate, DateTime? createDate, DateTime? signUpDate)? $default,) {final _that = this;
+switch (_that) {
+case _User() when $default != null:
+return $default(_that.userId,_that.hmsId,_that.firstName,_that.lastName,_that.addressCountry,_that.phoneNumber,_that.email,_that.shopperReference,_that.gender,_that.companyId,_that.companyName,_that.symplifyId,_that.signUpCampaign,_that.signUpSource,_that.locale,_that.nationality,_that.emailVerified,_that.isClubMember,_that.wasRecentlyCreated,_that.address,_that.points,_that.birthDate,_that.createDate,_that.signUpDate);case _:
+ return null;
+
+}
+}
+
+}
+
+/// @nodoc
+
+
+class _User implements User {
+ const _User({this.userId = "", this.hmsId = "", this.firstName = "", this.lastName = "", this.addressCountry = "", this.phoneNumber = "", this.email = "", this.shopperReference = "", this.gender = "", this.companyId = "", this.companyName = "", this.symplifyId = "", this.signUpCampaign = "", this.signUpSource = "", this.locale = "", this.nationality = "", this.emailVerified = false, this.isClubMember = false, this.wasRecentlyCreated = false, this.address = const Address(), this.points = 0, this.birthDate, this.createDate, this.signUpDate});
+
+
+@override@JsonKey() final String userId;
+@override@JsonKey() final String hmsId;
+@override@JsonKey() final String firstName;
+@override@JsonKey() final String lastName;
+@override@JsonKey() final String addressCountry;
+@override@JsonKey() final String phoneNumber;
+@override@JsonKey() final String email;
+@override@JsonKey() final String shopperReference;
+@override@JsonKey() final String gender;
+@override@JsonKey() final String companyId;
+@override@JsonKey() final String companyName;
+@override@JsonKey() final String symplifyId;
+@override@JsonKey() final String signUpCampaign;
+@override@JsonKey() final String signUpSource;
+@override@JsonKey() final String locale;
+@override@JsonKey() final String nationality;
+@override@JsonKey() final bool emailVerified;
+@override@JsonKey() final bool isClubMember;
+@override@JsonKey() final bool wasRecentlyCreated;
+@override@JsonKey() final Address address;
+@override@JsonKey() final int points;
+@override final DateTime? birthDate;
+@override final DateTime? createDate;
+@override final DateTime? signUpDate;
+
+/// Create a copy of User
+/// with the given fields replaced by the non-null parameter values.
+@override @JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+_$UserCopyWith<_User> get copyWith => __$UserCopyWithImpl<_User>(this, _$identity);
+
+
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is _User&&(identical(other.userId, userId) || other.userId == userId)&&(identical(other.hmsId, hmsId) || other.hmsId == hmsId)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.addressCountry, addressCountry) || other.addressCountry == addressCountry)&&(identical(other.phoneNumber, phoneNumber) || other.phoneNumber == phoneNumber)&&(identical(other.email, email) || other.email == email)&&(identical(other.shopperReference, shopperReference) || other.shopperReference == shopperReference)&&(identical(other.gender, gender) || other.gender == gender)&&(identical(other.companyId, companyId) || other.companyId == companyId)&&(identical(other.companyName, companyName) || other.companyName == companyName)&&(identical(other.symplifyId, symplifyId) || other.symplifyId == symplifyId)&&(identical(other.signUpCampaign, signUpCampaign) || other.signUpCampaign == signUpCampaign)&&(identical(other.signUpSource, signUpSource) || other.signUpSource == signUpSource)&&(identical(other.locale, locale) || other.locale == locale)&&(identical(other.nationality, nationality) || other.nationality == nationality)&&(identical(other.emailVerified, emailVerified) || other.emailVerified == emailVerified)&&(identical(other.isClubMember, isClubMember) || other.isClubMember == isClubMember)&&(identical(other.wasRecentlyCreated, wasRecentlyCreated) || other.wasRecentlyCreated == wasRecentlyCreated)&&(identical(other.address, address) || other.address == address)&&(identical(other.points, points) || other.points == points)&&(identical(other.birthDate, birthDate) || other.birthDate == birthDate)&&(identical(other.createDate, createDate) || other.createDate == createDate)&&(identical(other.signUpDate, signUpDate) || other.signUpDate == signUpDate));
+}
+
+
+@override
+int get hashCode => Object.hashAll([runtimeType,userId,hmsId,firstName,lastName,addressCountry,phoneNumber,email,shopperReference,gender,companyId,companyName,symplifyId,signUpCampaign,signUpSource,locale,nationality,emailVerified,isClubMember,wasRecentlyCreated,address,points,birthDate,createDate,signUpDate]);
+
+@override
+String toString() {
+ return 'User(userId: $userId, hmsId: $hmsId, firstName: $firstName, lastName: $lastName, addressCountry: $addressCountry, phoneNumber: $phoneNumber, email: $email, shopperReference: $shopperReference, gender: $gender, companyId: $companyId, companyName: $companyName, symplifyId: $symplifyId, signUpCampaign: $signUpCampaign, signUpSource: $signUpSource, locale: $locale, nationality: $nationality, emailVerified: $emailVerified, isClubMember: $isClubMember, wasRecentlyCreated: $wasRecentlyCreated, address: $address, points: $points, birthDate: $birthDate, createDate: $createDate, signUpDate: $signUpDate)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class _$UserCopyWith<$Res> implements $UserCopyWith<$Res> {
+ factory _$UserCopyWith(_User value, $Res Function(_User) _then) = __$UserCopyWithImpl;
+@override @useResult
+$Res call({
+ String userId, String hmsId, String firstName, String lastName, String addressCountry, String phoneNumber, String email, String shopperReference, String gender, String companyId, String companyName, String symplifyId, String signUpCampaign, String signUpSource, String locale, String nationality, bool emailVerified, bool isClubMember, bool wasRecentlyCreated, Address address, int points, DateTime? birthDate, DateTime? createDate, DateTime? signUpDate
+});
+
+
+@override $AddressCopyWith<$Res> get address;
+
+}
+/// @nodoc
+class __$UserCopyWithImpl<$Res>
+ implements _$UserCopyWith<$Res> {
+ __$UserCopyWithImpl(this._self, this._then);
+
+ final _User _self;
+ final $Res Function(_User) _then;
+
+/// Create a copy of User
+/// with the given fields replaced by the non-null parameter values.
+@override @pragma('vm:prefer-inline') $Res call({Object? userId = null,Object? hmsId = null,Object? firstName = null,Object? lastName = null,Object? addressCountry = null,Object? phoneNumber = null,Object? email = null,Object? shopperReference = null,Object? gender = null,Object? companyId = null,Object? companyName = null,Object? symplifyId = null,Object? signUpCampaign = null,Object? signUpSource = null,Object? locale = null,Object? nationality = null,Object? emailVerified = null,Object? isClubMember = null,Object? wasRecentlyCreated = null,Object? address = null,Object? points = null,Object? birthDate = freezed,Object? createDate = freezed,Object? signUpDate = freezed,}) {
+ return _then(_User(
+userId: null == userId ? _self.userId : userId // ignore: cast_nullable_to_non_nullable
+as String,hmsId: null == hmsId ? _self.hmsId : hmsId // ignore: cast_nullable_to_non_nullable
+as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable
+as String,lastName: null == lastName ? _self.lastName : lastName // ignore: cast_nullable_to_non_nullable
+as String,addressCountry: null == addressCountry ? _self.addressCountry : addressCountry // ignore: cast_nullable_to_non_nullable
+as String,phoneNumber: null == phoneNumber ? _self.phoneNumber : phoneNumber // ignore: cast_nullable_to_non_nullable
+as String,email: null == email ? _self.email : email // ignore: cast_nullable_to_non_nullable
+as String,shopperReference: null == shopperReference ? _self.shopperReference : shopperReference // ignore: cast_nullable_to_non_nullable
+as String,gender: null == gender ? _self.gender : gender // ignore: cast_nullable_to_non_nullable
+as String,companyId: null == companyId ? _self.companyId : companyId // ignore: cast_nullable_to_non_nullable
+as String,companyName: null == companyName ? _self.companyName : companyName // ignore: cast_nullable_to_non_nullable
+as String,symplifyId: null == symplifyId ? _self.symplifyId : symplifyId // ignore: cast_nullable_to_non_nullable
+as String,signUpCampaign: null == signUpCampaign ? _self.signUpCampaign : signUpCampaign // ignore: cast_nullable_to_non_nullable
+as String,signUpSource: null == signUpSource ? _self.signUpSource : signUpSource // ignore: cast_nullable_to_non_nullable
+as String,locale: null == locale ? _self.locale : locale // ignore: cast_nullable_to_non_nullable
+as String,nationality: null == nationality ? _self.nationality : nationality // ignore: cast_nullable_to_non_nullable
+as String,emailVerified: null == emailVerified ? _self.emailVerified : emailVerified // ignore: cast_nullable_to_non_nullable
+as bool,isClubMember: null == isClubMember ? _self.isClubMember : isClubMember // ignore: cast_nullable_to_non_nullable
+as bool,wasRecentlyCreated: null == wasRecentlyCreated ? _self.wasRecentlyCreated : wasRecentlyCreated // ignore: cast_nullable_to_non_nullable
+as bool,address: null == address ? _self.address : address // ignore: cast_nullable_to_non_nullable
+as Address,points: null == points ? _self.points : points // ignore: cast_nullable_to_non_nullable
+as int,birthDate: freezed == birthDate ? _self.birthDate : birthDate // ignore: cast_nullable_to_non_nullable
+as DateTime?,createDate: freezed == createDate ? _self.createDate : createDate // ignore: cast_nullable_to_non_nullable
+as DateTime?,signUpDate: freezed == signUpDate ? _self.signUpDate : signUpDate // ignore: cast_nullable_to_non_nullable
+as DateTime?,
+ ));
+}
+
+/// Create a copy of User
+/// with the given fields replaced by the non-null parameter values.
+@override
+@pragma('vm:prefer-inline')
+$AddressCopyWith<$Res> get address {
+
+ return $AddressCopyWith<$Res>(_self.address, (value) {
+ return _then(_self.copyWith(address: value));
+ });
+}
+}
+
+// dart format on
diff --git a/comwell_key_app/lib/.generated/presentation/app/app_state.freezed.dart b/comwell_key_app/lib/.generated/presentation/app/app_state.freezed.dart
deleted file mode 100644
index 3ad0e871..00000000
--- a/comwell_key_app/lib/.generated/presentation/app/app_state.freezed.dart
+++ /dev/null
@@ -1,277 +0,0 @@
-// GENERATED CODE - DO NOT MODIFY BY HAND
-// coverage:ignore-file
-// ignore_for_file: type=lint
-// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
-
-part of '../../../presentation/app/app_state.dart';
-
-// **************************************************************************
-// FreezedGenerator
-// **************************************************************************
-
-// dart format off
-T _$identity<T>(T value) => value;
-/// @nodoc
-mixin _$AppState {
-
- bool get isLoading; AppError get error; AppEvent? get event;
-/// Create a copy of AppState
-/// with the given fields replaced by the non-null parameter values.
-@JsonKey(includeFromJson: false, includeToJson: false)
-@pragma('vm:prefer-inline')
-$AppStateCopyWith<AppState> get copyWith => _$AppStateCopyWithImpl<AppState>(this as AppState, _$identity);
-
-
-
-@override
-bool operator ==(Object other) {
- return identical(this, other) || (other.runtimeType == runtimeType&&other is AppState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.error, error) || other.error == error)&&(identical(other.event, event) || other.event == event));
-}
-
-
-@override
-int get hashCode => Object.hash(runtimeType,isLoading,error,event);
-
-@override
-String toString() {
- return 'AppState(isLoading: $isLoading, error: $error, event: $event)';
-}
-
-
-}
-
-/// @nodoc
-abstract mixin class $AppStateCopyWith<$Res> {
- factory $AppStateCopyWith(AppState value, $Res Function(AppState) _then) = _$AppStateCopyWithImpl;
-@useResult
-$Res call({
- bool isLoading, AppError error, AppEvent? event
-});
-
-
-
-
-}
-/// @nodoc
-class _$AppStateCopyWithImpl<$Res>
- implements $AppStateCopyWith<$Res> {
- _$AppStateCopyWithImpl(this._self, this._then);
-
- final AppState _self;
- final $Res Function(AppState) _then;
-
-/// Create a copy of AppState
-/// with the given fields replaced by the non-null parameter values.
-@pragma('vm:prefer-inline') @override $Res call({Object? isLoading = null,Object? error = null,Object? event = freezed,}) {
- return _then(_self.copyWith(
-isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
-as bool,error: null == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
-as AppError,event: freezed == event ? _self.event : event // ignore: cast_nullable_to_non_nullable
-as AppEvent?,
- ));
-}
-
-}
-
-
-/// Adds pattern-matching-related methods to [AppState].
-extension AppStatePatterns on AppState {
-/// A variant of `map` that fallback to returning `orElse`.
-///
-/// It is equivalent to doing:
-/// ```dart
-/// switch (sealedClass) {
-/// case final Subclass value:
-/// return ...;
-/// case _:
-/// return orElse();
-/// }
-/// ```
-
-@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _AppState value)? $default,{required TResult orElse(),}){
-final _that = this;
-switch (_that) {
-case _AppState() when $default != null:
-return $default(_that);case _:
- return orElse();
-
-}
-}
-/// A `switch`-like method, using callbacks.
-///
-/// Callbacks receives the raw object, upcasted.
-/// It is equivalent to doing:
-/// ```dart
-/// switch (sealedClass) {
-/// case final Subclass value:
-/// return ...;
-/// case final Subclass2 value:
-/// return ...;
-/// }
-/// ```
-
-@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _AppState value) $default,){
-final _that = this;
-switch (_that) {
-case _AppState():
-return $default(_that);case _:
- throw StateError('Unexpected subclass');
-
-}
-}
-/// A variant of `map` that fallback to returning `null`.
-///
-/// It is equivalent to doing:
-/// ```dart
-/// switch (sealedClass) {
-/// case final Subclass value:
-/// return ...;
-/// case _:
-/// return null;
-/// }
-/// ```
-
-@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _AppState value)? $default,){
-final _that = this;
-switch (_that) {
-case _AppState() when $default != null:
-return $default(_that);case _:
- return null;
-
-}
-}
-/// A variant of `when` that fallback to an `orElse` callback.
-///
-/// It is equivalent to doing:
-/// ```dart
-/// switch (sealedClass) {
-/// case Subclass(:final field):
-/// return ...;
-/// case _:
-/// return orElse();
-/// }
-/// ```
-
-@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isLoading, AppError error, AppEvent? event)? $default,{required TResult orElse(),}) {final _that = this;
-switch (_that) {
-case _AppState() when $default != null:
-return $default(_that.isLoading,_that.error,_that.event);case _:
- return orElse();
-
-}
-}
-/// A `switch`-like method, using callbacks.
-///
-/// As opposed to `map`, this offers destructuring.
-/// It is equivalent to doing:
-/// ```dart
-/// switch (sealedClass) {
-/// case Subclass(:final field):
-/// return ...;
-/// case Subclass2(:final field2):
-/// return ...;
-/// }
-/// ```
-
-@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isLoading, AppError error, AppEvent? event) $default,) {final _that = this;
-switch (_that) {
-case _AppState():
-return $default(_that.isLoading,_that.error,_that.event);case _:
- throw StateError('Unexpected subclass');
-
-}
-}
-/// A variant of `when` that fallback to returning `null`
-///
-/// It is equivalent to doing:
-/// ```dart
-/// switch (sealedClass) {
-/// case Subclass(:final field):
-/// return ...;
-/// case _:
-/// return null;
-/// }
-/// ```
-
-@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isLoading, AppError error, AppEvent? event)? $default,) {final _that = this;
-switch (_that) {
-case _AppState() when $default != null:
-return $default(_that.isLoading,_that.error,_that.event);case _:
- return null;
-
-}
-}
-
-}
-
-/// @nodoc
-
-
-class _AppState implements AppState {
- const _AppState({this.isLoading = false, this.error = AppError.none, this.event = null});
-
-
-@override@JsonKey() final bool isLoading;
-@override@JsonKey() final AppError error;
-@override@JsonKey() final AppEvent? event;
-
-/// Create a copy of AppState
-/// with the given fields replaced by the non-null parameter values.
-@override @JsonKey(includeFromJson: false, includeToJson: false)
-@pragma('vm:prefer-inline')
-_$AppStateCopyWith<_AppState> get copyWith => __$AppStateCopyWithImpl<_AppState>(this, _$identity);
-
-
-
-@override
-bool operator ==(Object other) {
- return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.error, error) || other.error == error)&&(identical(other.event, event) || other.event == event));
-}
-
-
-@override
-int get hashCode => Object.hash(runtimeType,isLoading,error,event);
-
-@override
-String toString() {
- return 'AppState(isLoading: $isLoading, error: $error, event: $event)';
-}
-
-
-}
-
-/// @nodoc
-abstract mixin class _$AppStateCopyWith<$Res> implements $AppStateCopyWith<$Res> {
- factory _$AppStateCopyWith(_AppState value, $Res Function(_AppState) _then) = __$AppStateCopyWithImpl;
-@override @useResult
-$Res call({
- bool isLoading, AppError error, AppEvent? event
-});
-
-
-
-
-}
-/// @nodoc
-class __$AppStateCopyWithImpl<$Res>
- implements _$AppStateCopyWith<$Res> {
- __$AppStateCopyWithImpl(this._self, this._then);
-
- final _AppState _self;
- final $Res Function(_AppState) _then;
-
-/// Create a copy of AppState
-/// with the given fields replaced by the non-null parameter values.
-@override @pragma('vm:prefer-inline') $Res call({Object? isLoading = null,Object? error = null,Object? event = freezed,}) {
- return _then(_AppState(
-isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
-as bool,error: null == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
-as AppError,event: freezed == event ? _self.event : event // ignore: cast_nullable_to_non_nullable
-as AppEvent?,
- ));
-}
-
-
-}
-
-// dart format on
diff --git a/comwell_key_app/lib/.generated/presentation/app/bloc/app_cubit.freezed.dart b/comwell_key_app/lib/.generated/presentation/app/bloc/app_cubit.freezed.dart
new file mode 100644
index 00000000..baa8b8ff
--- /dev/null
+++ b/comwell_key_app/lib/.generated/presentation/app/bloc/app_cubit.freezed.dart
@@ -0,0 +1,277 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// coverage:ignore-file
+// ignore_for_file: type=lint
+// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
+
+part of '../../../../presentation/app/bloc/app_cubit.dart';
+
+// **************************************************************************
+// FreezedGenerator
+// **************************************************************************
+
+// dart format off
+T _$identity<T>(T value) => value;
+/// @nodoc
+mixin _$AppState {
+
+ bool get isLoading; AppError get error; AppEvent? get event;
+/// Create a copy of AppState
+/// with the given fields replaced by the non-null parameter values.
+@JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+$AppStateCopyWith<AppState> get copyWith => _$AppStateCopyWithImpl<AppState>(this as AppState, _$identity);
+
+
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is AppState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.error, error) || other.error == error)&&(identical(other.event, event) || other.event == event));
+}
+
+
+@override
+int get hashCode => Object.hash(runtimeType,isLoading,error,event);
+
+@override
+String toString() {
+ return 'AppState(isLoading: $isLoading, error: $error, event: $event)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class $AppStateCopyWith<$Res> {
+ factory $AppStateCopyWith(AppState value, $Res Function(AppState) _then) = _$AppStateCopyWithImpl;
+@useResult
+$Res call({
+ bool isLoading, AppError error, AppEvent? event
+});
+
+
+
+
+}
+/// @nodoc
+class _$AppStateCopyWithImpl<$Res>
+ implements $AppStateCopyWith<$Res> {
+ _$AppStateCopyWithImpl(this._self, this._then);
+
+ final AppState _self;
+ final $Res Function(AppState) _then;
+
+/// Create a copy of AppState
+/// with the given fields replaced by the non-null parameter values.
+@pragma('vm:prefer-inline') @override $Res call({Object? isLoading = null,Object? error = null,Object? event = freezed,}) {
+ return _then(_self.copyWith(
+isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
+as bool,error: null == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
+as AppError,event: freezed == event ? _self.event : event // ignore: cast_nullable_to_non_nullable
+as AppEvent?,
+ ));
+}
+
+}
+
+
+/// Adds pattern-matching-related methods to [AppState].
+extension AppStatePatterns on AppState {
+/// A variant of `map` that fallback to returning `orElse`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _AppState value)? $default,{required TResult orElse(),}){
+final _that = this;
+switch (_that) {
+case _AppState() when $default != null:
+return $default(_that);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// Callbacks receives the raw object, upcasted.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case final Subclass2 value:
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _AppState value) $default,){
+final _that = this;
+switch (_that) {
+case _AppState():
+return $default(_that);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `map` that fallback to returning `null`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _AppState value)? $default,){
+final _that = this;
+switch (_that) {
+case _AppState() when $default != null:
+return $default(_that);case _:
+ return null;
+
+}
+}
+/// A variant of `when` that fallback to an `orElse` callback.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isLoading, AppError error, AppEvent? event)? $default,{required TResult orElse(),}) {final _that = this;
+switch (_that) {
+case _AppState() when $default != null:
+return $default(_that.isLoading,_that.error,_that.event);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// As opposed to `map`, this offers destructuring.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case Subclass2(:final field2):
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isLoading, AppError error, AppEvent? event) $default,) {final _that = this;
+switch (_that) {
+case _AppState():
+return $default(_that.isLoading,_that.error,_that.event);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `when` that fallback to returning `null`
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isLoading, AppError error, AppEvent? event)? $default,) {final _that = this;
+switch (_that) {
+case _AppState() when $default != null:
+return $default(_that.isLoading,_that.error,_that.event);case _:
+ return null;
+
+}
+}
+
+}
+
+/// @nodoc
+
+
+class _AppState implements AppState {
+ const _AppState({this.isLoading = false, this.error = AppError.none, this.event = null});
+
+
+@override@JsonKey() final bool isLoading;
+@override@JsonKey() final AppError error;
+@override@JsonKey() final AppEvent? event;
+
+/// Create a copy of AppState
+/// with the given fields replaced by the non-null parameter values.
+@override @JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+_$AppStateCopyWith<_AppState> get copyWith => __$AppStateCopyWithImpl<_AppState>(this, _$identity);
+
+
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.error, error) || other.error == error)&&(identical(other.event, event) || other.event == event));
+}
+
+
+@override
+int get hashCode => Object.hash(runtimeType,isLoading,error,event);
+
+@override
+String toString() {
+ return 'AppState(isLoading: $isLoading, error: $error, event: $event)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class _$AppStateCopyWith<$Res> implements $AppStateCopyWith<$Res> {
+ factory _$AppStateCopyWith(_AppState value, $Res Function(_AppState) _then) = __$AppStateCopyWithImpl;
+@override @useResult
+$Res call({
+ bool isLoading, AppError error, AppEvent? event
+});
+
+
+
+
+}
+/// @nodoc
+class __$AppStateCopyWithImpl<$Res>
+ implements _$AppStateCopyWith<$Res> {
+ __$AppStateCopyWithImpl(this._self, this._then);
+
+ final _AppState _self;
+ final $Res Function(_AppState) _then;
+
+/// Create a copy of AppState
+/// with the given fields replaced by the non-null parameter values.
+@override @pragma('vm:prefer-inline') $Res call({Object? isLoading = null,Object? error = null,Object? event = freezed,}) {
+ return _then(_AppState(
+isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
+as bool,error: null == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
+as AppError,event: freezed == event ? _self.event : event // ignore: cast_nullable_to_non_nullable
+as AppEvent?,
+ ));
+}
+
+
+}
+
+// dart format on
diff --git a/comwell_key_app/lib/.generated/presentation/app/bloc/profile_cubit.freezed.dart b/comwell_key_app/lib/.generated/presentation/app/bloc/profile_cubit.freezed.dart
new file mode 100644
index 00000000..83984914
--- /dev/null
+++ b/comwell_key_app/lib/.generated/presentation/app/bloc/profile_cubit.freezed.dart
@@ -0,0 +1,301 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// coverage:ignore-file
+// ignore_for_file: type=lint
+// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
+
+part of '../../../../presentation/app/bloc/profile_cubit.dart';
+
+// **************************************************************************
+// FreezedGenerator
+// **************************************************************************
+
+// dart format off
+T _$identity<T>(T value) => value;
+/// @nodoc
+mixin _$ProfileState {
+
+ bool get isLoading; AppError get error; User get user; bool get isToSAccepted; bool get isNewsletterAccepted;
+/// Create a copy of ProfileState
+/// with the given fields replaced by the non-null parameter values.
+@JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+$ProfileStateCopyWith<ProfileState> get copyWith => _$ProfileStateCopyWithImpl<ProfileState>(this as ProfileState, _$identity);
+
+
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is ProfileState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.error, error) || other.error == error)&&(identical(other.user, user) || other.user == user)&&(identical(other.isToSAccepted, isToSAccepted) || other.isToSAccepted == isToSAccepted)&&(identical(other.isNewsletterAccepted, isNewsletterAccepted) || other.isNewsletterAccepted == isNewsletterAccepted));
+}
+
+
+@override
+int get hashCode => Object.hash(runtimeType,isLoading,error,user,isToSAccepted,isNewsletterAccepted);
+
+@override
+String toString() {
+ return 'ProfileState(isLoading: $isLoading, error: $error, user: $user, isToSAccepted: $isToSAccepted, isNewsletterAccepted: $isNewsletterAccepted)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class $ProfileStateCopyWith<$Res> {
+ factory $ProfileStateCopyWith(ProfileState value, $Res Function(ProfileState) _then) = _$ProfileStateCopyWithImpl;
+@useResult
+$Res call({
+ bool isLoading, AppError error, User user, bool isToSAccepted, bool isNewsletterAccepted
+});
+
+
+$UserCopyWith<$Res> get user;
+
+}
+/// @nodoc
+class _$ProfileStateCopyWithImpl<$Res>
+ implements $ProfileStateCopyWith<$Res> {
+ _$ProfileStateCopyWithImpl(this._self, this._then);
+
+ final ProfileState _self;
+ final $Res Function(ProfileState) _then;
+
+/// Create a copy of ProfileState
+/// with the given fields replaced by the non-null parameter values.
+@pragma('vm:prefer-inline') @override $Res call({Object? isLoading = null,Object? error = null,Object? user = null,Object? isToSAccepted = null,Object? isNewsletterAccepted = null,}) {
+ return _then(_self.copyWith(
+isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
+as bool,error: null == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
+as AppError,user: null == user ? _self.user : user // ignore: cast_nullable_to_non_nullable
+as User,isToSAccepted: null == isToSAccepted ? _self.isToSAccepted : isToSAccepted // ignore: cast_nullable_to_non_nullable
+as bool,isNewsletterAccepted: null == isNewsletterAccepted ? _self.isNewsletterAccepted : isNewsletterAccepted // ignore: cast_nullable_to_non_nullable
+as bool,
+ ));
+}
+/// Create a copy of ProfileState
+/// with the given fields replaced by the non-null parameter values.
+@override
+@pragma('vm:prefer-inline')
+$UserCopyWith<$Res> get user {
+
+ return $UserCopyWith<$Res>(_self.user, (value) {
+ return _then(_self.copyWith(user: value));
+ });
+}
+}
+
+
+/// Adds pattern-matching-related methods to [ProfileState].
+extension ProfileStatePatterns on ProfileState {
+/// A variant of `map` that fallback to returning `orElse`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ProfileState value)? $default,{required TResult orElse(),}){
+final _that = this;
+switch (_that) {
+case _ProfileState() when $default != null:
+return $default(_that);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// Callbacks receives the raw object, upcasted.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case final Subclass2 value:
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ProfileState value) $default,){
+final _that = this;
+switch (_that) {
+case _ProfileState():
+return $default(_that);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `map` that fallback to returning `null`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ProfileState value)? $default,){
+final _that = this;
+switch (_that) {
+case _ProfileState() when $default != null:
+return $default(_that);case _:
+ return null;
+
+}
+}
+/// A variant of `when` that fallback to an `orElse` callback.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isLoading, AppError error, User user, bool isToSAccepted, bool isNewsletterAccepted)? $default,{required TResult orElse(),}) {final _that = this;
+switch (_that) {
+case _ProfileState() when $default != null:
+return $default(_that.isLoading,_that.error,_that.user,_that.isToSAccepted,_that.isNewsletterAccepted);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// As opposed to `map`, this offers destructuring.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case Subclass2(:final field2):
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isLoading, AppError error, User user, bool isToSAccepted, bool isNewsletterAccepted) $default,) {final _that = this;
+switch (_that) {
+case _ProfileState():
+return $default(_that.isLoading,_that.error,_that.user,_that.isToSAccepted,_that.isNewsletterAccepted);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `when` that fallback to returning `null`
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isLoading, AppError error, User user, bool isToSAccepted, bool isNewsletterAccepted)? $default,) {final _that = this;
+switch (_that) {
+case _ProfileState() when $default != null:
+return $default(_that.isLoading,_that.error,_that.user,_that.isToSAccepted,_that.isNewsletterAccepted);case _:
+ return null;
+
+}
+}
+
+}
+
+/// @nodoc
+
+
+class _ProfileState extends ProfileState {
+ const _ProfileState({this.isLoading = false, this.error = AppError.none, this.user = const User(), this.isToSAccepted = false, this.isNewsletterAccepted = false}): super._();
+
+
+@override@JsonKey() final bool isLoading;
+@override@JsonKey() final AppError error;
+@override@JsonKey() final User user;
+@override@JsonKey() final bool isToSAccepted;
+@override@JsonKey() final bool isNewsletterAccepted;
+
+/// Create a copy of ProfileState
+/// with the given fields replaced by the non-null parameter values.
+@override @JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+_$ProfileStateCopyWith<_ProfileState> get copyWith => __$ProfileStateCopyWithImpl<_ProfileState>(this, _$identity);
+
+
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is _ProfileState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.error, error) || other.error == error)&&(identical(other.user, user) || other.user == user)&&(identical(other.isToSAccepted, isToSAccepted) || other.isToSAccepted == isToSAccepted)&&(identical(other.isNewsletterAccepted, isNewsletterAccepted) || other.isNewsletterAccepted == isNewsletterAccepted));
+}
+
+
+@override
+int get hashCode => Object.hash(runtimeType,isLoading,error,user,isToSAccepted,isNewsletterAccepted);
+
+@override
+String toString() {
+ return 'ProfileState(isLoading: $isLoading, error: $error, user: $user, isToSAccepted: $isToSAccepted, isNewsletterAccepted: $isNewsletterAccepted)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class _$ProfileStateCopyWith<$Res> implements $ProfileStateCopyWith<$Res> {
+ factory _$ProfileStateCopyWith(_ProfileState value, $Res Function(_ProfileState) _then) = __$ProfileStateCopyWithImpl;
+@override @useResult
+$Res call({
+ bool isLoading, AppError error, User user, bool isToSAccepted, bool isNewsletterAccepted
+});
+
+
+@override $UserCopyWith<$Res> get user;
+
+}
+/// @nodoc
+class __$ProfileStateCopyWithImpl<$Res>
+ implements _$ProfileStateCopyWith<$Res> {
+ __$ProfileStateCopyWithImpl(this._self, this._then);
+
+ final _ProfileState _self;
+ final $Res Function(_ProfileState) _then;
+
+/// Create a copy of ProfileState
+/// with the given fields replaced by the non-null parameter values.
+@override @pragma('vm:prefer-inline') $Res call({Object? isLoading = null,Object? error = null,Object? user = null,Object? isToSAccepted = null,Object? isNewsletterAccepted = null,}) {
+ return _then(_ProfileState(
+isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
+as bool,error: null == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
+as AppError,user: null == user ? _self.user : user // ignore: cast_nullable_to_non_nullable
+as User,isToSAccepted: null == isToSAccepted ? _self.isToSAccepted : isToSAccepted // ignore: cast_nullable_to_non_nullable
+as bool,isNewsletterAccepted: null == isNewsletterAccepted ? _self.isNewsletterAccepted : isNewsletterAccepted // ignore: cast_nullable_to_non_nullable
+as bool,
+ ));
+}
+
+/// Create a copy of ProfileState
+/// with the given fields replaced by the non-null parameter values.
+@override
+@pragma('vm:prefer-inline')
+$UserCopyWith<$Res> get user {
+
+ return $UserCopyWith<$Res>(_self.user, (value) {
+ return _then(_self.copyWith(user: value));
+ });
+}
+}
+
+// dart format on
diff --git a/comwell_key_app/lib/.generated/presentation/screens/profile_settings/bloc/profile_settings_state.freezed.dart b/comwell_key_app/lib/.generated/presentation/screens/profile_settings/bloc/profile_settings_state.freezed.dart
new file mode 100644
index 00000000..768f1bbd
--- /dev/null
+++ b/comwell_key_app/lib/.generated/presentation/screens/profile_settings/bloc/profile_settings_state.freezed.dart
@@ -0,0 +1,277 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// coverage:ignore-file
+// ignore_for_file: type=lint
+// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
+
+part of '../../../../../presentation/screens/profile_settings/bloc/profile_settings_state.dart';
+
+// **************************************************************************
+// FreezedGenerator
+// **************************************************************************
+
+// dart format off
+T _$identity<T>(T value) => value;
+/// @nodoc
+mixin _$ProfileSettingsState {
+
+ bool get isLoading; AppError get error; bool get isDeleted;
+/// Create a copy of ProfileSettingsState
+/// with the given fields replaced by the non-null parameter values.
+@JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+$ProfileSettingsStateCopyWith<ProfileSettingsState> get copyWith => _$ProfileSettingsStateCopyWithImpl<ProfileSettingsState>(this as ProfileSettingsState, _$identity);
+
+
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is ProfileSettingsState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.error, error) || other.error == error)&&(identical(other.isDeleted, isDeleted) || other.isDeleted == isDeleted));
+}
+
+
+@override
+int get hashCode => Object.hash(runtimeType,isLoading,error,isDeleted);
+
+@override
+String toString() {
+ return 'ProfileSettingsState(isLoading: $isLoading, error: $error, isDeleted: $isDeleted)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class $ProfileSettingsStateCopyWith<$Res> {
+ factory $ProfileSettingsStateCopyWith(ProfileSettingsState value, $Res Function(ProfileSettingsState) _then) = _$ProfileSettingsStateCopyWithImpl;
+@useResult
+$Res call({
+ bool isLoading, AppError error, bool isDeleted
+});
+
+
+
+
+}
+/// @nodoc
+class _$ProfileSettingsStateCopyWithImpl<$Res>
+ implements $ProfileSettingsStateCopyWith<$Res> {
+ _$ProfileSettingsStateCopyWithImpl(this._self, this._then);
+
+ final ProfileSettingsState _self;
+ final $Res Function(ProfileSettingsState) _then;
+
+/// Create a copy of ProfileSettingsState
+/// with the given fields replaced by the non-null parameter values.
+@pragma('vm:prefer-inline') @override $Res call({Object? isLoading = null,Object? error = null,Object? isDeleted = null,}) {
+ return _then(_self.copyWith(
+isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
+as bool,error: null == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
+as AppError,isDeleted: null == isDeleted ? _self.isDeleted : isDeleted // ignore: cast_nullable_to_non_nullable
+as bool,
+ ));
+}
+
+}
+
+
+/// Adds pattern-matching-related methods to [ProfileSettingsState].
+extension ProfileSettingsStatePatterns on ProfileSettingsState {
+/// A variant of `map` that fallback to returning `orElse`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ProfileSettingsState value)? $default,{required TResult orElse(),}){
+final _that = this;
+switch (_that) {
+case _ProfileSettingsState() when $default != null:
+return $default(_that);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// Callbacks receives the raw object, upcasted.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case final Subclass2 value:
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ProfileSettingsState value) $default,){
+final _that = this;
+switch (_that) {
+case _ProfileSettingsState():
+return $default(_that);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `map` that fallback to returning `null`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ProfileSettingsState value)? $default,){
+final _that = this;
+switch (_that) {
+case _ProfileSettingsState() when $default != null:
+return $default(_that);case _:
+ return null;
+
+}
+}
+/// A variant of `when` that fallback to an `orElse` callback.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isLoading, AppError error, bool isDeleted)? $default,{required TResult orElse(),}) {final _that = this;
+switch (_that) {
+case _ProfileSettingsState() when $default != null:
+return $default(_that.isLoading,_that.error,_that.isDeleted);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// As opposed to `map`, this offers destructuring.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case Subclass2(:final field2):
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isLoading, AppError error, bool isDeleted) $default,) {final _that = this;
+switch (_that) {
+case _ProfileSettingsState():
+return $default(_that.isLoading,_that.error,_that.isDeleted);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `when` that fallback to returning `null`
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isLoading, AppError error, bool isDeleted)? $default,) {final _that = this;
+switch (_that) {
+case _ProfileSettingsState() when $default != null:
+return $default(_that.isLoading,_that.error,_that.isDeleted);case _:
+ return null;
+
+}
+}
+
+}
+
+/// @nodoc
+
+
+class _ProfileSettingsState extends ProfileSettingsState {
+ const _ProfileSettingsState({this.isLoading = false, this.error = AppError.none, this.isDeleted = false}): super._();
+
+
+@override@JsonKey() final bool isLoading;
+@override@JsonKey() final AppError error;
+@override@JsonKey() final bool isDeleted;
+
+/// Create a copy of ProfileSettingsState
+/// with the given fields replaced by the non-null parameter values.
+@override @JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+_$ProfileSettingsStateCopyWith<_ProfileSettingsState> get copyWith => __$ProfileSettingsStateCopyWithImpl<_ProfileSettingsState>(this, _$identity);
+
+
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is _ProfileSettingsState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.error, error) || other.error == error)&&(identical(other.isDeleted, isDeleted) || other.isDeleted == isDeleted));
+}
+
+
+@override
+int get hashCode => Object.hash(runtimeType,isLoading,error,isDeleted);
+
+@override
+String toString() {
+ return 'ProfileSettingsState(isLoading: $isLoading, error: $error, isDeleted: $isDeleted)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class _$ProfileSettingsStateCopyWith<$Res> implements $ProfileSettingsStateCopyWith<$Res> {
+ factory _$ProfileSettingsStateCopyWith(_ProfileSettingsState value, $Res Function(_ProfileSettingsState) _then) = __$ProfileSettingsStateCopyWithImpl;
+@override @useResult
+$Res call({
+ bool isLoading, AppError error, bool isDeleted
+});
+
+
+
+
+}
+/// @nodoc
+class __$ProfileSettingsStateCopyWithImpl<$Res>
+ implements _$ProfileSettingsStateCopyWith<$Res> {
+ __$ProfileSettingsStateCopyWithImpl(this._self, this._then);
+
+ final _ProfileSettingsState _self;
+ final $Res Function(_ProfileSettingsState) _then;
+
+/// Create a copy of ProfileSettingsState
+/// with the given fields replaced by the non-null parameter values.
+@override @pragma('vm:prefer-inline') $Res call({Object? isLoading = null,Object? error = null,Object? isDeleted = null,}) {
+ return _then(_ProfileSettingsState(
+isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
+as bool,error: null == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
+as AppError,isDeleted: null == isDeleted ? _self.isDeleted : isDeleted // ignore: cast_nullable_to_non_nullable
+as bool,
+ ));
+}
+
+
+}
+
+// dart format on
diff --git a/comwell_key_app/lib/.generated/presentation/screens/profile_settings/profile_settings_route.g.dart b/comwell_key_app/lib/.generated/presentation/screens/profile_settings/profile_settings_route.g.dart
new file mode 100644
index 00000000..edb0a3f4
--- /dev/null
+++ b/comwell_key_app/lib/.generated/presentation/screens/profile_settings/profile_settings_route.g.dart
@@ -0,0 +1,35 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of '../../../../presentation/screens/profile_settings/profile_settings_route.dart';
+
+// **************************************************************************
+// GoRouterGenerator
+// **************************************************************************
+
+List<RouteBase> get $appRoutes => [$profileSettingsRoute];
+
+RouteBase get $profileSettingsRoute => GoRouteData.$route(
+ path: '/profile-settings',
+ factory: $ProfileSettingsRoute._fromState,
+);
+
+mixin $ProfileSettingsRoute on GoRouteData {
+ static ProfileSettingsRoute _fromState(GoRouterState state) =>
+ ProfileSettingsRoute();
+
+ @override
+ String get location => GoRouteData.$location('/profile-settings');
+
+ @override
+ void go(BuildContext context) => context.go(location);
+
+ @override
+ Future<T?> push<T>(BuildContext context) => context.push<T>(location);
+
+ @override
+ void pushReplacement(BuildContext context) =>
+ context.pushReplacement(location);
+
+ @override
+ void replace(BuildContext context) => context.replace(location);
+}
diff --git a/comwell_key_app/lib/check_in/check_in_repository.dart b/comwell_key_app/lib/check_in/check_in_repository.dart
index 1d840bc1..6a81924a 100644
--- a/comwell_key_app/lib/check_in/check_in_repository.dart
+++ b/comwell_key_app/lib/check_in/check_in_repository.dart
@@ -2,7 +2,7 @@
import 'package:comwell_key_app/database/comwell_db.dart';
import 'package:comwell_key_app/domain/repositories/booking_details_repository.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
-import 'package:comwell_key_app/profile/profile_repository.dart';
+import 'package:comwell_key_app/domain/repositories/profile_repository.dart';
import 'package:comwell_key_app/services/api.dart';
import 'package:comwell_key_app/utils/locator.dart';
import 'package:dio/dio.dart';
diff --git a/comwell_key_app/lib/check_out/bloc/check_out_cubit.dart b/comwell_key_app/lib/check_out/bloc/check_out_cubit.dart
index 0b01704c..0ea2f787 100644
--- a/comwell_key_app/lib/check_out/bloc/check_out_cubit.dart
+++ b/comwell_key_app/lib/check_out/bloc/check_out_cubit.dart
@@ -6,7 +6,7 @@ import 'package:comwell_key_app/check_out/pages/check_out_page.dart';
import 'package:comwell_key_app/domain/repositories/booking_details_repository.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/pregistration/pregistration_repository.dart';
-import 'package:comwell_key_app/profile/profile_repository.dart';
+import 'package:comwell_key_app/domain/repositories/profile_repository.dart';
import 'package:comwell_key_app/profile/utils/urls.dart';
import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:comwell_key_app/services/models/booking_dto.dart';
diff --git a/comwell_key_app/lib/comwell_app.dart b/comwell_key_app/lib/comwell_app.dart
index 590cb385..092c5276 100644
--- a/comwell_key_app/lib/comwell_app.dart
+++ b/comwell_key_app/lib/comwell_app.dart
@@ -4,9 +4,9 @@ import 'package:comwell_key_app/connection_state/connection_state_cubit.dart';
import 'package:comwell_key_app/key/bloc/key_bloc.dart';
import 'package:comwell_key_app/key/repository/key_repository.dart';
import 'package:comwell_key_app/overview/cubit/overview_cubit.dart';
-import 'package:comwell_key_app/presentation/app/app_cubit.dart';
-import 'package:comwell_key_app/profile/cubit/profile_cubit.dart';
-import 'package:comwell_key_app/profile_settings/cubit/profile_settings_cubit.dart';
+import 'package:comwell_key_app/presentation/app/bloc/app_cubit.dart';
+import 'package:comwell_key_app/presentation/app/bloc/profile_cubit.dart';
+import 'package:comwell_key_app/presentation/screens/profile_settings/bloc/profile_settings_cubit.dart';
import 'package:comwell_key_app/routing/app_router.dart';
import 'package:comwell_key_app/themes/app_button_styles.dart';
import 'package:comwell_key_app/themes/app_textstyles.dart';
@@ -71,14 +71,6 @@ class ComwellApp extends StatelessWidget {
locator.get(),
),
),
- BlocProvider<ProfileSettingsCubit>(
- lazy: false,
- create: (BuildContext context) => ProfileSettingsCubit(
- locator(),
- locator(),
- locator(),
- ),
- ),
BlocProvider<PaymentCubit>(
lazy: false,
create: (context) => PaymentCubit(adyenRepository: locator<AdyenRepository>()),
diff --git a/comwell_key_app/lib/contact/components/get_a_phone_call_section.dart b/comwell_key_app/lib/contact/components/get_a_phone_call_section.dart
index eba82f9e..2ead6a82 100644
--- a/comwell_key_app/lib/contact/components/get_a_phone_call_section.dart
+++ b/comwell_key_app/lib/contact/components/get_a_phone_call_section.dart
@@ -1,5 +1,5 @@
import 'package:comwell_key_app/contact/cubit/contact_cubit.dart';
-import 'package:comwell_key_app/profile_settings/components/intl_phone_field.dart';
+import 'package:comwell_key_app/presentation/screens/profile_settings/components/intl_phone_field.dart';
import 'package:comwell_key_app/utils/l10n_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
diff --git a/comwell_key_app/lib/contact/cubit/contact_cubit.dart b/comwell_key_app/lib/contact/cubit/contact_cubit.dart
index b4c1e942..744aa374 100644
--- a/comwell_key_app/lib/contact/cubit/contact_cubit.dart
+++ b/comwell_key_app/lib/contact/cubit/contact_cubit.dart
@@ -1,8 +1,8 @@
import 'package:bloc/bloc.dart';
import 'package:comwell_key_app/contact/repository/contact_repository.dart';
+import 'package:comwell_key_app/domain/models/user.dart';
import 'package:comwell_key_app/overview/repository/overview_repository.dart';
-import 'package:comwell_key_app/profile/profile_repository.dart';
-import 'package:comwell_key_app/profile_settings/model/user.dart';
+import 'package:comwell_key_app/domain/repositories/profile_repository.dart';
import 'package:comwell_key_app/utils/phone_utils.dart';
import 'package:country_code_picker/country_code_picker.dart';
import 'package:equatable/equatable.dart';
diff --git a/comwell_key_app/lib/database/daos/user_dao.dart b/comwell_key_app/lib/database/daos/user_dao.dart
index aa618d81..eaa1c814 100644
--- a/comwell_key_app/lib/database/daos/user_dao.dart
+++ b/comwell_key_app/lib/database/daos/user_dao.dart
@@ -1,7 +1,7 @@
import 'dart:convert';
import 'package:comwell_key_app/database/comwell_db.dart';
-import 'package:comwell_key_app/profile_settings/model/user.dart';
+import 'package:comwell_key_app/domain/models/user.dart';
import 'package:comwell_key_app/services/mappers/user_mapper.dart';
import 'package:comwell_key_app/services/models/user_dto.dart';
import 'package:comwell_key_app/utils/json.dart';
diff --git a/comwell_key_app/lib/domain/models/address.dart b/comwell_key_app/lib/domain/models/address.dart
new file mode 100644
index 00000000..a8866aba
--- /dev/null
+++ b/comwell_key_app/lib/domain/models/address.dart
@@ -0,0 +1,13 @@
+import 'package:freezed_annotation/freezed_annotation.dart';
+
+part '../../.generated/domain/models/address.freezed.dart';
+
+@freezed
+abstract class Address with _$Address {
+ const factory Address({
+ @Default("") String street,
+ @Default("") String city,
+ @Default("") String country,
+ @Default("") String zipCode,
+ }) = _Address;
+}
diff --git a/comwell_key_app/lib/domain/models/user.dart b/comwell_key_app/lib/domain/models/user.dart
new file mode 100644
index 00000000..bcf966a6
--- /dev/null
+++ b/comwell_key_app/lib/domain/models/user.dart
@@ -0,0 +1,35 @@
+import 'package:comwell_key_app/domain/models/address.dart';
+
+import 'package:freezed_annotation/freezed_annotation.dart';
+
+part '../../.generated/domain/models/user.freezed.dart';
+
+@freezed
+abstract class User with _$User {
+ const factory User({
+ @Default("") String userId,
+ @Default("") String hmsId,
+ @Default("") String firstName,
+ @Default("") String lastName,
+ @Default("") String addressCountry,
+ @Default("") String phoneNumber,
+ @Default("") String email,
+ @Default("") String shopperReference,
+ @Default("") String gender,
+ @Default("") String companyId,
+ @Default("") String companyName,
+ @Default("") String symplifyId,
+ @Default("") String signUpCampaign,
+ @Default("") String signUpSource,
+ @Default("") String locale,
+ @Default("") String nationality,
+ @Default(false) bool emailVerified,
+ @Default(false) bool isClubMember,
+ @Default(false) bool wasRecentlyCreated,
+ @Default(Address()) Address address,
+ @Default(0) int points,
+ DateTime? birthDate,
+ DateTime? createDate,
+ DateTime? signUpDate,
+ }) = _User;
+}
diff --git a/comwell_key_app/lib/domain/repositories/profile_repository.dart b/comwell_key_app/lib/domain/repositories/profile_repository.dart
new file mode 100644
index 00000000..e6fda2c0
--- /dev/null
+++ b/comwell_key_app/lib/domain/repositories/profile_repository.dart
@@ -0,0 +1,88 @@
+import 'package:comwell_key_app/authentication/authentication_repository.dart';
+import 'package:comwell_key_app/database/comwell_db.dart';
+import 'package:comwell_key_app/domain/models/user.dart';
+import 'package:comwell_key_app/services/api.dart';
+import 'package:comwell_key_app/services/mappers/user_mapper.dart';
+import 'package:comwell_key_app/services/models/user_dto.dart';
+import 'package:comwell_key_app/utils/json.dart';
+import 'package:comwell_key_app/utils/locator.dart';
+import 'package:flutter/material.dart';
+
+class ProfileRepository {
+ final AuthenticationRepository _authenticationRepository;
+ final Api _api;
+
+ ProfileRepository(
+ this._authenticationRepository,
+ this._api,
+ );
+
+ Future<void> logOut() async {
+ await _authenticationRepository.logOut();
+ }
+
+ Future<User> signupForComwellClub(User user) async {
+ try {
+ await _api.signupForComwellClub();
+ return await _updateAndPersistUser(user);
+ } catch (e, st) {
+ debugPrint('Error during Comwell Club signup: $e');
+ debugPrintStack(stackTrace: st);
+ rethrow;
+ }
+ }
+
+ Future<User> _updateAndPersistUser(User user) async {
+ final userResponse = await _api.updateUser(user.toSimpleUserDto());
+ final data = userResponse.data as Json;
+ final userDto = UserDto.fromJson(data);
+ final updatedUser = userDto.toUser();
+ await locator<ComwellDatabase>().userDAO.saveUser(userDto);
+ return updatedUser;
+ }
+
+ Future<User> fetchRemoteProfile() async {
+ final response = await _api.fetchProfileSettings();
+ final data = response.data as Json;
+ final userDto = UserDto.fromJson(data);
+ final user = userDto.toUser();
+ return user;
+ }
+
+ Future<User?> _checkIfProfileSettingsExists() async {
+ try {
+ final user = await locator<ComwellDatabase>().userDAO.getUser();
+ return user;
+ } catch (e) {
+ debugPrint("Error checking if profile settings exists: $e");
+ return null;
+ }
+ }
+
+ Future<User> _fetchAndSaveProfileSettingsToDatabase() async {
+ try {
+ final response = await _api.fetchProfileSettings();
+ final data = response.data as Json;
+ final userDto = UserDto.fromJson(data);
+ final user = userDto.toUser();
+ await locator<ComwellDatabase>().userDAO.saveUser(userDto);
+ return user;
+ } catch (e) {
+ debugPrint("Error fetching profile settings: $e");
+ rethrow;
+ }
+ }
+
+ Future<User> fetchProfileSettings({bool fetchRemote = false}) async {
+ if (fetchRemote) {
+ final user = await fetchRemoteProfile();
+ return user;
+ }
+ final user = await _checkIfProfileSettingsExists();
+ if (user != null) {
+ return user;
+ }
+ final newUser = await _fetchAndSaveProfileSettingsToDatabase();
+ return newUser;
+ }
+}
diff --git a/comwell_key_app/lib/domain/repositories/profile_settings_repository.dart b/comwell_key_app/lib/domain/repositories/profile_settings_repository.dart
new file mode 100644
index 00000000..c301a793
--- /dev/null
+++ b/comwell_key_app/lib/domain/repositories/profile_settings_repository.dart
@@ -0,0 +1,31 @@
+import 'package:comwell_key_app/database/comwell_db.dart';
+import 'package:comwell_key_app/domain/models/user.dart';
+import 'package:comwell_key_app/services/api.dart';
+import 'package:comwell_key_app/services/mappers/user_mapper.dart';
+import 'package:comwell_key_app/services/models/user_dto.dart';
+
+import 'package:comwell_key_app/utils/json.dart';
+import 'package:comwell_key_app/utils/locator.dart';
+
+class ProfileSettingsRepository {
+ final Api api = Api();
+
+ Future<User> updateUser(User updatedUser) async {
+ final userDto = updatedUser.toSimpleUserDto();
+ final response = await api.updateUser(userDto);
+ final data = response.data as Json;
+ final responseDto = UserDto.fromJson(data);
+ final user = responseDto.toUser();
+ await locator<ComwellDatabase>().userDAO.saveUser(responseDto);
+ return user;
+ }
+
+ Future<void> updateAddress(User updatedUser) async {
+ final userDto = updatedUser.toUserDto();
+ await locator<ComwellDatabase>().userDAO.saveUser(userDto);
+ }
+
+ Future<void> deleteProfile() {
+ return api.deleteProfile();
+ }
+}
diff --git a/comwell_key_app/lib/my_booking/cubit/my_booking_cubit.dart b/comwell_key_app/lib/my_booking/cubit/my_booking_cubit.dart
index 07722137..0d6c6df7 100644
--- a/comwell_key_app/lib/my_booking/cubit/my_booking_cubit.dart
+++ b/comwell_key_app/lib/my_booking/cubit/my_booking_cubit.dart
@@ -2,7 +2,7 @@ import 'package:comwell_key_app/my_booking/cubit/my_booking_state.dart';
import 'package:comwell_key_app/my_booking/my_booking_repository.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
-import 'package:comwell_key_app/profile/profile_repository.dart';
+import 'package:comwell_key_app/domain/repositories/profile_repository.dart';
import 'package:comwell_key_app/profile/utils/urls.dart';
import 'package:comwell_key_app/tracking/comwell_tracking.dart';
import 'package:comwell_key_app/tracking/models/analytics_event_item.dart';
diff --git a/comwell_key_app/lib/my_booking/my_booking_repository.dart b/comwell_key_app/lib/my_booking/my_booking_repository.dart
index 898b9687..b5f57b89 100644
--- a/comwell_key_app/lib/my_booking/my_booking_repository.dart
+++ b/comwell_key_app/lib/my_booking/my_booking_repository.dart
@@ -1,5 +1,5 @@
-import 'package:comwell_key_app/profile/profile_repository.dart';
-import 'package:comwell_key_app/profile_settings/model/user.dart';
+import 'package:comwell_key_app/domain/models/user.dart';
+import 'package:comwell_key_app/domain/repositories/profile_repository.dart';
import 'package:comwell_key_app/services/api.dart';
import 'package:comwell_key_app/utils/locator.dart';
diff --git a/comwell_key_app/lib/pregistration/cubit/preregistration_cubit.dart b/comwell_key_app/lib/pregistration/cubit/preregistration_cubit.dart
index a554066e..4c727af7 100644
--- a/comwell_key_app/lib/pregistration/cubit/preregistration_cubit.dart
+++ b/comwell_key_app/lib/pregistration/cubit/preregistration_cubit.dart
@@ -4,9 +4,9 @@ import 'package:comwell_key_app/pregistration/cubit/preregistration_state.dart';
import 'package:comwell_key_app/pregistration/prereg_request_model.dart';
import 'package:comwell_key_app/pregistration/pregistration_repository.dart';
import 'package:comwell_key_app/pregistration/utils/utils.dart';
-import 'package:comwell_key_app/profile/profile_repository.dart';
-import 'package:comwell_key_app/profile_settings/model/address.dart';
-import 'package:comwell_key_app/profile_settings/repostiory/profile_settings_repository.dart';
+import 'package:comwell_key_app/domain/repositories/profile_repository.dart';
+import 'package:comwell_key_app/domain/models/address.dart';
+import 'package:comwell_key_app/domain/repositories/profile_settings_repository.dart';
import 'package:comwell_key_app/tracking/comwell_tracking.dart';
import 'package:comwell_key_app/tracking/models/analytics_event_item.dart';
import 'package:comwell_key_app/up_sales/models/addon_list.dart';
@@ -300,7 +300,7 @@ class PreregistrationCubit extends Cubit<PreregistrationState> {
lastName: state.user!.lastName,
email: state.user!.email,
phoneNumber: state.user!.phoneNumber,
- birthDay: state.user!.birthDate.toIso8601String(),
+ birthDay: state.user!.birthDate!.toIso8601String() ?? "",
address: state.user!.address.street,
zipCode: state.user!.address.zipCode,
city: state.user!.address.city,
diff --git a/comwell_key_app/lib/pregistration/cubit/preregistration_state.dart b/comwell_key_app/lib/pregistration/cubit/preregistration_state.dart
index 726174ac..0c7b25ca 100644
--- a/comwell_key_app/lib/pregistration/cubit/preregistration_state.dart
+++ b/comwell_key_app/lib/pregistration/cubit/preregistration_state.dart
@@ -1,4 +1,5 @@
+import 'package:comwell_key_app/domain/models/user.dart';
import 'package:comwell_key_app/up_sales/models/addon_upgrade.dart';
import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
import 'package:comwell_key_app/up_sales/models/up_sales.dart';
@@ -7,8 +8,6 @@ import 'package:country_code_picker/country_code_picker.dart';
import 'package:equatable/equatable.dart';
import 'package:payment_plugin/domain/models/stored_payment_method.dart';
-import '../../profile_settings/model/user.dart';
-
class PreregistrationState extends Equatable {
final bool isLoading;
final bool selected;
diff --git a/comwell_key_app/lib/pregistration/pages/prereg_profile_page.dart b/comwell_key_app/lib/pregistration/pages/prereg_profile_page.dart
index fcf30da7..e35ce57c 100644
--- a/comwell_key_app/lib/pregistration/pages/prereg_profile_page.dart
+++ b/comwell_key_app/lib/pregistration/pages/prereg_profile_page.dart
@@ -1,5 +1,4 @@
import 'package:comwell_key_app/common/components/comwell_text_field.dart';
-import 'package:comwell_key_app/profile_settings/components/intl_phone_field.dart';
import 'package:comwell_key_app/pregistration/cubit/preregistration_cubit.dart';
import 'package:comwell_key_app/pregistration/cubit/preregistration_state.dart';
import 'package:comwell_key_app/utils/l10n_utils.dart';
@@ -7,6 +6,7 @@ import 'package:country_code_picker/country_code_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../common/components/shimmer_loader/prereg_profile_shimmer_loader.dart';
+import '../../presentation/screens/profile_settings/components/intl_phone_field.dart';
class PreregProfilePage extends StatelessWidget {
const PreregProfilePage({super.key});
diff --git a/comwell_key_app/lib/pregistration/pregistration_repository.dart b/comwell_key_app/lib/pregistration/pregistration_repository.dart
index ca97b728..5f6f96d8 100644
--- a/comwell_key_app/lib/pregistration/pregistration_repository.dart
+++ b/comwell_key_app/lib/pregistration/pregistration_repository.dart
@@ -1,5 +1,5 @@
import 'package:comwell_key_app/pregistration/prereg_request_model.dart';
-import 'package:comwell_key_app/profile_settings/repostiory/profile_settings_repository.dart';
+import 'package:comwell_key_app/domain/repositories/profile_settings_repository.dart';
import 'package:comwell_key_app/services/api.dart';
import 'package:comwell_key_app/utils/locator.dart';
import 'package:flutter/material.dart';
diff --git a/comwell_key_app/lib/presentation/app/app_cubit.dart b/comwell_key_app/lib/presentation/app/app_cubit.dart
deleted file mode 100644
index ec368dff..00000000
--- a/comwell_key_app/lib/presentation/app/app_cubit.dart
+++ /dev/null
@@ -1,33 +0,0 @@
-import 'dart:async';
-
-import 'package:app_links/app_links.dart';
-import 'package:comwell_key_app/base/base_cubit.dart';
-import 'package:comwell_key_app/presentation/app/app_events.dart';
-import 'package:comwell_key_app/presentation/app/app_state.dart';
-import 'package:comwell_key_app/utils/uri_utils.dart';
-
-class AppCubit extends BaseCubit<AppState> {
- AppCubit() : super(const AppState()) {
- _init();
- }
-
- late final StreamSubscription<Uri> _appLinksSubscription;
-
- void _init() {
- _appLinksSubscription = AppLinks().uriLinkStream.listen((uri) async {
- if (uri.isDeeplink) {
- navigate(uri);
- }
- });
- }
-
- void navigate(Uri uri) {
- safeEmit(state.copyWith(event: Navigate(uri)));
- }
-
- @override
- Future<void> close() async {
- await _appLinksSubscription.cancel();
- return super.close();
- }
-}
diff --git a/comwell_key_app/lib/presentation/app/app_event_listener.dart b/comwell_key_app/lib/presentation/app/app_event_listener.dart
index 83094ae8..a9b0a21b 100644
--- a/comwell_key_app/lib/presentation/app/app_event_listener.dart
+++ b/comwell_key_app/lib/presentation/app/app_event_listener.dart
@@ -1,9 +1,8 @@
import 'dart:async';
import 'package:comwell_key_app/authentication/authentication_repository.dart';
-import 'package:comwell_key_app/presentation/app/app_cubit.dart';
+import 'package:comwell_key_app/presentation/app/bloc/app_cubit.dart';
import 'package:comwell_key_app/presentation/app/app_events.dart';
-import 'package:comwell_key_app/presentation/app/app_state.dart';
import 'package:comwell_key_app/presentation/screens/login/login_route.dart';
import 'package:comwell_key_app/utils/locator.dart';
import 'package:flutter/material.dart';
diff --git a/comwell_key_app/lib/presentation/app/app_state.dart b/comwell_key_app/lib/presentation/app/app_state.dart
deleted file mode 100644
index 15fa67fd..00000000
--- a/comwell_key_app/lib/presentation/app/app_state.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-import 'package:comwell_key_app/domain/models/app_error.dart';
-import 'package:comwell_key_app/presentation/app/app_events.dart';
-import 'package:freezed_annotation/freezed_annotation.dart';
-
-part '../../.generated/presentation/app/app_state.freezed.dart';
-
-@freezed
-abstract class AppState with _$AppState {
- const factory AppState({
- @Default(false) bool isLoading,
- @Default(AppError.none) AppError error,
- @Default(null) AppEvent? event,
- }) = _AppState;
-}
\ No newline at end of file
diff --git a/comwell_key_app/lib/presentation/app/bloc/app_cubit.dart b/comwell_key_app/lib/presentation/app/bloc/app_cubit.dart
new file mode 100644
index 00000000..6074bae9
--- /dev/null
+++ b/comwell_key_app/lib/presentation/app/bloc/app_cubit.dart
@@ -0,0 +1,45 @@
+import 'dart:async';
+
+import 'package:app_links/app_links.dart';
+import 'package:comwell_key_app/base/base_cubit.dart';
+import 'package:comwell_key_app/presentation/app/app_events.dart';
+import 'package:comwell_key_app/utils/uri_utils.dart';
+import 'package:comwell_key_app/domain/models/app_error.dart';
+import 'package:freezed_annotation/freezed_annotation.dart';
+
+part '../../../.generated/presentation/app/bloc/app_cubit.freezed.dart';
+
+class AppCubit extends BaseCubit<AppState> {
+ AppCubit() : super(const AppState()) {
+ _init();
+ }
+
+ late final StreamSubscription<Uri> _appLinksSubscription;
+
+ void _init() {
+ _appLinksSubscription = AppLinks().uriLinkStream.listen((uri) async {
+ if (uri.isDeeplink) {
+ navigate(uri);
+ }
+ });
+ }
+
+ void navigate(Uri uri) {
+ safeEmit(state.copyWith(event: Navigate(uri)));
+ }
+
+ @override
+ Future<void> close() async {
+ await _appLinksSubscription.cancel();
+ return super.close();
+ }
+}
+
+@freezed
+abstract class AppState with _$AppState {
+ const factory AppState({
+ @Default(false) bool isLoading,
+ @Default(AppError.none) AppError error,
+ @Default(null) AppEvent? event,
+ }) = _AppState;
+}
\ No newline at end of file
diff --git a/comwell_key_app/lib/presentation/app/bloc/profile_cubit.dart b/comwell_key_app/lib/presentation/app/bloc/profile_cubit.dart
new file mode 100644
index 00000000..eaa8a706
--- /dev/null
+++ b/comwell_key_app/lib/presentation/app/bloc/profile_cubit.dart
@@ -0,0 +1,120 @@
+import 'package:comwell_key_app/authentication/authentication_repository.dart';
+import 'package:comwell_key_app/base/base_cubit.dart';
+import 'package:comwell_key_app/domain/models/user.dart';
+import 'package:comwell_key_app/domain/repositories/profile_repository.dart';
+import 'package:firebase_analytics/firebase_analytics.dart';
+import 'package:freezed_annotation/freezed_annotation.dart';
+import 'package:package_info_plus/package_info_plus.dart';
+import '../../../domain/models/app_error.dart';
+
+part '../../../.generated/presentation/app/bloc/profile_cubit.freezed.dart';
+
+class ProfileCubit extends BaseCubit<ProfileState> {
+ final ProfileRepository _profileRepository;
+ final AuthenticationRepository _authenticationRepository;
+
+ ProfileCubit(
+ this._profileRepository,
+ this._authenticationRepository,
+ ) : super(const ProfileState()) {
+ init();
+ }
+
+ void sendPageViewEvent() async {
+ await FirebaseAnalytics.instance.logScreenView(
+ screenName: 'Profile',
+ screenClass: '/profile',
+ );
+ }
+
+ Future<String> getVersion() async {
+ final packageInfo = await PackageInfo.fromPlatform();
+ return packageInfo.version;
+ }
+
+ void logOutPressed() {
+ _authenticationRepository.logOut();
+ safeEmit(const ProfileState());
+ }
+
+ void init() async {
+ try {
+ safeEmit(state.loading());
+ final user = await _profileRepository.fetchProfileSettings();
+ sendPageViewEvent();
+ safeEmit(state.copyWith(user: user));
+ } catch (e, st) {
+ logError(e, st);
+ safeEmit(state.copyWith(error: AppError.unknown(e.toString())));
+ } finally {
+ safeEmit(state.copyWith(isLoading: false));
+ }
+ }
+
+ void fetchRemoteProfile() async {
+ safeEmit(state.loading());
+ try {
+ final user = await _profileRepository.fetchProfileSettings(fetchRemote: true);
+ safeEmit(state.copyWith(user: user));
+ } catch (e, st) {
+ logError(e, st);
+ safeEmit(state.copyWith(error: AppError.unknown(e.toString())));
+ } finally {
+ safeEmit(state.copyWith(isLoading: false));
+ }
+ }
+
+ void onToSClick(bool? value) async {
+ emit(state.copyWith(isToSAccepted: value!));
+ }
+
+ void onNewsletterClick(bool? value) async {
+ emit(state.copyWith(isNewsletterAccepted: value!));
+ }
+
+ String getGender(String gender) {
+ switch (gender) {
+ case 'Male':
+ return 'M';
+ case 'Female':
+ return 'F';
+ default:
+ return 'O';
+ }
+ }
+
+ void updateUser(User user) {
+ safeEmit(state.copyWith(user: user));
+ }
+
+ Future<bool> onComwellClubSignupClick(User user) async {
+ try {
+ if (!state.isToSAccepted) return false;
+ safeEmit(state.loading());
+ User updatedUser = await _profileRepository.signupForComwellClub(user);
+ safeEmit(state.copyWith(user: updatedUser));
+ return true;
+ } catch (e, st) {
+ logError(e, st);
+ safeEmit(state.copyWith(error: AppError.unknown(e.toString())));
+ return false;
+ } finally {
+ safeEmit(state.copyWith(isLoading: false));
+ }
+ }
+}
+
+@freezed
+abstract class ProfileState with _$ProfileState {
+ const factory ProfileState({
+ @Default(false) bool isLoading,
+ @Default(AppError.none) AppError error,
+ @Default(User()) User user,
+ @Default(false) bool isToSAccepted,
+ @Default(false) bool isNewsletterAccepted,
+ }) = _ProfileState;
+
+ const ProfileState._();
+
+ ProfileState loading() => copyWith(isLoading: true, error: AppError.none);
+}
diff --git a/comwell_key_app/lib/presentation/screens/booking_details/bloc/booking_details_cubit.dart b/comwell_key_app/lib/presentation/screens/booking_details/bloc/booking_details_cubit.dart
index 97da729a..85e952c9 100644
--- a/comwell_key_app/lib/presentation/screens/booking_details/bloc/booking_details_cubit.dart
+++ b/comwell_key_app/lib/presentation/screens/booking_details/bloc/booking_details_cubit.dart
@@ -1,4 +1,5 @@
import 'dart:async';
+import 'package:comwell_key_app/domain/models/user.dart';
import 'package:comwell_key_app/domain/repositories/booking_details_repository.dart';
import 'package:comwell_key_app/domain/models/app_error.dart';
import 'package:comwell_key_app/housekeeping/components/housekeeping_service.dart';
@@ -7,8 +8,7 @@ import 'package:comwell_key_app/housekeeping/models/housekeeping.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/presentation/base/base_cubit.dart';
import 'package:comwell_key_app/presentation/screens/booking_details/bloc/booking_details_state.dart';
-import 'package:comwell_key_app/profile/profile_repository.dart';
-import 'package:comwell_key_app/profile_settings/model/user.dart';
+import 'package:comwell_key_app/domain/repositories/profile_repository.dart';
import 'package:comwell_key_app/share/share_booking_repository.dart';
import 'package:comwell_key_app/up_sales/up_sales_repository.dart';
import 'package:comwell_key_app/utils/seos_repository.dart';
diff --git a/comwell_key_app/lib/presentation/screens/login/bloc/login_cubit.dart b/comwell_key_app/lib/presentation/screens/login/bloc/login_cubit.dart
index 009f67ad..c7c626ea 100644
--- a/comwell_key_app/lib/presentation/screens/login/bloc/login_cubit.dart
+++ b/comwell_key_app/lib/presentation/screens/login/bloc/login_cubit.dart
@@ -1,5 +1,5 @@
import 'package:comwell_key_app/authentication/authentication_repository.dart';
-import 'package:comwell_key_app/presentation/app/app_cubit.dart';
+import 'package:comwell_key_app/presentation/app/bloc/app_cubit.dart';
import 'package:comwell_key_app/presentation/base/base_cubit.dart';
import 'package:comwell_key_app/presentation/screens/login/bloc/login_state.dart';
import 'package:comwell_key_app/routing/app_routes.dart';
diff --git a/comwell_key_app/lib/presentation/screens/profile_settings/bloc/profile_settings_cubit.dart b/comwell_key_app/lib/presentation/screens/profile_settings/bloc/profile_settings_cubit.dart
new file mode 100644
index 00000000..4444e7e9
--- /dev/null
+++ b/comwell_key_app/lib/presentation/screens/profile_settings/bloc/profile_settings_cubit.dart
@@ -0,0 +1,116 @@
+import 'package:comwell_key_app/domain/models/app_error.dart';
+import 'package:comwell_key_app/domain/models/user.dart';
+import 'package:comwell_key_app/presentation/app/bloc/profile_cubit.dart';
+import 'package:comwell_key_app/presentation/base/base_cubit.dart';
+import 'package:comwell_key_app/presentation/screens/profile_settings/bloc/profile_settings_state.dart';
+import 'package:comwell_key_app/domain/repositories/profile_settings_repository.dart';
+import 'package:comwell_key_app/tracking/comwell_tracking.dart';
+import 'package:comwell_key_app/utils/phone_utils.dart';
+import 'package:country_code_picker/country_code_picker.dart';
+import 'package:flutter/cupertino.dart';
+
+import '../../../../authentication/authentication_repository.dart';
+import '../../../../domain/repositories/profile_repository.dart';
+import '../../../../domain/models/address.dart';
+
+class ProfileSettingsCubit extends BaseCubit<ProfileSettingsState> {
+ final ProfileRepository _profileRepository;
+ final AuthenticationRepository _authenticationRepository;
+ final ProfileSettingsRepository _profileSettingsRepository;
+ final ComwellTracking _comwellTracking;
+ final ProfileCubit _profileCubit;
+ final TextEditingController firstNameController = TextEditingController();
+ final TextEditingController lastNameController = TextEditingController();
+ final TextEditingController phoneNumberController = TextEditingController();
+ late String selectedCountry = '';
+ CountryCode? countryCode;
+ String? phoneNumber;
+
+ User get user => _profileCubit.state.user;
+
+ ProfileSettingsCubit(
+ this._profileRepository,
+ this._authenticationRepository,
+ this._profileCubit,
+ this._profileSettingsRepository,
+ this._comwellTracking,
+ ) : super(const ProfileSettingsState()) {
+ init();
+ }
+
+ void init() async {
+ try {
+ safeEmit(state.loading());
+ final user = await _profileRepository.fetchProfileSettings();
+ countryCode = getCountryCodeFromPhoneNumber(user.phoneNumber).$1;
+ phoneNumber = getCountryCodeFromPhoneNumber(user.phoneNumber).$2;
+
+ firstNameController.text = user.firstName;
+ lastNameController.text = user.lastName;
+
+ phoneNumberController.text = user.phoneNumber;
+ selectedCountry = user.addressCountry != '' ? user.addressCountry : 'DK';
+
+ phoneNumberController.text = phoneNumber!;
+ } catch (e, st) {
+ logError(e, st);
+ safeEmit(state.copyWith(error: AppError.unknown(e.toString())));
+ } finally {
+ safeEmit(state.copyWith(isLoading: false));
+ }
+ }
+
+ void deleteProfile() async {
+ try {
+ await _profileSettingsRepository.deleteProfile();
+ _comwellTracking.trackEvent('delete_profile');
+ await _authenticationRepository.logOut();
+ safeEmit(state.copyWith(isDeleted: true));
+ } catch (e, st) {
+ logError(e, st);
+ safeEmit(state.copyWith(error: AppError.unknown(e.toString())));
+ } finally {
+ safeEmit(state.copyWith(isLoading: false));
+ }
+ }
+
+ void updateBirthDate(DateTime birthDate) {
+ final updatedUser = user.copyWith(birthDate: birthDate);
+ _profileCubit.updateUser(updatedUser);
+ }
+
+ void updateAddress(Address address) {
+ final updatedUser = user.copyWith(address: address);
+ _profileCubit.updateUser(updatedUser);
+ }
+
+ void updateProfile() async {
+ try {
+ safeEmit(state.loading());
+ final phoneNumber = concatCountryCodeAndPhoneNumber(countryCode!, phoneNumberController.text);
+ final updatedUser = user.copyWith(phoneNumber: phoneNumber);
+ await _profileSettingsRepository.updateUser(updatedUser);
+ _profileCubit.updateUser(updatedUser);
+ } catch (e, st) {
+ logError(e, st);
+ safeEmit(state.copyWith(error: AppError.unknown(e.toString())));
+ } finally {
+ safeEmit(state.copyWith(isLoading: false));
+ }
+ }
+
+ void updateLastName(String value) {
+ final updatedUser = user.copyWith(lastName: value);
+ _profileCubit.updateUser(updatedUser);
+ }
+
+ void updateFirstName(String value) {
+ final updatedUser = user.copyWith(firstName: value);
+ _profileCubit.updateUser(updatedUser);
+ }
+
+ void updatePhoneNumber(String value) {
+ final updatedUser = user.copyWith(phoneNumber: value);
+ _profileCubit.updateUser(updatedUser);
+ }
+}
diff --git a/comwell_key_app/lib/presentation/screens/profile_settings/bloc/profile_settings_state.dart b/comwell_key_app/lib/presentation/screens/profile_settings/bloc/profile_settings_state.dart
new file mode 100644
index 00000000..a57f8185
--- /dev/null
+++ b/comwell_key_app/lib/presentation/screens/profile_settings/bloc/profile_settings_state.dart
@@ -0,0 +1,17 @@
+import 'package:comwell_key_app/domain/models/app_error.dart';
+import 'package:freezed_annotation/freezed_annotation.dart';
+
+part '../../../../.generated/presentation/screens/profile_settings/bloc/profile_settings_state.freezed.dart';
+
+@freezed
+abstract class ProfileSettingsState with _$ProfileSettingsState {
+ const factory ProfileSettingsState({
+ @Default(false) bool isLoading,
+ @Default(AppError.none) AppError error,
+ @Default(false) bool isDeleted,
+ }) = _ProfileSettingsState;
+
+ const ProfileSettingsState._();
+
+ ProfileSettingsState loading() => copyWith(isLoading: true, error: AppError.none);
+}
diff --git a/comwell_key_app/lib/presentation/screens/profile_settings/components/address_bottom_sheet.dart b/comwell_key_app/lib/presentation/screens/profile_settings/components/address_bottom_sheet.dart
new file mode 100644
index 00000000..ffca60d4
--- /dev/null
+++ b/comwell_key_app/lib/presentation/screens/profile_settings/components/address_bottom_sheet.dart
@@ -0,0 +1,186 @@
+import 'package:comwell_key_app/common/components/round_icon_button.dart';
+import 'package:comwell_key_app/domain/models/user.dart';
+import 'package:comwell_key_app/domain/models/address.dart';
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:comwell_key_app/utils/l10n_utils.dart';
+import 'package:country_code_picker/country_code_picker.dart';
+import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
+
+import 'comwell_text_field.dart';
+
+class AddressBottomSheet extends StatefulWidget {
+ final User user;
+ final String selectedCountry;
+
+ const AddressBottomSheet({
+ required this.user,
+ required this.selectedCountry,
+ super.key,
+ });
+
+ @override
+ State<AddressBottomSheet> createState() => _AddressBottomSheetState();
+}
+
+class _AddressBottomSheetState extends State<AddressBottomSheet> {
+ late final TextEditingController _addressController;
+ late final TextEditingController _zipCodeController;
+ late final TextEditingController _cityController;
+ String _selectedCountry = '';
+
+ @override
+ void initState() {
+ super.initState();
+ _addressController = TextEditingController(text: widget.user.address.street);
+ _zipCodeController = TextEditingController(text: widget.user.address.zipCode);
+ _cityController = TextEditingController(text: widget.user.address.city);
+ _selectedCountry = widget.user.address.country.isNotEmpty ? widget.user.address.country : 'DK';
+ }
+
+ @override
+ void dispose() {
+ _addressController.dispose();
+ _zipCodeController.dispose();
+ _cityController.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+
+ return Wrap(
+ children: [
+ Padding(
+ padding: MediaQuery.of(context).viewInsets,
+ child: Container(
+ decoration: const BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.only(
+ topLeft: Radius.circular(24),
+ topRight: Radius.circular(24),
+ ),
+ ),
+ height: MediaQuery.of(context).copyWith().size.height * 0.7,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(top: 40, left: 16),
+ child: Container(
+ height: 47,
+ color: Colors.white,
+ child: Stack(
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ context.strings.profile_settings_address,
+ style: theme.textTheme.headlineLarge,
+ ),
+ RoundIconButton(
+ icon: 'assets/icons/close-icon.svg',
+ color: sandColor[20]!,
+ onPressed: () {
+ context.pop();
+ },
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ const SizedBox(height: 24),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: ComwellTextField(
+ fieldName: context.strings.profile_settings_address,
+ initialValue: widget.user.address.street,
+ readOnly: false,
+ controller: _addressController,
+ ),
+ ),
+ const SizedBox(height: 8),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: ComwellTextField(
+ fieldName: context.strings.zipCode,
+ initialValue: widget.user.address.zipCode,
+ readOnly: false,
+ controller: _zipCodeController,
+ ),
+ ),
+ const SizedBox(height: 8),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: ComwellTextField(
+ fieldName: context.strings.city,
+ initialValue: widget.user.address.city,
+ readOnly: false,
+ controller: _cityController,
+ ),
+ ),
+ const SizedBox(height: 8),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: Container(
+ height: 62,
+ width: double.infinity,
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(8),
+ border: Border.all(color: colorDivider),
+ ),
+ child: CountryCodePicker(
+ alignLeft: true,
+ textOverflow: TextOverflow.visible,
+ initialSelection: _selectedCountry,
+ showFlag: true,
+ favorite: const ['DK', 'SE', 'NO', 'DE'],
+ showDropDownButton: true,
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ textStyle: Theme.of(context).textTheme.headlineSmall,
+ showCountryOnly: true,
+ showOnlyCountryWhenClosed: true,
+ onChanged: (CountryCode countryCode) {
+ setState(() {
+ _selectedCountry = countryCode.name ?? '';
+ });
+ },
+ ),
+ ),
+ ),
+ const Spacer(),
+ const Divider(color: colorDivider),
+ const SizedBox(height: 10),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: ElevatedButton(
+ onPressed: () async {
+ final address = Address(
+ street: _addressController.text,
+ zipCode: _zipCodeController.text,
+ city: _cityController.text,
+ country: _selectedCountry,
+ );
+ context.pop(address);
+ },
+ child: Text(
+ context.strings.save,
+ style: theme.textTheme.headlineSmall?.copyWith(
+ color: Colors.white,
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(height: 40),
+ ],
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/comwell_key_app/lib/presentation/screens/profile_settings/components/comwell_text_field.dart b/comwell_key_app/lib/presentation/screens/profile_settings/components/comwell_text_field.dart
new file mode 100644
index 00000000..4a2d2c76
--- /dev/null
+++ b/comwell_key_app/lib/presentation/screens/profile_settings/components/comwell_text_field.dart
@@ -0,0 +1,74 @@
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:flutter/material.dart';
+
+class ComwellTextField extends StatefulWidget {
+ final String fieldName;
+ final String initialValue;
+ final bool readOnly;
+ final TextEditingController controller;
+ final void Function(String)? onSubmitted;
+ const ComwellTextField({
+ super.key,
+ required this.fieldName,
+ required this.initialValue,
+ required this.readOnly,
+ required this.controller,
+ this.onSubmitted,
+ });
+ @override
+ ComwellTextFieldState createState() => ComwellTextFieldState();
+}
+
+class ComwellTextFieldState extends State<ComwellTextField> {
+ late FocusNode _focusNode;
+ bool _isFocused = false;
+
+ @override
+ void initState() {
+ super.initState();
+
+ _focusNode = FocusNode();
+
+ _focusNode.addListener(() {
+ setState(() {
+ _isFocused = _focusNode.hasFocus;
+ });
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ return Container(
+ height: 62,
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(8),
+ border: Border.all(color: colorDivider),
+ ),
+ child: Center(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 10),
+ child: TextField(
+ readOnly: widget.readOnly,
+ controller: widget.controller,
+ focusNode: _focusNode,
+ decoration: InputDecoration(
+ label: Text(widget.fieldName,
+ style: _isFocused && !widget.readOnly
+ ? theme.textTheme.bodySmall?.copyWith(
+ color: colorHeadlineText)
+ : theme.textTheme.headlineSmall
+ ?.copyWith(color: colorTertiary)),
+ isDense: true,
+ border: InputBorder.none,
+ contentPadding: const EdgeInsets.symmetric(vertical: 0),
+
+ ),
+ style: !widget.readOnly ? theme.textTheme.headlineSmall : theme.textTheme.headlineSmall?.copyWith(color: colorHeadlineText),
+ onSubmitted: widget.onSubmitted,
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/presentation/screens/profile_settings/components/date_time_picker.dart b/comwell_key_app/lib/presentation/screens/profile_settings/components/date_time_picker.dart
new file mode 100644
index 00000000..c30f547d
--- /dev/null
+++ b/comwell_key_app/lib/presentation/screens/profile_settings/components/date_time_picker.dart
@@ -0,0 +1,147 @@
+import 'package:comwell_key_app/presentation/screens/profile_settings/bloc/profile_settings_cubit.dart';
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:comwell_key_app/utils/l10n_utils.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:comwell_key_app/common/components/generic_dialog.dart';
+import 'package:intl/intl.dart';
+
+class DateTimePicker extends StatefulWidget {
+ final String title;
+ final DateTime initialValue;
+ const DateTimePicker(
+ {required this.title, required this.initialValue, super.key});
+
+ @override
+ State<DateTimePicker> createState() => _DatePickerState();
+}
+
+class _DatePickerState extends State<DateTimePicker> {
+ DateTime? _selectedDate;
+
+ DateTime get _maxDate {
+ final today = DateTime.now();
+ return DateTime(today.year - 18, today.month, today.day);
+ }
+
+ Future<void> _selectDate(BuildContext context) async {
+ final maxDate = _maxDate;
+ final initial = widget.initialValue;
+ if (initial.isAfter(maxDate)) {
+ // Show generic dialog to user
+ await showDialog<void>(
+ context: context,
+ builder: (context) => GenericDialog(
+ title: context.strings.invalid_birthday,
+ content: context.strings.invalid_birthday_description,
+ confirmButtonText: context.strings.generic_ok,
+ confirmButtonTextColor: Colors.white,
+ cancelButtonText: '',
+ onConfirm: () {
+ Navigator.of(context).pop();
+ },
+ onCancel: () {},
+ ),
+ );
+ // Delete the invalid birthday (set to default value)
+ if (context.mounted) {
+ final defaultBirthday = maxDate;
+ setState(() => _selectedDate = null);
+ context.read<ProfileSettingsCubit>().updateBirthDate(defaultBirthday);
+ // Open the date picker after dialog is closed
+ await Future<void>.delayed(const Duration(milliseconds: 100));
+ if (context.mounted) {
+ await _showValidDatePicker(context, defaultBirthday, maxDate);
+ }
+ }
+ return;
+ }
+ await _showValidDatePicker(context, initial, maxDate);
+ }
+
+ Future<void> _showValidDatePicker(
+ BuildContext context, DateTime initial, DateTime maxDate) async {
+ await showDatePicker(
+ builder: (context, child) {
+ final theme = Theme.of(context);
+ return Theme(
+ data: theme.copyWith(
+ colorScheme: ColorScheme.light(
+ primary: sandColor,
+ onPrimary: Colors.white,
+ onSurface: colorHeadlineText,
+ surface: Colors.white,
+ onError: Colors.red,
+ ),
+ textButtonTheme: TextButtonThemeData(
+ style: TextButton.styleFrom(
+ foregroundColor: colorHeadlineText,
+ overlayColor: sandColor,
+ ),
+ ),
+ ),
+ child: child!,
+ );
+ },
+ context: context,
+ initialDate: initial,
+ firstDate: DateTime(0),
+ lastDate: maxDate,
+ errorInvalidText: context.strings.profile_settings_invalid_date,
+ ).then((DateTime? selected) {
+ if (selected != null && selected != _selectedDate) {
+ setState(() => _selectedDate = selected);
+ if (context.mounted) {
+ context.read<ProfileSettingsCubit>().updateBirthDate(selected);
+ }
+ }
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ final dateFormat = DateFormat('dd/MM/yyyy');
+
+ return GestureDetector(
+ onTap: () => _selectDate(context),
+ child: Container(
+ height: 62,
+ padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 10.0),
+ decoration: BoxDecoration(
+ border: Border.all(color: colorDivider),
+ borderRadius: BorderRadius.circular(8.0),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Text(
+ widget.title,
+ textAlign: TextAlign.start,
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: colorHeadlineText,
+ ),
+ ),
+ const SizedBox(height: 0.0),
+ Text(
+ _selectedDate != null
+ ? dateFormat.format(_selectedDate!)
+ : dateFormat.format(widget.initialValue),
+ style: theme.textTheme.headlineSmall),
+ ],
+ ),
+ SvgPicture.asset(
+ "assets/icons/ic_calendar.svg",
+ height: 24.0,
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/presentation/screens/profile_settings/components/delete_profile_dialog_widget.dart b/comwell_key_app/lib/presentation/screens/profile_settings/components/delete_profile_dialog_widget.dart
new file mode 100644
index 00000000..fc5852f1
--- /dev/null
+++ b/comwell_key_app/lib/presentation/screens/profile_settings/components/delete_profile_dialog_widget.dart
@@ -0,0 +1,89 @@
+import 'package:comwell_key_app/presentation/screens/profile_settings/bloc/profile_settings_cubit.dart';
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:comwell_key_app/utils/l10n_utils.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class DeleteProfileDialogWidget extends StatelessWidget {
+ const DeleteProfileDialogWidget({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+
+ return Dialog(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(20),
+ ),
+ child: Padding(
+ padding: const EdgeInsets.all(24.0),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ context.strings.delete_profile_title,
+ textAlign: TextAlign.center,
+ style: const TextStyle(
+ color: colorTertiary,
+ fontSize: 18,
+ fontWeight: FontWeight.w600,
+ ),
+ ),
+ const SizedBox(height: 16),
+ Text(
+ context.strings.delete_profile_description,
+ textAlign: TextAlign.center,
+ style: const TextStyle(
+ color: Colors.grey,
+ fontSize: 14,
+ ),
+ ),
+ const SizedBox(height: 24),
+ SizedBox(
+ width: double.infinity,
+ child: ElevatedButton(
+ style: theme.elevatedButtonTheme.style?.copyWith(
+ backgroundColor: const WidgetStatePropertyAll(Colors.red),
+ padding: const WidgetStatePropertyAll(
+ EdgeInsets.symmetric(vertical: 16)),
+ ),
+ onPressed: () {
+ context.read<ProfileSettingsCubit>().deleteProfile();
+ },
+ child: Text(
+ context.strings.delete_profile_button,
+ style: const TextStyle(
+ fontSize: 16,
+ fontWeight: FontWeight.w600,
+ color: Colors.white,
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(height: 12),
+ SizedBox(
+ width: double.infinity,
+ child: OutlinedButton(
+ style: OutlinedButton.styleFrom(
+ side: BorderSide(color: Colors.grey[400]!),
+ padding: const EdgeInsets.symmetric(vertical: 16),
+ ),
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ child: Text(
+ context.strings.delete_profile_cancel,
+ style: const TextStyle(
+ fontSize: 16,
+ fontWeight: FontWeight.w600,
+ color: colorTertiary,
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
\ No newline at end of file
diff --git a/comwell_key_app/lib/presentation/screens/profile_settings/components/intl_phone_field.dart b/comwell_key_app/lib/presentation/screens/profile_settings/components/intl_phone_field.dart
new file mode 100644
index 00000000..b27ada09
--- /dev/null
+++ b/comwell_key_app/lib/presentation/screens/profile_settings/components/intl_phone_field.dart
@@ -0,0 +1,154 @@
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:country_code_picker/country_code_picker.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+
+class IntlPhoneField extends StatefulWidget {
+ final String title;
+ final String phoneNumber;
+ final CountryCode countryCode;
+ final TextEditingController controller;
+ final bool readOnly;
+ final void Function(String)? onSubmitted;
+ final void Function(CountryCode)? onCountryCodeSelected;
+ final void Function(String)? onPhoneNumberChanged;
+ final String? errorMessage;
+ const IntlPhoneField({
+ required this.title,
+ required this.phoneNumber,
+ required this.countryCode,
+ required this.controller,
+ this.readOnly = false,
+ this.onSubmitted,
+ this.onCountryCodeSelected,
+ this.errorMessage,
+ this.onPhoneNumberChanged,
+ super.key,
+ });
+
+ @override
+ IntlPhoneFieldState createState() => IntlPhoneFieldState();
+}
+
+class IntlPhoneFieldState extends State<IntlPhoneField> {
+ final GlobalKey<FormState> formKey = GlobalKey<FormState>();
+ late FocusNode _focusNode;
+ bool _isFocused = false;
+
+ @override
+ void initState() {
+ super.initState();
+
+ _focusNode = FocusNode();
+
+ _focusNode.addListener(() {
+ setState(() {
+ _isFocused = _focusNode.hasFocus;
+ });
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+
+ return Form(
+ key: formKey,
+ child: Container(
+ height: 62,
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(8),
+ border: Border.all(color: colorDivider),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: <Widget>[
+ CountryCodePicker(
+ onChanged: widget.onCountryCodeSelected,
+ initialSelection: widget.countryCode.toString(),
+ showFlag: false,
+ favorite: const [
+ 'SE',
+ 'DK',
+ 'NO',
+ 'DE',
+ ],
+ showDropDownButton: true,
+ padding: const EdgeInsets.symmetric(horizontal: 0),
+ textStyle: theme.textTheme.headlineSmall,
+ ),
+ Container(
+ width: 1,
+ height: 40,
+ color: colorDivider,
+ ),
+ const SizedBox(
+ width: 20,
+ ),
+ const SizedBox(height: 0.0),
+ Expanded(
+ child: TextField(
+ focusNode: _focusNode,
+ controller: widget.controller,
+ readOnly: widget.readOnly,
+ style: theme.textTheme.headlineSmall,
+ onSubmitted: widget.onSubmitted,
+ onChanged: widget.onPhoneNumberChanged,
+ keyboardType: const TextInputType.numberWithOptions(signed: true),
+ textInputAction: TextInputAction.done,
+ onEditingComplete: () => _focusNode.unfocus(),
+ inputFormatters: [
+ FilteringTextInputFormatter.digitsOnly,
+ ],
+ decoration: InputDecoration(
+ errorText: widget.errorMessage,
+ errorStyle: Theme.of(context)
+ .textTheme
+ .bodySmall
+ ?.copyWith(color: const Color(0xFFEB0026)),
+ border: InputBorder.none,
+ label: Text(widget.title,
+ style: _isFocused
+ ? theme.textTheme.bodySmall?.copyWith(
+ color:
+ colorHeadlineText)
+ : theme.textTheme.headlineSmall
+ ?.copyWith(color: colorTertiary)),
+ ),
+ ),
+ /* InternationalPhoneNumberInput(
+
+ inputBorder: InputBorder.none,
+ onInputChanged: (PhoneNumber number) {
+ print(number.phoneNumber);
+ },
+ onInputValidated: (bool value) {
+ print(value);
+ },
+ selectorConfig: const SelectorConfig(
+ selectorType: PhoneInputSelectorType.DROPDOWN,
+ useBottomSheetSafeArea: true,
+ showFlags: false,
+ ),
+ ignoreBlank: false,
+ textStyle: theme.textTheme.headlineSmall,
+ autoValidateMode: AutovalidateMode.disabled,
+ selectorTextStyle: const TextStyle(color: colorTertiary),
+ initialValue: number,
+
+ textFieldController: controller,
+ formatInput: true,
+ keyboardType:
+ const TextInputType.numberWithOptions(signed: true, decimal: true),
+
+ onSaved: (PhoneNumber number) {
+ print('On Saved: $number');
+ },
+ ), */
+ )
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/presentation/screens/profile_settings/components/text_field_with_trailing_icon.dart b/comwell_key_app/lib/presentation/screens/profile_settings/components/text_field_with_trailing_icon.dart
new file mode 100644
index 00000000..6e645c4b
--- /dev/null
+++ b/comwell_key_app/lib/presentation/screens/profile_settings/components/text_field_with_trailing_icon.dart
@@ -0,0 +1,63 @@
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+
+class TextFieldWithTrailingIcon extends StatelessWidget {
+ final String title;
+ final String text;
+ final String trailingIcon;
+ final VoidCallback onTap;
+ final bool showTitle;
+
+ const TextFieldWithTrailingIcon({
+ super.key,
+ required this.title,
+ required this.text,
+ required this.trailingIcon,
+ required this.onTap,
+ required this.showTitle,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ return GestureDetector(
+ onTap: onTap,
+ child: Container(
+ height: 62,
+ padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 9.5),
+ decoration: BoxDecoration(
+ border: Border.all(color: colorDivider),
+ borderRadius: BorderRadius.circular(8.0),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ if (showTitle)
+ Text(
+ title,
+ textAlign: TextAlign.start,
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: colorHeadlineText,
+ ),
+ ),
+ const SizedBox(height: 0.0),
+ SizedBox(width: 250, child:Text(
+ overflow: TextOverflow.ellipsis,
+ text, style: theme.textTheme.headlineSmall),
+ )],
+ ),
+ SvgPicture.asset(
+ trailingIcon,
+ height: 24.0,
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/presentation/screens/profile_settings/profile_settings_route.dart b/comwell_key_app/lib/presentation/screens/profile_settings/profile_settings_route.dart
new file mode 100644
index 00000000..949b8532
--- /dev/null
+++ b/comwell_key_app/lib/presentation/screens/profile_settings/profile_settings_route.dart
@@ -0,0 +1,31 @@
+import 'package:comwell_key_app/utils/locator.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:go_router/go_router.dart';
+import 'package:comwell_key_app/presentation/navigation/transitions/slide_in_transition.dart';
+import 'package:comwell_key_app/presentation/screens/profile_settings/bloc/profile_settings_cubit.dart';
+import 'package:comwell_key_app/presentation/screens/profile_settings/profile_settings_screen.dart';
+
+import '../../../routing/app_routes.dart';
+
+part '../../../.generated/presentation/screens/profile_settings/profile_settings_route.g.dart';
+
+@TypedGoRoute<ProfileSettingsRoute>(path: AppRoutes.profileSettings)
+class ProfileSettingsRoute extends GoRouteData with $ProfileSettingsRoute {
+ @override
+ Page<void> buildPage(BuildContext context, GoRouterState state) {
+ return SlideInTransition(
+ state: state,
+ child: BlocProvider(
+ create: (context) => ProfileSettingsCubit(
+ locator(),
+ locator(),
+ context.read(),
+ locator(),
+ locator(),
+ ),
+ child: const ProfileSettingsScreen(),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/presentation/screens/profile_settings/profile_settings_screen.dart b/comwell_key_app/lib/presentation/screens/profile_settings/profile_settings_screen.dart
new file mode 100644
index 00000000..2f599b84
--- /dev/null
+++ b/comwell_key_app/lib/presentation/screens/profile_settings/profile_settings_screen.dart
@@ -0,0 +1,212 @@
+import 'package:comwell_key_app/.generated/assets/assets.gen.dart';
+import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
+import 'package:comwell_key_app/common/components/shimmer_loader/profile_settings_shimmer_loader.dart';
+import 'package:comwell_key_app/domain/models/user.dart';
+import 'package:comwell_key_app/presentation/app/bloc/profile_cubit.dart';
+import 'components/address_bottom_sheet.dart';
+import 'components/comwell_text_field.dart';
+import 'components/date_time_picker.dart';
+import 'components/delete_profile_dialog_widget.dart';
+import 'components/intl_phone_field.dart';
+import 'components/text_field_with_trailing_icon.dart';
+import 'package:comwell_key_app/domain/models/address.dart';
+import 'package:comwell_key_app/utils/address_utils.dart';
+import 'package:comwell_key_app/utils/l10n_utils.dart';
+import 'package:concierge/presentation/theme/app_colors.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:comwell_key_app/presentation/screens/profile_settings/bloc/profile_settings_cubit.dart';
+import 'package:comwell_key_app/presentation/screens/profile_settings/bloc/profile_settings_state.dart';
+
+class ProfileSettingsScreen extends StatelessWidget {
+ const ProfileSettingsScreen({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ final profileCubit = context.watch<ProfileCubit>();
+ return BlocBuilder<ProfileSettingsCubit, ProfileSettingsState>(
+ builder: (context, state) {
+ if (state.isLoading) {
+ return const Scaffold(
+ appBar: ComwellAppBar(
+ shouldShowProfileButton: false,
+ ),
+ backgroundColor: Colors.white,
+ body: Center(child: ProfileSettingsShimmerLoader()),
+ );
+ }
+ return _buildProfileSettingsPage(
+ context,
+ theme,
+ state,
+ profileCubit.state.user,
+ );
+ },
+ );
+ }
+
+ Widget _buildProfileSettingsPage(
+ BuildContext context,
+ ThemeData theme,
+ ProfileSettingsState state,
+ User user,
+ ) {
+ final cubit = context.read<ProfileSettingsCubit>();
+ final address = formatAddress(user.address);
+
+ return Scaffold(
+ resizeToAvoidBottomInset: false,
+ backgroundColor: Colors.white,
+ appBar: const ComwellAppBar(
+ shouldShowProfileButton: false,
+ ),
+ body: SingleChildScrollView(
+ child: Container(
+ margin: const EdgeInsets.symmetric(horizontal: 16),
+ child: SafeArea(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const SizedBox(height: 36),
+ Text(
+ context.strings.profile_settings,
+ style: theme.textTheme.headlineLarge?.copyWith(color: AppColors.colorPrimaryText),
+ textAlign: TextAlign.start,
+ ),
+ const SizedBox(height: 36),
+ ComwellTextField(
+ fieldName: context.strings.profile_settings_firstname,
+ initialValue: user.firstName,
+ readOnly: false,
+ controller: cubit.firstNameController,
+ onSubmitted: (value) {
+ cubit.updateFirstName(value);
+ },
+ ),
+ const SizedBox(height: 8),
+ ComwellTextField(
+ fieldName: context.strings.profile_settings_lastname,
+ initialValue: user.lastName,
+ readOnly: false,
+ controller: cubit.lastNameController,
+ onSubmitted: (value) {
+ cubit.updateLastName(value);
+ },
+ ),
+ const SizedBox(height: 8),
+ ComwellTextField(
+ fieldName: context.strings.profile_settings_email,
+ initialValue: user.email,
+ readOnly: true,
+ controller: TextEditingController(text: user.email),
+ ),
+ const SizedBox(height: 8),
+ IntlPhoneField(
+ title: context.strings.profile_settings_phone,
+ phoneNumber: cubit.phoneNumber!,
+ countryCode: cubit.countryCode!,
+ controller: cubit.phoneNumberController,
+ readOnly: false,
+ onSubmitted: (value) {
+ cubit.updatePhoneNumber(value);
+ },
+ ),
+ const SizedBox(height: 8),
+ TextFieldWithTrailingIcon(
+ title: context.strings.profile_settings_address,
+ text: address,
+ trailingIcon: "assets/icons/edit-alt.svg",
+ onTap: () async {
+ final response = await showModalBottomSheet<Address>(
+ context: context,
+ isScrollControlled: true,
+ backgroundColor: Colors.white,
+ builder: (context) => AddressBottomSheet(
+ user: user,
+ selectedCountry: cubit.selectedCountry,
+ ),
+ );
+
+ if (response is Address) {
+ cubit.updateAddress(response);
+ } else {
+ debugPrint("Not an address $response");
+ }
+ },
+ showTitle: true,
+ ),
+ const SizedBox(height: 8),
+ DateTimePicker(
+ title: context.strings.profile_settings_birthday,
+ initialValue: user.birthDate ?? DateTime(1990, 1, 1),
+ ),
+ const SizedBox(height: 20),
+ Center(
+ child: OutlinedButton(
+ onPressed: () {
+ cubit.updateProfile();
+ },
+ style: OutlinedButton.styleFrom(
+ backgroundColor: AppColors.colorTertiary,
+ elevation: 0,
+ minimumSize: const Size(135, 40),
+ maximumSize: const Size(155, 40),
+ ),
+ child: Text(
+ context.strings.update_profile,
+ style: const TextStyle(
+ color: Colors.white,
+ ),
+ ),
+ ),
+ ),
+ Center(
+ child: OutlinedButton(
+ onPressed: () {
+ showDeleteProfileDialog(context);
+ },
+ style: OutlinedButton.styleFrom(
+ side: const BorderSide(color: AppColors.colorDivider),
+ backgroundColor: Colors.transparent,
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(Radius.circular(20)),
+ ),
+ minimumSize: const Size(135, 40),
+ maximumSize: const Size(200, 40),
+ padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
+ ),
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Assets.icons.trashCan.svg(height: 16),
+ const SizedBox(width: 8),
+ Text(
+ context.strings.delete_profile,
+ style: theme.textTheme.labelLarge?.copyWith(
+ color: Colors.red,
+ fontWeight: FontWeight.w600,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ Future<void> showDeleteProfileDialog(BuildContext context) {
+ return showDialog<void>(
+ context: context,
+ builder: (BuildContext context) {
+ return const DeleteProfileDialogWidget();
+ },
+ );
+ }
+}
diff --git a/comwell_key_app/lib/profile/components/card_content_widget.dart b/comwell_key_app/lib/profile/components/card_content_widget.dart
index 13f58b72..d28d2d59 100644
--- a/comwell_key_app/lib/profile/components/card_content_widget.dart
+++ b/comwell_key_app/lib/profile/components/card_content_widget.dart
@@ -1,4 +1,4 @@
-import 'package:comwell_key_app/profile/cubit/profile_cubit.dart';
+import 'package:comwell_key_app/presentation/app/bloc/profile_cubit.dart';
import 'package:comwell_key_app/utils/l10n_utils.dart';
import 'package:flutter/material.dart';
diff --git a/comwell_key_app/lib/profile/components/comwell_club_container.dart b/comwell_key_app/lib/profile/components/comwell_club_container.dart
index 72e89bd8..60dd2ad9 100644
--- a/comwell_key_app/lib/profile/components/comwell_club_container.dart
+++ b/comwell_key_app/lib/profile/components/comwell_club_container.dart
@@ -1,6 +1,6 @@
+import 'package:comwell_key_app/domain/models/user.dart';
import 'package:comwell_key_app/profile/components/comwell_club_signup_bottom_sheet.dart';
-import 'package:comwell_key_app/profile/cubit/profile_cubit.dart';
-import 'package:comwell_key_app/profile_settings/model/user.dart';
+import 'package:comwell_key_app/presentation/app/bloc/profile_cubit.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:comwell_key_app/utils/l10n_utils.dart';
import 'package:flutter/material.dart';
diff --git a/comwell_key_app/lib/profile/components/comwell_club_signup_bottom_sheet.dart b/comwell_key_app/lib/profile/components/comwell_club_signup_bottom_sheet.dart
index 34c633b8..902075af 100644
--- a/comwell_key_app/lib/profile/components/comwell_club_signup_bottom_sheet.dart
+++ b/comwell_key_app/lib/profile/components/comwell_club_signup_bottom_sheet.dart
@@ -1,36 +1,35 @@
import 'package:comwell_key_app/common/components/round_icon_button.dart';
-import 'package:comwell_key_app/profile/cubit/profile_cubit.dart';
+import 'package:comwell_key_app/domain/models/user.dart';
+import 'package:comwell_key_app/presentation/app/bloc/profile_cubit.dart';
+import 'package:comwell_key_app/presentation/screens/profile_settings/components/comwell_text_field.dart';
import 'package:comwell_key_app/profile/utils/constants.dart';
import 'package:comwell_key_app/profile/utils/urls.dart';
-import 'package:comwell_key_app/profile_settings/components/comwell_text_field.dart';
-import 'package:comwell_key_app/profile_settings/model/address.dart';
-import 'package:comwell_key_app/profile_settings/model/user.dart';
+import 'package:comwell_key_app/domain/models/address.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:comwell_key_app/utils/l10n_utils.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:go_router/go_router.dart';
import 'package:url_launcher/url_launcher.dart';
class ComwellClubSignupBottomSheet extends StatefulWidget {
final User user;
+
const ComwellClubSignupBottomSheet({super.key, required this.user});
@override
- State<ComwellClubSignupBottomSheet> createState() =>
- _ComwellClubSignupBottomSheetState();
+ State<ComwellClubSignupBottomSheet> createState() => _ComwellClubSignupBottomSheetState();
}
-class _ComwellClubSignupBottomSheetState
- extends State<ComwellClubSignupBottomSheet> {
+class _ComwellClubSignupBottomSheetState extends State<ComwellClubSignupBottomSheet> {
late final TextEditingController _postNumberController;
String _selectedGender = '';
@override
void initState() {
super.initState();
- _postNumberController =
- TextEditingController(text: widget.user.address.zipCode);
+ _postNumberController = TextEditingController(text: widget.user.address.zipCode);
}
@override
@@ -55,10 +54,8 @@ class _ComwellClubSignupBottomSheetState
topRight: Radius.circular(24),
),
),
- height: MediaQuery.of(context)
- .copyWith(viewInsets: EdgeInsets.zero)
- .size
- .height *
+ height:
+ MediaQuery.of(context).copyWith(viewInsets: EdgeInsets.zero).size.height *
ComwellClubConstants.imageHeightRatio,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -73,16 +70,19 @@ class _ComwellClubSignupBottomSheetState
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
- Text(context.strings.comwell_club_dialog_title,
- style: theme.textTheme.headlineLarge),
+ Text(
+ context.strings.comwell_club_dialog_title,
+ style: theme.textTheme.headlineLarge,
+ ),
RoundIconButton(
- icon: 'assets/icons/close-icon.svg',
- color: sandColor[20]!,
- onPressed: () {
- Navigator.pop(context);
- }),
+ icon: 'assets/icons/close-icon.svg',
+ color: sandColor[20]!,
+ onPressed: () {
+ Navigator.pop(context);
+ },
+ ),
],
- )
+ ),
],
),
),
@@ -176,8 +176,7 @@ class _ComwellClubSignupBottomSheetState
TextSpan(
text: context.strings.tos_accept,
style: TextStyle(
- fontSize:
- theme.textTheme.bodySmall!.fontSize,
+ fontSize: theme.textTheme.bodySmall!.fontSize,
color: theme.textTheme.bodySmall!.color,
fontWeight: FontWeight.w300,
),
@@ -186,12 +185,10 @@ class _ComwellClubSignupBottomSheetState
text: context.strings.tos_accept_link,
recognizer: TapGestureRecognizer()
..onTap = () {
- launchUrl(
- Uri.parse(ComwellUrls.clubRules));
+ launchUrl(Uri.parse(ComwellUrls.clubRules));
},
style: TextStyle(
- fontSize:
- theme.textTheme.bodySmall!.fontSize,
+ fontSize: theme.textTheme.bodySmall!.fontSize,
color: sandColor[80],
decoration: TextDecoration.underline,
),
@@ -235,8 +232,7 @@ class _ComwellClubSignupBottomSheetState
text: context.strings.read_more,
recognizer: TapGestureRecognizer()
..onTap = () {
- launchUrl(
- Uri.parse(ComwellUrls.clubPermission));
+ launchUrl(Uri.parse(ComwellUrls.clubPermission));
},
style: TextStyle(
fontSize: theme.textTheme.bodySmall!.fontSize,
@@ -259,36 +255,32 @@ class _ComwellClubSignupBottomSheetState
child: ElevatedButton(
style: theme.elevatedButtonTheme.style?.copyWith(
backgroundColor: WidgetStatePropertyAll(
- cubit.state.isToSAccepted &&
- _selectedGender.isNotEmpty
- ? sandColor
- : Colors.grey[200]),
+ cubit.state.isToSAccepted && _selectedGender.isNotEmpty
+ ? sandColor
+ : Colors.grey[200],
+ ),
),
onPressed: () async {
- final response = cubit.state.isToSAccepted &&
- _selectedGender.isNotEmpty
- ? await cubit.onComwellClubSignupClick(widget.user
- .copyWith(
- gender: _selectedGender,
- address: Address(
- zipCode: _postNumberController.text,
- street: '',
- city: '',
- country: '')))
- : null;
+ final response = await cubit.onComwellClubSignupClick(
+ widget.user.copyWith(
+ gender: _selectedGender,
+ address: Address(
+ zipCode: _postNumberController.text,
+ street: '',
+ city: '',
+ country: '',
+ ),
+ ),
+ );
- if (response != null) {
- if (context.mounted) {
- Navigator.pop(context);
- }
+ if (response == true && context.mounted) {
+ context.pop();
}
},
child: Text(
context.strings.save,
style: theme.textTheme.headlineSmall?.copyWith(
- color: cubit.state.isToSAccepted
- ? Colors.white
- : Colors.grey[400],
+ color: cubit.state.isToSAccepted ? Colors.white : Colors.grey[400],
),
),
),
diff --git a/comwell_key_app/lib/profile/components/error_page_widget.dart b/comwell_key_app/lib/profile/components/error_page_widget.dart
index 2a68a3f7..2a8a413d 100644
--- a/comwell_key_app/lib/profile/components/error_page_widget.dart
+++ b/comwell_key_app/lib/profile/components/error_page_widget.dart
@@ -2,7 +2,7 @@ import 'package:comwell_key_app/common/components/comwell_card_component.dart';
import 'package:comwell_key_app/common/components/comwell_error_widget.dart';
import 'package:comwell_key_app/common/components/round_icon_button.dart';
import 'package:comwell_key_app/profile/components/logout_dialog_widget.dart';
-import 'package:comwell_key_app/profile/cubit/profile_cubit.dart';
+import 'package:comwell_key_app/presentation/app/bloc/profile_cubit.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:comwell_key_app/utils/l10n_utils.dart';
import 'package:flutter/material.dart';
diff --git a/comwell_key_app/lib/profile/components/logout_dialog_widget.dart b/comwell_key_app/lib/profile/components/logout_dialog_widget.dart
index 3491fdd3..3f3b13b8 100644
--- a/comwell_key_app/lib/profile/components/logout_dialog_widget.dart
+++ b/comwell_key_app/lib/profile/components/logout_dialog_widget.dart
@@ -1,4 +1,4 @@
-import 'package:comwell_key_app/profile/cubit/profile_cubit.dart';
+import 'package:comwell_key_app/presentation/app/bloc/profile_cubit.dart';
import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:comwell_key_app/utils/l10n_utils.dart';
import 'package:flutter/material.dart';
diff --git a/comwell_key_app/lib/profile/components/profile_page_widget.dart b/comwell_key_app/lib/profile/components/profile_page_widget.dart
index 7139a688..dff00027 100644
--- a/comwell_key_app/lib/profile/components/profile_page_widget.dart
+++ b/comwell_key_app/lib/profile/components/profile_page_widget.dart
@@ -6,7 +6,7 @@ import 'package:comwell_key_app/profile/components/card_content_widget.dart';
import 'package:comwell_key_app/profile/components/comwell_club_container.dart';
import 'package:comwell_key_app/profile/components/logout_dialog_widget.dart';
import 'package:comwell_key_app/profile/components/profile_settings_item.dart';
-import 'package:comwell_key_app/profile/cubit/profile_cubit.dart';
+import 'package:comwell_key_app/presentation/app/bloc/profile_cubit.dart';
import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:comwell_key_app/themes/app_spaces.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
diff --git a/comwell_key_app/lib/profile/cubit/profile_cubit.dart b/comwell_key_app/lib/profile/cubit/profile_cubit.dart
deleted file mode 100644
index 84f6139a..00000000
--- a/comwell_key_app/lib/profile/cubit/profile_cubit.dart
+++ /dev/null
@@ -1,120 +0,0 @@
-import 'package:bloc/bloc.dart';
-import 'package:comwell_key_app/authentication/authentication_repository.dart';
-import 'package:comwell_key_app/profile/profile_repository.dart';
-import 'package:comwell_key_app/profile_settings/model/user.dart';
-import 'package:equatable/equatable.dart';
-import 'package:firebase_analytics/firebase_analytics.dart';
-import 'package:package_info_plus/package_info_plus.dart';
-
-part 'profile_state.dart';
-
-class ProfileCubit extends Cubit<ProfileState> {
- final ProfileRepository _profileRepository;
- final AuthenticationRepository _authenticationRepository;
-
- ProfileCubit(
- this._profileRepository,
- this._authenticationRepository,
- ) : super(
- const ProfileState(
- isLoading: false,
- user: null,
- error: null,
- isToSAccepted: false,
- isNewsletterAccepted: false,
- ),
- ) {
- init();
- }
-
- void sendPageViewEvent() async {
- await FirebaseAnalytics.instance.logScreenView(
- screenName: 'Profile',
- screenClass: '/profile',
- );
- }
-
- Future<String> getVersion() async {
- final packageInfo = await PackageInfo.fromPlatform();
- return packageInfo.version;
- }
-
- void logOutPressed() {
- _authenticationRepository.logOut();
- emit(
- const ProfileState(
- isLoading: false,
- user: null,
- error: null,
- isToSAccepted: false,
- isNewsletterAccepted: false,
- ),
- );
- }
-
- void deleteAllInfoOnLogOut() async {
- emit(
- const ProfileState(
- isLoading: false,
- user: null,
- error: null,
- isToSAccepted: false,
- isNewsletterAccepted: false,
- ),
- );
- }
-
- void init() async {
- emit(const ProfileState(isLoading: true, user: null, error: null));
-
- try {
- final user = await _profileRepository.fetchProfileSettings();
- sendPageViewEvent();
- if (!isClosed) emit(ProfileState(user: user, isLoading: false));
- } catch (e) {
- if (!isClosed) emit(ProfileState(isLoading: false, error: Error()));
- }
- }
-
- void fetchRemoteProfile() async {
- emit(const ProfileState(isLoading: true, user: null, error: null));
- try {
- final user = await _profileRepository.fetchProfileSettings(fetchRemote: true);
-
- if (!isClosed) emit(ProfileState(user: user, isLoading: false));
- } catch (e) {
- if (!isClosed) emit(ProfileState(isLoading: false, error: Error()));
- }
- }
-
- void onToSClick(bool? value) async {
- emit(state.setToSAccepted(isToSAccepted: value!));
- }
-
- void onNewsletterClick(bool? value) async {
- emit(state.setNewsletterAccepted(isNewsletterAccepted: value!));
- }
-
- String getGender(String gender) {
- switch (gender) {
- case 'Male':
- return 'M';
- case 'Female':
- return 'F';
- default:
- return 'O';
- }
- }
-
- Future<dynamic> onComwellClubSignupClick(User user) async {
- try {
- emit(const ProfileState(isLoading: true, user: null, error: null));
- User updatedUser = await _profileRepository.signupForComwellClub(user);
- emit(ProfileState(user: updatedUser, isLoading: false, error: null));
- return updatedUser;
- } catch (e) {
- emit(ProfileState(isLoading: false, error: Error()));
- rethrow;
- }
- }
-}
diff --git a/comwell_key_app/lib/profile/cubit/profile_state.dart b/comwell_key_app/lib/profile/cubit/profile_state.dart
deleted file mode 100644
index 173bdbac..00000000
--- a/comwell_key_app/lib/profile/cubit/profile_state.dart
+++ /dev/null
@@ -1,37 +0,0 @@
-part of 'profile_cubit.dart';
-
-class ProfileState extends Equatable {
- final Error? error;
- final bool isLoading;
- final User? user;
- final bool isToSAccepted;
- final bool isNewsletterAccepted;
-
- const ProfileState({this.error, required this.isLoading, this.user, this.isToSAccepted = false, this.isNewsletterAccepted = false});
-
- @override
- List<Object?> get props => [isLoading, isToSAccepted, isNewsletterAccepted, error, user];
-
- const ProfileState.initial()
- : isLoading = false,
- user = null,
- error = null,
- isToSAccepted = false,
- isNewsletterAccepted = false;
-
- ProfileState userFetched({required User user}) => _copyWith(user: user);
- ProfileState loading() => _copyWith(isLoading: true);
- ProfileState setError(Error error) => _copyWith(error: error);
- ProfileState setNewsletterAccepted({required bool isNewsletterAccepted}) => _copyWith(isNewsletterAccepted: isNewsletterAccepted);
- ProfileState setToSAccepted({required bool isToSAccepted}) => _copyWith(isToSAccepted: isToSAccepted);
-
- ProfileState _copyWith({User? user, Error? error, bool? isLoading, bool? isToSAccepted, bool? isNewsletterAccepted}) {
- return ProfileState(
- user: user ?? this.user,
- error: error ?? this.error,
- isLoading: isLoading ?? this.isLoading,
- isToSAccepted: isToSAccepted ?? this.isToSAccepted,
- isNewsletterAccepted: isNewsletterAccepted ?? this.isNewsletterAccepted,
- );
- }
-}
diff --git a/comwell_key_app/lib/profile/profile_page.dart b/comwell_key_app/lib/profile/profile_page.dart
index 96ced68d..7e99488b 100644
--- a/comwell_key_app/lib/profile/profile_page.dart
+++ b/comwell_key_app/lib/profile/profile_page.dart
@@ -1,6 +1,6 @@
import 'package:comwell_key_app/profile/components/error_page_widget.dart';
import 'package:comwell_key_app/profile/components/profile_page_widget.dart';
-import 'package:comwell_key_app/profile/cubit/profile_cubit.dart';
+import 'package:comwell_key_app/presentation/app/bloc/profile_cubit.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:comwell_key_app/utils/secure_storage.dart';
import 'package:flutter/material.dart';
@@ -54,7 +54,7 @@ class _ProfilePageState extends State<ProfilePage> with WidgetsBindingObserver {
padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 40.0),
child: ProfileShimmerLoader(),
);
- } else if (state.error != null) {
+ } else if (state.error.isError) {
return const ErrorPageWidget();
} else {
return ProfilePageWidget(cubit: _cubit);
diff --git a/comwell_key_app/lib/profile/profile_repository.dart b/comwell_key_app/lib/profile/profile_repository.dart
deleted file mode 100644
index 0286495f..00000000
--- a/comwell_key_app/lib/profile/profile_repository.dart
+++ /dev/null
@@ -1,89 +0,0 @@
-import 'package:comwell_key_app/authentication/authentication_repository.dart';
-import 'package:comwell_key_app/database/comwell_db.dart';
-import 'package:comwell_key_app/profile_settings/model/user.dart';
-import 'package:comwell_key_app/services/api.dart';
-import 'package:comwell_key_app/services/mappers/user_mapper.dart';
-import 'package:comwell_key_app/services/models/user_dto.dart';
-import 'package:comwell_key_app/utils/json.dart';
-import 'package:comwell_key_app/utils/locator.dart';
-import 'package:flutter/material.dart';
-
-class ProfileRepository {
- final AuthenticationRepository _authenticationRepository;
- final Api _api;
- late User user;
-
- ProfileRepository(
- this._authenticationRepository,
- this._api,
- );
-
- Future<void> logOut() async {
- await _authenticationRepository.logOut();
- }
-
- Future<User> signupForComwellClub(User user) async {
- try {
- await _api.signupForComwellClub();
- return await _updateAndPersistUser(user);
- } catch (e, st) {
- debugPrint('Error during Comwell Club signup: $e');
- debugPrintStack(stackTrace: st);
- rethrow;
- }
- }
-
- Future<User> _updateAndPersistUser(User user) async {
- final userResponse = await _api.updateUser(user.toSimpleUserDto());
- final data = userResponse.data as Json;
- final userDto = UserDto.fromJson(data);
- final updatedUser = userDto.toUser();
- await locator<ComwellDatabase>().userDAO.saveUser(userDto);
- return updatedUser;
- }
-
- Future<User> fetchRemoteProfile() async {
- final response = await _api.fetchProfileSettings();
- final data = response.data as Json;
- final userDto = UserDto.fromJson(data);
- final user = userDto.toUser();
- return user;
- }
-
- Future<User?> _checkIfProfileSettingsExists() async {
- try {
- final user = await locator<ComwellDatabase>().userDAO.getUser();
- return user;
- } catch (e) {
- debugPrint("Error checking if profile settings exists: $e");
- return null;
- }
- }
-
- Future<User> _fetchAndSaveProfileSettingsToDatabase() async {
- try {
- final response = await _api.fetchProfileSettings();
- final data = response.data as Json;
- final userDto = UserDto.fromJson(data);
- final user = userDto.toUser();
- await locator<ComwellDatabase>().userDAO.saveUser(userDto);
- return user;
- } catch (e) {
- debugPrint("Error fetching profile settings: $e");
- rethrow;
- }
- }
-
- Future<User> fetchProfileSettings({bool fetchRemote = false}) async {
- if (fetchRemote) {
- final user = await fetchRemoteProfile();
- return user;
- }
- final user = await _checkIfProfileSettingsExists();
- if (user != null) {
- return user;
- }
- final newUser = await _fetchAndSaveProfileSettingsToDatabase();
- return newUser;
- }
-}
diff --git a/comwell_key_app/lib/profile_settings/components/address_bottom_sheet.dart b/comwell_key_app/lib/profile_settings/components/address_bottom_sheet.dart
deleted file mode 100644
index 3216b64a..00000000
--- a/comwell_key_app/lib/profile_settings/components/address_bottom_sheet.dart
+++ /dev/null
@@ -1,173 +0,0 @@
-import 'package:comwell_key_app/common/components/round_icon_button.dart';
-import 'package:comwell_key_app/profile_settings/components/comwell_text_field.dart';
-import 'package:comwell_key_app/profile_settings/model/address.dart';
-import 'package:comwell_key_app/profile_settings/model/user.dart';
-import 'package:comwell_key_app/themes/light_theme.dart';
-import 'package:comwell_key_app/utils/l10n_utils.dart';
-import 'package:country_code_picker/country_code_picker.dart';
-import 'package:flutter/material.dart';
-import 'package:go_router/go_router.dart';
-
-class AddressBottomSheet extends StatefulWidget {
- final User? user;
- final String selectedCountry;
-
- const AddressBottomSheet({
- required this.user,
- required this.selectedCountry,
- super.key,
- });
-
- @override
- State<AddressBottomSheet> createState() => _AddressBottomSheetState();
-}
-
-class _AddressBottomSheetState extends State<AddressBottomSheet> {
- late final TextEditingController _addressController;
- late final TextEditingController _zipCodeController;
- late final TextEditingController _cityController;
- String _selectedCountry = '';
-
- @override
- void initState() {
- super.initState();
- _addressController =
- TextEditingController(text: widget.user?.address.street);
- _zipCodeController =
- TextEditingController(text: widget.user?.address.zipCode);
- _cityController = TextEditingController(text: widget.user?.address.city);
- _selectedCountry = widget.user?.address.country != '' ? widget.user?.address.country ?? '' : 'DK';
- }
-
- @override
- void dispose() {
- _addressController.dispose();
- _zipCodeController.dispose();
- _cityController.dispose();
- super.dispose();
- }
-
- @override
- Widget build(BuildContext context) {
- final theme = Theme.of(context);
-
- return Wrap(children: [
- Padding(
- padding: MediaQuery.of(context).viewInsets,
- child: Container(
- decoration: const BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.only(
- topLeft: Radius.circular(24),
- topRight: Radius.circular(24),
- ),
- ),
- height: MediaQuery.of(context).copyWith().size.height * 0.7,
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Padding(
- padding: const EdgeInsets.only(top: 40, left: 16),
- child: Container(
- height: 47,
- color: Colors.white,
- child: Stack(
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Text(context.strings.profile_settings_address,
- style: theme.textTheme.headlineLarge),
- RoundIconButton(
- icon: 'assets/icons/close-icon.svg',
- color: sandColor[20]!,
- onPressed: () {
- context.pop();
- }),
- ],
- )
- ],
- ),
- ),
- ),
- const SizedBox(height: 24),
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16),
- child: ComwellTextField(
- fieldName: context.strings.profile_settings_address,
- initialValue: widget.user?.address.street ?? '',
- readOnly: false,
- controller: _addressController)),
- const SizedBox(height: 8),
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16),
- child: ComwellTextField(
- fieldName: context.strings.zipCode,
- initialValue: widget.user?.address.zipCode ?? '',
- readOnly: false,
- controller: _zipCodeController)),
- const SizedBox(height: 8),
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16),
- child: ComwellTextField(
- fieldName: context.strings.city,
- initialValue: widget.user?.address.city ?? '',
- readOnly: false,
- controller: _cityController)),
- const SizedBox(height: 8),
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16),
- child: Container(
- height: 62,
- width: double.infinity,
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(8),
- border: Border.all(color: colorDivider),
- ),
- child: CountryCodePicker(
- alignLeft: true,
- textOverflow: TextOverflow.visible,
- initialSelection: _selectedCountry,
- showFlag: true,
- favorite: const ['DK', 'SE', 'NO', 'DE'],
- showDropDownButton: true,
- padding: const EdgeInsets.symmetric(horizontal: 16),
- textStyle: Theme.of(context).textTheme.headlineSmall,
- showCountryOnly: true,
- showOnlyCountryWhenClosed: true,
- onChanged: (CountryCode countryCode) {
- setState(() {
- _selectedCountry = countryCode.name ?? '';
- });
- },
- ),
- ),
- ),
- const Spacer(),
- const Divider(color: colorDivider),
- const SizedBox(height: 10),
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16),
- child: ElevatedButton(
- onPressed: () async {
- final address = Address(
- street: _addressController.text,
- zipCode: _zipCodeController.text,
- city: _cityController.text,
- country: _selectedCountry);
- context.pop(address);
- },
- child: Text(
- context.strings.save,
- style: theme.textTheme.headlineSmall?.copyWith(
- color: Colors.white,
- ),
- ),
- ),
- ),
- const SizedBox(height: 40),
- ])),
- )
- ]);
- }
-}
diff --git a/comwell_key_app/lib/profile_settings/components/comwell_text_field.dart b/comwell_key_app/lib/profile_settings/components/comwell_text_field.dart
deleted file mode 100644
index 4a2d2c76..00000000
--- a/comwell_key_app/lib/profile_settings/components/comwell_text_field.dart
+++ /dev/null
@@ -1,74 +0,0 @@
-import 'package:comwell_key_app/themes/light_theme.dart';
-import 'package:flutter/material.dart';
-
-class ComwellTextField extends StatefulWidget {
- final String fieldName;
- final String initialValue;
- final bool readOnly;
- final TextEditingController controller;
- final void Function(String)? onSubmitted;
- const ComwellTextField({
- super.key,
- required this.fieldName,
- required this.initialValue,
- required this.readOnly,
- required this.controller,
- this.onSubmitted,
- });
- @override
- ComwellTextFieldState createState() => ComwellTextFieldState();
-}
-
-class ComwellTextFieldState extends State<ComwellTextField> {
- late FocusNode _focusNode;
- bool _isFocused = false;
-
- @override
- void initState() {
- super.initState();
-
- _focusNode = FocusNode();
-
- _focusNode.addListener(() {
- setState(() {
- _isFocused = _focusNode.hasFocus;
- });
- });
- }
-
- @override
- Widget build(BuildContext context) {
- final theme = Theme.of(context);
- return Container(
- height: 62,
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(8),
- border: Border.all(color: colorDivider),
- ),
- child: Center(
- child: Padding(
- padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 10),
- child: TextField(
- readOnly: widget.readOnly,
- controller: widget.controller,
- focusNode: _focusNode,
- decoration: InputDecoration(
- label: Text(widget.fieldName,
- style: _isFocused && !widget.readOnly
- ? theme.textTheme.bodySmall?.copyWith(
- color: colorHeadlineText)
- : theme.textTheme.headlineSmall
- ?.copyWith(color: colorTertiary)),
- isDense: true,
- border: InputBorder.none,
- contentPadding: const EdgeInsets.symmetric(vertical: 0),
-
- ),
- style: !widget.readOnly ? theme.textTheme.headlineSmall : theme.textTheme.headlineSmall?.copyWith(color: colorHeadlineText),
- onSubmitted: widget.onSubmitted,
- ),
- ),
- ),
- );
- }
-}
diff --git a/comwell_key_app/lib/profile_settings/components/date_time_picker.dart b/comwell_key_app/lib/profile_settings/components/date_time_picker.dart
deleted file mode 100644
index 86262461..00000000
--- a/comwell_key_app/lib/profile_settings/components/date_time_picker.dart
+++ /dev/null
@@ -1,147 +0,0 @@
-import 'package:comwell_key_app/themes/light_theme.dart';
-import 'package:comwell_key_app/utils/l10n_utils.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:flutter_svg/svg.dart';
-import 'package:comwell_key_app/profile_settings/cubit/profile_settings_cubit.dart';
-import 'package:comwell_key_app/common/components/generic_dialog.dart';
-import 'package:intl/intl.dart';
-
-class DateTimePicker extends StatefulWidget {
- final String title;
- final DateTime initialValue;
- const DateTimePicker(
- {required this.title, required this.initialValue, super.key});
-
- @override
- State<DateTimePicker> createState() => _DatePickerState();
-}
-
-class _DatePickerState extends State<DateTimePicker> {
- DateTime? _selectedDate;
-
- DateTime get _maxDate {
- final today = DateTime.now();
- return DateTime(today.year - 18, today.month, today.day);
- }
-
- Future<void> _selectDate(BuildContext context) async {
- final maxDate = _maxDate;
- final initial = widget.initialValue;
- if (initial.isAfter(maxDate)) {
- // Show generic dialog to user
- await showDialog<void>(
- context: context,
- builder: (context) => GenericDialog(
- title: context.strings.invalid_birthday,
- content: context.strings.invalid_birthday_description,
- confirmButtonText: context.strings.generic_ok,
- confirmButtonTextColor: Colors.white,
- cancelButtonText: '',
- onConfirm: () {
- Navigator.of(context).pop();
- },
- onCancel: () {},
- ),
- );
- // Delete the invalid birthday (set to default value)
- if (context.mounted) {
- final defaultBirthday = maxDate;
- setState(() => _selectedDate = null);
- context.read<ProfileSettingsCubit>().updateBirthDate(defaultBirthday);
- // Open the date picker after dialog is closed
- await Future<void>.delayed(const Duration(milliseconds: 100));
- if (context.mounted) {
- await _showValidDatePicker(context, defaultBirthday, maxDate);
- }
- }
- return;
- }
- await _showValidDatePicker(context, initial, maxDate);
- }
-
- Future<void> _showValidDatePicker(
- BuildContext context, DateTime initial, DateTime maxDate) async {
- await showDatePicker(
- builder: (context, child) {
- final theme = Theme.of(context);
- return Theme(
- data: theme.copyWith(
- colorScheme: ColorScheme.light(
- primary: sandColor,
- onPrimary: Colors.white,
- onSurface: colorHeadlineText,
- surface: Colors.white,
- onError: Colors.red,
- ),
- textButtonTheme: TextButtonThemeData(
- style: TextButton.styleFrom(
- foregroundColor: colorHeadlineText,
- overlayColor: sandColor,
- ),
- ),
- ),
- child: child!,
- );
- },
- context: context,
- initialDate: initial,
- firstDate: DateTime(0),
- lastDate: maxDate,
- errorInvalidText: context.strings.profile_settings_invalid_date,
- ).then((DateTime? selected) {
- if (selected != null && selected != _selectedDate) {
- setState(() => _selectedDate = selected);
- if (context.mounted) {
- context.read<ProfileSettingsCubit>().updateBirthDate(selected);
- }
- }
- });
- }
-
- @override
- Widget build(BuildContext context) {
- final theme = Theme.of(context);
- final dateFormat = DateFormat('dd/MM/yyyy');
-
- return GestureDetector(
- onTap: () => _selectDate(context),
- child: Container(
- height: 62,
- padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 10.0),
- decoration: BoxDecoration(
- border: Border.all(color: colorDivider),
- borderRadius: BorderRadius.circular(8.0),
- ),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Text(
- widget.title,
- textAlign: TextAlign.start,
- style: theme.textTheme.bodySmall?.copyWith(
- color: colorHeadlineText,
- ),
- ),
- const SizedBox(height: 0.0),
- Text(
- _selectedDate != null
- ? dateFormat.format(_selectedDate!)
- : dateFormat.format(widget.initialValue),
- style: theme.textTheme.headlineSmall),
- ],
- ),
- SvgPicture.asset(
- "assets/icons/ic_calendar.svg",
- height: 24.0,
- ),
- ],
- ),
- ),
- );
- }
-}
diff --git a/comwell_key_app/lib/profile_settings/components/delete_profile_dialog_widget.dart b/comwell_key_app/lib/profile_settings/components/delete_profile_dialog_widget.dart
deleted file mode 100644
index 3a6c65ef..00000000
--- a/comwell_key_app/lib/profile_settings/components/delete_profile_dialog_widget.dart
+++ /dev/null
@@ -1,89 +0,0 @@
-import 'package:comwell_key_app/profile_settings/cubit/profile_settings_cubit.dart';
-import 'package:comwell_key_app/themes/light_theme.dart';
-import 'package:comwell_key_app/utils/l10n_utils.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_bloc/flutter_bloc.dart';
-
-class DeleteProfileDialogWidget extends StatelessWidget {
- const DeleteProfileDialogWidget({super.key});
-
- @override
- Widget build(BuildContext context) {
- final theme = Theme.of(context);
-
- return Dialog(
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(20),
- ),
- child: Padding(
- padding: const EdgeInsets.all(24.0),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Text(
- context.strings.delete_profile_title,
- textAlign: TextAlign.center,
- style: const TextStyle(
- color: colorTertiary,
- fontSize: 18,
- fontWeight: FontWeight.w600,
- ),
- ),
- const SizedBox(height: 16),
- Text(
- context.strings.delete_profile_description,
- textAlign: TextAlign.center,
- style: const TextStyle(
- color: Colors.grey,
- fontSize: 14,
- ),
- ),
- const SizedBox(height: 24),
- SizedBox(
- width: double.infinity,
- child: ElevatedButton(
- style: theme.elevatedButtonTheme.style?.copyWith(
- backgroundColor: const WidgetStatePropertyAll(Colors.red),
- padding: const WidgetStatePropertyAll(
- EdgeInsets.symmetric(vertical: 16)),
- ),
- onPressed: () {
- context.read<ProfileSettingsCubit>().deleteProfile();
- },
- child: Text(
- context.strings.delete_profile_button,
- style: const TextStyle(
- fontSize: 16,
- fontWeight: FontWeight.w600,
- color: Colors.white,
- ),
- ),
- ),
- ),
- const SizedBox(height: 12),
- SizedBox(
- width: double.infinity,
- child: OutlinedButton(
- style: OutlinedButton.styleFrom(
- side: BorderSide(color: Colors.grey[400]!),
- padding: const EdgeInsets.symmetric(vertical: 16),
- ),
- onPressed: () {
- Navigator.of(context).pop();
- },
- child: Text(
- context.strings.delete_profile_cancel,
- style: const TextStyle(
- fontSize: 16,
- fontWeight: FontWeight.w600,
- color: colorTertiary,
- ),
- ),
- ),
- ),
- ],
- ),
- ),
- );
- }
-}
\ No newline at end of file
diff --git a/comwell_key_app/lib/profile_settings/components/intl_phone_field.dart b/comwell_key_app/lib/profile_settings/components/intl_phone_field.dart
deleted file mode 100644
index b27ada09..00000000
--- a/comwell_key_app/lib/profile_settings/components/intl_phone_field.dart
+++ /dev/null
@@ -1,154 +0,0 @@
-import 'package:comwell_key_app/themes/light_theme.dart';
-import 'package:country_code_picker/country_code_picker.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter/services.dart';
-
-class IntlPhoneField extends StatefulWidget {
- final String title;
- final String phoneNumber;
- final CountryCode countryCode;
- final TextEditingController controller;
- final bool readOnly;
- final void Function(String)? onSubmitted;
- final void Function(CountryCode)? onCountryCodeSelected;
- final void Function(String)? onPhoneNumberChanged;
- final String? errorMessage;
- const IntlPhoneField({
- required this.title,
- required this.phoneNumber,
- required this.countryCode,
- required this.controller,
- this.readOnly = false,
- this.onSubmitted,
- this.onCountryCodeSelected,
- this.errorMessage,
- this.onPhoneNumberChanged,
- super.key,
- });
-
- @override
- IntlPhoneFieldState createState() => IntlPhoneFieldState();
-}
-
-class IntlPhoneFieldState extends State<IntlPhoneField> {
- final GlobalKey<FormState> formKey = GlobalKey<FormState>();
- late FocusNode _focusNode;
- bool _isFocused = false;
-
- @override
- void initState() {
- super.initState();
-
- _focusNode = FocusNode();
-
- _focusNode.addListener(() {
- setState(() {
- _isFocused = _focusNode.hasFocus;
- });
- });
- }
-
- @override
- Widget build(BuildContext context) {
- final theme = Theme.of(context);
-
- return Form(
- key: formKey,
- child: Container(
- height: 62,
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(8),
- border: Border.all(color: colorDivider),
- ),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.start,
- children: <Widget>[
- CountryCodePicker(
- onChanged: widget.onCountryCodeSelected,
- initialSelection: widget.countryCode.toString(),
- showFlag: false,
- favorite: const [
- 'SE',
- 'DK',
- 'NO',
- 'DE',
- ],
- showDropDownButton: true,
- padding: const EdgeInsets.symmetric(horizontal: 0),
- textStyle: theme.textTheme.headlineSmall,
- ),
- Container(
- width: 1,
- height: 40,
- color: colorDivider,
- ),
- const SizedBox(
- width: 20,
- ),
- const SizedBox(height: 0.0),
- Expanded(
- child: TextField(
- focusNode: _focusNode,
- controller: widget.controller,
- readOnly: widget.readOnly,
- style: theme.textTheme.headlineSmall,
- onSubmitted: widget.onSubmitted,
- onChanged: widget.onPhoneNumberChanged,
- keyboardType: const TextInputType.numberWithOptions(signed: true),
- textInputAction: TextInputAction.done,
- onEditingComplete: () => _focusNode.unfocus(),
- inputFormatters: [
- FilteringTextInputFormatter.digitsOnly,
- ],
- decoration: InputDecoration(
- errorText: widget.errorMessage,
- errorStyle: Theme.of(context)
- .textTheme
- .bodySmall
- ?.copyWith(color: const Color(0xFFEB0026)),
- border: InputBorder.none,
- label: Text(widget.title,
- style: _isFocused
- ? theme.textTheme.bodySmall?.copyWith(
- color:
- colorHeadlineText)
- : theme.textTheme.headlineSmall
- ?.copyWith(color: colorTertiary)),
- ),
- ),
- /* InternationalPhoneNumberInput(
-
- inputBorder: InputBorder.none,
- onInputChanged: (PhoneNumber number) {
- print(number.phoneNumber);
- },
- onInputValidated: (bool value) {
- print(value);
- },
- selectorConfig: const SelectorConfig(
- selectorType: PhoneInputSelectorType.DROPDOWN,
- useBottomSheetSafeArea: true,
- showFlags: false,
- ),
- ignoreBlank: false,
- textStyle: theme.textTheme.headlineSmall,
- autoValidateMode: AutovalidateMode.disabled,
- selectorTextStyle: const TextStyle(color: colorTertiary),
- initialValue: number,
-
- textFieldController: controller,
- formatInput: true,
- keyboardType:
- const TextInputType.numberWithOptions(signed: true, decimal: true),
-
- onSaved: (PhoneNumber number) {
- print('On Saved: $number');
- },
- ), */
- )
- ],
- ),
- ),
- );
- }
-}
diff --git a/comwell_key_app/lib/profile_settings/components/text_field_with_trailing_icon.dart b/comwell_key_app/lib/profile_settings/components/text_field_with_trailing_icon.dart
deleted file mode 100644
index 6e645c4b..00000000
--- a/comwell_key_app/lib/profile_settings/components/text_field_with_trailing_icon.dart
+++ /dev/null
@@ -1,63 +0,0 @@
-import 'package:comwell_key_app/themes/light_theme.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_svg/svg.dart';
-
-class TextFieldWithTrailingIcon extends StatelessWidget {
- final String title;
- final String text;
- final String trailingIcon;
- final VoidCallback onTap;
- final bool showTitle;
-
- const TextFieldWithTrailingIcon({
- super.key,
- required this.title,
- required this.text,
- required this.trailingIcon,
- required this.onTap,
- required this.showTitle,
- });
-
- @override
- Widget build(BuildContext context) {
- final theme = Theme.of(context);
- return GestureDetector(
- onTap: onTap,
- child: Container(
- height: 62,
- padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 9.5),
- decoration: BoxDecoration(
- border: Border.all(color: colorDivider),
- borderRadius: BorderRadius.circular(8.0),
- ),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- if (showTitle)
- Text(
- title,
- textAlign: TextAlign.start,
- style: theme.textTheme.bodySmall?.copyWith(
- color: colorHeadlineText,
- ),
- ),
- const SizedBox(height: 0.0),
- SizedBox(width: 250, child:Text(
- overflow: TextOverflow.ellipsis,
- text, style: theme.textTheme.headlineSmall),
- )],
- ),
- SvgPicture.asset(
- trailingIcon,
- height: 24.0,
- ),
- ],
- ),
- ),
- );
- }
-}
diff --git a/comwell_key_app/lib/profile_settings/cubit/profile_settings_cubit.dart b/comwell_key_app/lib/profile_settings/cubit/profile_settings_cubit.dart
deleted file mode 100644
index 926cebc8..00000000
--- a/comwell_key_app/lib/profile_settings/cubit/profile_settings_cubit.dart
+++ /dev/null
@@ -1,122 +0,0 @@
-import 'package:bloc/bloc.dart';
-import 'package:comwell_key_app/authentication/authentication_repository.dart';
-import 'package:comwell_key_app/profile/profile_repository.dart';
-import 'package:comwell_key_app/profile_settings/model/address.dart';
-import 'package:comwell_key_app/profile_settings/model/user.dart';
-import 'package:comwell_key_app/profile_settings/repostiory/profile_settings_repository.dart';
-import 'package:comwell_key_app/tracking/comwell_tracking.dart';
-import 'package:comwell_key_app/utils/locator.dart';
-import 'package:comwell_key_app/utils/phone_utils.dart';
-import 'package:country_code_picker/country_code_picker.dart';
-import 'package:equatable/equatable.dart';
-import 'package:flutter/material.dart';
-
-part 'profile_settings_state.dart';
-
-class ProfileSettingsCubit extends Cubit<ProfileSettingsState> {
- final ProfileRepository _profileRepository;
- final ProfileSettingsRepository _profileSettingsRepository;
- final AuthenticationRepository _authenticationRepository;
- final TextEditingController firstNameController = TextEditingController();
- final TextEditingController lastNameController = TextEditingController();
- final TextEditingController phoneNumberController = TextEditingController();
- late String selectedCountry = '';
- CountryCode? countryCode;
- String? phoneNumber;
-
- ProfileSettingsCubit(
- this._profileRepository,
- this._profileSettingsRepository,
- this._authenticationRepository,
- ) : super(const ProfileSettingsState.initial()) {
- init();
- }
-
- void init() async {
- emit(const ProfileSettingsState(isLoading: true, user: null, error: null));
- try {
- final user = await _profileRepository.fetchProfileSettings();
-
- countryCode = getCountryCodeFromPhoneNumber(user.phoneNumber).$1;
- phoneNumber = getCountryCodeFromPhoneNumber(user.phoneNumber).$2;
-
- firstNameController.text = user.firstName;
- lastNameController.text = user.lastName;
-
- phoneNumberController.text = user.phoneNumber;
- selectedCountry = user.addressCountry != '' ? user.addressCountry : 'DK';
-
- phoneNumberController.text = phoneNumber!;
-
- emit(ProfileSettingsState(isLoading: false, user: user, error: null));
- } catch (e) {
- emit(ProfileSettingsState(isLoading: false, user: null, error: Error()));
- }
- }
-
- void deleteProfile() async {
- try {
- await _profileSettingsRepository.deleteProfile();
- locator<ComwellTracking>().trackEvent('delete_profile');
- await _authenticationRepository.logOut();
- emit(const ProfileSettingsState(isDeleted: true, isLoading: false, user: null, error: null));
- } catch (e) {
- emit(ProfileSettingsState(isDeleted: false, isLoading: false, user: null, error: Error()));
- }
- }
-
- void updateBirthDate(DateTime birthDate) {
- if (state.user != null) {
- final updatedUser = state.user!.copyWith(birthDate: birthDate);
- emit(state.userLoaded(user: updatedUser));
- }
- }
-
- void updateAddress(Address address) {
- final updatedUser = state.user!.copyWith(address: address);
- emit(state.userLoaded(user: updatedUser));
- }
-
- void updateProfile() async {
- emit(ProfileSettingsState(isLoading: true, user: state.user, error: null));
- try {
- final phoneNumber = concatCountryCodeAndPhoneNumber(countryCode!, phoneNumberController.text);
-
- final updatedUser = state.user!.copyWith(
- id: state.user!.id,
- firstName: firstNameController.text,
- lastName: lastNameController.text,
- email: state.user!.email,
- phoneNumber: phoneNumber,
- birthDate: state.user!.birthDate,
- address: state.user!.address,
- shopperReference: state.user!.shopperReference,
- points: state.user!.points,
- addressCountry: state.user!.addressCountry,
- gender: state.user!.gender,
- isClubMember: state.user!.isClubMember,
- );
-
- await _profileSettingsRepository.updateUser(updatedUser);
- emit(ProfileSettingsState(isLoading: false, user: updatedUser, error: null));
- } catch (e) {
- debugPrint("error in cubit: $e");
- emit(ProfileSettingsState(isLoading: false, user: null, error: Error()));
- }
- }
-
- void updateLastName(String value) {
- final updatedUser = state.user!.copyWith(lastName: value);
- emit(state.userLoaded(user: updatedUser));
- }
-
- void updateFirstName(String value) {
- final updatedUser = state.user!.copyWith(firstName: value);
- emit(state.userLoaded(user: updatedUser));
- }
-
- void updatePhoneNumber(String value) {
- final updatedUser = state.user!.copyWith(phoneNumber: value);
- emit(state.userLoaded(user: updatedUser));
- }
-}
diff --git a/comwell_key_app/lib/profile_settings/cubit/profile_settings_state.dart b/comwell_key_app/lib/profile_settings/cubit/profile_settings_state.dart
deleted file mode 100644
index 446a2e3c..00000000
--- a/comwell_key_app/lib/profile_settings/cubit/profile_settings_state.dart
+++ /dev/null
@@ -1,43 +0,0 @@
-part of 'profile_settings_cubit.dart';
-
-class ProfileSettingsState extends Equatable {
- final Error? error;
- final bool isLoading;
- final User? user;
- final bool isDeleted;
-
- const ProfileSettingsState({
- this.error,
- required this.isLoading,
- this.user,
- this.isDeleted = false,
- });
-
- @override
- List<Object?> get props => [isLoading, isDeleted, user, error];
-
- const ProfileSettingsState.initial()
- : isLoading = false,
- user = null,
- error = null,
- isDeleted = false;
-
- ProfileSettingsState userLoaded({required User user}) =>
- _copyWith(user: user);
-
-
-
- ProfileSettingsState _copyWith({
- User? user,
- Error? error,
- bool? isLoading,
- bool? isDeleted,
- }) {
- return ProfileSettingsState(
- user: user ?? this.user,
- error: error ?? this.error,
- isLoading: isLoading ?? this.isLoading,
- isDeleted: isDeleted ?? this.isDeleted,
- );
- }
-}
diff --git a/comwell_key_app/lib/profile_settings/model/address.dart b/comwell_key_app/lib/profile_settings/model/address.dart
deleted file mode 100644
index 01f608b3..00000000
--- a/comwell_key_app/lib/profile_settings/model/address.dart
+++ /dev/null
@@ -1,18 +0,0 @@
-class Address {
- final String street;
- final String city;
- final String country;
- final String zipCode;
-
- Address({
- required this.street,
- required this.city,
- required this.country,
- required this.zipCode
- });
-
- @override
- String toString() {
- return 'Address(street: $street, city: $city, country: $country, zipCode: $zipCode)';
- }
-}
diff --git a/comwell_key_app/lib/profile_settings/model/user.dart b/comwell_key_app/lib/profile_settings/model/user.dart
deleted file mode 100644
index 4e89e862..00000000
--- a/comwell_key_app/lib/profile_settings/model/user.dart
+++ /dev/null
@@ -1,118 +0,0 @@
-import 'package:comwell_key_app/profile_settings/model/address.dart';
-
-class User {
- final int id;
- final String userId;
- final String? hmsId;
- final String firstName;
- final String lastName;
- final String addressCountry;
- final String phoneNumber;
- final String email;
- final bool emailVerified;
- final Address address;
- final DateTime birthDate;
- final String shopperReference;
- final int points;
- final String? gender;
- final bool isClubMember;
- final DateTime? createDate;
- final String? companyId;
- final String? companyName;
- final String? symplifyId;
- final DateTime? signUpDate;
- final String? signUpCampaign;
- final String? signUpSource;
- final String? locale;
- final bool wasRecentlyCreated;
- final String? nationality;
-
- User({
- required this.id,
- required this.userId,
- this.hmsId,
- required this.firstName,
- required this.lastName,
- required this.addressCountry,
- required this.phoneNumber,
- required this.email,
- required this.emailVerified,
- required this.address,
- required this.birthDate,
- required this.shopperReference,
- required this.points,
- this.gender,
- required this.isClubMember,
- this.createDate,
- this.companyId = '',
- this.companyName = '',
- this.symplifyId = '',
- this.signUpDate,
- this.signUpCampaign,
- this.signUpSource,
- this.locale,
- required this.wasRecentlyCreated,
- this.nationality,
- });
-
- @override
- String toString() {
- return 'User(id: $id, firstName: $firstName, lastName: $lastName, addressCountry: $addressCountry, phone: $phoneNumber, email: $email, address: $address, birthDate: $birthDate, shopperReference: $shopperReference, points: $points, isClubMember: $isClubMember)';
- }
-
- User copyWith({
- int? id,
- String? userId,
- String? hmsId,
- String? firstName,
- String? lastName,
- String? addressCountry,
- String? phoneNumber,
- String? email,
- bool? emailVerified,
- Address? address,
- String? shopperReference,
- DateTime? birthDate,
- int? points,
- String? gender,
- bool? isClubMember,
- DateTime? createDate,
- String? companyId,
- String? companyName,
- String? symplifyId,
- DateTime? signUpDate,
- String? signUpCampaign,
- String? signUpSource,
- String? locale,
- bool? wasRecentlyCreated,
- String? nationality,
- }) {
- return User(
- id: id ?? this.id,
- userId: userId ?? this.userId,
- hmsId: hmsId ?? this.hmsId,
- firstName: firstName ?? this.firstName,
- lastName: lastName ?? this.lastName,
- addressCountry: addressCountry ?? this.addressCountry,
- phoneNumber: phoneNumber ?? this.phoneNumber,
- email: email ?? this.email,
- emailVerified: emailVerified ?? this.emailVerified,
- address: address ?? this.address,
- birthDate: birthDate ?? this.birthDate,
- shopperReference: shopperReference ?? this.shopperReference,
- points: points ?? this.points,
- gender: gender ?? this.gender,
- isClubMember: isClubMember ?? this.isClubMember,
- createDate: createDate ?? this.createDate,
- companyId: companyId ?? this.companyId,
- companyName: companyName ?? this.companyName,
- symplifyId: symplifyId ?? this.symplifyId,
- signUpDate: signUpDate ?? this.signUpDate,
- signUpCampaign: signUpCampaign ?? this.signUpCampaign,
- signUpSource: signUpSource ?? this.signUpSource,
- locale: locale ?? this.locale,
- wasRecentlyCreated: wasRecentlyCreated ?? this.wasRecentlyCreated,
- nationality: nationality ?? this.nationality,
- );
- }
-}
diff --git a/comwell_key_app/lib/profile_settings/profile_settings_page.dart b/comwell_key_app/lib/profile_settings/profile_settings_page.dart
deleted file mode 100644
index 6d7addef..00000000
--- a/comwell_key_app/lib/profile_settings/profile_settings_page.dart
+++ /dev/null
@@ -1,217 +0,0 @@
-import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
-import 'package:comwell_key_app/profile_settings/components/address_bottom_sheet.dart';
-import 'package:comwell_key_app/profile_settings/components/comwell_text_field.dart';
-import 'package:comwell_key_app/profile_settings/components/date_time_picker.dart';
-import 'package:comwell_key_app/profile_settings/components/delete_profile_dialog_widget.dart';
-import 'package:comwell_key_app/profile_settings/components/intl_phone_field.dart';
-import 'package:comwell_key_app/profile_settings/components/text_field_with_trailing_icon.dart';
-import 'package:comwell_key_app/profile_settings/cubit/profile_settings_cubit.dart';
-import 'package:comwell_key_app/profile_settings/model/address.dart';
-import 'package:comwell_key_app/themes/light_theme.dart';
-import 'package:comwell_key_app/utils/address_utils.dart';
-import 'package:comwell_key_app/utils/l10n_utils.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:flutter_svg/flutter_svg.dart';
-import '../common/components/shimmer_loader/profile_settings_shimmer_loader.dart';
-
-class ProfileSettingsPage extends StatelessWidget {
- const ProfileSettingsPage({super.key});
-
- @override
- Widget build(BuildContext context) {
- final theme = Theme.of(context);
- return BlocBuilder<ProfileSettingsCubit, ProfileSettingsState>(
- builder: (context, state) {
- if (state.isLoading) {
- return const Scaffold(
- appBar: ComwellAppBar(
- shouldShowProfileButton: false,
- ),
- backgroundColor: Colors.white,
- body: Center(child: ProfileSettingsShimmerLoader()),
- );
- } else if (state.user != null) {
- return _buildProfileSettingsPage(theme, state, context);
- } else {
- return Scaffold(
- appBar: const ComwellAppBar(
- shouldShowProfileButton: false,
- ),
- backgroundColor: Colors.white,
- body: Center(
- child: Text(
- context.strings.generic_error,
- style: theme.textTheme.headlineLarge,
- ),
- ),
- );
- }
- },
- );
- }
-
- Widget _buildProfileSettingsPage(
- ThemeData theme,
- ProfileSettingsState state,
- BuildContext context,
- ) {
- final cubit = context.read<ProfileSettingsCubit>();
-
- final address = formatAddress(state.user!.address);
-
- return Scaffold(
- resizeToAvoidBottomInset: false,
- backgroundColor: Colors.white,
- appBar: const ComwellAppBar(
- shouldShowProfileButton: false,
- ),
- body: SingleChildScrollView(
- child: Container(
- margin: const EdgeInsets.symmetric(horizontal: 16),
- child: SafeArea(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- const SizedBox(height: 36),
- Text(
- context.strings.profile_settings,
- style: theme.textTheme.headlineLarge?.copyWith(color: colorPrimaryText),
- textAlign: TextAlign.start,
- ),
- const SizedBox(height: 36),
- ComwellTextField(
- fieldName: context.strings.profile_settings_firstname,
- initialValue: state.user!.firstName,
- readOnly: false,
- controller: cubit.firstNameController,
- onSubmitted: (value) {
- cubit.updateFirstName(value);
- },
- ),
- const SizedBox(height: 8),
- ComwellTextField(
- fieldName: context.strings.profile_settings_lastname,
- initialValue: state.user!.lastName,
- readOnly: false,
- controller: cubit.lastNameController,
- onSubmitted: (value) {
- cubit.updateLastName(value);
- },
- ),
- const SizedBox(height: 8),
- ComwellTextField(
- fieldName: context.strings.profile_settings_email,
- initialValue: state.user?.email ?? '',
- readOnly: true,
- controller: TextEditingController(text: state.user?.email ?? ''),
- ),
- const SizedBox(height: 8),
- IntlPhoneField(
- title: context.strings.profile_settings_phone,
- phoneNumber: cubit.phoneNumber!,
- countryCode: cubit.countryCode!,
- controller: cubit.phoneNumberController,
- readOnly: false,
- onSubmitted: (value) {
- cubit.updatePhoneNumber(value);
- },
- ),
- const SizedBox(height: 8),
- TextFieldWithTrailingIcon(
- title: context.strings.profile_settings_address,
- text: address,
- trailingIcon: "assets/icons/edit-alt.svg",
- onTap: () async {
- final response = await showModalBottomSheet<Address>(
- context: context,
- isScrollControlled: true,
- backgroundColor: Colors.white,
- builder: (context) => AddressBottomSheet(
- user: state.user,
- selectedCountry: cubit.selectedCountry,
- ),
- );
-
- if (response is Address) {
- cubit.updateAddress(response);
- } else {
- debugPrint("Not an address $response");
- }
- },
- showTitle: true,
- ),
- const SizedBox(height: 8),
- DateTimePicker(
- title: context.strings.profile_settings_birthday,
- initialValue: state.user?.birthDate ?? DateTime(1990, 1, 1),
- ),
- const SizedBox(height: 20),
- Center(
- child: OutlinedButton(
- onPressed: () {
- cubit.updateProfile();
- },
- style: OutlinedButton.styleFrom(
- backgroundColor: colorTertiary,
- elevation: 0,
- minimumSize: const Size(135, 40),
- maximumSize: const Size(155, 40),
- ),
- child: Text(
- context.strings.update_profile,
- style: const TextStyle(
- color: Colors.white,
- ),
- ),
- ),
- ),
- Center(
- child: OutlinedButton(
- onPressed: () {
- showDeleteProfileDialog(context);
- },
- style: OutlinedButton.styleFrom(
- side: const BorderSide(color: colorDivider),
- backgroundColor: Colors.transparent,
- shape: const RoundedRectangleBorder(
- borderRadius: BorderRadius.all(Radius.circular(20)),
- ),
- minimumSize: const Size(135, 40),
- maximumSize: const Size(200, 40),
- padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
- ),
- child: Row(
- mainAxisSize: MainAxisSize.min,
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- SvgPicture.asset("assets/icons/trash-can.svg", height: 16),
- const SizedBox(width: 8),
- Text(
- context.strings.delete_profile,
- style: theme.textTheme.labelLarge?.copyWith(
- color: Colors.red,
- fontWeight: FontWeight.w600,
- ),
- ),
- ],
- ),
- ),
- ),
- ],
- ),
- ),
- ),
- ),
- );
- }
-
- Future<void> showDeleteProfileDialog(BuildContext context) {
- return showDialog<void>(
- context: context,
- builder: (BuildContext context) {
- return const DeleteProfileDialogWidget();
- },
- );
- }
-}
diff --git a/comwell_key_app/lib/profile_settings/profile_settings_route.dart b/comwell_key_app/lib/profile_settings/profile_settings_route.dart
deleted file mode 100644
index 34f64bfd..00000000
--- a/comwell_key_app/lib/profile_settings/profile_settings_route.dart
+++ /dev/null
@@ -1,10 +0,0 @@
-import 'package:comwell_key_app/profile_settings/profile_settings_page.dart';
-import 'package:comwell_key_app/routing/app_routes.dart';
-import 'package:go_router/go_router.dart';
-
-final profileSettingsRoute = GoRoute(
- path: AppRoutes.profileSettings,
- builder: (context, state) {
- return const ProfileSettingsPage();
- },
-);
diff --git a/comwell_key_app/lib/profile_settings/repostiory/profile_settings_repository.dart b/comwell_key_app/lib/profile_settings/repostiory/profile_settings_repository.dart
deleted file mode 100644
index 83baa6c1..00000000
--- a/comwell_key_app/lib/profile_settings/repostiory/profile_settings_repository.dart
+++ /dev/null
@@ -1,35 +0,0 @@
-import 'package:comwell_key_app/database/comwell_db.dart';
-import 'package:comwell_key_app/profile_settings/model/user.dart';
-
-import 'package:comwell_key_app/services/api.dart';
-import 'package:comwell_key_app/services/mappers/user_mapper.dart';
-import 'package:comwell_key_app/services/models/user_dto.dart';
-
-import 'package:comwell_key_app/utils/json.dart';
-import 'package:comwell_key_app/utils/locator.dart';
-
-class ProfileSettingsRepository {
- final Api api = Api();
-
- Future<User> updateUser(User updatedUser) async {
- final userDto = updatedUser.toSimpleUserDto();
- final response = await api.updateUser(userDto);
-
- final data = response.data as Json;
- final responseDto = UserDto.fromJson(data);
- final user = responseDto.toUser();
-
- await locator<ComwellDatabase>().userDAO.saveUser(responseDto);
-
- return user;
- }
-
- Future<void> updateAddress(User updatedUser) async {
- final userDto = updatedUser.toUserDto();
- await locator<ComwellDatabase>().userDAO.saveUser(userDto);
- }
-
- Future<void> deleteProfile() {
- return api.deleteProfile();
- }
-}
diff --git a/comwell_key_app/lib/routing/app_router.dart b/comwell_key_app/lib/routing/app_router.dart
index 0a7c79f0..c7ca2db1 100644
--- a/comwell_key_app/lib/routing/app_router.dart
+++ b/comwell_key_app/lib/routing/app_router.dart
@@ -12,6 +12,7 @@ import 'package:comwell_key_app/presentation/screens/concierge/concierge_route.d
import 'package:comwell_key_app/presentation/screens/notifications/notifications_route.dart';
import 'package:comwell_key_app/presentation/screens/payment_processing/payment_processing_route.dart';
import 'package:comwell_key_app/presentation/screens/permission_overview/permission_overview_route.dart';
+import 'package:comwell_key_app/presentation/screens/profile_settings/profile_settings_route.dart';
import 'package:comwell_key_app/presentation/screens/room_info/room_info_route.dart';
import 'package:comwell_key_app/contact/contact_route.dart';
import 'package:comwell_key_app/find_booking/find_booking_route.dart';
@@ -21,7 +22,6 @@ import 'package:comwell_key_app/overview/overview_route.dart';
import 'package:comwell_key_app/presentation/screens/past_cancelled_booking_details/past_cancelled_booking_detail_route.dart';
import 'package:comwell_key_app/presentation/screens/webview/webview_route.dart';
import 'package:comwell_key_app/profile/profile_route.dart';
-import 'package:comwell_key_app/profile_settings/profile_settings_route.dart';
import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:comwell_key_app/routing/go_router_observer.dart';
import 'package:comwell_key_app/share/share_booking_route.dart';
@@ -80,9 +80,9 @@ final router = GoRouter(
$usageTrackingPermissionRoute,
$internetDisabledRoute,
$permissionOverviewRoute,
+ $profileSettingsRoute,
overviewRoute,
profileRoute,
- profileSettingsRoute,
changePasswordRoute,
webviewRoute,
pastCancelledBookingDetailsRoute,
diff --git a/comwell_key_app/lib/services/mappers/user_mapper.dart b/comwell_key_app/lib/services/mappers/user_mapper.dart
index 9a7f728b..52e2c91c 100644
--- a/comwell_key_app/lib/services/mappers/user_mapper.dart
+++ b/comwell_key_app/lib/services/mappers/user_mapper.dart
@@ -1,14 +1,13 @@
-import 'package:comwell_key_app/profile_settings/model/address.dart';
-import 'package:comwell_key_app/profile_settings/model/user.dart';
+import 'package:comwell_key_app/domain/models/address.dart';
+import 'package:comwell_key_app/domain/models/user.dart';
import 'package:comwell_key_app/services/models/simple_user_dto.dart';
import 'package:comwell_key_app/services/models/user_dto.dart';
extension UserMapper on UserDto {
User toUser() {
return User(
- id: id,
userId: userId,
- hmsId: hmsId,
+ hmsId: hmsId ?? "",
firstName: firstName,
lastName: lastName,
email: email,
@@ -24,18 +23,18 @@ extension UserMapper on UserDto {
birthDate: birthDate ?? DateTime.now(),
shopperReference: userId,
points: points,
- gender: gender,
+ gender: gender ?? "",
isClubMember: isClubMember,
createDate: createDate,
- companyId: companyId,
- companyName: companyName,
- symplifyId: symplifyId,
+ companyId: companyId ?? "",
+ companyName: companyName ?? "",
+ symplifyId: symplifyId ?? "",
signUpDate: signUpDate,
- signUpCampaign: signUpCampaign,
- signUpSource: signUpSource,
- locale: null,
+ signUpCampaign: signUpCampaign ?? "",
+ signUpSource: signUpSource ?? "",
+ locale: "",
wasRecentlyCreated: wasRecentlyCreated,
- nationality: nationality,
+ nationality: nationality ?? "",
);
}
}
@@ -43,7 +42,7 @@ extension UserMapper on UserDto {
extension UserDtoMapper on User {
UserDto toUserDto() {
return UserDto(
- id: id,
+ id: 0,
userId: userId,
hmsId: hmsId,
firstName: firstName,
@@ -68,7 +67,8 @@ extension UserDtoMapper on User {
signUpSource: signUpSource,
locale: null,
wasRecentlyCreated: wasRecentlyCreated,
- permissions: null, // Permissions are not stored in User model
+ permissions: null,
+ // Permissions are not stored in User model
nationality: nationality,
);
}
@@ -77,10 +77,9 @@ extension UserDtoMapper on User {
extension SimpleUserDtoMapper on User {
SimpleUserDto toSimpleUserDto() {
return SimpleUserDto(
-
firstName: firstName,
lastName: lastName,
- birthDate: birthDate.toIso8601String(),
+ birthDate: birthDate?.toIso8601String(),
phoneNumber: phoneNumber,
gender: gender,
addressStreet: address.street,
@@ -89,7 +88,6 @@ extension SimpleUserDtoMapper on User {
addressCountry: addressCountry,
locale: locale,
permissions: {}, // Permissions are not stored in User model
-
);
}
-}
\ No newline at end of file
+}
diff --git a/comwell_key_app/lib/utils/address_utils.dart b/comwell_key_app/lib/utils/address_utils.dart
index 7721cb43..2fede6aa 100644
--- a/comwell_key_app/lib/utils/address_utils.dart
+++ b/comwell_key_app/lib/utils/address_utils.dart
@@ -1,4 +1,4 @@
- import 'package:comwell_key_app/profile_settings/model/address.dart';
+ import 'package:comwell_key_app/domain/models/address.dart';
String formatAddress(Address? address) {
final List<String> parts = [];
diff --git a/comwell_key_app/lib/utils/locator.dart b/comwell_key_app/lib/utils/locator.dart
index 904cfe11..015f8f64 100644
--- a/comwell_key_app/lib/utils/locator.dart
+++ b/comwell_key_app/lib/utils/locator.dart
@@ -15,8 +15,8 @@ import 'package:comwell_key_app/my_booking/my_booking_repository.dart';
import 'package:comwell_key_app/domain/repositories/notifications_repository.dart';
import 'package:comwell_key_app/overview/repository/overview_repository.dart';
import 'package:comwell_key_app/pregistration/pregistration_repository.dart';
-import 'package:comwell_key_app/profile/profile_repository.dart';
-import 'package:comwell_key_app/profile_settings/repostiory/profile_settings_repository.dart';
+import 'package:comwell_key_app/domain/repositories/profile_repository.dart';
+import 'package:comwell_key_app/domain/repositories/profile_settings_repository.dart';
import 'package:comwell_key_app/services/api.dart';
import 'package:comwell_key_app/services/http_client.dart';
import 'package:comwell_key_app/share/share_booking_repository.dart';
diff --git a/comwell_key_app/test/profile_settings_test/profile_settings_cubit_test.dart b/comwell_key_app/test/profile_settings_test/profile_settings_cubit_test.dart
index 16c3889e..ac8eb87a 100644
--- a/comwell_key_app/test/profile_settings_test/profile_settings_cubit_test.dart
+++ b/comwell_key_app/test/profile_settings_test/profile_settings_cubit_test.dart
@@ -1,12 +1,16 @@
import 'package:bloc_test/bloc_test.dart';
import 'package:comwell_key_app/authentication/authentication_repository.dart';
-import 'package:comwell_key_app/profile/profile_repository.dart';
-import 'package:comwell_key_app/profile_settings/model/address.dart';
-import 'package:comwell_key_app/profile_settings/model/user.dart';
-import 'package:comwell_key_app/profile_settings/repostiory/profile_settings_repository.dart';
+import 'package:comwell_key_app/domain/models/app_error.dart';
+import 'package:comwell_key_app/domain/models/user.dart';
+import 'package:comwell_key_app/domain/repositories/profile_repository.dart';
+import 'package:comwell_key_app/domain/models/address.dart';
+import 'package:comwell_key_app/presentation/app/bloc/profile_cubit.dart';
+import 'package:comwell_key_app/presentation/screens/profile_settings/bloc/profile_settings_cubit.dart';
+import 'package:comwell_key_app/presentation/screens/profile_settings/bloc/profile_settings_state.dart';
+import 'package:comwell_key_app/domain/repositories/profile_settings_repository.dart';
+import 'package:comwell_key_app/tracking/comwell_tracking.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
-import 'package:comwell_key_app/profile_settings/cubit/profile_settings_cubit.dart';
class MockProfileSettingsRepository extends Mock implements ProfileSettingsRepository {}
@@ -14,51 +18,61 @@ class MockAuthenticationRepository extends Mock implements AuthenticationReposit
class MockProfileRepository extends Mock implements ProfileRepository {}
+class MockTracking extends Mock implements ComwellTracking {}
+
+class MockProfileCubit extends Mock implements ProfileCubit {}
+
+final user = User(
+ userId: '1',
+ email: 'john.doe@example.com',
+ emailVerified: true,
+ locale: 'en',
+ wasRecentlyCreated: false,
+ firstName: 'John',
+ lastName: 'Doe',
+ phoneNumber: '1234567890',
+ gender: 'Male',
+ address: const Address(
+ street: '123 Main St',
+ city: 'Anytown',
+ zipCode: '12345',
+ country: 'USA',
+ ),
+ birthDate: DateTime(1990, 1, 1),
+ addressCountry: 'SE',
+ shopperReference: '1234567890',
+ points: 100,
+ isClubMember: false,
+);
+
void main() {
late ProfileSettingsCubit profileSettingsCubit;
late MockProfileSettingsRepository mockProfileSettingsRepository;
late MockAuthenticationRepository mockAuthenticationRepository;
late MockProfileRepository mockProfileRepository;
+ late MockTracking mockTracking;
+ late MockProfileCubit mockProfileCubit;
setUp(() {
mockProfileSettingsRepository = MockProfileSettingsRepository();
+
mockAuthenticationRepository = MockAuthenticationRepository();
mockProfileRepository = MockProfileRepository();
+ when(() => mockProfileRepository.fetchProfileSettings()).thenAnswer((_) async => user);
+ mockTracking = MockTracking();
+ mockProfileCubit = MockProfileCubit();
profileSettingsCubit = ProfileSettingsCubit(
mockProfileRepository,
- mockProfileSettingsRepository,
mockAuthenticationRepository,
+ mockProfileCubit,
+ mockProfileSettingsRepository,
+ mockTracking,
);
});
-
tearDown(() {
profileSettingsCubit.close();
});
group('ProfileSettingsCubit', () {
- final user = User(
- id: 1,
- userId: '1',
- email: 'john.doe@example.com',
- emailVerified: true,
- locale: 'en',
- wasRecentlyCreated: false,
- firstName: 'John',
- lastName: 'Doe',
- phoneNumber: '1234567890',
- gender: 'Male',
- address: Address(
- street: '123 Main St',
- city: 'Anytown',
- zipCode: '12345',
- country: 'USA',
- ),
- birthDate: DateTime(1990, 1, 1),
- addressCountry: 'SE',
- shopperReference: '1234567890',
- points: 100,
- isClubMember: false,
- );
-
blocTest<ProfileSettingsCubit, ProfileSettingsState>(
'emits [ProfileSettingsLoading, ProfileSettingsLoaded] when fetchProfileSettings is successful',
build: () {
@@ -67,7 +81,7 @@ void main() {
},
act: (cubit) => cubit.init(),
expect: () => [
- ProfileSettingsState(user: user, isLoading: false, error: Error()),
+ ProfileSettingsState(),
],
);
@@ -81,7 +95,18 @@ void main() {
},
act: (cubit) => cubit.init(),
expect: () => [
- ProfileSettingsState(user: null, isLoading: false, error: Error()),
+ const ProfileSettingsState(
+ error: AppError.none,
+ isLoading: true,
+ ),
+ ProfileSettingsState(
+ error: AppError.unknown('Failed to fetch profile settings'),
+ isLoading: true,
+ ),
+ ProfileSettingsState(
+ error: AppError.unknown('Failed to fetch profile settings'),
+ isLoading: false,
+ ),
],
);
@@ -94,7 +119,7 @@ void main() {
},
act: (cubit) => cubit.deleteProfile(),
expect: () => [
- ProfileSettingsState(user: null, isLoading: false, error: Error()),
+ const ProfileSettingsState(isDeleted: true),
],
);
@@ -108,7 +133,7 @@ void main() {
},
act: (cubit) => cubit.deleteProfile(),
expect: () => [
- ProfileSettingsState(user: null, isLoading: false, error: Error()),
+ const ProfileSettingsState(),
],
);
});