Implement profile completion checks in shift details flow and update UI accordingly
This commit is contained in:
@@ -20,7 +20,6 @@ class StaffConnectorRepositoryImpl implements StaffConnectorRepository {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> getProfileCompletion() async {
|
Future<bool> getProfileCompletion() async {
|
||||||
return true;
|
|
||||||
return _service.run(() async {
|
return _service.run(() async {
|
||||||
final String staffId = await _service.getStaffId();
|
final String staffId = await _service.getStaffId();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:krow_core/core.dart';
|
import 'package:krow_core/core.dart';
|
||||||
|
import 'package:krow_data_connect/krow_data_connect.dart';
|
||||||
import '../../../domain/usecases/apply_for_shift_usecase.dart';
|
import '../../../domain/usecases/apply_for_shift_usecase.dart';
|
||||||
import '../../../domain/usecases/decline_shift_usecase.dart';
|
import '../../../domain/usecases/decline_shift_usecase.dart';
|
||||||
import '../../../domain/usecases/get_shift_details_usecase.dart';
|
import '../../../domain/usecases/get_shift_details_usecase.dart';
|
||||||
@@ -12,11 +13,13 @@ class ShiftDetailsBloc extends Bloc<ShiftDetailsEvent, ShiftDetailsState>
|
|||||||
final GetShiftDetailsUseCase getShiftDetails;
|
final GetShiftDetailsUseCase getShiftDetails;
|
||||||
final ApplyForShiftUseCase applyForShift;
|
final ApplyForShiftUseCase applyForShift;
|
||||||
final DeclineShiftUseCase declineShift;
|
final DeclineShiftUseCase declineShift;
|
||||||
|
final GetProfileCompletionUseCase getProfileCompletion;
|
||||||
|
|
||||||
ShiftDetailsBloc({
|
ShiftDetailsBloc({
|
||||||
required this.getShiftDetails,
|
required this.getShiftDetails,
|
||||||
required this.applyForShift,
|
required this.applyForShift,
|
||||||
required this.declineShift,
|
required this.declineShift,
|
||||||
|
required this.getProfileCompletion,
|
||||||
}) : super(ShiftDetailsInitial()) {
|
}) : super(ShiftDetailsInitial()) {
|
||||||
on<LoadShiftDetailsEvent>(_onLoadDetails);
|
on<LoadShiftDetailsEvent>(_onLoadDetails);
|
||||||
on<BookShiftDetailsEvent>(_onBookShift);
|
on<BookShiftDetailsEvent>(_onBookShift);
|
||||||
@@ -34,8 +37,9 @@ class ShiftDetailsBloc extends Bloc<ShiftDetailsEvent, ShiftDetailsState>
|
|||||||
final shift = await getShiftDetails(
|
final shift = await getShiftDetails(
|
||||||
GetShiftDetailsArguments(shiftId: event.shiftId, roleId: event.roleId),
|
GetShiftDetailsArguments(shiftId: event.shiftId, roleId: event.roleId),
|
||||||
);
|
);
|
||||||
|
final isProfileComplete = await getProfileCompletion();
|
||||||
if (shift != null) {
|
if (shift != null) {
|
||||||
emit(ShiftDetailsLoaded(shift));
|
emit(ShiftDetailsLoaded(shift, isProfileComplete: isProfileComplete));
|
||||||
} else {
|
} else {
|
||||||
emit(const ShiftDetailsError("Shift not found"));
|
emit(const ShiftDetailsError("Shift not found"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,11 @@ class ShiftDetailsLoading extends ShiftDetailsState {}
|
|||||||
|
|
||||||
class ShiftDetailsLoaded extends ShiftDetailsState {
|
class ShiftDetailsLoaded extends ShiftDetailsState {
|
||||||
final Shift shift;
|
final Shift shift;
|
||||||
const ShiftDetailsLoaded(this.shift);
|
final bool isProfileComplete;
|
||||||
|
const ShiftDetailsLoaded(this.shift, {this.isProfileComplete = false});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [shift];
|
List<Object?> get props => [shift, isProfileComplete];
|
||||||
}
|
}
|
||||||
|
|
||||||
class ShiftDetailsError extends ShiftDetailsState {
|
class ShiftDetailsError extends ShiftDetailsState {
|
||||||
|
|||||||
@@ -125,6 +125,9 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
|
|||||||
|
|
||||||
final Shift displayShift = widget.shift;
|
final Shift displayShift = widget.shift;
|
||||||
final i18n = Translations.of(context).staff_shifts.shift_details;
|
final i18n = Translations.of(context).staff_shifts.shift_details;
|
||||||
|
final isProfileComplete = state is ShiftDetailsLoaded
|
||||||
|
? state.isProfileComplete
|
||||||
|
: false;
|
||||||
|
|
||||||
final duration = _calculateDuration(displayShift);
|
final duration = _calculateDuration(displayShift);
|
||||||
final estimatedTotal =
|
final estimatedTotal =
|
||||||
@@ -142,6 +145,16 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
if (!isProfileComplete)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(UiConstants.space6),
|
||||||
|
child: UiNoticeBanner(
|
||||||
|
title: 'Complete Your Account',
|
||||||
|
description:
|
||||||
|
'Complete your account to book this shift and start earning',
|
||||||
|
icon: UiIcons.sparkles,
|
||||||
|
),
|
||||||
|
),
|
||||||
ShiftDetailsHeader(shift: displayShift),
|
ShiftDetailsHeader(shift: displayShift),
|
||||||
const Divider(height: 1, thickness: 0.5),
|
const Divider(height: 1, thickness: 0.5),
|
||||||
ShiftStatsRow(
|
ShiftStatsRow(
|
||||||
@@ -194,6 +207,7 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (isProfileComplete)
|
||||||
ShiftDetailsBottomBar(
|
ShiftDetailsBottomBar(
|
||||||
shift: displayShift,
|
shift: displayShift,
|
||||||
onApply: () => _bookShift(context, displayShift),
|
onApply: () => _bookShift(context, displayShift),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter_modular/flutter_modular.dart';
|
import 'package:flutter_modular/flutter_modular.dart';
|
||||||
|
import 'package:krow_data_connect/krow_data_connect.dart';
|
||||||
import 'domain/repositories/shifts_repository_interface.dart';
|
import 'domain/repositories/shifts_repository_interface.dart';
|
||||||
import 'data/repositories_impl/shifts_repository_impl.dart';
|
import 'data/repositories_impl/shifts_repository_impl.dart';
|
||||||
import 'domain/usecases/get_shift_details_usecase.dart';
|
import 'domain/usecases/get_shift_details_usecase.dart';
|
||||||
@@ -14,11 +15,21 @@ class ShiftDetailsModule extends Module {
|
|||||||
// Repository
|
// Repository
|
||||||
i.add<ShiftsRepositoryInterface>(ShiftsRepositoryImpl.new);
|
i.add<ShiftsRepositoryInterface>(ShiftsRepositoryImpl.new);
|
||||||
|
|
||||||
|
// StaffConnectorRepository for profile completion
|
||||||
|
i.addLazySingleton<StaffConnectorRepository>(
|
||||||
|
() => StaffConnectorRepositoryImpl(),
|
||||||
|
);
|
||||||
|
|
||||||
// UseCases
|
// UseCases
|
||||||
i.add(GetShiftDetailsUseCase.new);
|
i.add(GetShiftDetailsUseCase.new);
|
||||||
i.add(AcceptShiftUseCase.new);
|
i.add(AcceptShiftUseCase.new);
|
||||||
i.add(DeclineShiftUseCase.new);
|
i.add(DeclineShiftUseCase.new);
|
||||||
i.add(ApplyForShiftUseCase.new);
|
i.add(ApplyForShiftUseCase.new);
|
||||||
|
i.addLazySingleton<GetProfileCompletionUseCase>(
|
||||||
|
() => GetProfileCompletionUseCase(
|
||||||
|
repository: i.get<StaffConnectorRepository>(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
// Bloc
|
// Bloc
|
||||||
i.add(ShiftDetailsBloc.new);
|
i.add(ShiftDetailsBloc.new);
|
||||||
|
|||||||
@@ -32,18 +32,18 @@ class StaffShiftsModule extends Module {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Repository
|
// Repository
|
||||||
i.add<ShiftsRepositoryInterface>(ShiftsRepositoryImpl.new);
|
i.addLazySingleton<ShiftsRepositoryInterface>(ShiftsRepositoryImpl.new);
|
||||||
|
|
||||||
// UseCases
|
// UseCases
|
||||||
i.add(GetMyShiftsUseCase.new);
|
i.addLazySingleton(GetMyShiftsUseCase.new);
|
||||||
i.add(GetAvailableShiftsUseCase.new);
|
i.addLazySingleton(GetAvailableShiftsUseCase.new);
|
||||||
i.add(GetPendingAssignmentsUseCase.new);
|
i.addLazySingleton(GetPendingAssignmentsUseCase.new);
|
||||||
i.add(GetCancelledShiftsUseCase.new);
|
i.addLazySingleton(GetCancelledShiftsUseCase.new);
|
||||||
i.add(GetHistoryShiftsUseCase.new);
|
i.addLazySingleton(GetHistoryShiftsUseCase.new);
|
||||||
i.add(AcceptShiftUseCase.new);
|
i.addLazySingleton(AcceptShiftUseCase.new);
|
||||||
i.add(DeclineShiftUseCase.new);
|
i.addLazySingleton(DeclineShiftUseCase.new);
|
||||||
i.add(ApplyForShiftUseCase.new);
|
i.addLazySingleton(ApplyForShiftUseCase.new);
|
||||||
i.add(GetShiftDetailsUseCase.new);
|
i.addLazySingleton(GetShiftDetailsUseCase.new);
|
||||||
|
|
||||||
// Bloc
|
// Bloc
|
||||||
i.add(
|
i.add(
|
||||||
|
|||||||
@@ -54,6 +54,22 @@ M4 delivers three key areas of improvement:
|
|||||||
- OTP Code: `123456` (testing mode)
|
- OTP Code: `123456` (testing mode)
|
||||||
- Name: "Mariana Torres"
|
- Name: "Mariana Torres"
|
||||||
|
|
||||||
|
**Note on Profile Completion:**
|
||||||
|
When a staff user hasn't completed their profile, they see an empty/incomplete state on their home screen. Currently tracked sections to mark as complete:
|
||||||
|
- Profile Information (full name, email, phone, preferred locations)
|
||||||
|
- Emergency Contact
|
||||||
|
|
||||||
|
Future sections can be added as mandatory, such as Tax Forms, Bank Account, Documents, Certificates, and Attires.
|
||||||
|
|
||||||
|
**Profile Blocking Rules:**
|
||||||
|
When the profile is incomplete, the following features are blocked to encourage completion:
|
||||||
|
- Clock-in page is hidden
|
||||||
|
- Payments are blocked
|
||||||
|
- "My Shifts" and History sections are hidden
|
||||||
|
- Users can view available shifts but cannot book them
|
||||||
|
|
||||||
|
This ensures we have all necessary information for compliance and payroll before workers are allowed to work.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. M4 Key Deliverables
|
## 3. M4 Key Deliverables
|
||||||
|
|||||||
Reference in New Issue
Block a user