diff --git a/apps/mobile/packages/data_connect/lib/krow_data_connect.dart b/apps/mobile/packages/data_connect/lib/krow_data_connect.dart index 445db229..a67d149b 100644 --- a/apps/mobile/packages/data_connect/lib/krow_data_connect.dart +++ b/apps/mobile/packages/data_connect/lib/krow_data_connect.dart @@ -18,6 +18,7 @@ export 'src/mocks/home_repository_mock.dart'; export 'src/mocks/business_repository_mock.dart'; export 'src/mocks/order_repository_mock.dart'; export 'src/data_connect_module.dart'; +export 'src/session/client_session_store.dart'; // Export the generated Data Connect SDK export 'src/dataconnect_generated/generated.dart'; diff --git a/apps/mobile/packages/data_connect/lib/src/session/client_session_store.dart b/apps/mobile/packages/data_connect/lib/src/session/client_session_store.dart new file mode 100644 index 00000000..e17f22a4 --- /dev/null +++ b/apps/mobile/packages/data_connect/lib/src/session/client_session_store.dart @@ -0,0 +1,49 @@ +import 'package:krow_domain/krow_domain.dart' as domain; + +class ClientBusinessSession { + final String id; + final String businessName; + final String? email; + final String? city; + final String? contactName; + final String? companyLogoUrl; + + const ClientBusinessSession({ + required this.id, + required this.businessName, + this.email, + this.city, + this.contactName, + this.companyLogoUrl, + }); +} + +class ClientSession { + final domain.User user; + final String? userPhotoUrl; + final ClientBusinessSession? business; + + const ClientSession({ + required this.user, + required this.userPhotoUrl, + required this.business, + }); +} + +class ClientSessionStore { + ClientSession? _session; + + ClientSession? get session => _session; + + void setSession(ClientSession session) { + _session = session; + } + + void clear() { + _session = null; + } + + static final ClientSessionStore instance = ClientSessionStore._(); + + ClientSessionStore._(); +} diff --git a/apps/mobile/packages/features/client/authentication/lib/src/data/repositories_impl/auth_repository_impl.dart b/apps/mobile/packages/features/client/authentication/lib/src/data/repositories_impl/auth_repository_impl.dart index ede79873..0756527f 100644 --- a/apps/mobile/packages/features/client/authentication/lib/src/data/repositories_impl/auth_repository_impl.dart +++ b/apps/mobile/packages/features/client/authentication/lib/src/data/repositories_impl/auth_repository_impl.dart @@ -122,6 +122,7 @@ class AuthRepositoryImpl implements AuthRepositoryInterface { Future signOut() async { try { await _firebaseAuth.signOut(); + dc.ClientSessionStore.instance.clear(); } catch (e) { throw Exception('Error signing out: ${e.toString()}'); } @@ -147,10 +148,36 @@ class AuthRepositoryImpl implements AuthRepositoryInterface { throw Exception('User email is missing in profile data.'); } - return domain.User( + final domainUser = domain.User( id: user.id, email: email, role: user.role.stringValue, ); + + final businessResponse = await _dataConnect.getBusinessesByUserId( + userId: firebaseUserId, + ).execute(); + final business = businessResponse.data.businesses.isNotEmpty + ? businessResponse.data.businesses.first + : null; + + dc.ClientSessionStore.instance.setSession( + dc.ClientSession( + user: domainUser, + userPhotoUrl: user.photoUrl, + business: business == null + ? null + : dc.ClientBusinessSession( + id: business.id, + businessName: business.businessName, + email: business.email, + city: business.city, + contactName: business.contactName, + companyLogoUrl: business.companyLogoUrl, + ), + ), + ); + + return domainUser; } } diff --git a/apps/mobile/packages/features/client/home/lib/src/presentation/pages/client_home_page.dart b/apps/mobile/packages/features/client/home/lib/src/presentation/pages/client_home_page.dart index 6f3840df..32c698d8 100644 --- a/apps/mobile/packages/features/client/home/lib/src/presentation/pages/client_home_page.dart +++ b/apps/mobile/packages/features/client/home/lib/src/presentation/pages/client_home_page.dart @@ -3,6 +3,7 @@ import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_modular/flutter_modular.dart'; +import 'package:krow_data_connect/krow_data_connect.dart' as dc; import '../blocs/client_home_bloc.dart'; import '../blocs/client_home_event.dart'; @@ -116,6 +117,14 @@ class ClientHomePage extends StatelessWidget { Widget _buildHeader(BuildContext context, dynamic i18n) { return BlocBuilder( builder: (context, state) { + final session = dc.ClientSessionStore.instance.session; + final businessName = + session?.business?.businessName ?? 'Your Company'; + final photoUrl = session?.userPhotoUrl; + final avatarLetter = businessName.trim().isNotEmpty + ? businessName.trim()[0].toUpperCase() + : 'C'; + return Padding( padding: const EdgeInsets.fromLTRB( UiConstants.space4, @@ -140,12 +149,19 @@ class ClientHomePage extends StatelessWidget { ), child: CircleAvatar( backgroundColor: UiColors.primary.withValues(alpha: 0.1), - child: Text( - 'C', - style: UiTypography.body2b.copyWith( - color: UiColors.primary, - ), - ), + backgroundImage: + photoUrl != null && photoUrl.isNotEmpty + ? NetworkImage(photoUrl) + : null, + child: + photoUrl != null && photoUrl.isNotEmpty + ? null + : Text( + avatarLetter, + style: UiTypography.body2b.copyWith( + color: UiColors.primary, + ), + ), ), ), const SizedBox(width: UiConstants.space3), @@ -156,7 +172,7 @@ class ClientHomePage extends StatelessWidget { i18n.dashboard.welcome_back, style: UiTypography.footnote2r.textSecondary, ), - Text('Your Company', style: UiTypography.body1b), + Text(businessName, style: UiTypography.body1b), ], ), ], diff --git a/apps/mobile/packages/features/client/settings/lib/src/presentation/widgets/client_settings_page/settings_profile_header.dart b/apps/mobile/packages/features/client/settings/lib/src/presentation/widgets/client_settings_page/settings_profile_header.dart index 48f6a57f..9f795f35 100644 --- a/apps/mobile/packages/features/client/settings/lib/src/presentation/widgets/client_settings_page/settings_profile_header.dart +++ b/apps/mobile/packages/features/client/settings/lib/src/presentation/widgets/client_settings_page/settings_profile_header.dart @@ -2,6 +2,7 @@ import 'package:core_localization/core_localization.dart'; import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter_modular/flutter_modular.dart'; +import 'package:krow_data_connect/krow_data_connect.dart' as dc; /// A widget that displays the profile header with avatar and company info. class SettingsProfileHeader extends StatelessWidget { @@ -12,6 +13,14 @@ class SettingsProfileHeader extends StatelessWidget { /// Builds the profile header UI. Widget build(BuildContext context) { final labels = t.client_settings.profile; + final session = dc.ClientSessionStore.instance.session; + final businessName = + session?.business?.businessName ?? 'Your Company'; + final email = session?.user.email ?? 'client@example.com'; + final photoUrl = session?.userPhotoUrl; + final avatarLetter = businessName.trim().isNotEmpty + ? businessName.trim()[0].toUpperCase() + : 'C'; return SliverAppBar( backgroundColor: UiColors.bgSecondary, @@ -40,20 +49,28 @@ class SettingsProfileHeader extends StatelessWidget { border: Border.all(color: UiColors.border, width: 2), color: UiColors.white, ), - child: Center( - child: Text( - 'C', - style: UiTypography.headline1m.copyWith( - color: UiColors.primary, - ), - ), + child: CircleAvatar( + backgroundColor: UiColors.primary.withValues(alpha: 0.1), + backgroundImage: + photoUrl != null && photoUrl.isNotEmpty + ? NetworkImage(photoUrl) + : null, + child: + photoUrl != null && photoUrl.isNotEmpty + ? null + : Text( + avatarLetter, + style: UiTypography.headline1m.copyWith( + color: UiColors.primary, + ), + ), ), ), Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ - Text('Your Company', style: UiTypography.body1b.textPrimary), + Text(businessName, style: UiTypography.body1b.textPrimary), const SizedBox(height: UiConstants.space1), Row( mainAxisAlignment: MainAxisAlignment.start, @@ -65,7 +82,7 @@ class SettingsProfileHeader extends StatelessWidget { color: UiColors.textSecondary, ), Text( - 'client@example.com', + email, style: UiTypography.footnote1r.textSecondary, ), ],