diff --git a/apps/mobile/packages/features/staff/profile/lib/src/presentation/pages/staff_profile_page.dart b/apps/mobile/packages/features/staff/profile/lib/src/presentation/pages/staff_profile_page.dart index 430048b9..e5e28b50 100644 --- a/apps/mobile/packages/features/staff/profile/lib/src/presentation/pages/staff_profile_page.dart +++ b/apps/mobile/packages/features/staff/profile/lib/src/presentation/pages/staff_profile_page.dart @@ -29,207 +29,209 @@ class StaffProfilePage extends StatelessWidget { @override Widget build(BuildContext context) { final i18n = t.staff.profile; + final cubit = Modular.get(); - return BlocProvider( - create: (_) { - // TODO: Get actual userId from auth session - // For now, using mock userId that matches ProfileRepositoryMock data - const userId = 't8P3fYh4y1cPoZbbVPXUhfQCsDo3'; - return Modular.get()..loadProfile(userId); - }, - child: Scaffold( - backgroundColor: UiColors.background, - body: BlocBuilder( - builder: (context, state) { - if (state.status == ProfileStatus.loading) { - return const Center(child: CircularProgressIndicator()); - } + // Load profile data on first build + // TODO: Get actual userId from auth session + // For now, using mock userId that matches ProfileRepositoryMock data + const userId = 't8P3fYh4y1cPoZbbVPXUhfQCsDo3'; + if (cubit.state.status == ProfileStatus.initial) { + cubit.loadProfile(userId); + } - if (state.status == ProfileStatus.error) { - return Center( - child: Text( - state.errorMessage ?? 'An error occurred', - style: UiTypography.body1r.copyWith( - color: UiColors.destructive, - ), + return Scaffold( + backgroundColor: UiColors.background, + body: BlocBuilder( + bloc: cubit, + builder: (context, state) { + if (state.status == ProfileStatus.loading) { + return const Center(child: CircularProgressIndicator()); + } + + if (state.status == ProfileStatus.error) { + return Center( + child: Text( + state.errorMessage ?? 'An error occurred', + style: UiTypography.body1r.copyWith( + color: UiColors.destructive, ), - ); - } - - final profile = state.profile; - if (profile == null) { - return const Center(child: CircularProgressIndicator()); - } - - return SingleChildScrollView( - padding: const EdgeInsets.only(bottom: UiConstants.space16), - child: Column( - children: [ - ProfileHeader( - fullName: profile.fullName, - level: profile.level, - photoUrl: profile.photoUrl, - onSignOutTap: () { - context.read().signOut(); - Modular.to.navigateToGetStarted(); - }, - ), - Transform.translate( - offset: const Offset(0, -24), - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: UiConstants.space5, - ), - child: Column( - children: [ - ReliabilityStatsCard( - totalShifts: profile.totalShifts, - averageRating: profile.averageRating, - onTimeRate: profile.onTimeRate, - noShowCount: profile.noShowCount, - cancellationCount: profile.cancellationCount, - ), - const SizedBox(height: UiConstants.space6), - ReliabilityScoreBar( - reliabilityScore: profile.reliabilityScore, - ), - const SizedBox(height: UiConstants.space6), - SectionTitle(i18n.sections.onboarding), - ProfileMenuGrid( - children: [ - ProfileMenuItem( - icon: UiIcons.user, - label: i18n.menu_items.personal_info, - completed: profile.hasPersonalInfo, - onTap: () => Modular.to.pushPersonalInfo(), - ), - ProfileMenuItem( - icon: UiIcons.phone, - label: i18n.menu_items.emergency_contact, - completed: profile.hasEmergencyContact, - onTap: () => Modular.to.pushEmergencyContact(), - ), - ProfileMenuItem( - icon: UiIcons.briefcase, - label: i18n.menu_items.experience, - completed: profile.hasExperience, - onTap: () => Modular.to.pushExperience(), - ), - ProfileMenuItem( - icon: UiIcons.user, - label: i18n.menu_items.attire, - completed: profile.hasAttire, - onTap: () => Modular.to.pushAttire(), - ), - ], - ), - const SizedBox(height: UiConstants.space6), - SectionTitle(i18n.sections.compliance), - ProfileMenuGrid( - crossAxisCount: 3, - children: [ - ProfileMenuItem( - icon: UiIcons.file, - label: i18n.menu_items.documents, - completed: profile.hasDocuments, - onTap: () => Modular.to.pushDocuments(), - ), - ProfileMenuItem( - icon: UiIcons.shield, - label: i18n.menu_items.certificates, - completed: profile.hasCertificates, - onTap: () => Modular.to.pushCertificates(), - ), - ProfileMenuItem( - icon: UiIcons.file, - label: i18n.menu_items.tax_forms, - completed: profile.hasTaxForms, - onTap: () => Modular.to.pushTaxForms(), - ), - ], - ), - const SizedBox(height: UiConstants.space6), - SectionTitle(i18n.sections.level_up), - ProfileMenuGrid( - crossAxisCount: 3, - children: [ - ProfileMenuItem( - icon: UiIcons.sparkles, - label: i18n.menu_items.krow_university, - onTap: () => Modular.to.pushKrowUniversity(), - ), - ProfileMenuItem( - icon: UiIcons.briefcase, - label: i18n.menu_items.trainings, - onTap: () => Modular.to.pushTrainings(), - ), - ProfileMenuItem( - icon: UiIcons.target, - label: i18n.menu_items.leaderboard, - onTap: () => Modular.to.pushLeaderboard(), - ), - ], - ), - const SizedBox(height: UiConstants.space6), - SectionTitle(i18n.sections.finance), - ProfileMenuGrid( - crossAxisCount: 3, - children: [ - ProfileMenuItem( - icon: UiIcons.building, - label: i18n.menu_items.bank_account, - onTap: () => Modular.to.pushBankAccount(), - ), - ProfileMenuItem( - icon: UiIcons.creditCard, - label: i18n.menu_items.payments, - onTap: () => Modular.to.navigate('/payments'), - ), - ProfileMenuItem( - icon: UiIcons.clock, - label: i18n.menu_items.timecard, - onTap: () => Modular.to.pushTimecard(), - ), - ], - ), - const SizedBox(height: UiConstants.space6), - SectionTitle(i18n.sections.support), - ProfileMenuGrid( - crossAxisCount: 3, - children: [ - ProfileMenuItem( - icon: UiIcons.help, - label: i18n.menu_items.faqs, - onTap: () => Modular.to.pushFaqs(), - ), - ProfileMenuItem( - icon: UiIcons.shield, - label: i18n.menu_items.privacy_security, - onTap: () => Modular.to.pushPrivacy(), - ), - ProfileMenuItem( - icon: UiIcons.messageCircle, - label: i18n.menu_items.messages, - onTap: () => Modular.to.pushMessages(), - ), - ], - ), - const SizedBox(height: UiConstants.space6), - LogoutButton( - onTap: () { - context.read().signOut(); - Modular.to.navigateToGetStarted(); - }, - ), - ], - ), - ), - ), - ], ), ); - }, - ), + } + + final profile = state.profile; + if (profile == null) { + return const Center(child: CircularProgressIndicator()); + } + + return SingleChildScrollView( + padding: const EdgeInsets.only(bottom: UiConstants.space16), + child: Column( + children: [ + ProfileHeader( + fullName: profile.fullName, + level: profile.level, + photoUrl: profile.photoUrl, + onSignOutTap: () { + context.read().signOut(); + Modular.to.navigateToGetStarted(); + }, + ), + Transform.translate( + offset: const Offset(0, -24), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: UiConstants.space5, + ), + child: Column( + children: [ + ReliabilityStatsCard( + totalShifts: profile.totalShifts, + averageRating: profile.averageRating, + onTimeRate: profile.onTimeRate, + noShowCount: profile.noShowCount, + cancellationCount: profile.cancellationCount, + ), + const SizedBox(height: UiConstants.space6), + ReliabilityScoreBar( + reliabilityScore: profile.reliabilityScore, + ), + const SizedBox(height: UiConstants.space6), + SectionTitle(i18n.sections.onboarding), + ProfileMenuGrid( + children: [ + ProfileMenuItem( + icon: UiIcons.user, + label: i18n.menu_items.personal_info, + completed: profile.hasPersonalInfo, + onTap: () => Modular.to.pushPersonalInfo(), + ), + ProfileMenuItem( + icon: UiIcons.phone, + label: i18n.menu_items.emergency_contact, + completed: profile.hasEmergencyContact, + onTap: () => Modular.to.pushEmergencyContact(), + ), + ProfileMenuItem( + icon: UiIcons.briefcase, + label: i18n.menu_items.experience, + completed: profile.hasExperience, + onTap: () => Modular.to.pushExperience(), + ), + ProfileMenuItem( + icon: UiIcons.user, + label: i18n.menu_items.attire, + completed: profile.hasAttire, + onTap: () => Modular.to.pushAttire(), + ), + ], + ), + const SizedBox(height: UiConstants.space6), + SectionTitle(i18n.sections.compliance), + ProfileMenuGrid( + crossAxisCount: 3, + children: [ + ProfileMenuItem( + icon: UiIcons.file, + label: i18n.menu_items.documents, + completed: profile.hasDocuments, + onTap: () => Modular.to.pushDocuments(), + ), + ProfileMenuItem( + icon: UiIcons.shield, + label: i18n.menu_items.certificates, + completed: profile.hasCertificates, + onTap: () => Modular.to.pushCertificates(), + ), + ProfileMenuItem( + icon: UiIcons.file, + label: i18n.menu_items.tax_forms, + completed: profile.hasTaxForms, + onTap: () => Modular.to.pushTaxForms(), + ), + ], + ), + const SizedBox(height: UiConstants.space6), + SectionTitle(i18n.sections.level_up), + ProfileMenuGrid( + crossAxisCount: 3, + children: [ + ProfileMenuItem( + icon: UiIcons.sparkles, + label: i18n.menu_items.krow_university, + onTap: () => Modular.to.pushKrowUniversity(), + ), + ProfileMenuItem( + icon: UiIcons.briefcase, + label: i18n.menu_items.trainings, + onTap: () => Modular.to.pushTrainings(), + ), + ProfileMenuItem( + icon: UiIcons.target, + label: i18n.menu_items.leaderboard, + onTap: () => Modular.to.pushLeaderboard(), + ), + ], + ), + const SizedBox(height: UiConstants.space6), + SectionTitle(i18n.sections.finance), + ProfileMenuGrid( + crossAxisCount: 3, + children: [ + ProfileMenuItem( + icon: UiIcons.building, + label: i18n.menu_items.bank_account, + onTap: () => Modular.to.pushBankAccount(), + ), + ProfileMenuItem( + icon: UiIcons.creditCard, + label: i18n.menu_items.payments, + onTap: () => Modular.to.navigate('/payments'), + ), + ProfileMenuItem( + icon: UiIcons.clock, + label: i18n.menu_items.timecard, + onTap: () => Modular.to.pushTimecard(), + ), + ], + ), + const SizedBox(height: UiConstants.space6), + SectionTitle(i18n.sections.support), + ProfileMenuGrid( + crossAxisCount: 3, + children: [ + ProfileMenuItem( + icon: UiIcons.help, + label: i18n.menu_items.faqs, + onTap: () => Modular.to.pushFaqs(), + ), + ProfileMenuItem( + icon: UiIcons.shield, + label: i18n.menu_items.privacy_security, + onTap: () => Modular.to.pushPrivacy(), + ), + ProfileMenuItem( + icon: UiIcons.messageCircle, + label: i18n.menu_items.messages, + onTap: () => Modular.to.pushMessages(), + ), + ], + ), + const SizedBox(height: UiConstants.space6), + LogoutButton( + onTap: () { + context.read().signOut(); + Modular.to.navigateToGetStarted(); + }, + ), + ], + ), + ), + ), + ], + ), + ); + }, ), ); } diff --git a/apps/mobile/packages/features/staff/profile/lib/src/staff_profile_module.dart b/apps/mobile/packages/features/staff/profile/lib/src/staff_profile_module.dart index 73a3ffbf..4ad1dcca 100644 --- a/apps/mobile/packages/features/staff/profile/lib/src/staff_profile_module.dart +++ b/apps/mobile/packages/features/staff/profile/lib/src/staff_profile_module.dart @@ -39,7 +39,8 @@ class StaffProfileModule extends Module { ); // Presentation layer - Cubit depends on use cases - i.addSingleton( + // Use addLazySingleton to create a new instance per module lifecycle + i.addLazySingleton( () => ProfileCubit( i.get(), i.get(), diff --git a/apps/mobile/packages/features/staff/profile/pubspec.yaml b/apps/mobile/packages/features/staff/profile/pubspec.yaml index b6366fc6..8552ba94 100644 --- a/apps/mobile/packages/features/staff/profile/pubspec.yaml +++ b/apps/mobile/packages/features/staff/profile/pubspec.yaml @@ -1,41 +1,40 @@ name: staff_profile description: Staff Profile feature package. version: 0.0.1 -publish_to: 'none' +publish_to: none +resolution: workspace environment: - sdk: '>=3.0.0 <4.0.0' - flutter: ">=1.17.0" + sdk: '>=3.10.0 <4.0.0' + flutter: ">=3.0.0" dependencies: flutter: sdk: flutter + flutter_bloc: ^8.1.0 + bloc: ^8.1.0 + flutter_modular: ^6.3.0 + equatable: ^2.0.5 + lucide_icons: ^0.257.0 - # Architecture - flutter_modular: ^5.0.0 - flutter_bloc: ^8.1.3 - - # Utility/DI - injectable: ^2.3.0 - get_it: ^7.6.4 - - # Project-specific packages - domain: - path: ../../../domain - data_connect: - path: ../../../data_connect + # Architecture Packages + design_system: + path: ../../../design_system core_localization: path: ../../../core_localization - design_system: - path: ../../../design_system # Assuming this path + krow_core: + path: ../../../core + krow_domain: + path: ../../../domain + krow_data_connect: + path: ../../../data_connect dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^2.0.0 - injectable_generator: ^2.4.1 - build_runner: ^2.4.6 + bloc_test: ^9.1.0 + mocktail: ^1.0.0 + flutter_lints: ^6.0.0 -# Flutter modular configuration flutter: uses-material-design: true diff --git a/apps/mobile/packages/features/staff/staff_main/lib/src/staff_main_module.dart b/apps/mobile/packages/features/staff/staff_main/lib/src/staff_main_module.dart index 5a8a355e..1971ea8d 100644 --- a/apps/mobile/packages/features/staff/staff_main/lib/src/staff_main_module.dart +++ b/apps/mobile/packages/features/staff/staff_main/lib/src/staff_main_module.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_modular/flutter_modular.dart'; import 'package:staff_home/staff_home.dart'; +import 'package:staff_profile/staff_profile.dart'; import 'package:staff_main/src/presentation/blocs/staff_main_cubit.dart'; import 'package:staff_main/src/presentation/constants/staff_main_routes.dart'; @@ -38,10 +39,9 @@ class StaffMainModule extends Module { child: (BuildContext context) => const PlaceholderPage(title: 'Clock In'), ), - ChildRoute( + ModuleRoute( StaffMainRoutes.profile, - child: (BuildContext context) => - const PlaceholderPage(title: 'Profile'), + module: StaffProfileModule(), ), ], ); diff --git a/apps/mobile/packages/features/staff/staff_main/pubspec.yaml b/apps/mobile/packages/features/staff/staff_main/pubspec.yaml index dfa57fa3..9044124d 100644 --- a/apps/mobile/packages/features/staff/staff_main/pubspec.yaml +++ b/apps/mobile/packages/features/staff/staff_main/pubspec.yaml @@ -25,12 +25,12 @@ dependencies: # Features staff_home: path: ../home + staff_profile: + path: ../profile # staff_shifts: # path: ../shifts # staff_payments: # path: ../payments - # staff_profile: - # path: ../profile dev_dependencies: flutter_test: diff --git a/apps/mobile/pubspec.lock b/apps/mobile/pubspec.lock index 21ca16ea..99c2d280 100644 --- a/apps/mobile/pubspec.lock +++ b/apps/mobile/pubspec.lock @@ -1064,6 +1064,13 @@ packages: url: "https://pub.dev" source: hosted version: "1.12.1" + staff_profile: + dependency: transitive + description: + path: "packages/features/staff/profile" + relative: true + source: path + version: "0.0.1" stream_channel: dependency: transitive description: