feat: Refactor staff profile page and logout button for improved state management and navigation
This commit is contained in:
@@ -38,24 +38,12 @@ class StaffProfilePage extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
void _onSignOut(ProfileCubit cubit, ProfileState state) {
|
||||
if (state.status != ProfileStatus.loading) {
|
||||
cubit.signOut();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ProfileCubit cubit = Modular.get<ProfileCubit>();
|
||||
|
||||
// Load profile data on first build
|
||||
if (cubit.state.status == ProfileStatus.initial) {
|
||||
cubit.loadProfile();
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
body: BlocConsumer<ProfileCubit, ProfileState>(
|
||||
bloc: cubit,
|
||||
body: BlocProvider<ProfileCubit>(
|
||||
create: (_) => Modular.get<ProfileCubit>()..loadProfile(),
|
||||
child: BlocConsumer<ProfileCubit, ProfileState>(
|
||||
listener: (BuildContext context, ProfileState state) {
|
||||
if (state.status == ProfileStatus.signedOut) {
|
||||
Modular.to.toGetStartedPage();
|
||||
@@ -104,7 +92,6 @@ class StaffProfilePage extends StatelessWidget {
|
||||
fullName: profile.name,
|
||||
level: _mapStatusToLevel(profile.status),
|
||||
photoUrl: profile.avatar,
|
||||
onSignOutTap: () => _onSignOut(cubit, state),
|
||||
),
|
||||
Transform.translate(
|
||||
offset: const Offset(0, -UiConstants.space6),
|
||||
@@ -113,7 +100,9 @@ class StaffProfilePage extends StatelessWidget {
|
||||
horizontal: UiConstants.space5,
|
||||
),
|
||||
child: Column(
|
||||
spacing: UiConstants.space6,
|
||||
children: <Widget>[
|
||||
// Reliability Stats and Score
|
||||
ReliabilityStatsCard(
|
||||
totalShifts: profile.totalShifts,
|
||||
averageRating: profile.averageRating,
|
||||
@@ -121,25 +110,31 @@ class StaffProfilePage extends StatelessWidget {
|
||||
noShowCount: profile.noShowCount,
|
||||
cancellationCount: profile.cancellationCount,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
|
||||
// Reliability Score Bar
|
||||
ReliabilityScoreBar(
|
||||
reliabilityScore: profile.reliabilityScore,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
|
||||
// Ordered sections
|
||||
const OnboardingSection(),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
|
||||
// Compliance section
|
||||
const ComplianceSection(),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
|
||||
// Finance section
|
||||
const FinanceSection(),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
|
||||
// Support section
|
||||
const SupportSection(),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
|
||||
// Settings section
|
||||
const SettingsSection(),
|
||||
|
||||
// Logout button at the bottom
|
||||
const LogoutButton(),
|
||||
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
LogoutButton(
|
||||
onTap: () => _onSignOut(cubit, state),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space12),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -149,6 +144,7 @@ class StaffProfilePage extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,40 @@
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../blocs/profile_cubit.dart';
|
||||
import '../blocs/profile_state.dart';
|
||||
|
||||
/// The sign-out button widget.
|
||||
///
|
||||
/// Uses design system tokens for all colors, typography, spacing, and icons.
|
||||
/// Handles logout logic when tapped and navigates to onboarding on success.
|
||||
class LogoutButton extends StatelessWidget {
|
||||
final VoidCallback onTap;
|
||||
const LogoutButton({super.key});
|
||||
|
||||
const LogoutButton({super.key, required this.onTap});
|
||||
/// Handles the sign-out action.
|
||||
///
|
||||
/// Checks if the profile is not currently loading, then triggers the
|
||||
/// sign-out process via the ProfileCubit.
|
||||
void _handleSignOut(BuildContext context, ProfileState state) {
|
||||
if (state.status != ProfileStatus.loading) {
|
||||
context.read<ProfileCubit>().signOut();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = t.staff.profile.header;
|
||||
final TranslationsStaffProfileHeaderEn i18n = t.staff.profile.header;
|
||||
|
||||
return Container(
|
||||
return BlocListener<ProfileCubit, ProfileState>(
|
||||
listener: (BuildContext context, ProfileState state) {
|
||||
if (state.status == ProfileStatus.signedOut) {
|
||||
// Navigate to get started page after successful sign-out
|
||||
// This will be handled by the profile page listener
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
@@ -24,13 +44,18 @@ class LogoutButton extends StatelessWidget {
|
||||
child: Material(
|
||||
color: UiColors.transparent,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
onTap: () {
|
||||
_handleSignOut(
|
||||
context,
|
||||
context.read<ProfileCubit>().state,
|
||||
);
|
||||
},
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: UiConstants.space4),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
const Icon(
|
||||
UiIcons.logOut,
|
||||
color: UiColors.destructive,
|
||||
@@ -46,6 +71,7 @@ class LogoutButton extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
|
||||
/// The header section of the staff profile page, containing avatar, name, level,
|
||||
/// and a sign-out button.
|
||||
/// The header section of the staff profile page, containing avatar, name, and level.
|
||||
///
|
||||
/// Uses design system tokens for all colors, typography, and spacing.
|
||||
class ProfileHeader extends StatelessWidget {
|
||||
@@ -16,21 +15,17 @@ class ProfileHeader extends StatelessWidget {
|
||||
/// Optional photo URL for the avatar
|
||||
final String? photoUrl;
|
||||
|
||||
/// Callback when sign out is tapped
|
||||
final VoidCallback onSignOutTap;
|
||||
|
||||
/// Creates a [ProfileHeader].
|
||||
const ProfileHeader({
|
||||
super.key,
|
||||
required this.fullName,
|
||||
required this.level,
|
||||
this.photoUrl,
|
||||
required this.onSignOutTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = t.staff.profile.header;
|
||||
final TranslationsStaffProfileHeaderEn i18n = t.staff.profile.header;
|
||||
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
@@ -49,31 +44,22 @@ class ProfileHeader extends StatelessWidget {
|
||||
child: SafeArea(
|
||||
bottom: false,
|
||||
child: Column(
|
||||
children: [
|
||||
children: <Widget>[
|
||||
// Top Bar
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
i18n.title,
|
||||
style: UiTypography.headline4m.textSecondary,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: onSignOutTap,
|
||||
child: Text(
|
||||
i18n.sign_out,
|
||||
style: UiTypography.body2m.copyWith(
|
||||
color: UiColors.primaryForeground.withValues(alpha: 0.8),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: UiConstants.space8),
|
||||
// Avatar Section
|
||||
Stack(
|
||||
alignment: Alignment.bottomRight,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: 112,
|
||||
height: 112,
|
||||
@@ -83,13 +69,13 @@ class ProfileHeader extends StatelessWidget {
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
colors: <Color>[
|
||||
UiColors.accent,
|
||||
UiColors.accent.withValues(alpha: 0.5),
|
||||
UiColors.primaryForeground,
|
||||
],
|
||||
),
|
||||
boxShadow: [
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: UiColors.foreground.withValues(alpha: 0.2),
|
||||
blurRadius: 10,
|
||||
@@ -119,7 +105,7 @@ class ProfileHeader extends StatelessWidget {
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
colors: <Color>[
|
||||
UiColors.accent,
|
||||
UiColors.accent.withValues(alpha: 0.7),
|
||||
],
|
||||
@@ -144,7 +130,7 @@ class ProfileHeader extends StatelessWidget {
|
||||
color: UiColors.primaryForeground,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(color: UiColors.primary, width: 2),
|
||||
boxShadow: [
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: UiColors.foreground.withValues(alpha: 0.1),
|
||||
blurRadius: 4,
|
||||
|
||||
@@ -68,7 +68,7 @@ graph TD
|
||||
- `data/`: Repository Implementations.
|
||||
- `presentation/`:
|
||||
- Pages, BLoCs, Widgets.
|
||||
- For performance make the pages as `StatelessWidget` and move the state management to the BLoC or `StatefulWidget` to an external separate widget file.
|
||||
- For performance make the pages as `StatelessWidget` and move the state management to the BLoC (always use a BlocProvider when providing the BLoC to the widget tree) or `StatefulWidget` to an external separate widget file.
|
||||
- **Responsibilities**:
|
||||
- **Presentation**: UI Pages, Modular Routes.
|
||||
- **State Management**: BLoCs / Cubits.
|
||||
|
||||
Reference in New Issue
Block a user