feat: Refactor Staff Profile page to use ProfileCubit and improve loading logic
This commit is contained in:
@@ -29,207 +29,209 @@ class StaffProfilePage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = t.staff.profile;
|
||||
final cubit = Modular.get<ProfileCubit>();
|
||||
|
||||
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<ProfileCubit>()..loadProfile(userId);
|
||||
},
|
||||
child: Scaffold(
|
||||
backgroundColor: UiColors.background,
|
||||
body: BlocBuilder<ProfileCubit, ProfileState>(
|
||||
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<ProfileCubit, ProfileState>(
|
||||
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<ProfileCubit>().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<ProfileCubit>().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<ProfileCubit>().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<ProfileCubit>().signOut();
|
||||
Modular.to.navigateToGetStarted();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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<GetProfileUseCase>(),
|
||||
i.get<SignOutUseCase>(),
|
||||
|
||||
Reference in New Issue
Block a user