diff --git a/apps/mobile/packages/core_localization/lib/src/l10n/en.i18n.json b/apps/mobile/packages/core_localization/lib/src/l10n/en.i18n.json index 4f74094c..be7f2b3a 100644 --- a/apps/mobile/packages/core_localization/lib/src/l10n/en.i18n.json +++ b/apps/mobile/packages/core_localization/lib/src/l10n/en.i18n.json @@ -1360,7 +1360,8 @@ "timesheet_submitted": "Timesheet submitted for client approval", "checked_in": "Checked in", "submitted": "SUBMITTED", - "ready_to_submit": "READY TO SUBMIT" + "ready_to_submit": "READY TO SUBMIT", + "submitting": "SUBMITTING..." }, "shift_location": { "could_not_open_maps": "Could not open maps" diff --git a/apps/mobile/packages/core_localization/lib/src/l10n/es.i18n.json b/apps/mobile/packages/core_localization/lib/src/l10n/es.i18n.json index 3ed49e2d..420d0ef6 100644 --- a/apps/mobile/packages/core_localization/lib/src/l10n/es.i18n.json +++ b/apps/mobile/packages/core_localization/lib/src/l10n/es.i18n.json @@ -1355,7 +1355,8 @@ "timesheet_submitted": "Hoja de tiempo enviada para aprobación del cliente", "checked_in": "Registrado", "submitted": "ENVIADO", - "ready_to_submit": "LISTO PARA ENVIAR" + "ready_to_submit": "LISTO PARA ENVIAR", + "submitting": "ENVIANDO..." }, "shift_location": { "could_not_open_maps": "No se pudo abrir mapas" diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/pages/shifts_page.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/pages/shifts_page.dart index ba32bb84..bb0bc006 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/pages/shifts_page.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/pages/shifts_page.dart @@ -266,6 +266,7 @@ class _ShiftsPageState extends State { cancelledShifts: cancelledShifts, initialDate: _selectedDate, submittedShiftIds: state.submittedShiftIds, + submittingShiftId: state.submittingShiftId, ); case ShiftTabType.find: if (availableLoading) { @@ -282,6 +283,7 @@ class _ShiftsPageState extends State { return HistoryShiftsTab( historyShifts: historyShifts, submittedShiftIds: state.submittedShiftIds, + submittingShiftId: state.submittingShiftId, ); } } diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/shift_card/shift_card.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/shift_card/shift_card.dart index aa5a6b4d..eca3dd34 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/shift_card/shift_card.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/shift_card/shift_card.dart @@ -21,6 +21,7 @@ class ShiftCard extends StatelessWidget { this.onSubmitForApproval, this.showApprovalAction = false, this.isSubmitted = false, + this.isSubmitting = false, this.onAccept, this.onDecline, this.isAccepting = false, @@ -41,6 +42,9 @@ class ShiftCard extends StatelessWidget { /// Whether the timesheet has already been submitted. final bool isSubmitted; + /// Whether the timesheet submission is currently in progress. + final bool isSubmitting; + /// Callback when the accept action is pressed (pending assignments only). final VoidCallback? onAccept; @@ -91,6 +95,7 @@ class ShiftCard extends StatelessWidget { const SizedBox(height: UiConstants.space2), ShiftCardApprovalFooter( isSubmitted: isSubmitted, + isSubmitting: isSubmitting, onSubmit: onSubmitForApproval, ), ], diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/shift_card/shift_card_approval_footer.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/shift_card/shift_card_approval_footer.dart index 60794010..cff59051 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/shift_card/shift_card_approval_footer.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/shift_card/shift_card_approval_footer.dart @@ -8,12 +8,16 @@ class ShiftCardApprovalFooter extends StatelessWidget { const ShiftCardApprovalFooter({ super.key, required this.isSubmitted, + this.isSubmitting = false, this.onSubmit, }); /// Whether the timesheet has already been submitted. final bool isSubmitted; + /// Whether the submission is currently in progress. + final bool isSubmitting; + /// Callback when the submit button is pressed. final VoidCallback? onSubmit; @@ -23,14 +27,25 @@ class ShiftCardApprovalFooter extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - isSubmitted - ? context.t.staff_shifts.my_shift_card.submitted - : context.t.staff_shifts.my_shift_card.ready_to_submit, + isSubmitting + ? context.t.staff_shifts.my_shift_card.submitting + : isSubmitted + ? context.t.staff_shifts.my_shift_card.submitted + : context.t.staff_shifts.my_shift_card.ready_to_submit, style: UiTypography.footnote2b.copyWith( color: isSubmitted ? UiColors.textSuccess : UiColors.textSecondary, ), ), - if (!isSubmitted) + if (isSubmitting) + const SizedBox( + height: UiConstants.space4, + width: UiConstants.space4, + child: CircularProgressIndicator( + strokeWidth: 2, + color: UiColors.primary, + ), + ) + else if (!isSubmitted) UiButton.secondary( text: context.t.staff_shifts.my_shift_card.submit_for_approval, size: UiButtonSize.small, diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/history_shifts_tab.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/history_shifts_tab.dart index e6dd586f..5577fb24 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/history_shifts_tab.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/history_shifts_tab.dart @@ -17,6 +17,7 @@ class HistoryShiftsTab extends StatelessWidget { super.key, required this.historyShifts, this.submittedShiftIds = const {}, + this.submittingShiftId, }); /// Completed shifts. @@ -25,6 +26,9 @@ class HistoryShiftsTab extends StatelessWidget { /// Set of shift IDs that have been successfully submitted for approval. final Set submittedShiftIds; + /// The shift ID currently being submitted (null when idle). + final String? submittingShiftId; + @override Widget build(BuildContext context) { if (historyShifts.isEmpty) { @@ -44,6 +48,8 @@ class HistoryShiftsTab extends StatelessWidget { (CompletedShift shift) { final bool isSubmitted = submittedShiftIds.contains(shift.shiftId); + final bool isSubmitting = + submittingShiftId == shift.shiftId; return Padding( padding: const EdgeInsets.only(bottom: UiConstants.space3), child: ShiftCard( @@ -52,6 +58,7 @@ class HistoryShiftsTab extends StatelessWidget { Modular.to.toShiftDetailsById(shift.shiftId), showApprovalAction: !isSubmitted, isSubmitted: isSubmitted, + isSubmitting: isSubmitting, onSubmitForApproval: () { ReadContext(context).read().add( SubmitForApprovalEvent(shiftId: shift.shiftId), diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/my_shifts_tab.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/my_shifts_tab.dart index ceba6210..67063ce3 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/my_shifts_tab.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/my_shifts_tab.dart @@ -22,6 +22,7 @@ class MyShiftsTab extends StatefulWidget { required this.cancelledShifts, this.initialDate, this.submittedShiftIds = const {}, + this.submittingShiftId, }); /// Assigned shifts for the current week. @@ -39,6 +40,9 @@ class MyShiftsTab extends StatefulWidget { /// Set of shift IDs that have been successfully submitted for approval. final Set submittedShiftIds; + /// The shift ID currently being submitted (null when idle). + final String? submittingShiftId; + @override State createState() => _MyShiftsTabState(); } @@ -392,6 +396,8 @@ class _MyShiftsTabState extends State { shift.status == AssignmentStatus.completed; final bool isSubmitted = widget.submittedShiftIds.contains(shift.shiftId); + final bool isSubmitting = + widget.submittingShiftId == shift.shiftId; return Padding( padding: const EdgeInsets.only( @@ -403,6 +409,7 @@ class _MyShiftsTabState extends State { .toShiftDetailsById(shift.shiftId), showApprovalAction: isCompleted, isSubmitted: isSubmitted, + isSubmitting: isSubmitting, onSubmitForApproval: () { ReadContext(context).read().add( SubmitForApprovalEvent(