feat(shifts): implement submit for approval functionality
- Added `submitForApproval` method to `ShiftsRepositoryInterface` and its implementation in `ShiftsRepositoryImpl`. - Created `SubmitForApprovalUseCase` to handle the submission logic. - Updated `ShiftsBloc` to handle `SubmitForApprovalEvent` and manage submission state. - Enhanced `HistoryShiftsTab` and `MyShiftsTab` to support submission actions and display appropriate UI feedback. - Refactored date utilities for better calendar management and filtering of past shifts. - Improved UI components for better spacing and alignment. - Localized success messages for shift submission actions.
This commit is contained in:
@@ -32,14 +32,11 @@ class _TimeCardPageState extends State<TimeCardPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Translations t = Translations.of(context);
|
||||
return BlocProvider.value(
|
||||
value: _bloc,
|
||||
child: Scaffold(
|
||||
appBar: UiAppBar(
|
||||
title: t.staff_time_card.title,
|
||||
showBackButton: true,
|
||||
),
|
||||
body: BlocConsumer<TimeCardBloc, TimeCardState>(
|
||||
return Scaffold(
|
||||
appBar: UiAppBar(title: t.staff_time_card.title, showBackButton: true),
|
||||
body: BlocProvider.value(
|
||||
value: _bloc,
|
||||
child: BlocConsumer<TimeCardBloc, TimeCardState>(
|
||||
listener: (BuildContext context, TimeCardState state) {
|
||||
if (state is TimeCardError) {
|
||||
UiSnackbar.show(
|
||||
|
||||
@@ -17,9 +17,7 @@ class ShiftHistoryList extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
t.staff_time_card.shift_history,
|
||||
style: UiTypography.title2b.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.title2b,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
if (timesheets.isEmpty)
|
||||
|
||||
@@ -6,7 +6,6 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
/// A card widget displaying details of a single shift/timecard.
|
||||
class TimesheetCard extends StatelessWidget {
|
||||
|
||||
const TimesheetCard({super.key, required this.timesheet});
|
||||
final TimeCardEntry timesheet;
|
||||
|
||||
@@ -25,9 +24,10 @@ class TimesheetCard extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
border: Border.all(color: UiColors.border),
|
||||
border: Border.all(color: UiColors.border, width: 0.5),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
@@ -60,20 +60,22 @@ class TimesheetCard extends StatelessWidget {
|
||||
if (timesheet.clockInAt != null && timesheet.clockOutAt != null)
|
||||
_IconText(
|
||||
icon: UiIcons.clock,
|
||||
text: '${DateFormat('h:mm a').format(timesheet.clockInAt!)} - ${DateFormat('h:mm a').format(timesheet.clockOutAt!)}',
|
||||
text:
|
||||
'${DateFormat('h:mm a').format(timesheet.clockInAt!)} - ${DateFormat('h:mm a').format(timesheet.clockOutAt!)}',
|
||||
),
|
||||
if (timesheet.location != null)
|
||||
_IconText(icon: UiIcons.mapPin, text: timesheet.location!),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
const SizedBox(height: UiConstants.space5),
|
||||
Container(
|
||||
padding: const EdgeInsets.only(top: UiConstants.space3),
|
||||
padding: const EdgeInsets.only(top: UiConstants.space4),
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(top: BorderSide(color: UiColors.border)),
|
||||
border: Border(top: BorderSide(color: UiColors.border, width: 0.5)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'${totalHours.toStringAsFixed(1)} ${t.staff_time_card.hours} @ \$${hourlyRate.toStringAsFixed(2)}${t.staff_time_card.per_hr}',
|
||||
@@ -81,7 +83,7 @@ class TimesheetCard extends StatelessWidget {
|
||||
),
|
||||
Text(
|
||||
'\$${totalPay.toStringAsFixed(2)}',
|
||||
style: UiTypography.title2b.primary,
|
||||
style: UiTypography.title1b,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -93,7 +95,6 @@ class TimesheetCard extends StatelessWidget {
|
||||
}
|
||||
|
||||
class _IconText extends StatelessWidget {
|
||||
|
||||
const _IconText({required this.icon, required this.text});
|
||||
final IconData icon;
|
||||
final String text;
|
||||
@@ -105,10 +106,7 @@ class _IconText extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Icon(icon, size: 14, color: UiColors.iconSecondary),
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
Text(
|
||||
text,
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
Text(text, style: UiTypography.body2r.textSecondary),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user