feat: Centralized Error Handling & Crash Fixes
This commit is contained in:
@@ -32,6 +32,7 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = Translations.of(context).staff.clock_in;
|
||||
return BlocProvider<ClockInBloc>.value(
|
||||
value: _bloc,
|
||||
child: BlocConsumer<ClockInBloc, ClockInState>(
|
||||
@@ -68,7 +69,7 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
return Scaffold(
|
||||
appBar: UiAppBar(
|
||||
titleWidget: Text(
|
||||
'Clock In to your Shift',
|
||||
i18n.title,
|
||||
style: UiTypography.title1m.textPrimary,
|
||||
),
|
||||
showBackButton: false,
|
||||
@@ -115,7 +116,7 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
|
||||
// Your Activity Header
|
||||
Text(
|
||||
"Your Activity",
|
||||
i18n.your_activity,
|
||||
textAlign: TextAlign.start,
|
||||
style: UiTypography.headline4m,
|
||||
),
|
||||
@@ -161,21 +162,23 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
shift.id ==
|
||||
selectedShift?.id
|
||||
? "SELECTED SHIFT"
|
||||
: "TODAY'S SHIFT",
|
||||
style: UiTypography
|
||||
.titleUppercase4b
|
||||
.copyWith(
|
||||
color: shift.id ==
|
||||
Text(
|
||||
shift.id ==
|
||||
selectedShift?.id
|
||||
? UiColors.primary
|
||||
: UiColors
|
||||
.textSecondary,
|
||||
? i18n
|
||||
.selected_shift_badge
|
||||
: i18n
|
||||
.today_shift_badge,
|
||||
style: UiTypography
|
||||
.titleUppercase4b
|
||||
.copyWith(
|
||||
color: shift.id ==
|
||||
selectedShift?.id
|
||||
? UiColors.primary
|
||||
: UiColors
|
||||
.textSecondary,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
shift.title,
|
||||
@@ -237,12 +240,16 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
Text(
|
||||
"You're early!",
|
||||
i18n.early_title,
|
||||
style: UiTypography.body1m.textSecondary,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Text(
|
||||
"Check-in available at ${_getCheckInAvailabilityTime(selectedShift)}",
|
||||
i18n.check_in_at(
|
||||
time: _getCheckInAvailabilityTime(
|
||||
selectedShift,
|
||||
),
|
||||
),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
@@ -316,12 +323,12 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
Text(
|
||||
"Shift Completed!",
|
||||
i18n.shift_completed,
|
||||
style: UiTypography.body1b.textSuccess,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Text(
|
||||
"Great work today",
|
||||
i18n.great_work,
|
||||
style: UiTypography.body2r.textSuccess,
|
||||
),
|
||||
],
|
||||
@@ -339,13 +346,13 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
"No confirmed shifts for today",
|
||||
i18n.no_shifts_today,
|
||||
style: UiTypography.body1m.textSecondary,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Text(
|
||||
"Accept a shift to clock in",
|
||||
i18n.accept_shift_cta,
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
@@ -377,7 +384,7 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
"Checked in at",
|
||||
i18n.checked_in_at_label,
|
||||
style: UiTypography.body3m.textSuccess,
|
||||
),
|
||||
Text(
|
||||
@@ -472,6 +479,7 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
}
|
||||
|
||||
Future<void> _showNFCDialog(BuildContext context) async {
|
||||
final i18n = Translations.of(context).staff.clock_in;
|
||||
bool scanned = false;
|
||||
|
||||
// Using a local navigator context since we are in a dialog
|
||||
@@ -482,7 +490,11 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
return StatefulBuilder(
|
||||
builder: (BuildContext context, setState) {
|
||||
return AlertDialog(
|
||||
title: Text(scanned ? 'Tag Scanned!' : 'Scan NFC Tag'),
|
||||
title: Text(
|
||||
scanned
|
||||
? i18n.nfc_dialog.scanned_title
|
||||
: i18n.nfc_dialog.scan_title,
|
||||
),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
@@ -503,14 +515,16 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
Text(
|
||||
scanned ? 'Processing check-in...' : 'Ready to scan',
|
||||
scanned
|
||||
? i18n.nfc_dialog.processing
|
||||
: i18n.nfc_dialog.ready_to_scan,
|
||||
style: UiTypography.headline4m,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
Text(
|
||||
scanned
|
||||
? 'Please wait...'
|
||||
: 'Hold your phone near the NFC tag at the clock-in station',
|
||||
? i18n.nfc_dialog.please_wait
|
||||
: i18n.nfc_dialog.scan_instruction,
|
||||
textAlign: TextAlign.center,
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
@@ -538,7 +552,7 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
},
|
||||
icon: const Icon(UiIcons.nfc, size: 24),
|
||||
label: Text(
|
||||
'Tap to Scan',
|
||||
i18n.nfc_dialog.tap_to_scan,
|
||||
style: UiTypography.headline4m.white,
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
@@ -608,7 +622,8 @@ class _ClockInPageState extends State<ClockInPage> {
|
||||
final DateTime windowStart = shiftStart.subtract(const Duration(minutes: 15));
|
||||
return DateFormat('h:mm a').format(windowStart);
|
||||
} catch (e) {
|
||||
return 'soon';
|
||||
final i18n = Translations.of(context).staff.clock_in;
|
||||
return i18n.soon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
@@ -131,6 +132,7 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final CommuteMode mode = _getAppMode();
|
||||
final i18n = Translations.of(context).staff.clock_in.commute;
|
||||
|
||||
// Notify parent of mode change
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
@@ -142,20 +144,20 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
return const SizedBox.shrink();
|
||||
|
||||
case CommuteMode.needsConsent:
|
||||
return _buildConsentCard();
|
||||
return _buildConsentCard(i18n);
|
||||
|
||||
case CommuteMode.preShiftCommuteAllowed:
|
||||
return _buildPreShiftCard();
|
||||
return _buildPreShiftCard(i18n);
|
||||
|
||||
case CommuteMode.commuteModeActive:
|
||||
return _buildActiveCommuteScreen();
|
||||
return _buildActiveCommuteScreen(i18n);
|
||||
|
||||
case CommuteMode.arrivedCanClockIn:
|
||||
return _buildArrivedCard();
|
||||
return _buildArrivedCard(i18n);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildConsentCard() {
|
||||
Widget _buildConsentCard(TranslationsStaffClockInCommuteEn i18n) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: UiConstants.space5),
|
||||
padding: const EdgeInsets.all(UiConstants.space3),
|
||||
@@ -202,12 +204,12 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Enable Commute Tracking?',
|
||||
i18n.enable_title,
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Text(
|
||||
'Share location 1hr before shift so your manager can see you\'re on the way.',
|
||||
i18n.enable_desc,
|
||||
style: UiTypography.body4r.textSecondary,
|
||||
),
|
||||
],
|
||||
@@ -229,7 +231,7 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
),
|
||||
side: const BorderSide(color: UiColors.border),
|
||||
),
|
||||
child: Text('Not Now', style: UiTypography.footnote1m),
|
||||
child: Text(i18n.not_now, style: UiTypography.footnote1m),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: UiConstants.space2),
|
||||
@@ -245,7 +247,7 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
'Enable',
|
||||
i18n.enable,
|
||||
style: UiTypography.footnote1m.white,
|
||||
),
|
||||
),
|
||||
@@ -257,7 +259,7 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPreShiftCard() {
|
||||
Widget _buildPreShiftCard(TranslationsStaffClockInCommuteEn i18n) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: UiConstants.space5),
|
||||
padding: const EdgeInsets.all(UiConstants.space3),
|
||||
@@ -295,7 +297,7 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'On My Way',
|
||||
i18n.on_my_way,
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
const SizedBox(width: UiConstants.space2),
|
||||
@@ -308,7 +310,7 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
Text(
|
||||
'Shift starts in ${_getMinutesUntilShift()} min',
|
||||
i18n.starts_in(min: _getMinutesUntilShift().toString()),
|
||||
style: UiTypography.titleUppercase4m.textSecondary,
|
||||
),
|
||||
],
|
||||
@@ -316,7 +318,7 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
],
|
||||
),
|
||||
Text(
|
||||
'Track arrival',
|
||||
i18n.track_arrival,
|
||||
style: UiTypography.titleUppercase4m.textSecondary,
|
||||
),
|
||||
],
|
||||
@@ -335,7 +337,7 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActiveCommuteScreen() {
|
||||
Widget _buildActiveCommuteScreen(TranslationsStaffClockInCommuteEn i18n) {
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
decoration: const BoxDecoration(
|
||||
@@ -353,11 +355,11 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(UiConstants.space5),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(UiConstants.space5),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
TweenAnimationBuilder(
|
||||
tween: Tween<double>(begin: 1.0, end: 1.1),
|
||||
duration: const Duration(seconds: 1),
|
||||
@@ -387,12 +389,12 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
Text(
|
||||
'On My Way',
|
||||
i18n.on_my_way,
|
||||
style: UiTypography.displayMb.white,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
Text(
|
||||
'Your manager can see you\'re heading to the site',
|
||||
i18n.heading_to_site,
|
||||
style: UiTypography.body2r.copyWith(
|
||||
color: UiColors.primaryForeground.withValues(alpha: 0.8),
|
||||
),
|
||||
@@ -414,7 +416,7 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Distance to Site',
|
||||
i18n.distance_to_site,
|
||||
style: UiTypography.body2r.copyWith(
|
||||
color: UiColors.primaryForeground.withValues(alpha: 0.8),
|
||||
),
|
||||
@@ -443,14 +445,14 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Estimated Arrival',
|
||||
i18n.estimated_arrival,
|
||||
style: UiTypography.body2r.copyWith(
|
||||
color: UiColors.primaryForeground.withValues(alpha: 0.8),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Text(
|
||||
'${widget.etaMinutes} min',
|
||||
i18n.eta_label(min: widget.etaMinutes.toString()),
|
||||
style: UiTypography.headline1m.white,
|
||||
),
|
||||
],
|
||||
@@ -460,7 +462,7 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
],
|
||||
const SizedBox(height: UiConstants.space8),
|
||||
Text(
|
||||
'Most app features are locked while commute mode is on. You\'ll be able to clock in once you arrive.',
|
||||
i18n.locked_desc,
|
||||
style: UiTypography.footnote1r.copyWith(
|
||||
color: UiColors.primaryForeground.withValues(alpha: 0.8),
|
||||
),
|
||||
@@ -485,7 +487,7 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
),
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
),
|
||||
child: Text('Turn Off Commute Mode', style: UiTypography.buttonL),
|
||||
child: Text(i18n.turn_off, style: UiTypography.buttonL),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -494,7 +496,7 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildArrivedCard() {
|
||||
Widget _buildArrivedCard(TranslationsStaffClockInCommuteEn i18n) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: UiConstants.space5),
|
||||
padding: const EdgeInsets.all(UiConstants.space5),
|
||||
@@ -533,12 +535,12 @@ class _CommuteTrackerState extends State<CommuteTracker> {
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
Text(
|
||||
'You\'ve Arrived! 🎉',
|
||||
i18n.arrived_title,
|
||||
style: UiTypography.headline3m.textPrimary,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
Text(
|
||||
'You\'re at the shift location. Ready to clock in?',
|
||||
i18n.arrived_desc,
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -22,13 +23,6 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
String _additionalNotes = '';
|
||||
|
||||
final List<String> _timeOptions = _generateTimeOptions();
|
||||
final List<String> _noLunchReasons = <String>[
|
||||
'Unpredictable Workflows',
|
||||
'Poor Time Management',
|
||||
'Lack of coverage or short Staff',
|
||||
'No Lunch Area',
|
||||
'Other (Please specify)',
|
||||
];
|
||||
|
||||
static List<String> _generateTimeOptions() {
|
||||
final List<String> options = <String>[];
|
||||
@@ -45,6 +39,7 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = Translations.of(context).staff.clock_in.lunch_break;
|
||||
return Dialog(
|
||||
backgroundColor: UiColors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
@@ -52,29 +47,29 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
),
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: _buildCurrentStep(),
|
||||
child: _buildCurrentStep(i18n),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCurrentStep() {
|
||||
Widget _buildCurrentStep(TranslationsStaffClockInLunchBreakEn i18n) {
|
||||
switch (_step) {
|
||||
case 1:
|
||||
return _buildStep1();
|
||||
return _buildStep1(i18n);
|
||||
case 2:
|
||||
return _buildStep2();
|
||||
return _buildStep2(i18n);
|
||||
case 102: // 2b: No lunch reason
|
||||
return _buildStep2b();
|
||||
return _buildStep2b(i18n);
|
||||
case 3:
|
||||
return _buildStep3();
|
||||
return _buildStep3(i18n);
|
||||
case 4:
|
||||
return _buildStep4();
|
||||
return _buildStep4(i18n);
|
||||
default:
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildStep1() {
|
||||
Widget _buildStep1(TranslationsStaffClockInLunchBreakEn i18n) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(UiConstants.space6),
|
||||
child: Column(
|
||||
@@ -95,7 +90,7 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
Text(
|
||||
"Did You Take\na Lunch?",
|
||||
i18n.title,
|
||||
textAlign: TextAlign.center,
|
||||
style: UiTypography.headline1m.textPrimary,
|
||||
),
|
||||
@@ -121,7 +116,7 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
"No",
|
||||
i18n.no,
|
||||
style: UiTypography.body1m.textPrimary,
|
||||
),
|
||||
),
|
||||
@@ -146,7 +141,7 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
"Yes",
|
||||
i18n.yes,
|
||||
style: UiTypography.body1m.white,
|
||||
),
|
||||
),
|
||||
@@ -158,7 +153,7 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStep2() {
|
||||
Widget _buildStep2(TranslationsStaffClockInLunchBreakEn i18n) {
|
||||
// Time input
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(UiConstants.space6),
|
||||
@@ -166,7 +161,7 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
"When did you take lunch?",
|
||||
i18n.when_title,
|
||||
style: UiTypography.headline4m,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
@@ -186,9 +181,9 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
)
|
||||
.toList(),
|
||||
onChanged: (String? v) => setState(() => _breakStart = v),
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Start',
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
decoration: InputDecoration(
|
||||
labelText: i18n.start,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 8,
|
||||
),
|
||||
@@ -209,9 +204,9 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
)
|
||||
.toList(),
|
||||
onChanged: (String? v) => setState(() => _breakEnd = v),
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'End',
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
decoration: InputDecoration(
|
||||
labelText: i18n.end,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 8,
|
||||
),
|
||||
@@ -230,14 +225,14 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
backgroundColor: UiColors.primary,
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
),
|
||||
child: Text("Next", style: UiTypography.body1m.white),
|
||||
child: Text(i18n.next, style: UiTypography.body1m.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStep2b() {
|
||||
Widget _buildStep2b(TranslationsStaffClockInLunchBreakEn i18n) {
|
||||
// No lunch reason
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(UiConstants.space6),
|
||||
@@ -246,11 +241,11 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
"Why didn't you take lunch?",
|
||||
i18n.why_no_lunch,
|
||||
style: UiTypography.headline4m,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
..._noLunchReasons.map(
|
||||
...i18n.reasons.map(
|
||||
(String reason) => RadioListTile<String>(
|
||||
title: Text(reason, style: UiTypography.body2r),
|
||||
value: reason,
|
||||
@@ -269,14 +264,14 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
backgroundColor: UiColors.primary,
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
),
|
||||
child: Text("Next", style: UiTypography.body1m.white),
|
||||
child: Text(i18n.next, style: UiTypography.body1m.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStep3() {
|
||||
Widget _buildStep3(TranslationsStaffClockInLunchBreakEn i18n) {
|
||||
// Additional Notes
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(UiConstants.space6),
|
||||
@@ -284,16 +279,16 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
"Additional Notes",
|
||||
i18n.additional_notes,
|
||||
style: UiTypography.headline4m,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
TextField(
|
||||
onChanged: (String v) => _additionalNotes = v,
|
||||
style: UiTypography.body2r,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Add any details...',
|
||||
border: OutlineInputBorder(),
|
||||
decoration: InputDecoration(
|
||||
hintText: i18n.notes_placeholder,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
maxLines: 3,
|
||||
),
|
||||
@@ -307,14 +302,14 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
backgroundColor: UiColors.primary,
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
),
|
||||
child: Text("Submit", style: UiTypography.body1m.white),
|
||||
child: Text(i18n.submit, style: UiTypography.body1m.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStep4() {
|
||||
Widget _buildStep4(TranslationsStaffClockInLunchBreakEn i18n) {
|
||||
// Success
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(UiConstants.space6),
|
||||
@@ -324,7 +319,7 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
const Icon(UiIcons.checkCircle, size: 64, color: UiColors.success),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
Text(
|
||||
"Break Logged!",
|
||||
i18n.success_title,
|
||||
style: UiTypography.headline1m,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
@@ -334,7 +329,7 @@ class _LunchBreakDialogState extends State<LunchBreakDialog> {
|
||||
backgroundColor: UiColors.primary,
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
),
|
||||
child: Text("Close", style: UiTypography.body1m.white),
|
||||
child: Text(i18n.close, style: UiTypography.body1m.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -71,6 +72,7 @@ class _SwipeToCheckInState extends State<SwipeToCheckIn>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = Translations.of(context).staff.clock_in.swipe;
|
||||
final Color baseColor = widget.isCheckedIn
|
||||
? UiColors.success
|
||||
: UiColors.primary;
|
||||
@@ -110,9 +112,9 @@ class _SwipeToCheckInState extends State<SwipeToCheckIn>
|
||||
Text(
|
||||
widget.isLoading
|
||||
? (widget.isCheckedIn
|
||||
? "Checking out..."
|
||||
: "Checking in...")
|
||||
: (widget.isCheckedIn ? "NFC Check Out" : "NFC Check In"),
|
||||
? i18n.checking_out
|
||||
: i18n.checking_in)
|
||||
: (widget.isCheckedIn ? i18n.nfc_checkout : i18n.nfc_checkin),
|
||||
style: UiTypography.body1b.white,
|
||||
),
|
||||
],
|
||||
@@ -157,8 +159,8 @@ class _SwipeToCheckInState extends State<SwipeToCheckIn>
|
||||
opacity: 1.0 - progress,
|
||||
child: Text(
|
||||
widget.isCheckedIn
|
||||
? "Swipe to Check Out"
|
||||
: "Swipe to Check In",
|
||||
? i18n.swipe_checkout
|
||||
: i18n.swipe_checkin,
|
||||
style: UiTypography.body1b,
|
||||
),
|
||||
),
|
||||
@@ -166,7 +168,7 @@ class _SwipeToCheckInState extends State<SwipeToCheckIn>
|
||||
if (_isComplete)
|
||||
Center(
|
||||
child: Text(
|
||||
widget.isCheckedIn ? "Check Out!" : "Check In!",
|
||||
widget.isCheckedIn ? i18n.checkout_complete : i18n.checkin_complete,
|
||||
style: UiTypography.body1b,
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user