refactor: enhance navigation robustness by introducing popSafe and safePushNamedAndRemoveUntil methods and updating their usage.

This commit is contained in:
Achintha Isuru
2026-02-28 17:23:53 -05:00
parent c26128f1f2
commit 53b612851c
24 changed files with 481 additions and 334 deletions

View File

@@ -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),

View File

@@ -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),
),

View File

@@ -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,
),
],
],
),

View File

@@ -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> {
);
}
}

View File

@@ -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),
],
),
);