refactor: enhance navigation robustness by introducing popSafe and safePushNamedAndRemoveUntil methods and updating their usage.
This commit is contained in:
@@ -74,7 +74,9 @@ class _SessionListenerState extends State<SessionListener> {
|
||||
// Only show if not initial state (avoid showing on cold start)
|
||||
if (!_isInitialState) {
|
||||
debugPrint('[SessionListener] Session error: ${state.errorMessage}');
|
||||
_showSessionErrorDialog(state.errorMessage ?? 'Session error occurred');
|
||||
_showSessionErrorDialog(
|
||||
state.errorMessage ?? 'Session error occurred',
|
||||
);
|
||||
} else {
|
||||
_isInitialState = false;
|
||||
Modular.to.toClientGetStartedPage();
|
||||
@@ -126,7 +128,7 @@ class _SessionListenerState extends State<SessionListener> {
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
// User can retry by dismissing and continuing
|
||||
Modular.to.pop();
|
||||
Modular.to.popSafe();
|
||||
},
|
||||
child: const Text('Continue'),
|
||||
),
|
||||
|
||||
@@ -65,7 +65,6 @@ class _SessionListenerState extends State<SessionListener> {
|
||||
_sessionExpiredDialogShown = false;
|
||||
debugPrint('[SessionListener] Authenticated: ${state.userId}');
|
||||
|
||||
|
||||
// Navigate to the main app
|
||||
Modular.to.toStaffHome();
|
||||
break;
|
||||
@@ -75,7 +74,9 @@ class _SessionListenerState extends State<SessionListener> {
|
||||
// Only show if not initial state (avoid showing on cold start)
|
||||
if (!_isInitialState) {
|
||||
debugPrint('[SessionListener] Session error: ${state.errorMessage}');
|
||||
_showSessionErrorDialog(state.errorMessage ?? 'Session error occurred');
|
||||
_showSessionErrorDialog(
|
||||
state.errorMessage ?? 'Session error occurred',
|
||||
);
|
||||
} else {
|
||||
_isInitialState = false;
|
||||
Modular.to.toGetStartedPage();
|
||||
@@ -127,7 +128,7 @@ class _SessionListenerState extends State<SessionListener> {
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
// User can retry by dismissing and continuing
|
||||
Modular.to.pop();
|
||||
Modular.to.popSafe();
|
||||
},
|
||||
child: const Text('Continue'),
|
||||
),
|
||||
|
||||
@@ -103,7 +103,7 @@ extension ClientNavigator on IModularNavigator {
|
||||
|
||||
/// Navigates to the full list of invoices awaiting approval.
|
||||
void toAwaitingApproval({Object? arguments}) {
|
||||
safeNavigate(ClientPaths.awaitingApproval, arguments: arguments);
|
||||
safePush(ClientPaths.awaitingApproval, arguments: arguments);
|
||||
}
|
||||
|
||||
/// Navigates to the Invoice Ready page.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'client/route_paths.dart';
|
||||
import 'staff/route_paths.dart';
|
||||
@@ -29,8 +30,8 @@ extension NavigationExtensions on IModularNavigator {
|
||||
return true;
|
||||
} catch (e) {
|
||||
// In production, you might want to log this to a monitoring service
|
||||
// ignore: avoid_print
|
||||
print('Navigation error to $path: $e');
|
||||
// ignore: avoid_debugPrint
|
||||
debugPrint('Navigation error to $path: $e');
|
||||
navigateToHome();
|
||||
return false;
|
||||
}
|
||||
@@ -54,8 +55,29 @@ extension NavigationExtensions on IModularNavigator {
|
||||
return await pushNamed<T>(routeName, arguments: arguments);
|
||||
} catch (e) {
|
||||
// In production, you might want to log this to a monitoring service
|
||||
// ignore: avoid_print
|
||||
print('Push navigation error to $routeName: $e');
|
||||
// ignore: avoid_debugPrint
|
||||
debugPrint('Push navigation error to $routeName: $e');
|
||||
navigateToHome();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Safely pushes a named route and removes until a predicate is met.
|
||||
Future<T?> safePushNamedAndRemoveUntil<T extends Object?>(
|
||||
String routeName,
|
||||
bool Function(Route<dynamic>) predicate, {
|
||||
Object? arguments,
|
||||
}) async {
|
||||
try {
|
||||
return await pushNamedAndRemoveUntil<T>(
|
||||
routeName,
|
||||
predicate,
|
||||
arguments: arguments,
|
||||
);
|
||||
} catch (e) {
|
||||
// In production, you might want to log this to a monitoring service
|
||||
// ignore: avoid_debugPrint
|
||||
debugPrint('PushNamedAndRemoveUntil error to $routeName: $e');
|
||||
navigateToHome();
|
||||
return null;
|
||||
}
|
||||
@@ -72,9 +94,9 @@ extension NavigationExtensions on IModularNavigator {
|
||||
/// Pops the current route if possible, otherwise navigates to home.
|
||||
///
|
||||
/// Returns `true` if a route was popped, `false` if it navigated to home.
|
||||
bool popSafe() {
|
||||
bool popSafe<T extends Object?>([T? result]) {
|
||||
if (canPop()) {
|
||||
pop();
|
||||
pop(result);
|
||||
return true;
|
||||
}
|
||||
navigateToHome();
|
||||
|
||||
@@ -53,7 +53,7 @@ extension StaffNavigator on IModularNavigator {
|
||||
}
|
||||
|
||||
void toStaffHome() {
|
||||
pushNamedAndRemoveUntil(StaffPaths.home, (_) => false);
|
||||
safePushNamedAndRemoveUntil(StaffPaths.home, (_) => false);
|
||||
}
|
||||
|
||||
void toBenefits() {
|
||||
@@ -61,7 +61,7 @@ extension StaffNavigator on IModularNavigator {
|
||||
}
|
||||
|
||||
void toStaffMain() {
|
||||
pushNamedAndRemoveUntil('${StaffPaths.main}/home/', (_) => false);
|
||||
safePushNamedAndRemoveUntil('${StaffPaths.main}/home/', (_) => false);
|
||||
}
|
||||
|
||||
void toShifts({
|
||||
@@ -83,11 +83,11 @@ extension StaffNavigator on IModularNavigator {
|
||||
}
|
||||
|
||||
void toPayments() {
|
||||
pushNamedAndRemoveUntil(StaffPaths.payments, (_) => false);
|
||||
safePushNamedAndRemoveUntil(StaffPaths.payments, (_) => false);
|
||||
}
|
||||
|
||||
void toClockIn() {
|
||||
pushNamedAndRemoveUntil(StaffPaths.clockIn, (_) => false);
|
||||
safePushNamedAndRemoveUntil(StaffPaths.clockIn, (_) => false);
|
||||
}
|
||||
|
||||
void toProfile() {
|
||||
@@ -154,6 +154,18 @@ extension StaffNavigator on IModularNavigator {
|
||||
safePush(StaffPaths.taxForms);
|
||||
}
|
||||
|
||||
void toLanguageSelection() {
|
||||
safePush(StaffPaths.languageSelection);
|
||||
}
|
||||
|
||||
void toFormI9() {
|
||||
safeNavigate(StaffPaths.formI9);
|
||||
}
|
||||
|
||||
void toFormW4() {
|
||||
safeNavigate(StaffPaths.formW4);
|
||||
}
|
||||
|
||||
void toTimeCard() {
|
||||
safePush(StaffPaths.timeCard);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
|
||||
import '../blocs/billing_bloc.dart';
|
||||
import '../blocs/billing_state.dart';
|
||||
@@ -20,6 +21,7 @@ class PendingInvoicesPage extends StatelessWidget {
|
||||
appBar: UiAppBar(
|
||||
title: t.client_billing.awaiting_approval,
|
||||
showBackButton: true,
|
||||
onLeadingPressed: () => Modular.to.toClientBilling(),
|
||||
),
|
||||
body: _buildBody(context, state),
|
||||
);
|
||||
|
||||
@@ -46,19 +46,19 @@ class ClientMainCubit extends Cubit<ClientMainState> implements Disposable {
|
||||
|
||||
switch (index) {
|
||||
case 0:
|
||||
Modular.to.navigate(ClientPaths.coverage);
|
||||
Modular.to.toClientCoverage();
|
||||
break;
|
||||
case 1:
|
||||
Modular.to.navigate(ClientPaths.billing);
|
||||
Modular.to.toClientBilling();
|
||||
break;
|
||||
case 2:
|
||||
Modular.to.navigate(ClientPaths.home);
|
||||
Modular.to.toClientHome();
|
||||
break;
|
||||
case 3:
|
||||
Modular.to.navigate(ClientPaths.orders);
|
||||
Modular.to.toClientOrders();
|
||||
break;
|
||||
case 4:
|
||||
Modular.to.navigate(ClientPaths.reports);
|
||||
Modular.to.toClientReports();
|
||||
break;
|
||||
}
|
||||
// State update will happen via _onRouteChanged
|
||||
|
||||
@@ -80,7 +80,7 @@ class _RapidOrderFormState extends State<_RapidOrderForm> {
|
||||
subtitle: labels.subtitle,
|
||||
date: dateStr,
|
||||
time: timeStr,
|
||||
onBack: () => Modular.to.navigate(ClientPaths.createOrder),
|
||||
onBack: () => Modular.to.toCreateOrder(),
|
||||
),
|
||||
|
||||
// Content
|
||||
|
||||
@@ -2,13 +2,13 @@ import 'package:core_localization/core_localization.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
|
||||
/// A quick report card widget for navigating to specific reports.
|
||||
///
|
||||
/// Displays an icon, name, and a quick navigation to a report page.
|
||||
/// Used in the quick reports grid of the reports page.
|
||||
class ReportCard extends StatelessWidget {
|
||||
|
||||
const ReportCard({
|
||||
super.key,
|
||||
required this.icon,
|
||||
@@ -17,6 +17,7 @@ class ReportCard extends StatelessWidget {
|
||||
required this.iconColor,
|
||||
required this.route,
|
||||
});
|
||||
|
||||
/// The icon to display for this report.
|
||||
final IconData icon;
|
||||
|
||||
@@ -35,7 +36,7 @@ class ReportCard extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () => Modular.to.pushNamed(route),
|
||||
onTap: () => Modular.to.safePush(route),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
@@ -86,8 +87,7 @@ class ReportCard extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
context.t.client_reports.quick_reports
|
||||
.two_click_export,
|
||||
context.t.client_reports.quick_reports.two_click_export,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: UiColors.textSecondary,
|
||||
|
||||
@@ -17,9 +17,9 @@ import '../widgets/phone_verification_page/phone_input.dart';
|
||||
/// This page coordinates the authentication flow by switching between
|
||||
/// [PhoneInput] and [OtpVerification] based on the current [AuthState].
|
||||
class PhoneVerificationPage extends StatefulWidget {
|
||||
|
||||
/// Creates a [PhoneVerificationPage].
|
||||
const PhoneVerificationPage({super.key, required this.mode});
|
||||
|
||||
/// The authentication mode (login or signup).
|
||||
final AuthMode mode;
|
||||
|
||||
@@ -123,10 +123,10 @@ class _PhoneVerificationPageState extends State<PhoneVerificationPage> {
|
||||
);
|
||||
Future<void>.delayed(const Duration(seconds: 5), () {
|
||||
if (!mounted) return;
|
||||
Modular.to.navigate('/');
|
||||
Modular.to.toInitialPage();
|
||||
});
|
||||
} else if (messageKey == 'errors.auth.unauthorized_app') {
|
||||
Modular.to.pop();
|
||||
Modular.to.popSafe();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -155,7 +155,7 @@ class _CertificateUploadPageState extends State<CertificateUploadPage> {
|
||||
message: t.staff_certificates.upload_modal.success_snackbar,
|
||||
type: UiSnackbarType.success,
|
||||
);
|
||||
Modular.to.pop(); // Returns to certificates list
|
||||
Modular.to.popSafe(); // Returns to certificates list
|
||||
} else if (state.status == CertificateUploadStatus.failure) {
|
||||
UiSnackbar.show(
|
||||
context,
|
||||
@@ -170,7 +170,7 @@ class _CertificateUploadPageState extends State<CertificateUploadPage> {
|
||||
title:
|
||||
widget.certificate?.name ??
|
||||
t.staff_certificates.upload_modal.title,
|
||||
onLeadingPressed: () => Modular.to.pop(),
|
||||
onLeadingPressed: () => Modular.to.popSafe(),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(UiConstants.space5),
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
|
||||
class CertificatesHeader extends StatelessWidget {
|
||||
|
||||
const CertificatesHeader({
|
||||
super.key,
|
||||
required this.completedCount,
|
||||
@@ -16,8 +16,12 @@ class CertificatesHeader extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Prevent division by zero
|
||||
final double progressValue = totalCount == 0 ? 0 : completedCount / totalCount;
|
||||
final int progressPercent = totalCount == 0 ? 0 : (progressValue * 100).round();
|
||||
final double progressValue = totalCount == 0
|
||||
? 0
|
||||
: completedCount / totalCount;
|
||||
final int progressPercent = totalCount == 0
|
||||
? 0
|
||||
: (progressValue * 100).round();
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
@@ -42,7 +46,7 @@ class CertificatesHeader extends StatelessWidget {
|
||||
Row(
|
||||
children: <Widget>[
|
||||
GestureDetector(
|
||||
onTap: () => Modular.to.pop(),
|
||||
onTap: () => Modular.to.popSafe(),
|
||||
child: Container(
|
||||
width: UiConstants.space10,
|
||||
height: UiConstants.space10,
|
||||
@@ -101,7 +105,9 @@ class CertificatesHeader extends StatelessWidget {
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Text(
|
||||
t.staff_certificates.progress.verified_count(
|
||||
completed: completedCount, total: totalCount),
|
||||
completed: completedCount,
|
||||
total: totalCount,
|
||||
),
|
||||
style: UiTypography.body3r.copyWith(
|
||||
color: UiColors.white.withValues(alpha: 0.7),
|
||||
),
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart' hide ModularWatchExtension;
|
||||
import 'package:flutter_modular/flutter_modular.dart'
|
||||
hide ModularWatchExtension;
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
import '../blocs/i9/form_i9_cubit.dart';
|
||||
@@ -18,11 +20,56 @@ class FormI9Page extends StatefulWidget {
|
||||
|
||||
class _FormI9PageState extends State<FormI9Page> {
|
||||
final List<String> _usStates = <String>[
|
||||
'AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'FL', 'GA',
|
||||
'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MD',
|
||||
'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ',
|
||||
'NM', 'NY', 'NC', 'ND', 'OH', 'OK', 'OR', 'PA', 'RI', 'SC',
|
||||
'SD', 'TN', 'TX', 'UT', 'VT', 'VA', 'WA', 'WV', 'WI', 'WY'
|
||||
'AL',
|
||||
'AK',
|
||||
'AZ',
|
||||
'AR',
|
||||
'CA',
|
||||
'CO',
|
||||
'CT',
|
||||
'DE',
|
||||
'FL',
|
||||
'GA',
|
||||
'HI',
|
||||
'ID',
|
||||
'IL',
|
||||
'IN',
|
||||
'IA',
|
||||
'KS',
|
||||
'KY',
|
||||
'LA',
|
||||
'ME',
|
||||
'MD',
|
||||
'MA',
|
||||
'MI',
|
||||
'MN',
|
||||
'MS',
|
||||
'MO',
|
||||
'MT',
|
||||
'NE',
|
||||
'NV',
|
||||
'NH',
|
||||
'NJ',
|
||||
'NM',
|
||||
'NY',
|
||||
'NC',
|
||||
'ND',
|
||||
'OH',
|
||||
'OK',
|
||||
'OR',
|
||||
'PA',
|
||||
'RI',
|
||||
'SC',
|
||||
'SD',
|
||||
'TN',
|
||||
'TX',
|
||||
'UT',
|
||||
'VT',
|
||||
'VA',
|
||||
'WA',
|
||||
'WV',
|
||||
'WI',
|
||||
'WY',
|
||||
];
|
||||
|
||||
@override
|
||||
@@ -36,10 +83,19 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
}
|
||||
|
||||
final List<Map<String, String>> _steps = <Map<String, String>>[
|
||||
<String, String>{'title': 'Personal Information', 'subtitle': 'Name and contact details'},
|
||||
<String, String>{
|
||||
'title': 'Personal Information',
|
||||
'subtitle': 'Name and contact details',
|
||||
},
|
||||
<String, String>{'title': 'Address', 'subtitle': 'Your current address'},
|
||||
<String, String>{'title': 'Citizenship Status', 'subtitle': 'Work authorization verification'},
|
||||
<String, String>{'title': 'Review & Sign', 'subtitle': 'Confirm your information'},
|
||||
<String, String>{
|
||||
'title': 'Citizenship Status',
|
||||
'subtitle': 'Work authorization verification',
|
||||
},
|
||||
<String, String>{
|
||||
'title': 'Review & Sign',
|
||||
'subtitle': 'Confirm your information',
|
||||
},
|
||||
];
|
||||
|
||||
bool _canProceed(FormI9State state) {
|
||||
@@ -77,13 +133,27 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final TranslationsStaffComplianceTaxFormsI9En i18n = Translations.of(context).staff_compliance.tax_forms.i9;
|
||||
final TranslationsStaffComplianceTaxFormsI9En i18n = Translations.of(
|
||||
context,
|
||||
).staff_compliance.tax_forms.i9;
|
||||
|
||||
final List<Map<String, String>> steps = <Map<String, String>>[
|
||||
<String, String>{'title': i18n.steps.personal, 'subtitle': i18n.steps.personal_sub},
|
||||
<String, String>{'title': i18n.steps.address, 'subtitle': i18n.steps.address_sub},
|
||||
<String, String>{'title': i18n.steps.citizenship, 'subtitle': i18n.steps.citizenship_sub},
|
||||
<String, String>{'title': i18n.steps.review, 'subtitle': i18n.steps.review_sub},
|
||||
<String, String>{
|
||||
'title': i18n.steps.personal,
|
||||
'subtitle': i18n.steps.personal_sub,
|
||||
},
|
||||
<String, String>{
|
||||
'title': i18n.steps.address,
|
||||
'subtitle': i18n.steps.address_sub,
|
||||
},
|
||||
<String, String>{
|
||||
'title': i18n.steps.citizenship,
|
||||
'subtitle': i18n.steps.citizenship_sub,
|
||||
},
|
||||
<String, String>{
|
||||
'title': i18n.steps.review,
|
||||
'subtitle': i18n.steps.review_sub,
|
||||
},
|
||||
];
|
||||
|
||||
return BlocProvider<FormI9Cubit>.value(
|
||||
@@ -95,7 +165,9 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
} else if (state.status == FormI9Status.failure) {
|
||||
UiSnackbar.show(
|
||||
context,
|
||||
message: translateErrorKey(state.errorMessage ?? 'An error occurred'),
|
||||
message: translateErrorKey(
|
||||
state.errorMessage ?? 'An error occurred',
|
||||
),
|
||||
type: UiSnackbarType.error,
|
||||
margin: const EdgeInsets.only(
|
||||
left: UiConstants.space4,
|
||||
@@ -106,7 +178,8 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
}
|
||||
},
|
||||
builder: (BuildContext context, FormI9State state) {
|
||||
if (state.status == FormI9Status.success) return _buildSuccessView(i18n);
|
||||
if (state.status == FormI9Status.success)
|
||||
return _buildSuccessView(i18n);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: UiColors.background,
|
||||
@@ -175,7 +248,7 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: () => Modular.to.pop(true),
|
||||
onPressed: () => Modular.to.popSafe(true),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: UiColors.primary,
|
||||
foregroundColor: UiColors.white,
|
||||
@@ -187,7 +260,11 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
),
|
||||
elevation: 0,
|
||||
),
|
||||
child: Text(Translations.of(context).staff_compliance.tax_forms.w4.back_to_docs),
|
||||
child: Text(
|
||||
Translations.of(
|
||||
context,
|
||||
).staff_compliance.tax_forms.w4.back_to_docs,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -218,7 +295,7 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
Row(
|
||||
children: <Widget>[
|
||||
GestureDetector(
|
||||
onTap: () => Modular.to.pop(),
|
||||
onTap: () => Modular.to.popSafe(),
|
||||
child: const Icon(
|
||||
UiIcons.arrowLeft,
|
||||
color: UiColors.white,
|
||||
@@ -229,10 +306,7 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
i18n.title,
|
||||
style: UiTypography.headline4m.white,
|
||||
),
|
||||
Text(i18n.title, style: UiTypography.headline4m.white),
|
||||
Text(
|
||||
i18n.subtitle,
|
||||
style: UiTypography.body3r.copyWith(
|
||||
@@ -245,10 +319,9 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
Row(
|
||||
children: steps
|
||||
.asMap()
|
||||
.entries
|
||||
.map((MapEntry<int, Map<String, String>> entry) {
|
||||
children: steps.asMap().entries.map((
|
||||
MapEntry<int, Map<String, String>> entry,
|
||||
) {
|
||||
final int idx = entry.key;
|
||||
final bool isLast = idx == steps.length - 1;
|
||||
return Expanded(
|
||||
@@ -384,7 +457,8 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
child: _buildTextField(
|
||||
i18n.fields.first_name,
|
||||
value: state.firstName,
|
||||
onChanged: (String val) => context.read<FormI9Cubit>().firstNameChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormI9Cubit>().firstNameChanged(val),
|
||||
placeholder: i18n.fields.hints.first_name,
|
||||
),
|
||||
),
|
||||
@@ -393,7 +467,8 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
child: _buildTextField(
|
||||
i18n.fields.last_name,
|
||||
value: state.lastName,
|
||||
onChanged: (String val) => context.read<FormI9Cubit>().lastNameChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormI9Cubit>().lastNameChanged(val),
|
||||
placeholder: i18n.fields.hints.last_name,
|
||||
),
|
||||
),
|
||||
@@ -406,7 +481,8 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
child: _buildTextField(
|
||||
i18n.fields.middle_initial,
|
||||
value: state.middleInitial,
|
||||
onChanged: (String val) => context.read<FormI9Cubit>().middleInitialChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormI9Cubit>().middleInitialChanged(val),
|
||||
placeholder: i18n.fields.hints.middle_initial,
|
||||
),
|
||||
),
|
||||
@@ -416,7 +492,8 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
child: _buildTextField(
|
||||
i18n.fields.other_last_names,
|
||||
value: state.otherLastNames,
|
||||
onChanged: (String val) => context.read<FormI9Cubit>().otherLastNamesChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormI9Cubit>().otherLastNamesChanged(val),
|
||||
placeholder: i18n.fields.maiden_name,
|
||||
),
|
||||
),
|
||||
@@ -426,7 +503,8 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
_buildTextField(
|
||||
i18n.fields.dob,
|
||||
value: state.dob,
|
||||
onChanged: (String val) => context.read<FormI9Cubit>().dobChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormI9Cubit>().dobChanged(val),
|
||||
placeholder: i18n.fields.hints.dob,
|
||||
keyboardType: TextInputType.datetime,
|
||||
),
|
||||
@@ -446,7 +524,8 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
_buildTextField(
|
||||
i18n.fields.email,
|
||||
value: state.email,
|
||||
onChanged: (String val) => context.read<FormI9Cubit>().emailChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormI9Cubit>().emailChanged(val),
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
placeholder: i18n.fields.hints.email,
|
||||
),
|
||||
@@ -454,7 +533,8 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
_buildTextField(
|
||||
i18n.fields.phone,
|
||||
value: state.phone,
|
||||
onChanged: (String val) => context.read<FormI9Cubit>().phoneChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormI9Cubit>().phoneChanged(val),
|
||||
keyboardType: TextInputType.phone,
|
||||
placeholder: i18n.fields.hints.phone,
|
||||
),
|
||||
@@ -472,14 +552,16 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
_buildTextField(
|
||||
i18n.fields.address_long,
|
||||
value: state.address,
|
||||
onChanged: (String val) => context.read<FormI9Cubit>().addressChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormI9Cubit>().addressChanged(val),
|
||||
placeholder: i18n.fields.hints.address,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
_buildTextField(
|
||||
i18n.fields.apt,
|
||||
value: state.aptNumber,
|
||||
onChanged: (String val) => context.read<FormI9Cubit>().aptNumberChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormI9Cubit>().aptNumberChanged(val),
|
||||
placeholder: i18n.fields.hints.apt,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
@@ -490,7 +572,8 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
child: _buildTextField(
|
||||
i18n.fields.city,
|
||||
value: state.city,
|
||||
onChanged: (String val) => context.read<FormI9Cubit>().cityChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormI9Cubit>().cityChanged(val),
|
||||
placeholder: i18n.fields.hints.city,
|
||||
),
|
||||
),
|
||||
@@ -541,7 +624,8 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
_buildTextField(
|
||||
i18n.fields.zip,
|
||||
value: state.zipCode,
|
||||
onChanged: (String val) => context.read<FormI9Cubit>().zipCodeChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormI9Cubit>().zipCodeChanged(val),
|
||||
placeholder: i18n.fields.hints.zip,
|
||||
keyboardType: TextInputType.number,
|
||||
),
|
||||
@@ -557,24 +641,11 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
i18n.fields.attestation,
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
Text(i18n.fields.attestation, style: UiTypography.body2m.textPrimary),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
_buildRadioOption(
|
||||
context,
|
||||
state,
|
||||
'CITIZEN',
|
||||
i18n.fields.citizen,
|
||||
),
|
||||
_buildRadioOption(context, state, 'CITIZEN', i18n.fields.citizen),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
_buildRadioOption(
|
||||
context,
|
||||
state,
|
||||
'NONCITIZEN',
|
||||
i18n.fields.noncitizen,
|
||||
),
|
||||
_buildRadioOption(context, state, 'NONCITIZEN', i18n.fields.noncitizen),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
_buildRadioOption(
|
||||
context,
|
||||
@@ -587,7 +658,8 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
child: _buildTextField(
|
||||
i18n.fields.uscis_number_label,
|
||||
value: state.uscisNumber,
|
||||
onChanged: (String val) => context.read<FormI9Cubit>().uscisNumberChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormI9Cubit>().uscisNumberChanged(val),
|
||||
placeholder: i18n.fields.hints.uscis,
|
||||
),
|
||||
)
|
||||
@@ -607,19 +679,25 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
_buildTextField(
|
||||
i18n.fields.admission_number,
|
||||
value: state.admissionNumber,
|
||||
onChanged: (String val) => context.read<FormI9Cubit>().admissionNumberChanged(val),
|
||||
onChanged: (String val) => context
|
||||
.read<FormI9Cubit>()
|
||||
.admissionNumberChanged(val),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
_buildTextField(
|
||||
i18n.fields.passport,
|
||||
value: state.passportNumber,
|
||||
onChanged: (String val) => context.read<FormI9Cubit>().passportNumberChanged(val),
|
||||
onChanged: (String val) => context
|
||||
.read<FormI9Cubit>()
|
||||
.passportNumberChanged(val),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
_buildTextField(
|
||||
i18n.fields.country,
|
||||
value: state.countryIssuance,
|
||||
onChanged: (String val) => context.read<FormI9Cubit>().countryIssuanceChanged(val),
|
||||
onChanged: (String val) => context
|
||||
.read<FormI9Cubit>()
|
||||
.countryIssuanceChanged(val),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -667,10 +745,7 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Expanded(
|
||||
child: Text(
|
||||
label,
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
child: Text(label, style: UiTypography.body2m.textPrimary),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -704,8 +779,14 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
style: UiTypography.headline4m.copyWith(fontSize: 14),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
_buildSummaryRow(i18n.fields.summary_name, '${state.firstName} ${state.lastName}'),
|
||||
_buildSummaryRow(i18n.fields.summary_address, '${state.address}, ${state.city}'),
|
||||
_buildSummaryRow(
|
||||
i18n.fields.summary_name,
|
||||
'${state.firstName} ${state.lastName}',
|
||||
),
|
||||
_buildSummaryRow(
|
||||
i18n.fields.summary_address,
|
||||
'${state.address}, ${state.city}',
|
||||
),
|
||||
_buildSummaryRow(
|
||||
i18n.fields.summary_ssn,
|
||||
'***-**-${state.ssn.length >= 4 ? state.ssn.substring(state.ssn.length - 4) : '****'}',
|
||||
@@ -780,10 +861,7 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
style: const TextStyle(fontFamily: 'Cursive', fontSize: 18),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
Text(
|
||||
i18n.fields.date_label,
|
||||
style: UiTypography.body3m.textSecondary,
|
||||
),
|
||||
Text(i18n.fields.date_label, style: UiTypography.body3m.textSecondary),
|
||||
const SizedBox(height: UiConstants.space1 + 2),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
@@ -811,10 +889,7 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
label,
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
Text(label, style: UiTypography.body2r.textSecondary),
|
||||
Expanded(
|
||||
child: Text(
|
||||
value,
|
||||
@@ -828,7 +903,9 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
}
|
||||
|
||||
String _getReadableCitizenship(String status) {
|
||||
final TranslationsStaffComplianceTaxFormsI9FieldsEn i18n = Translations.of(context).staff_compliance.tax_forms.i9.fields;
|
||||
final TranslationsStaffComplianceTaxFormsI9FieldsEn i18n = Translations.of(
|
||||
context,
|
||||
).staff_compliance.tax_forms.i9.fields;
|
||||
switch (status) {
|
||||
case 'CITIZEN':
|
||||
return i18n.status_us_citizen;
|
||||
@@ -848,7 +925,9 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
FormI9State state,
|
||||
List<Map<String, String>> steps,
|
||||
) {
|
||||
final TranslationsStaffComplianceTaxFormsI9En i18n = Translations.of(context).staff_compliance.tax_forms.i9;
|
||||
final TranslationsStaffComplianceTaxFormsI9En i18n = Translations.of(
|
||||
context,
|
||||
).staff_compliance.tax_forms.i9;
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
@@ -883,10 +962,7 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
const SizedBox(width: UiConstants.space2),
|
||||
Text(
|
||||
i18n.back,
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
Text(i18n.back, style: UiTypography.body2r.textPrimary),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -895,8 +971,8 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: ElevatedButton(
|
||||
onPressed: (
|
||||
_canProceed(state) &&
|
||||
onPressed:
|
||||
(_canProceed(state) &&
|
||||
state.status != FormI9Status.submitting)
|
||||
? () => _handleNext(context, state.currentStep)
|
||||
: null,
|
||||
@@ -931,7 +1007,11 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
),
|
||||
if (state.currentStep < steps.length - 1) ...<Widget>[
|
||||
const SizedBox(width: UiConstants.space2),
|
||||
const Icon(UiIcons.arrowRight, size: 16, color: UiColors.white),
|
||||
const Icon(
|
||||
UiIcons.arrowRight,
|
||||
size: 16,
|
||||
color: UiColors.white,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart' hide ModularWatchExtension;
|
||||
import 'package:flutter_modular/flutter_modular.dart'
|
||||
hide ModularWatchExtension;
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
import '../blocs/w4/form_w4_cubit.dart';
|
||||
@@ -84,7 +86,10 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
<String, String>{'title': 'Filing Status', 'subtitle': 'Step 1c'},
|
||||
<String, String>{'title': 'Multiple Jobs', 'subtitle': 'Step 2 (optional)'},
|
||||
<String, String>{'title': 'Dependents', 'subtitle': 'Step 3'},
|
||||
<String, String>{'title': 'Other Adjustments', 'subtitle': 'Step 4 (optional)'},
|
||||
<String, String>{
|
||||
'title': 'Other Adjustments',
|
||||
'subtitle': 'Step 4 (optional)',
|
||||
},
|
||||
<String, String>{'title': 'Review & Sign', 'subtitle': 'Step 5'},
|
||||
];
|
||||
|
||||
@@ -116,23 +121,41 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
context.read<FormW4Cubit>().previousStep();
|
||||
}
|
||||
|
||||
|
||||
int _totalCredits(FormW4State state) {
|
||||
return (state.qualifyingChildren * 2000) +
|
||||
(state.otherDependents * 500);
|
||||
return (state.qualifyingChildren * 2000) + (state.otherDependents * 500);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final TranslationsStaffComplianceTaxFormsW4En i18n = Translations.of(context).staff_compliance.tax_forms.w4;
|
||||
final TranslationsStaffComplianceTaxFormsW4En i18n = Translations.of(
|
||||
context,
|
||||
).staff_compliance.tax_forms.w4;
|
||||
|
||||
final List<Map<String, String>> steps = <Map<String, String>>[
|
||||
<String, String>{'title': i18n.steps.personal, 'subtitle': i18n.step_label(current: '1', total: '5')},
|
||||
<String, String>{'title': i18n.steps.filing, 'subtitle': i18n.step_label(current: '1c', total: '5')},
|
||||
<String, String>{'title': i18n.steps.multiple_jobs, 'subtitle': i18n.step_label(current: '2', total: '5')},
|
||||
<String, String>{'title': i18n.steps.dependents, 'subtitle': i18n.step_label(current: '3', total: '5')},
|
||||
<String, String>{'title': i18n.steps.adjustments, 'subtitle': i18n.step_label(current: '4', total: '5')},
|
||||
<String, String>{'title': i18n.steps.review, 'subtitle': i18n.step_label(current: '5', total: '5')},
|
||||
<String, String>{
|
||||
'title': i18n.steps.personal,
|
||||
'subtitle': i18n.step_label(current: '1', total: '5'),
|
||||
},
|
||||
<String, String>{
|
||||
'title': i18n.steps.filing,
|
||||
'subtitle': i18n.step_label(current: '1c', total: '5'),
|
||||
},
|
||||
<String, String>{
|
||||
'title': i18n.steps.multiple_jobs,
|
||||
'subtitle': i18n.step_label(current: '2', total: '5'),
|
||||
},
|
||||
<String, String>{
|
||||
'title': i18n.steps.dependents,
|
||||
'subtitle': i18n.step_label(current: '3', total: '5'),
|
||||
},
|
||||
<String, String>{
|
||||
'title': i18n.steps.adjustments,
|
||||
'subtitle': i18n.step_label(current: '4', total: '5'),
|
||||
},
|
||||
<String, String>{
|
||||
'title': i18n.steps.review,
|
||||
'subtitle': i18n.step_label(current: '5', total: '5'),
|
||||
},
|
||||
];
|
||||
|
||||
return BlocProvider<FormW4Cubit>.value(
|
||||
@@ -144,7 +167,9 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
} else if (state.status == FormW4Status.failure) {
|
||||
UiSnackbar.show(
|
||||
context,
|
||||
message: translateErrorKey(state.errorMessage ?? 'An error occurred'),
|
||||
message: translateErrorKey(
|
||||
state.errorMessage ?? 'An error occurred',
|
||||
),
|
||||
type: UiSnackbarType.error,
|
||||
margin: const EdgeInsets.only(
|
||||
left: UiConstants.space4,
|
||||
@@ -155,7 +180,8 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
}
|
||||
},
|
||||
builder: (BuildContext context, FormW4State state) {
|
||||
if (state.status == FormW4Status.success) return _buildSuccessView(i18n);
|
||||
if (state.status == FormW4Status.success)
|
||||
return _buildSuccessView(i18n);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: UiColors.background,
|
||||
@@ -224,7 +250,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: () => Modular.to.pop(true),
|
||||
onPressed: () => Modular.to.popSafe(true),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: UiColors.primary,
|
||||
foregroundColor: UiColors.white,
|
||||
@@ -267,7 +293,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
Row(
|
||||
children: <Widget>[
|
||||
GestureDetector(
|
||||
onTap: () => Modular.to.pop(),
|
||||
onTap: () => Modular.to.popSafe(),
|
||||
child: const Icon(
|
||||
UiIcons.arrowLeft,
|
||||
color: UiColors.white,
|
||||
@@ -278,10 +304,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
i18n.title,
|
||||
style: UiTypography.headline4m.white,
|
||||
),
|
||||
Text(i18n.title, style: UiTypography.headline4m.white),
|
||||
Text(
|
||||
i18n.subtitle,
|
||||
style: UiTypography.body3r.copyWith(
|
||||
@@ -294,10 +317,9 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
Row(
|
||||
children: steps
|
||||
.asMap()
|
||||
.entries
|
||||
.map((MapEntry<int, Map<String, String>> entry) {
|
||||
children: steps.asMap().entries.map((
|
||||
MapEntry<int, Map<String, String>> entry,
|
||||
) {
|
||||
final int idx = entry.key;
|
||||
final bool isLast = idx == steps.length - 1;
|
||||
return Expanded(
|
||||
@@ -434,7 +456,8 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
child: _buildTextField(
|
||||
i18n.fields.first_name,
|
||||
value: state.firstName,
|
||||
onChanged: (String val) => context.read<FormW4Cubit>().firstNameChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormW4Cubit>().firstNameChanged(val),
|
||||
placeholder: i18n.fields.placeholder_john,
|
||||
),
|
||||
),
|
||||
@@ -443,7 +466,8 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
child: _buildTextField(
|
||||
i18n.fields.last_name,
|
||||
value: state.lastName,
|
||||
onChanged: (String val) => context.read<FormW4Cubit>().lastNameChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormW4Cubit>().lastNameChanged(val),
|
||||
placeholder: i18n.fields.placeholder_smith,
|
||||
),
|
||||
),
|
||||
@@ -465,14 +489,16 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
_buildTextField(
|
||||
i18n.fields.address,
|
||||
value: state.address,
|
||||
onChanged: (String val) => context.read<FormW4Cubit>().addressChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormW4Cubit>().addressChanged(val),
|
||||
placeholder: i18n.fields.placeholder_address,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
_buildTextField(
|
||||
i18n.fields.city_state_zip,
|
||||
value: state.cityStateZip,
|
||||
onChanged: (String val) => context.read<FormW4Cubit>().cityStateZipChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormW4Cubit>().cityStateZipChanged(val),
|
||||
placeholder: i18n.fields.placeholder_csz,
|
||||
),
|
||||
],
|
||||
@@ -506,21 +532,9 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
_buildRadioOption(
|
||||
context,
|
||||
state,
|
||||
'SINGLE',
|
||||
i18n.fields.single,
|
||||
null,
|
||||
),
|
||||
_buildRadioOption(context, state, 'SINGLE', i18n.fields.single, null),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
_buildRadioOption(
|
||||
context,
|
||||
state,
|
||||
'MARRIED',
|
||||
i18n.fields.married,
|
||||
null,
|
||||
),
|
||||
_buildRadioOption(context, state, 'MARRIED', i18n.fields.married, null),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
_buildRadioOption(
|
||||
context,
|
||||
@@ -573,16 +587,10 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
label,
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
Text(label, style: UiTypography.body2m.textPrimary),
|
||||
if (subLabel != null) ...<Widget>[
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
subLabel,
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
Text(subLabel, style: UiTypography.body3r.textSecondary),
|
||||
],
|
||||
],
|
||||
),
|
||||
@@ -609,11 +617,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
const Icon(
|
||||
UiIcons.help,
|
||||
color: UiColors.accent,
|
||||
size: 20,
|
||||
),
|
||||
const Icon(UiIcons.help, color: UiColors.accent, size: 20),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Expanded(
|
||||
child: Column(
|
||||
@@ -636,8 +640,9 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
GestureDetector(
|
||||
onTap: () =>
|
||||
context.read<FormW4Cubit>().multipleJobsChanged(!state.multipleJobs),
|
||||
onTap: () => context.read<FormW4Cubit>().multipleJobsChanged(
|
||||
!state.multipleJobs,
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
@@ -654,10 +659,14 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
width: 24,
|
||||
height: 24,
|
||||
decoration: BoxDecoration(
|
||||
color: state.multipleJobs ? UiColors.primary : UiColors.bgPopup,
|
||||
color: state.multipleJobs
|
||||
? UiColors.primary
|
||||
: UiColors.bgPopup,
|
||||
borderRadius: UiConstants.radiusMd,
|
||||
border: Border.all(
|
||||
color: state.multipleJobs ? UiColors.primary : UiColors.border,
|
||||
color: state.multipleJobs
|
||||
? UiColors.primary
|
||||
: UiColors.border,
|
||||
),
|
||||
),
|
||||
child: state.multipleJobs
|
||||
@@ -741,7 +750,8 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
i18n.fields.children_under_17,
|
||||
i18n.fields.children_each,
|
||||
(FormW4State s) => s.qualifyingChildren,
|
||||
(int val) => context.read<FormW4Cubit>().qualifyingChildrenChanged(val),
|
||||
(int val) =>
|
||||
context.read<FormW4Cubit>().qualifyingChildrenChanged(val),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
@@ -753,7 +763,8 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
i18n.fields.other_dependents,
|
||||
i18n.fields.other_each,
|
||||
(FormW4State s) => s.otherDependents,
|
||||
(int val) => context.read<FormW4Cubit>().otherDependentsChanged(val),
|
||||
(int val) =>
|
||||
context.read<FormW4Cubit>().otherDependentsChanged(val),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -775,9 +786,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
),
|
||||
Text(
|
||||
'\$${_totalCredits(state)}',
|
||||
style: UiTypography.body2b.textSuccess.copyWith(
|
||||
fontSize: 18,
|
||||
),
|
||||
style: UiTypography.body2b.textSuccess.copyWith(fontSize: 18),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -802,22 +811,14 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
label,
|
||||
style: UiTypography.body2m,
|
||||
),
|
||||
),
|
||||
Expanded(child: Text(label, style: UiTypography.body2m)),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.tagSuccess,
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
child: Text(
|
||||
badge,
|
||||
style: UiTypography.footnote2b.textSuccess,
|
||||
),
|
||||
child: Text(badge, style: UiTypography.footnote2b.textSuccess),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -839,10 +840,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
),
|
||||
),
|
||||
),
|
||||
_buildCircleBtn(
|
||||
UiIcons.add,
|
||||
() => onChanged(value + 1),
|
||||
),
|
||||
_buildCircleBtn(UiIcons.add, () => onChanged(value + 1)),
|
||||
],
|
||||
),
|
||||
],
|
||||
@@ -881,7 +879,8 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
_buildTextField(
|
||||
i18n.fields.other_income,
|
||||
value: state.otherIncome,
|
||||
onChanged: (String val) => context.read<FormW4Cubit>().otherIncomeChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormW4Cubit>().otherIncomeChanged(val),
|
||||
placeholder: i18n.fields.hints.zero,
|
||||
keyboardType: TextInputType.number,
|
||||
),
|
||||
@@ -896,7 +895,8 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
_buildTextField(
|
||||
i18n.fields.deductions,
|
||||
value: state.deductions,
|
||||
onChanged: (String val) => context.read<FormW4Cubit>().deductionsChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormW4Cubit>().deductionsChanged(val),
|
||||
placeholder: i18n.fields.hints.zero,
|
||||
keyboardType: TextInputType.number,
|
||||
),
|
||||
@@ -911,7 +911,8 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
_buildTextField(
|
||||
i18n.fields.extra_withholding,
|
||||
value: state.extraWithholding,
|
||||
onChanged: (String val) => context.read<FormW4Cubit>().extraWithholdingChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormW4Cubit>().extraWithholdingChanged(val),
|
||||
placeholder: i18n.fields.hints.zero,
|
||||
keyboardType: TextInputType.number,
|
||||
),
|
||||
@@ -1019,10 +1020,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
style: const TextStyle(fontFamily: 'Cursive', fontSize: 18),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
Text(
|
||||
i18n.fields.date_label,
|
||||
style: UiTypography.body3m.textSecondary,
|
||||
),
|
||||
Text(i18n.fields.date_label, style: UiTypography.body3m.textSecondary),
|
||||
const SizedBox(height: 6),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
@@ -1050,10 +1048,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
label,
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
Text(label, style: UiTypography.body2r.textSecondary),
|
||||
Text(
|
||||
value,
|
||||
style: UiTypography.body2m.copyWith(
|
||||
@@ -1066,7 +1061,9 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
}
|
||||
|
||||
String _getFilingStatusLabel(String status) {
|
||||
final TranslationsStaffComplianceTaxFormsW4FieldsEn i18n = Translations.of(context).staff_compliance.tax_forms.w4.fields;
|
||||
final TranslationsStaffComplianceTaxFormsW4FieldsEn i18n = Translations.of(
|
||||
context,
|
||||
).staff_compliance.tax_forms.w4.fields;
|
||||
switch (status) {
|
||||
case 'SINGLE':
|
||||
return i18n.status_single;
|
||||
@@ -1084,7 +1081,9 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
FormW4State state,
|
||||
List<Map<String, String>> steps,
|
||||
) {
|
||||
final TranslationsStaffComplianceTaxFormsW4En i18n = Translations.of(context).staff_compliance.tax_forms.w4;
|
||||
final TranslationsStaffComplianceTaxFormsW4En i18n = Translations.of(
|
||||
context,
|
||||
).staff_compliance.tax_forms.w4;
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
@@ -1131,8 +1130,8 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: ElevatedButton(
|
||||
onPressed: (
|
||||
_canProceed(state) &&
|
||||
onPressed:
|
||||
(_canProceed(state) &&
|
||||
state.status != FormW4Status.submitting)
|
||||
? () => _handleNext(context, state.currentStep)
|
||||
: null,
|
||||
@@ -1167,7 +1166,11 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
),
|
||||
if (state.currentStep < steps.length - 1) ...<Widget>[
|
||||
const SizedBox(width: UiConstants.space2),
|
||||
const Icon(UiIcons.arrowRight, size: 16, color: UiColors.white),
|
||||
const Icon(
|
||||
UiIcons.arrowRight,
|
||||
size: 16,
|
||||
color: UiColors.white,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
@@ -1179,5 +1182,3 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
import '../blocs/tax_forms/tax_forms_cubit.dart';
|
||||
import '../blocs/tax_forms/tax_forms_state.dart';
|
||||
@@ -18,7 +19,7 @@ class TaxFormsPage extends StatelessWidget {
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: const Icon(UiIcons.arrowLeft, color: UiColors.bgPopup),
|
||||
onPressed: () => Modular.to.pop(),
|
||||
onPressed: () => Modular.to.popSafe(),
|
||||
),
|
||||
title: Text(
|
||||
'Tax Documents',
|
||||
@@ -64,7 +65,9 @@ class TaxFormsPage extends StatelessWidget {
|
||||
if (state.status == TaxFormsStatus.failure) {
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: UiConstants.space5),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space5,
|
||||
),
|
||||
child: Text(
|
||||
state.errorMessage != null
|
||||
? translateErrorKey(state.errorMessage!)
|
||||
@@ -84,7 +87,9 @@ class TaxFormsPage extends StatelessWidget {
|
||||
spacing: UiConstants.space6,
|
||||
children: <Widget>[
|
||||
_buildProgressOverview(state.forms),
|
||||
...state.forms.map((TaxForm form) => _buildFormCard(context, form)),
|
||||
...state.forms.map(
|
||||
(TaxForm form) => _buildFormCard(context, form),
|
||||
),
|
||||
_buildInfoCard(),
|
||||
],
|
||||
),
|
||||
@@ -118,10 +123,7 @@ class TaxFormsPage extends StatelessWidget {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Document Progress',
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
Text('Document Progress', style: UiTypography.body2m.textPrimary),
|
||||
Text(
|
||||
'$completedCount/$totalCount',
|
||||
style: UiTypography.body2m.textSecondary,
|
||||
@@ -150,12 +152,18 @@ class TaxFormsPage extends StatelessWidget {
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
if (form is I9TaxForm) {
|
||||
final Object? result = await Modular.to.pushNamed('i9', arguments: form);
|
||||
final Object? result = await Modular.to.pushNamed(
|
||||
'i9',
|
||||
arguments: form,
|
||||
);
|
||||
if (result == true && context.mounted) {
|
||||
await BlocProvider.of<TaxFormsCubit>(context).loadTaxForms();
|
||||
}
|
||||
} else if (form is W4TaxForm) {
|
||||
final Object? result = await Modular.to.pushNamed('w4', arguments: form);
|
||||
final Object? result = await Modular.to.pushNamed(
|
||||
'w4',
|
||||
arguments: form,
|
||||
);
|
||||
if (result == true && context.mounted) {
|
||||
await BlocProvider.of<TaxFormsCubit>(context).loadTaxForms();
|
||||
}
|
||||
@@ -245,10 +253,7 @@ class TaxFormsPage extends StatelessWidget {
|
||||
color: UiColors.textSuccess,
|
||||
),
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
Text(
|
||||
'Completed',
|
||||
style: UiTypography.footnote2b.textSuccess,
|
||||
),
|
||||
Text('Completed', style: UiTypography.footnote2b.textSuccess),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -267,10 +272,7 @@ class TaxFormsPage extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
const Icon(UiIcons.clock, size: 12, color: UiColors.textWarning),
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
Text(
|
||||
'In Progress',
|
||||
style: UiTypography.footnote2b.textWarning,
|
||||
),
|
||||
Text('In Progress', style: UiTypography.footnote2b.textWarning),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@ import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
// ignore: depend_on_referenced_packages
|
||||
import 'package:krow_core/core.dart';
|
||||
|
||||
import '../blocs/bank_account_cubit.dart';
|
||||
import '../blocs/bank_account_state.dart';
|
||||
@@ -32,12 +32,9 @@ class BankAccountPage extends StatelessWidget {
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: const Icon(UiIcons.arrowLeft, color: UiColors.textSecondary),
|
||||
onPressed: () => Modular.to.pop(),
|
||||
),
|
||||
title: Text(
|
||||
strings.title,
|
||||
style: UiTypography.headline3m.textPrimary,
|
||||
onPressed: () => Modular.to.popSafe(),
|
||||
),
|
||||
title: Text(strings.title, style: UiTypography.headline3m.textPrimary),
|
||||
bottom: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(1.0),
|
||||
child: Container(color: UiColors.border, height: 1.0),
|
||||
@@ -61,7 +58,8 @@ class BankAccountPage extends StatelessWidget {
|
||||
// Error is already shown on the page itself (lines 73-85), no need for snackbar
|
||||
},
|
||||
builder: (BuildContext context, BankAccountState state) {
|
||||
if (state.status == BankAccountStatus.loading && state.accounts.isEmpty) {
|
||||
if (state.status == BankAccountStatus.loading &&
|
||||
state.accounts.isEmpty) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
@@ -74,7 +72,9 @@ class BankAccountPage extends StatelessWidget {
|
||||
? translateErrorKey(state.errorMessage!)
|
||||
: 'Error',
|
||||
textAlign: TextAlign.center,
|
||||
style: UiTypography.body1m.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body1m.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -92,11 +92,14 @@ class BankAccountPage extends StatelessWidget {
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
Text(
|
||||
strings.linked_accounts,
|
||||
style: UiTypography.headline4m.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.headline4m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
...state.accounts.map((StaffBankAccount a) => _buildAccountCard(a, strings)), // Added type
|
||||
|
||||
...state.accounts.map(
|
||||
(StaffBankAccount a) => _buildAccountCard(a, strings),
|
||||
), // Added type
|
||||
// Add extra padding at bottom
|
||||
const SizedBox(height: UiConstants.space20),
|
||||
],
|
||||
@@ -121,17 +124,23 @@ class BankAccountPage extends StatelessWidget {
|
||||
backgroundColor: UiColors.transparent,
|
||||
child: AddAccountForm(
|
||||
strings: strings,
|
||||
onSubmit: (String bankName, String routing, String account, String type) {
|
||||
cubit.addAccount(
|
||||
bankName: bankName,
|
||||
routingNumber: routing,
|
||||
accountNumber: account,
|
||||
type: type,
|
||||
);
|
||||
Modular.to.pop();
|
||||
},
|
||||
onSubmit:
|
||||
(
|
||||
String bankName,
|
||||
String routing,
|
||||
String account,
|
||||
String type,
|
||||
) {
|
||||
cubit.addAccount(
|
||||
bankName: bankName,
|
||||
routingNumber: routing,
|
||||
accountNumber: account,
|
||||
type: type,
|
||||
);
|
||||
Modular.to.popSafe();
|
||||
},
|
||||
onCancel: () {
|
||||
Modular.to.pop();
|
||||
Modular.to.popSafe();
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -249,12 +258,13 @@ class BankAccountPage extends StatelessWidget {
|
||||
),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
const Icon(UiIcons.check, size: UiConstants.iconXs, color: primaryColor),
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
Text(
|
||||
strings.primary,
|
||||
style: UiTypography.body3m.primary,
|
||||
const Icon(
|
||||
UiIcons.check,
|
||||
size: UiConstants.iconXs,
|
||||
color: primaryColor,
|
||||
),
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
Text(strings.primary, style: UiTypography.body3m.primary),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
import '../blocs/time_card_bloc.dart';
|
||||
import '../widgets/month_selector.dart';
|
||||
import '../widgets/shift_history_list.dart';
|
||||
@@ -37,8 +38,11 @@ class _TimeCardPageState extends State<TimeCardPage> {
|
||||
backgroundColor: UiColors.bgPopup,
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: const Icon(UiIcons.chevronLeft, color: UiColors.iconSecondary),
|
||||
onPressed: () => Modular.to.pop(),
|
||||
icon: const Icon(
|
||||
UiIcons.chevronLeft,
|
||||
color: UiColors.iconSecondary,
|
||||
),
|
||||
onPressed: () => Modular.to.popSafe(),
|
||||
),
|
||||
title: Text(
|
||||
t.staff_time_card.title,
|
||||
@@ -69,7 +73,9 @@ class _TimeCardPageState extends State<TimeCardPage> {
|
||||
child: Text(
|
||||
translateErrorKey(state.message),
|
||||
textAlign: TextAlign.center,
|
||||
style: UiTypography.body1m.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body1m.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -83,12 +89,22 @@ class _TimeCardPageState extends State<TimeCardPage> {
|
||||
children: <Widget>[
|
||||
MonthSelector(
|
||||
selectedDate: state.selectedMonth,
|
||||
onPreviousMonth: () => _bloc.add(ChangeMonth(
|
||||
DateTime(state.selectedMonth.year, state.selectedMonth.month - 1),
|
||||
)),
|
||||
onNextMonth: () => _bloc.add(ChangeMonth(
|
||||
DateTime(state.selectedMonth.year, state.selectedMonth.month + 1),
|
||||
)),
|
||||
onPreviousMonth: () => _bloc.add(
|
||||
ChangeMonth(
|
||||
DateTime(
|
||||
state.selectedMonth.year,
|
||||
state.selectedMonth.month - 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
onNextMonth: () => _bloc.add(
|
||||
ChangeMonth(
|
||||
DateTime(
|
||||
state.selectedMonth.year,
|
||||
state.selectedMonth.month + 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
TimeCardSummary(
|
||||
@@ -108,4 +124,3 @@ class _TimeCardPageState extends State<TimeCardPage> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ class _AttireCapturePageState extends State<AttireCapturePage> {
|
||||
leading: const Icon(Icons.photo_library),
|
||||
title: Text(t.common.gallery),
|
||||
onTap: () {
|
||||
Modular.to.pop();
|
||||
Modular.to.popSafe();
|
||||
_onGallery(context);
|
||||
},
|
||||
),
|
||||
@@ -143,7 +143,7 @@ class _AttireCapturePageState extends State<AttireCapturePage> {
|
||||
leading: const Icon(Icons.camera_alt),
|
||||
title: Text(t.common.camera),
|
||||
onTap: () {
|
||||
Modular.to.pop();
|
||||
Modular.to.popSafe();
|
||||
_onCamera(context);
|
||||
},
|
||||
),
|
||||
@@ -215,10 +215,16 @@ class _AttireCapturePageState extends State<AttireCapturePage> {
|
||||
|
||||
String _getStatusText(bool hasUploadedPhoto) {
|
||||
return switch (widget.item.verificationStatus) {
|
||||
AttireVerificationStatus.approved => t.staff_profile_attire.capture.approved,
|
||||
AttireVerificationStatus.rejected => t.staff_profile_attire.capture.rejected,
|
||||
AttireVerificationStatus.pending => t.staff_profile_attire.capture.pending_verification,
|
||||
_ => hasUploadedPhoto ? t.staff_profile_attire.capture.pending_verification : t.staff_profile_attire.capture.not_uploaded,
|
||||
AttireVerificationStatus.approved =>
|
||||
t.staff_profile_attire.capture.approved,
|
||||
AttireVerificationStatus.rejected =>
|
||||
t.staff_profile_attire.capture.rejected,
|
||||
AttireVerificationStatus.pending =>
|
||||
t.staff_profile_attire.capture.pending_verification,
|
||||
_ =>
|
||||
hasUploadedPhoto
|
||||
? t.staff_profile_attire.capture.pending_verification
|
||||
: t.staff_profile_attire.capture.not_uploaded,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -281,7 +287,9 @@ class _AttireCapturePageState extends State<AttireCapturePage> {
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
_FileTypesBanner(
|
||||
message: t.staff_profile_attire.upload_file_types_banner,
|
||||
message: t
|
||||
.staff_profile_attire
|
||||
.upload_file_types_banner,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
ImagePreviewSection(
|
||||
@@ -350,17 +358,10 @@ class _FileTypesBanner extends StatelessWidget {
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Icon(
|
||||
UiIcons.info,
|
||||
size: 20,
|
||||
color: UiColors.primary,
|
||||
),
|
||||
Icon(UiIcons.info, size: 20, color: UiColors.primary),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Expanded(
|
||||
child: Text(
|
||||
message,
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
child: Text(message, style: UiTypography.body2r.textSecondary),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
|
||||
import 'attire_upload_buttons.dart';
|
||||
|
||||
@@ -98,7 +99,7 @@ class FooterSection extends StatelessWidget {
|
||||
text: 'Submit Image',
|
||||
onPressed: () {
|
||||
if (updatedItem != null) {
|
||||
Modular.to.pop(updatedItem);
|
||||
Modular.to.popSafe(updatedItem);
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
import '../blocs/emergency_contact_bloc.dart';
|
||||
import '../widgets/emergency_contact_add_button.dart';
|
||||
import '../widgets/emergency_contact_form_item.dart';
|
||||
@@ -25,7 +26,7 @@ class EmergencyContactScreen extends StatelessWidget {
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: const Icon(UiIcons.chevronLeft, color: UiColors.textSecondary),
|
||||
onPressed: () => Modular.to.pop(),
|
||||
onPressed: () => Modular.to.popSafe(),
|
||||
),
|
||||
title: Text(
|
||||
'Emergency Contact',
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
|
||||
/// Language selection page for staff profile.
|
||||
///
|
||||
@@ -30,7 +31,7 @@ class LanguageSelectionPage extends StatelessWidget {
|
||||
);
|
||||
|
||||
Modular.to
|
||||
.pop(); // Close the language selection page after showing the snackbar
|
||||
.popSafe(); // Close the language selection page after showing the snackbar
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -3,12 +3,12 @@ import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
|
||||
import '../blocs/personal_info_bloc.dart';
|
||||
import '../blocs/personal_info_state.dart';
|
||||
import '../widgets/personal_info_content.dart';
|
||||
|
||||
|
||||
/// The Personal Info page for staff onboarding.
|
||||
///
|
||||
/// This page allows staff members to view and edit their personal information
|
||||
@@ -22,7 +22,9 @@ class PersonalInfoPage extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final TranslationsStaffOnboardingPersonalInfoEn i18n = Translations.of(context).staff.onboarding.personal_info;
|
||||
final TranslationsStaffOnboardingPersonalInfoEn i18n = Translations.of(
|
||||
context,
|
||||
).staff.onboarding.personal_info;
|
||||
return BlocProvider<PersonalInfoBloc>(
|
||||
create: (BuildContext context) => Modular.get<PersonalInfoBloc>(),
|
||||
child: BlocListener<PersonalInfoBloc, PersonalInfoState>(
|
||||
@@ -33,7 +35,7 @@ class PersonalInfoPage extends StatelessWidget {
|
||||
message: i18n.save_success,
|
||||
type: UiSnackbarType.success,
|
||||
);
|
||||
Modular.to.pop();
|
||||
Modular.to.popSafe();
|
||||
} else if (state.status == PersonalInfoStatus.error) {
|
||||
UiSnackbar.show(
|
||||
context,
|
||||
@@ -54,19 +56,13 @@ class PersonalInfoPage extends StatelessWidget {
|
||||
UiIcons.chevronLeft,
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
onPressed: () => Modular.to.pop(),
|
||||
onPressed: () => Modular.to.popSafe(),
|
||||
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
|
||||
),
|
||||
title: Text(
|
||||
i18n.title,
|
||||
style: UiTypography.title1m.textPrimary,
|
||||
),
|
||||
title: Text(i18n.title, style: UiTypography.title1m.textPrimary),
|
||||
bottom: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(1.0),
|
||||
child: Container(
|
||||
color: UiColors.border,
|
||||
height: 1.0,
|
||||
),
|
||||
child: Container(color: UiColors.border, height: 1.0),
|
||||
),
|
||||
),
|
||||
body: SafeArea(
|
||||
@@ -74,9 +70,7 @@ class PersonalInfoPage extends StatelessWidget {
|
||||
builder: (BuildContext context, PersonalInfoState state) {
|
||||
if (state.status == PersonalInfoStatus.loading ||
|
||||
state.status == PersonalInfoStatus.initial) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (state.staff == null) {
|
||||
|
||||
@@ -11,7 +11,6 @@ import 'package:krow_core/core.dart';
|
||||
/// The Preferred Locations row navigates to a dedicated Uber-style page.
|
||||
/// Uses only design system tokens for colors, typography, and spacing.
|
||||
class PersonalInfoForm extends StatelessWidget {
|
||||
|
||||
/// Creates a [PersonalInfoForm].
|
||||
const PersonalInfoForm({
|
||||
super.key,
|
||||
@@ -22,6 +21,7 @@ class PersonalInfoForm extends StatelessWidget {
|
||||
required this.currentLocations,
|
||||
this.enabled = true,
|
||||
});
|
||||
|
||||
/// The staff member's full name (read-only).
|
||||
final String fullName;
|
||||
|
||||
@@ -42,7 +42,8 @@ class PersonalInfoForm extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final TranslationsStaffOnboardingPersonalInfoEn i18n = t.staff.onboarding.personal_info;
|
||||
final TranslationsStaffOnboardingPersonalInfoEn i18n =
|
||||
t.staff.onboarding.personal_info;
|
||||
final String locationSummary = currentLocations.isEmpty
|
||||
? i18n.locations_summary_none
|
||||
: currentLocations.join(', ');
|
||||
@@ -84,17 +85,13 @@ class PersonalInfoForm extends StatelessWidget {
|
||||
hint: i18n.locations_hint,
|
||||
icon: UiIcons.mapPin,
|
||||
enabled: enabled,
|
||||
onTap: enabled
|
||||
? () => Modular.to.pushNamed(StaffPaths.preferredLocations)
|
||||
: null,
|
||||
onTap: enabled ? () => Modular.to.toPreferredLocations() : null,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
|
||||
const _FieldLabel(text: 'Language'),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
_LanguageSelector(
|
||||
enabled: enabled,
|
||||
),
|
||||
_LanguageSelector(enabled: enabled),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -132,7 +129,9 @@ class _TappableRow extends StatelessWidget {
|
||||
color: enabled ? UiColors.bgPopup : UiColors.bgSecondary,
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusMdValue),
|
||||
border: Border.all(
|
||||
color: enabled ? UiColors.border : UiColors.border.withValues(alpha: 0.5),
|
||||
color: enabled
|
||||
? UiColors.border
|
||||
: UiColors.border.withValues(alpha: 0.5),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
@@ -164,9 +163,7 @@ class _TappableRow extends StatelessWidget {
|
||||
|
||||
/// A language selector widget that displays the current language and navigates to language selection page.
|
||||
class _LanguageSelector extends StatelessWidget {
|
||||
const _LanguageSelector({
|
||||
this.enabled = true,
|
||||
});
|
||||
const _LanguageSelector({this.enabled = true});
|
||||
|
||||
final bool enabled;
|
||||
|
||||
@@ -176,9 +173,7 @@ class _LanguageSelector extends StatelessWidget {
|
||||
final String languageName = currentLocale == 'es' ? 'Español' : 'English';
|
||||
|
||||
return GestureDetector(
|
||||
onTap: enabled
|
||||
? () => Modular.to.pushNamed(StaffPaths.languageSelection)
|
||||
: null,
|
||||
onTap: enabled ? () => Modular.to.toLanguageSelection() : null,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space3,
|
||||
@@ -188,18 +183,21 @@ class _LanguageSelector extends StatelessWidget {
|
||||
color: enabled ? UiColors.bgPopup : UiColors.bgSecondary,
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusMdValue),
|
||||
border: Border.all(
|
||||
color: enabled ? UiColors.border : UiColors.border.withValues(alpha: 0.5),
|
||||
color: enabled
|
||||
? UiColors.border
|
||||
: UiColors.border.withValues(alpha: 0.5),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
const Icon(UiIcons.settings, size: 18, color: UiColors.iconSecondary),
|
||||
const Icon(
|
||||
UiIcons.settings,
|
||||
size: 18,
|
||||
color: UiColors.iconSecondary,
|
||||
),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Expanded(
|
||||
child: Text(
|
||||
languageName,
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
child: Text(languageName, style: UiTypography.body2r.textPrimary),
|
||||
),
|
||||
if (enabled)
|
||||
const Icon(
|
||||
@@ -220,10 +218,7 @@ class _FieldLabel extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Text(
|
||||
text,
|
||||
style: UiTypography.titleUppercase3m.textSecondary,
|
||||
);
|
||||
return Text(text, style: UiTypography.titleUppercase3m.textSecondary);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,10 +239,7 @@ class _ReadOnlyField extends StatelessWidget {
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusMdValue),
|
||||
border: Border.all(color: UiColors.border),
|
||||
),
|
||||
child: Text(
|
||||
value,
|
||||
style: UiTypography.body2r.textInactive,
|
||||
),
|
||||
child: Text(value, style: UiTypography.body2r.textInactive),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,12 +227,12 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
|
||||
content: Text(i18n.message),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Modular.to.pop(),
|
||||
onPressed: () => Modular.to.popSafe(),
|
||||
child: Text(Translations.of(context).common.cancel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Modular.to.pop();
|
||||
Modular.to.popSafe();
|
||||
_showApplyingDialog(context, shift);
|
||||
BlocProvider.of<ShiftDetailsBloc>(context).add(
|
||||
BookShiftDetailsEvent(
|
||||
@@ -317,7 +317,11 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
|
||||
children: [
|
||||
const Icon(UiIcons.warning, color: UiColors.error),
|
||||
const SizedBox(width: UiConstants.space2),
|
||||
Expanded(child: Text(context.t.staff_shifts.shift_details.eligibility_requirements)),
|
||||
Expanded(
|
||||
child: Text(
|
||||
context.t.staff_shifts.shift_details.eligibility_requirements,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
content: Text(
|
||||
@@ -333,7 +337,7 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
|
||||
text: "Go to Certificates",
|
||||
onPressed: () {
|
||||
Navigator.of(ctx).pop();
|
||||
Modular.to.pushNamed(StaffPaths.certificates);
|
||||
Modular.to.toCertificates();
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user