Standardize UI to design system tokens
Refactor multiple UI components to use design system tokens and primitives. Added new UiIcons (coffee, wifi, xCircle, ban) and typography color getters (primary, accent). Replaced hardcoded paddings, spacings, radii, borderRadius, and icon imports (lucide_icons -> UiIcons) with UiConstants, UiColors, UiTypography and UiIcons, and switched to UiColors.withValues for opacity. Changes apply across authentication, availability, clock_in (and its widgets), commute tracker, lunch break modal, location map placeholder, attendance card, date selector, and related presentation files to improve visual consistency.
This commit is contained in:
@@ -53,7 +53,7 @@ class CertificatesPage extends StatelessWidget {
|
||||
Transform.translate(
|
||||
offset: const Offset(0, -48),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
padding: const EdgeInsets.symmetric(horizontal: UiConstants.space5),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
...documents.map((StaffDocument doc) => CertificateCard(
|
||||
@@ -70,11 +70,11 @@ class CertificatesPage extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
)),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
AddCertificateCard(
|
||||
onTap: () => _showUploadModal(context, null),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
const SizedBox(height: UiConstants.space8),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -12,37 +12,36 @@ class AddCertificateCard extends StatelessWidget {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
padding: const EdgeInsets.all(UiConstants.space5),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: <Color>[Colors.grey[50]!, Colors.grey[100]!], // Keep prototype style
|
||||
colors: <Color>[
|
||||
UiColors.bgSecondary.withValues(alpha: 0.5),
|
||||
UiColors.bgSecondary,
|
||||
],
|
||||
),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
border: Border.all(
|
||||
color: Colors.grey[300]!,
|
||||
color: UiColors.border,
|
||||
style: BorderStyle.solid,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
const Icon(UiIcons.add, color: UiColors.primary, size: 24),
|
||||
const SizedBox(width: 16),
|
||||
const SizedBox(width: UiConstants.space4),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
t.staff_certificates.add_more.title,
|
||||
style: UiTypography.body1b.copyWith( // 16px Bold
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.body1b.textPrimary,
|
||||
),
|
||||
Text(
|
||||
t.staff_certificates.add_more.subtitle,
|
||||
style: UiTypography.body3r.copyWith( // 12px Regular
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
|
||||
class CertificateCard extends StatelessWidget {
|
||||
final StaffDocument document;
|
||||
@@ -39,13 +39,13 @@ class CertificateCard extends StatelessWidget {
|
||||
final _CertificateUiProps uiProps = _getUiProps(document.documentId);
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 16),
|
||||
margin: const EdgeInsets.only(bottom: UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.white,
|
||||
borderRadius: BorderRadius.circular(UiConstants.space4),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: UiColors.black.withOpacity(0.05),
|
||||
color: UiColors.black.withValues(alpha: 0.05),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -57,11 +57,14 @@ class CertificateCard extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
if (isExpiring || isExpired)
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space4,
|
||||
vertical: UiConstants.space2,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF9E547).withOpacity(0.2), // Yellow tint
|
||||
border: const Border(
|
||||
bottom: BorderSide(color: Color(0x66F9E547)),
|
||||
color: UiColors.accent.withValues(alpha: 0.2), // Yellow tint
|
||||
border: Border(
|
||||
bottom: BorderSide(color: UiColors.accent.withValues(alpha: 0.4)),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
@@ -76,16 +79,14 @@ class CertificateCard extends StatelessWidget {
|
||||
isExpired
|
||||
? t.staff_certificates.card.expired
|
||||
: t.staff_certificates.card.expires_in_days(days: _daysUntilExpiry(document.expiryDate)),
|
||||
style: UiTypography.body3m.copyWith( // 12px Medium
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.body3m.textPrimary,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
padding: const EdgeInsets.all(UiConstants.space5),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
@@ -96,8 +97,8 @@ class CertificateCard extends StatelessWidget {
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: BoxDecoration(
|
||||
color: uiProps.color.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
color: uiProps.color.withValues(alpha: 0.1),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
child: Center(
|
||||
child: Icon(
|
||||
@@ -137,7 +138,7 @@ class CertificateCard extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
const SizedBox(width: UiConstants.space4),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -151,16 +152,12 @@ class CertificateCard extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
document.name,
|
||||
style: UiTypography.body1m.copyWith( // 16px Medium
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.body1m.textPrimary,
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
document.description ?? '', // Optional description
|
||||
style: UiTypography.body3r.copyWith( // 12px Regular
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -172,7 +169,7 @@ class CertificateCard extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
|
||||
if (showComplete) _buildCompleteStatus(document.expiryDate),
|
||||
|
||||
@@ -186,9 +183,11 @@ class CertificateCard extends StatelessWidget {
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: UiColors.primary,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: UiConstants.space3,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
elevation: 0,
|
||||
),
|
||||
child: Row(
|
||||
@@ -202,9 +201,7 @@ class CertificateCard extends StatelessWidget {
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
t.staff_certificates.card.upload_button,
|
||||
style: UiTypography.body2m.copyWith( // 14px Medium
|
||||
color: UiColors.white,
|
||||
),
|
||||
style: UiTypography.body2m.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -212,7 +209,7 @@ class CertificateCard extends StatelessWidget {
|
||||
),
|
||||
|
||||
if (showComplete || isExpiring || isExpired) ...<Widget>[
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: OutlinedButton.icon(
|
||||
@@ -223,13 +220,15 @@ class CertificateCard extends StatelessWidget {
|
||||
foregroundColor: UiColors.textPrimary,
|
||||
side: const BorderSide(color: UiColors.border),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: UiConstants.space3,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: TextButton.icon(
|
||||
@@ -238,9 +237,11 @@ class CertificateCard extends StatelessWidget {
|
||||
label: Text(t.staff_certificates.card.remove),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: UiColors.destructive,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: UiConstants.space3,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -274,16 +275,14 @@ class CertificateCard extends StatelessWidget {
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
t.staff_certificates.card.verified,
|
||||
style: UiTypography.body2m.copyWith(
|
||||
color: UiColors.primary,
|
||||
),
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
],
|
||||
),
|
||||
if (expiryDate != null)
|
||||
Text(
|
||||
t.staff_certificates.card.exp(date: DateFormat('MMM d, yyyy').format(expiryDate)),
|
||||
style: UiTypography.body3r.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -6,7 +6,8 @@ import 'package:flutter/material.dart';
|
||||
class CertificateUploadModal extends StatelessWidget {
|
||||
/// The document being edited, or null for a new upload.
|
||||
// ignore: unused_field
|
||||
final dynamic document; // Using dynamic for now as we don't import domain here to avoid direct coupling if possible, but actually we should import domain.
|
||||
final dynamic
|
||||
document; // Using dynamic for now as we don't import domain here to avoid direct coupling if possible, but actually we should import domain.
|
||||
// Ideally, widgets should be dumb. Let's import domain.
|
||||
|
||||
final VoidCallback onSave;
|
||||
@@ -24,13 +25,13 @@ class CertificateUploadModal extends StatelessWidget {
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height * 0.75,
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: UiColors.bgPopup,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(24),
|
||||
topRight: Radius.circular(24),
|
||||
topLeft: Radius.circular(UiConstants.radiusBase),
|
||||
topRight: Radius.circular(UiConstants.radiusBase),
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.all(24),
|
||||
padding: const EdgeInsets.all(UiConstants.space6),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
@@ -39,7 +40,7 @@ class CertificateUploadModal extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
t.staff_certificates.upload_modal.title,
|
||||
style: UiTypography.headline3m.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.headline3m.textPrimary,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: onCancel,
|
||||
@@ -47,35 +48,42 @@ class CertificateUploadModal extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
const SizedBox(height: UiConstants.space8),
|
||||
Text(
|
||||
t.staff_certificates.upload_modal.expiry_label,
|
||||
style: UiTypography.body1m,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space4,
|
||||
vertical: UiConstants.space3,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: UiColors.border),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
const Icon(UiIcons.calendar, size: 20, color: UiColors.textSecondary),
|
||||
const SizedBox(width: 12),
|
||||
const Icon(
|
||||
UiIcons.calendar,
|
||||
size: 20,
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Text(
|
||||
t.staff_certificates.upload_modal.select_date,
|
||||
style: UiTypography.body1m.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body1m.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
Text(
|
||||
t.staff_certificates.upload_modal.upload_file,
|
||||
style: UiTypography.body1m,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
Expanded(
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
@@ -84,16 +92,16 @@ class CertificateUploadModal extends StatelessWidget {
|
||||
color: UiColors.border,
|
||||
style: BorderStyle.solid,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
color: UiColors.background,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFEFF6FF), // Light blue
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.tagActive,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
@@ -102,7 +110,7 @@ class CertificateUploadModal extends StatelessWidget {
|
||||
color: UiColors.primary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
Text(
|
||||
t.staff_certificates.upload_modal.drag_drop,
|
||||
style: UiTypography.body1m,
|
||||
@@ -110,43 +118,51 @@ class CertificateUploadModal extends StatelessWidget {
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
t.staff_certificates.upload_modal.supported_formats,
|
||||
style: UiTypography.body3r.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: OutlinedButton(
|
||||
onPressed: onCancel,
|
||||
style: OutlinedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: UiConstants.space4,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
side: const BorderSide(color: UiColors.border),
|
||||
),
|
||||
child: Text(t.staff_certificates.upload_modal.cancel,
|
||||
style: UiTypography.body1m.copyWith(color: UiColors.textPrimary)),
|
||||
child: Text(
|
||||
t.staff_certificates.upload_modal.cancel,
|
||||
style: UiTypography.body1m.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
const SizedBox(width: UiConstants.space4),
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: onSave,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: UiColors.primary,
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: UiConstants.space4,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
elevation: 0,
|
||||
),
|
||||
child: Text(t.staff_certificates.upload_modal.save,
|
||||
style: UiTypography.body1m.copyWith(color: Colors.white)),
|
||||
child: Text(
|
||||
t.staff_certificates.upload_modal.save,
|
||||
style: UiTypography.body1m.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -20,13 +20,21 @@ class CertificatesHeader extends StatelessWidget {
|
||||
final int progressPercent = totalCount == 0 ? 0 : (progressValue * 100).round();
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.fromLTRB(20, 60, 20, 80),
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
UiConstants.space5,
|
||||
60,
|
||||
UiConstants.space5,
|
||||
80,
|
||||
),
|
||||
// Keeping gradient as per prototype layout requirement
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: <Color>[UiColors.primary, Color(0xFF1E40AF)], // Using Primary and a darker shade
|
||||
colors: <Color>[
|
||||
UiColors.primary,
|
||||
Color(0xFF1E40AF),
|
||||
], // Using Primary and a darker shade
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
@@ -39,7 +47,7 @@ class CertificatesHeader extends StatelessWidget {
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.white.withOpacity(0.1),
|
||||
color: UiColors.white.withValues(alpha: 0.1),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
@@ -49,16 +57,14 @@ class CertificatesHeader extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Text(
|
||||
t.staff_certificates.title,
|
||||
style: UiTypography.headline3m.copyWith( // 18px Bold
|
||||
color: UiColors.white,
|
||||
),
|
||||
style: UiTypography.headline3m.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
const SizedBox(height: UiConstants.space8),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
@@ -70,53 +76,48 @@ class CertificatesHeader extends StatelessWidget {
|
||||
CircularProgressIndicator(
|
||||
value: progressValue,
|
||||
strokeWidth: 8,
|
||||
backgroundColor: UiColors.white.withOpacity(0.2),
|
||||
backgroundColor: UiColors.white.withValues(alpha: 0.2),
|
||||
valueColor: const AlwaysStoppedAnimation<Color>(
|
||||
Color(0xFFF9E547), // Yellow from prototype
|
||||
UiColors.accent, // Yellow from prototype
|
||||
),
|
||||
),
|
||||
Center(
|
||||
child: Text(
|
||||
'$progressPercent%',
|
||||
style: UiTypography.display1b.copyWith( // 26px Bold
|
||||
color: UiColors.white,
|
||||
),
|
||||
style: UiTypography.display1b.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 24),
|
||||
const SizedBox(width: UiConstants.space6),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
t.staff_certificates.progress.title,
|
||||
style: UiTypography.body1b.copyWith( // 16px Bold
|
||||
color: UiColors.white,
|
||||
),
|
||||
style: UiTypography.body1b.white,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
t.staff_certificates.progress.verified_count(completed: completedCount, total: totalCount),
|
||||
style: UiTypography.body3r.copyWith( // 12px Regular
|
||||
color: UiColors.white.withOpacity(0.7),
|
||||
t.staff_certificates.progress.verified_count(
|
||||
completed: completedCount, total: totalCount),
|
||||
style: UiTypography.body3r.copyWith(
|
||||
color: UiColors.white.withValues(alpha: 0.7),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
const Icon(
|
||||
UiIcons.shield,
|
||||
color: Color(0xFFF9E547),
|
||||
color: UiColors.accent,
|
||||
size: 16,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
t.staff_certificates.progress.active,
|
||||
style: UiTypography.body3m.copyWith( // 12px Medium
|
||||
color: const Color(0xFFF9E547),
|
||||
),
|
||||
style: UiTypography.body3m.accent,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -25,15 +25,14 @@ class DocumentsPage extends StatelessWidget {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
backgroundColor: UiColors.bgPopup,
|
||||
leading: IconButton(
|
||||
icon: const Icon(UiIcons.arrowLeft, color: UiColors.iconSecondary),
|
||||
onPressed: () => Modular.to.pop(),
|
||||
),
|
||||
title: Text(
|
||||
t.staff_documents.title,
|
||||
style: UiTypography.headline3m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.headline3m.textPrimary,
|
||||
),
|
||||
bottom: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(1.0),
|
||||
@@ -56,7 +55,7 @@ class DocumentsPage extends StatelessWidget {
|
||||
t.staff_documents.list.error(
|
||||
message: state.errorMessage ?? 'Unknown',
|
||||
),
|
||||
style: UiTypography.body1m.copyWith(color: UiColors.textError),
|
||||
style: UiTypography.body1m.textError,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -64,20 +63,23 @@ class DocumentsPage extends StatelessWidget {
|
||||
return Center(
|
||||
child: Text(
|
||||
t.staff_documents.list.empty,
|
||||
style: UiTypography.body1m.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body1m.textSecondary,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space5,
|
||||
vertical: UiConstants.space6,
|
||||
),
|
||||
children: <Widget>[
|
||||
DocumentsProgressCard(
|
||||
completedCount: state.completedCount,
|
||||
totalCount: state.totalCount,
|
||||
progress: state.progress,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
...state.documents.map(
|
||||
(StaffDocument doc) => DocumentCard(
|
||||
document: doc,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
// ignore: depend_on_referenced_packages
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
|
||||
@@ -18,11 +17,11 @@ class DocumentCard extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
padding: const EdgeInsets.all(16),
|
||||
margin: const EdgeInsets.only(bottom: UiConstants.space3),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
border: Border.all(color: UiColors.border),
|
||||
),
|
||||
child: Row(
|
||||
@@ -32,7 +31,7 @@ class DocumentCard extends StatelessWidget {
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.primary.withOpacity(0.1),
|
||||
color: UiColors.primary.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: const Center(
|
||||
@@ -43,7 +42,7 @@ class DocumentCard extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -53,9 +52,7 @@ class DocumentCard extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
document.name,
|
||||
style: UiTypography.body1m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.body1m.textPrimary,
|
||||
),
|
||||
_getStatusIcon(document.status),
|
||||
],
|
||||
@@ -64,15 +61,13 @@ class DocumentCard extends StatelessWidget {
|
||||
if (document.description != null)
|
||||
Text(
|
||||
document.description!,
|
||||
style: UiTypography.body2r.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
_buildStatusBadge(document.status),
|
||||
const SizedBox(width: 8),
|
||||
const SizedBox(width: UiConstants.space2),
|
||||
_buildActionButton(document.status),
|
||||
],
|
||||
),
|
||||
@@ -114,27 +109,27 @@ class DocumentCard extends StatelessWidget {
|
||||
|
||||
switch (status) {
|
||||
case DocumentStatus.verified:
|
||||
bg = UiColors.textSuccess.withOpacity(0.2);
|
||||
bg = UiColors.tagSuccess;
|
||||
text = UiColors.textSuccess;
|
||||
label = t.staff_documents.card.verified;
|
||||
break;
|
||||
case DocumentStatus.pending:
|
||||
bg = UiColors.textWarning.withOpacity(0.2);
|
||||
bg = UiColors.tagPending;
|
||||
text = UiColors.textWarning;
|
||||
label = t.staff_documents.card.pending;
|
||||
break;
|
||||
case DocumentStatus.missing:
|
||||
bg = UiColors.textError.withOpacity(0.2);
|
||||
bg = UiColors.textError.withValues(alpha: 0.1);
|
||||
text = UiColors.textError;
|
||||
label = t.staff_documents.card.missing;
|
||||
break;
|
||||
case DocumentStatus.rejected:
|
||||
bg = UiColors.textError.withOpacity(0.2);
|
||||
bg = UiColors.textError.withValues(alpha: 0.1);
|
||||
text = UiColors.textError;
|
||||
label = t.staff_documents.card.rejected;
|
||||
break;
|
||||
case DocumentStatus.expired:
|
||||
bg = UiColors.textError.withOpacity(0.2);
|
||||
bg = UiColors.textError.withValues(alpha: 0.1);
|
||||
text = UiColors.textError;
|
||||
label = t.staff_documents.card.rejected; // Or define "Expired" string
|
||||
break;
|
||||
@@ -165,7 +160,7 @@ class DocumentCard extends StatelessWidget {
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(
|
||||
isVerified ? UiIcons.eye : LucideIcons.upload,
|
||||
isVerified ? UiIcons.eye : UiIcons.upload,
|
||||
size: 16,
|
||||
color: UiColors.primary,
|
||||
),
|
||||
@@ -174,9 +169,7 @@ class DocumentCard extends StatelessWidget {
|
||||
isVerified
|
||||
? t.staff_documents.card.view
|
||||
: t.staff_documents.card.upload,
|
||||
style: UiTypography.body3m.copyWith(
|
||||
color: UiColors.primary,
|
||||
),
|
||||
style: UiTypography.body3m.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -24,10 +24,10 @@ class DocumentsProgressCard extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
border: Border.all(color: UiColors.border),
|
||||
),
|
||||
child: Column(
|
||||
@@ -37,16 +37,14 @@ class DocumentsProgressCard extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
t.staff_documents.verification_card.title,
|
||||
style: UiTypography.body1m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.body1m.textPrimary,
|
||||
),
|
||||
Text(
|
||||
t.staff_documents.verification_card.progress(
|
||||
completed: completedCount,
|
||||
total: totalCount,
|
||||
),
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.primary),
|
||||
style: UiTypography.body2r.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -83,10 +83,13 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
if (state.status == FormI9Status.success) {
|
||||
// Success view is handled by state check in build or we can navigate
|
||||
} else if (state.status == FormI9Status.failure) {
|
||||
final ScaffoldMessengerState messenger = ScaffoldMessenger.of(context);
|
||||
final ScaffoldMessengerState messenger =
|
||||
ScaffoldMessenger.of(context);
|
||||
messenger.hideCurrentSnackBar();
|
||||
messenger.showSnackBar(
|
||||
SnackBar(content: Text(state.errorMessage ?? 'An error occurred')),
|
||||
SnackBar(
|
||||
content: Text(state.errorMessage ?? 'An error occurred'),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
@@ -100,7 +103,10 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
_buildHeader(context, state),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space5,
|
||||
vertical: UiConstants.space6,
|
||||
),
|
||||
child: _buildCurrentStep(context, state),
|
||||
),
|
||||
),
|
||||
@@ -118,9 +124,9 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
backgroundColor: UiColors.background,
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
padding: const EdgeInsets.all(UiConstants.space6),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(32),
|
||||
padding: const EdgeInsets.all(UiConstants.space8),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
@@ -132,40 +138,40 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
Container(
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFDCFCE7),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.tagSuccess,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
UiIcons.success,
|
||||
color: Color(0xFF16A34A),
|
||||
color: UiColors.textSuccess,
|
||||
size: 32,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
Text(
|
||||
'Form I-9 Submitted!',
|
||||
style: UiTypography.headline4m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.headline4m.textPrimary,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
Text(
|
||||
'Your employment eligibility verification has been submitted.',
|
||||
textAlign: TextAlign.center,
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: () => Modular.to.pop(true),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: UiColors.primary,
|
||||
foregroundColor: UiColors.bgPopup,
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
foregroundColor: UiColors.white,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: UiConstants.space4,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
elevation: 0,
|
||||
),
|
||||
@@ -183,7 +189,12 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
Widget _buildHeader(BuildContext context, FormI9State state) {
|
||||
return Container(
|
||||
color: UiColors.primary,
|
||||
padding: const EdgeInsets.only(top: 60, bottom: 24, left: 20, right: 20),
|
||||
padding: const EdgeInsets.only(
|
||||
top: 60,
|
||||
bottom: UiConstants.space6,
|
||||
left: UiConstants.space5,
|
||||
right: UiConstants.space5,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
@@ -193,31 +204,34 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
onTap: () => Modular.to.pop(),
|
||||
child: const Icon(
|
||||
UiIcons.arrowLeft,
|
||||
color: UiColors.bgPopup,
|
||||
color: UiColors.white,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Form I-9',
|
||||
style: UiTypography.headline4m.copyWith(
|
||||
color: UiColors.bgPopup,
|
||||
),
|
||||
style: UiTypography.headline4m.white,
|
||||
),
|
||||
Text(
|
||||
'Employment Eligibility Verification',
|
||||
style: UiTypography.body3r.copyWith(color: UiColors.bgPopup.withOpacity(0.7)),
|
||||
style: UiTypography.body3r.copyWith(
|
||||
color: UiColors.white.withValues(alpha: 0.7),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
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(
|
||||
@@ -228,8 +242,8 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: idx <= state.currentStep
|
||||
? UiColors.bgPopup
|
||||
: UiColors.bgPopup.withOpacity(0.3),
|
||||
? UiColors.white
|
||||
: UiColors.white.withValues(alpha: 0.3),
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
@@ -240,20 +254,21 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Step ${state.currentStep + 1} of ${_steps.length}',
|
||||
style: UiTypography.body3r.copyWith(color: UiColors.bgPopup.withOpacity(0.7)),
|
||||
style: UiTypography.body3r.copyWith(
|
||||
color: UiColors.white.withValues(alpha: 0.7),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
_steps[state.currentStep]['title']!,
|
||||
textAlign: TextAlign.end,
|
||||
style: UiTypography.body3m.copyWith(
|
||||
color: UiColors.bgPopup,
|
||||
style: UiTypography.body3m.white.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
@@ -292,8 +307,7 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
label,
|
||||
style: UiTypography.body3m.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
style: UiTypography.body3m.textSecondary.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
@@ -305,26 +319,26 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
),
|
||||
onChanged: onChanged,
|
||||
keyboardType: keyboardType,
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
decoration: InputDecoration(
|
||||
hintText: placeholder,
|
||||
hintStyle: TextStyle(color: Colors.grey[400]),
|
||||
hintStyle: const TextStyle(color: UiColors.textPlaceholder),
|
||||
filled: true,
|
||||
fillColor: UiColors.bgPopup,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 16,
|
||||
horizontal: UiConstants.space4,
|
||||
vertical: UiConstants.space4,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
borderSide: const BorderSide(color: UiColors.border),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
borderSide: const BorderSide(color: UiColors.border),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
borderSide: const BorderSide(color: UiColors.primary),
|
||||
),
|
||||
),
|
||||
@@ -455,15 +469,15 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'State *',
|
||||
style: UiTypography.body3m.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
style: UiTypography.body3m.textSecondary.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
DropdownButtonFormField<String>(
|
||||
value: state.state.isEmpty ? null : state.state,
|
||||
onChanged: (String? val) => context.read<FormI9Cubit>().stateChanged(val ?? ''),
|
||||
onChanged: (String? val) =>
|
||||
context.read<FormI9Cubit>().stateChanged(val ?? ''),
|
||||
items: _usStates.map((String stateAbbr) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: stateAbbr,
|
||||
@@ -473,13 +487,15 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
decoration: InputDecoration(
|
||||
filled: true,
|
||||
fillColor: UiColors.bgPopup,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space4,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
borderSide: const BorderSide(color: UiColors.border),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
borderSide: const BorderSide(color: UiColors.border),
|
||||
),
|
||||
),
|
||||
@@ -507,9 +523,9 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'I attest, under penalty of perjury, that I am (check one of the following boxes):',
|
||||
style: UiTypography.body2m.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
_buildRadioOption(
|
||||
context,
|
||||
state,
|
||||
@@ -578,15 +594,21 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRadioOption(BuildContext context, FormI9State state, String value, String label, {Widget? child}) {
|
||||
Widget _buildRadioOption(
|
||||
BuildContext context,
|
||||
FormI9State state,
|
||||
String value,
|
||||
String label, {
|
||||
Widget? child,
|
||||
}) {
|
||||
final bool isSelected = state.citizenshipStatus == value;
|
||||
return GestureDetector(
|
||||
onTap: () => context.read<FormI9Cubit>().citizenshipStatusChanged(value),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
border: Border.all(
|
||||
color: isSelected ? UiColors.primary : UiColors.border,
|
||||
width: isSelected ? 2 : 1,
|
||||
@@ -602,18 +624,16 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: isSelected ? UiColors.primary : Colors.grey,
|
||||
color: isSelected ? UiColors.primary : UiColors.border,
|
||||
width: isSelected ? 6 : 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Expanded(
|
||||
child: Text(
|
||||
label,
|
||||
style: UiTypography.body2m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -630,10 +650,10 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
border: Border.all(color: UiColors.border),
|
||||
),
|
||||
child: Column(
|
||||
@@ -643,15 +663,21 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
'Summary',
|
||||
style: UiTypography.headline4m.copyWith(fontSize: 14),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
_buildSummaryRow('Name', '${state.firstName} ${state.lastName}'),
|
||||
_buildSummaryRow('Address', '${state.address}, ${state.city}'),
|
||||
_buildSummaryRow('SSN', '***-**-${state.ssn.length >= 4 ? state.ssn.substring(state.ssn.length - 4) : '****'}'),
|
||||
_buildSummaryRow('Citizenship', _getReadableCitizenship(state.citizenshipStatus)),
|
||||
_buildSummaryRow(
|
||||
'SSN',
|
||||
'***-**-${state.ssn.length >= 4 ? state.ssn.substring(state.ssn.length - 4) : '****'}',
|
||||
),
|
||||
_buildSummaryRow(
|
||||
'Citizenship',
|
||||
_getReadableCitizenship(state.citizenshipStatus),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
CheckboxListTile(
|
||||
value: state.preparerUsed,
|
||||
onChanged: (bool? val) {
|
||||
@@ -660,29 +686,27 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(
|
||||
'I used a preparer or translator',
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
activeColor: UiColors.primary,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.amber[50],
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: UiColors.accent.withValues(alpha: 0.1),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
child: const Text(
|
||||
child: Text(
|
||||
'I am aware that federal law provides for imprisonment and/or fines for false statements or use of false documents in connection with the completion of this form.',
|
||||
style: TextStyle(fontSize: 12, color: Color(0xFFB45309)),
|
||||
style: UiTypography.body3r.textWarning.copyWith(fontSize: 12),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
Text(
|
||||
'Signature (type your full name) *',
|
||||
style: UiTypography.body3m.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.body3m.textSecondary,
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
TextField(
|
||||
@@ -690,44 +714,46 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
..selection = TextSelection.fromPosition(
|
||||
TextPosition(offset: state.signature.length),
|
||||
),
|
||||
onChanged: (String val) => context.read<FormI9Cubit>().signatureChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormI9Cubit>().signatureChanged(val),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Type your full name',
|
||||
filled: true,
|
||||
fillColor: UiColors.bgPopup,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 16,
|
||||
horizontal: UiConstants.space4,
|
||||
vertical: UiConstants.space4,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
borderSide: const BorderSide(color: UiColors.border),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
borderSide: const BorderSide(color: UiColors.border),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
borderSide: const BorderSide(color: UiColors.primary),
|
||||
),
|
||||
),
|
||||
style: const TextStyle(fontFamily: 'Cursive', fontSize: 18),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
Text(
|
||||
'Date',
|
||||
style: UiTypography.body3m.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.body3m.textSecondary,
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space4,
|
||||
vertical: UiConstants.space4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF3F4F6),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: UiColors.bgSecondary,
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
border: Border.all(color: UiColors.border),
|
||||
),
|
||||
child: Text(
|
||||
@@ -747,15 +773,13 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
label,
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
value,
|
||||
textAlign: TextAlign.end,
|
||||
style: UiTypography.body2m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -780,7 +804,7 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
|
||||
Widget _buildFooter(BuildContext context, FormI9State state) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: const BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
border: Border(top: BorderSide(color: UiColors.border)),
|
||||
@@ -791,24 +815,30 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
if (state.currentStep > 0)
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
padding: const EdgeInsets.only(right: UiConstants.space3),
|
||||
child: OutlinedButton(
|
||||
onPressed: () => _handleBack(context),
|
||||
style: OutlinedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: UiConstants.space4,
|
||||
),
|
||||
side: const BorderSide(color: UiColors.border),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
const Icon(UiIcons.arrowLeft, size: 16, color: UiColors.textPrimary),
|
||||
const Icon(
|
||||
UiIcons.arrowLeft,
|
||||
size: 16,
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Back',
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -818,16 +848,20 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: ElevatedButton(
|
||||
onPressed: (_canProceed(state) && state.status != FormI9Status.submitting)
|
||||
onPressed: (
|
||||
_canProceed(state) &&
|
||||
state.status != FormI9Status.submitting)
|
||||
? () => _handleNext(context, state.currentStep)
|
||||
: null,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: UiColors.primary,
|
||||
disabledBackgroundColor: Colors.grey[300],
|
||||
foregroundColor: UiColors.bgPopup,
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
disabledBackgroundColor: UiColors.bgSecondary,
|
||||
foregroundColor: UiColors.white,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: UiConstants.space4,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
elevation: 0,
|
||||
),
|
||||
@@ -836,7 +870,7 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(
|
||||
color: UiColors.bgPopup,
|
||||
color: UiColors.white,
|
||||
strokeWidth: 2,
|
||||
),
|
||||
)
|
||||
@@ -850,7 +884,7 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
),
|
||||
if (state.currentStep < _steps.length - 1) ...<Widget>[
|
||||
const SizedBox(width: 8),
|
||||
const Icon(UiIcons.arrowRight, size: 16, color: UiColors.bgPopup),
|
||||
const Icon(UiIcons.arrowRight, size: 16, color: UiColors.white),
|
||||
],
|
||||
],
|
||||
),
|
||||
|
||||
@@ -146,7 +146,10 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
_buildHeader(context, state),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space5,
|
||||
vertical: UiConstants.space6,
|
||||
),
|
||||
child: _buildCurrentStep(context, state),
|
||||
),
|
||||
),
|
||||
@@ -164,9 +167,9 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
backgroundColor: UiColors.background,
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
padding: const EdgeInsets.all(UiConstants.space6),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(32),
|
||||
padding: const EdgeInsets.all(UiConstants.space8),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
@@ -178,40 +181,40 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
Container(
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFDCFCE7),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.tagSuccess,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
UiIcons.success,
|
||||
color: Color(0xFF16A34A),
|
||||
color: UiColors.textSuccess,
|
||||
size: 32,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
Text(
|
||||
'Form W-4 Submitted!',
|
||||
style: UiTypography.headline4m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.headline4m.textPrimary,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
Text(
|
||||
'Your withholding certificate has been submitted to your employer.',
|
||||
textAlign: TextAlign.center,
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: () => Modular.to.pop(true),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: UiColors.primary,
|
||||
foregroundColor: UiColors.bgPopup,
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
foregroundColor: UiColors.white,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: UiConstants.space4,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
elevation: 0,
|
||||
),
|
||||
@@ -229,7 +232,12 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
Widget _buildHeader(BuildContext context, FormW4State state) {
|
||||
return Container(
|
||||
color: UiColors.primary,
|
||||
padding: const EdgeInsets.only(top: 60, bottom: 24, left: 20, right: 20),
|
||||
padding: const EdgeInsets.only(
|
||||
top: 60,
|
||||
bottom: UiConstants.space6,
|
||||
left: UiConstants.space5,
|
||||
right: UiConstants.space5,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
@@ -239,31 +247,34 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
onTap: () => Modular.to.pop(),
|
||||
child: const Icon(
|
||||
UiIcons.arrowLeft,
|
||||
color: UiColors.bgPopup,
|
||||
color: UiColors.white,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Form W-4',
|
||||
style: UiTypography.headline4m.copyWith(
|
||||
color: UiColors.bgPopup,
|
||||
),
|
||||
style: UiTypography.headline4m.white,
|
||||
),
|
||||
Text(
|
||||
'Employee\'s Withholding Certificate',
|
||||
style: UiTypography.body3r.copyWith(color: UiColors.bgPopup.withOpacity(0.7)),
|
||||
style: UiTypography.body3r.copyWith(
|
||||
color: UiColors.white.withValues(alpha: 0.7),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
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(
|
||||
@@ -274,8 +285,8 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: idx <= state.currentStep
|
||||
? UiColors.bgPopup
|
||||
: UiColors.bgPopup.withOpacity(0.3),
|
||||
? UiColors.white
|
||||
: UiColors.white.withValues(alpha: 0.3),
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
@@ -286,18 +297,19 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Step ${state.currentStep + 1} of ${_steps.length}',
|
||||
style: UiTypography.body3r.copyWith(color: UiColors.bgPopup.withOpacity(0.7)),
|
||||
style: UiTypography.body3r.copyWith(
|
||||
color: UiColors.white.withValues(alpha: 0.7),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
_steps[state.currentStep]['title']!,
|
||||
style: UiTypography.body3m.copyWith(
|
||||
color: UiColors.bgPopup,
|
||||
style: UiTypography.body3m.white.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
@@ -339,8 +351,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
label,
|
||||
style: UiTypography.body3m.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
style: UiTypography.body3m.textSecondary.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
@@ -352,26 +363,26 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
),
|
||||
onChanged: onChanged,
|
||||
keyboardType: keyboardType,
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
decoration: InputDecoration(
|
||||
hintText: placeholder,
|
||||
hintStyle: TextStyle(color: Colors.grey[400]),
|
||||
hintStyle: const TextStyle(color: UiColors.textPlaceholder),
|
||||
filled: true,
|
||||
fillColor: UiColors.bgPopup,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 16,
|
||||
horizontal: UiConstants.space4,
|
||||
vertical: UiConstants.space4,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
borderSide: const BorderSide(color: UiColors.border),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
borderSide: const BorderSide(color: UiColors.border),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
borderSide: const BorderSide(color: UiColors.primary),
|
||||
),
|
||||
),
|
||||
@@ -438,25 +449,25 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue[50],
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: UiColors.tagActive,
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
child: Row(
|
||||
children: const <Widget>[
|
||||
Icon(UiIcons.info, color: Color(0xFF2563EB), size: 20),
|
||||
SizedBox(width: 12),
|
||||
children: <Widget>[
|
||||
const Icon(UiIcons.info, color: UiColors.primary, size: 20),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Your filing status determines your standard deduction and tax rates.',
|
||||
style: TextStyle(fontSize: 14, color: Color(0xFF1D4ED8)),
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
_buildRadioOption(
|
||||
context,
|
||||
state,
|
||||
@@ -484,15 +495,21 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRadioOption(BuildContext context, FormW4State state, String value, String label, String? subLabel) {
|
||||
Widget _buildRadioOption(
|
||||
BuildContext context,
|
||||
FormW4State state,
|
||||
String value,
|
||||
String label,
|
||||
String? subLabel,
|
||||
) {
|
||||
final bool isSelected = state.filingStatus == value;
|
||||
return GestureDetector(
|
||||
onTap: () => context.read<FormW4Cubit>().filingStatusChanged(value),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
border: Border.all(
|
||||
color: isSelected ? UiColors.primary : UiColors.border,
|
||||
width: isSelected ? 2 : 1,
|
||||
@@ -508,29 +525,25 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: isSelected ? UiColors.primary : Colors.grey,
|
||||
color: isSelected ? UiColors.primary : UiColors.border,
|
||||
width: isSelected ? 6 : 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
label,
|
||||
style: UiTypography.body2m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
if (subLabel != null) ...<Widget>[
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
subLabel,
|
||||
style: UiTypography.body3r.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
],
|
||||
],
|
||||
@@ -546,36 +559,32 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.amber[50],
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: UiColors.accent.withValues(alpha: 0.1),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
child: const Row(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Icon(
|
||||
const Icon(
|
||||
UiIcons.help,
|
||||
color: Color(0xFFD97706),
|
||||
color: UiColors.accent,
|
||||
size: 20,
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'When to complete this step?',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF92400E),
|
||||
fontSize: 14,
|
||||
),
|
||||
style: UiTypography.body2m.accent,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'Complete this step only if you hold more than one job at a time, or are married filing jointly and your spouse also works.',
|
||||
style: TextStyle(fontSize: 12, color: Color(0xFFB45309)),
|
||||
style: UiTypography.body3r.accent,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -583,18 +592,17 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
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(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
border: Border.all(
|
||||
color: state.multipleJobs
|
||||
? UiColors.primary
|
||||
: UiColors.border,
|
||||
color: state.multipleJobs ? UiColors.primary : UiColors.border,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
@@ -604,20 +612,16 @@ 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: BorderRadius.circular(6),
|
||||
border: Border.all(
|
||||
color: state.multipleJobs
|
||||
? UiColors.primary
|
||||
: Colors.grey,
|
||||
color: state.multipleJobs ? UiColors.primary : UiColors.border,
|
||||
),
|
||||
),
|
||||
child: state.multipleJobs
|
||||
? const Icon(
|
||||
UiIcons.check,
|
||||
color: UiColors.bgPopup,
|
||||
color: UiColors.white,
|
||||
size: 16,
|
||||
)
|
||||
: null,
|
||||
@@ -629,16 +633,12 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'I have multiple jobs or my spouse works',
|
||||
style: UiTypography.body2m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'Check this box if there are only two jobs total',
|
||||
style: UiTypography.body3r.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -651,7 +651,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
Text(
|
||||
'If this does not apply, you can continue to the next step',
|
||||
textAlign: TextAlign.center,
|
||||
style: UiTypography.body3r.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -661,30 +661,30 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue[50], // Same note about blue migration
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: UiColors.tagActive,
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
child: const Row(
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(UiIcons.info, color: Color(0xFF2563EB), size: 20),
|
||||
SizedBox(width: 12),
|
||||
const Icon(UiIcons.info, color: UiColors.primary, size: 20),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'If your total income will be \$200,000 or less (\$400,000 if married filing jointly), you may claim credits for dependents.',
|
||||
style: TextStyle(fontSize: 14, color: Color(0xFF1D4ED8)),
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
border: Border.all(color: UiColors.border),
|
||||
),
|
||||
child: Column(
|
||||
@@ -715,10 +715,10 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
if (_totalCredits(state) > 0) ...<Widget>[
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFDCFCE7),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
@@ -770,16 +770,12 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFDCFCE7),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: UiColors.tagSuccess,
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
child: Text(
|
||||
badge,
|
||||
style: const TextStyle(
|
||||
fontSize: 10,
|
||||
color: Color(0xFF15803D),
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
style: UiTypography.footnote2b.textSuccess,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -834,7 +830,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'These adjustments are optional. You can skip them if they don\'t apply.',
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
_buildTextField(
|
||||
@@ -848,7 +844,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
padding: const EdgeInsets.only(top: 4, bottom: 16),
|
||||
child: Text(
|
||||
'Include interest, dividends, retirement income',
|
||||
style: UiTypography.body3r.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -863,7 +859,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
padding: const EdgeInsets.only(top: 4, bottom: 16),
|
||||
child: Text(
|
||||
'If you expect to claim deductions other than the standard deduction',
|
||||
style: UiTypography.body3r.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -878,7 +874,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
padding: const EdgeInsets.only(top: 4, bottom: 16),
|
||||
child: Text(
|
||||
'Any additional tax you want withheld each pay period',
|
||||
style: UiTypography.body3r.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -890,10 +886,10 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
border: Border.all(color: UiColors.border),
|
||||
),
|
||||
child: Column(
|
||||
@@ -927,22 +923,20 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.amber[50],
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: UiColors.accent.withValues(alpha: 0.1),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
child: const Text(
|
||||
child: Text(
|
||||
'Under penalties of perjury, I declare that this certificate, to the best of my knowledge and belief, is true, correct, and complete.',
|
||||
style: TextStyle(fontSize: 12, color: Color(0xFFB45309)),
|
||||
style: UiTypography.body3r.textWarning.copyWith(fontSize: 12),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
Text(
|
||||
'Signature (type your full name) *',
|
||||
style: UiTypography.body3m.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.body3m.textSecondary,
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
TextField(
|
||||
@@ -950,44 +944,46 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
..selection = TextSelection.fromPosition(
|
||||
TextPosition(offset: state.signature.length),
|
||||
),
|
||||
onChanged: (String val) => context.read<FormW4Cubit>().signatureChanged(val),
|
||||
onChanged: (String val) =>
|
||||
context.read<FormW4Cubit>().signatureChanged(val),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Type your full name',
|
||||
filled: true,
|
||||
fillColor: UiColors.bgPopup,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 16,
|
||||
horizontal: UiConstants.space4,
|
||||
vertical: UiConstants.space4,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
borderSide: const BorderSide(color: UiColors.border),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
borderSide: const BorderSide(color: UiColors.border),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
borderSide: const BorderSide(color: UiColors.primary),
|
||||
),
|
||||
),
|
||||
style: const TextStyle(fontFamily: 'Cursive', fontSize: 18),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
Text(
|
||||
'Date',
|
||||
style: UiTypography.body3m.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.body3m.textSecondary,
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space4,
|
||||
vertical: UiConstants.space4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF3F4F6),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: UiColors.bgSecondary,
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
border: Border.all(color: UiColors.border),
|
||||
),
|
||||
child: Text(
|
||||
@@ -1007,7 +1003,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
label,
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
Text(
|
||||
value,
|
||||
@@ -1035,7 +1031,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
|
||||
Widget _buildFooter(BuildContext context, FormW4State state) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: const BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
border: Border(top: BorderSide(color: UiColors.border)),
|
||||
@@ -1046,24 +1042,30 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
if (state.currentStep > 0)
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
padding: const EdgeInsets.only(right: UiConstants.space3),
|
||||
child: OutlinedButton(
|
||||
onPressed: () => _handleBack(context),
|
||||
style: OutlinedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: UiConstants.space4,
|
||||
),
|
||||
side: const BorderSide(color: UiColors.border),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
const Icon(UiIcons.arrowLeft, size: 16, color: UiColors.textPrimary),
|
||||
const Icon(
|
||||
UiIcons.arrowLeft,
|
||||
size: 16,
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Back',
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -1073,16 +1075,20 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: ElevatedButton(
|
||||
onPressed: (_canProceed(state) && state.status != FormW4Status.submitting)
|
||||
onPressed: (
|
||||
_canProceed(state) &&
|
||||
state.status != FormW4Status.submitting)
|
||||
? () => _handleNext(context, state.currentStep)
|
||||
: null,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: UiColors.primary,
|
||||
disabledBackgroundColor: Colors.grey[300],
|
||||
foregroundColor: UiColors.bgPopup,
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
disabledBackgroundColor: UiColors.bgSecondary,
|
||||
foregroundColor: UiColors.white,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: UiConstants.space4,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
elevation: 0,
|
||||
),
|
||||
@@ -1091,7 +1097,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(
|
||||
color: UiColors.bgPopup,
|
||||
color: UiColors.white,
|
||||
strokeWidth: 2,
|
||||
),
|
||||
)
|
||||
@@ -1105,7 +1111,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
),
|
||||
if (state.currentStep < _steps.length - 1) ...<Widget>[
|
||||
const SizedBox(width: 8),
|
||||
const Icon(UiIcons.arrowRight, size: 16, color: UiColors.bgPopup),
|
||||
const Icon(UiIcons.arrowRight, size: 16, color: UiColors.white),
|
||||
],
|
||||
],
|
||||
),
|
||||
|
||||
@@ -21,7 +21,7 @@ class TaxFormsPage extends StatelessWidget {
|
||||
),
|
||||
title: Text(
|
||||
'Tax Documents',
|
||||
style: UiTypography.headline3m.copyWith(color: UiColors.bgPopup),
|
||||
style: UiTypography.headline3m.textSecondary,
|
||||
),
|
||||
bottom: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(24),
|
||||
@@ -37,7 +37,7 @@ class TaxFormsPage extends StatelessWidget {
|
||||
child: Text(
|
||||
'Complete required forms to start working',
|
||||
style: UiTypography.body3r.copyWith(
|
||||
color: UiColors.bgPopup.withOpacity(0.8),
|
||||
color: UiColors.primaryForeground.withValues(alpha: 0.8),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -111,15 +111,11 @@ class TaxFormsPage extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Document Progress',
|
||||
style: UiTypography.body2m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
Text(
|
||||
'$completedCount/$totalCount',
|
||||
style: UiTypography.body2m.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.body2m.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -171,7 +167,7 @@ class TaxFormsPage extends StatelessWidget {
|
||||
width: 48,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.primary.withOpacity(0.1),
|
||||
color: UiColors.primary.withValues(alpha: 0.1),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
child: Center(child: Text(icon, style: UiTypography.headline1m)),
|
||||
@@ -186,9 +182,7 @@ class TaxFormsPage extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
form.title,
|
||||
style: UiTypography.headline4m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.headline4m.textPrimary,
|
||||
),
|
||||
_buildStatusBadge(form.status),
|
||||
],
|
||||
@@ -196,17 +190,14 @@ class TaxFormsPage extends StatelessWidget {
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Text(
|
||||
form.subtitle ?? '',
|
||||
style: UiTypography.body2m.copyWith(
|
||||
style: UiTypography.body2m.textSecondary.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Text(
|
||||
form.description ?? '',
|
||||
style: UiTypography.body3r.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -247,9 +238,7 @@ class TaxFormsPage extends StatelessWidget {
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
Text(
|
||||
'Completed',
|
||||
style: UiTypography.footnote2b.copyWith(
|
||||
color: UiColors.textSuccess,
|
||||
),
|
||||
style: UiTypography.footnote2b.textSuccess,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -271,9 +260,7 @@ class TaxFormsPage extends StatelessWidget {
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
Text(
|
||||
'In Progress',
|
||||
style: UiTypography.footnote2b.copyWith(
|
||||
color: UiColors.textWarning,
|
||||
),
|
||||
style: UiTypography.footnote2b.textWarning,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -290,9 +277,7 @@ class TaxFormsPage extends StatelessWidget {
|
||||
),
|
||||
child: Text(
|
||||
'Not Started',
|
||||
style: UiTypography.footnote2b.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.footnote2b.textSecondary,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -316,16 +301,12 @@ class TaxFormsPage extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Why are these needed?',
|
||||
style: UiTypography.headline4m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.headline4m.textPrimary,
|
||||
),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Text(
|
||||
'I-9 and W-4 forms are required by federal law to verify your employment eligibility and set up correct tax withholding.',
|
||||
style: UiTypography.body3r.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -37,7 +37,7 @@ class BankAccountPage extends StatelessWidget {
|
||||
),
|
||||
title: Text(
|
||||
strings.title,
|
||||
style: UiTypography.headline3m.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.headline3m.textPrimary,
|
||||
),
|
||||
bottom: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(1.0),
|
||||
@@ -143,7 +143,7 @@ class BankAccountPage extends StatelessWidget {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.primary.withOpacity(0.08),
|
||||
color: UiColors.primary.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
),
|
||||
child: Row(
|
||||
@@ -157,15 +157,12 @@ class BankAccountPage extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
strings.secure_title,
|
||||
style: UiTypography.body2r.copyWith( // Was body2
|
||||
fontWeight: FontWeight.w500,
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
strings.secure_subtitle,
|
||||
style: UiTypography.body3r.copyWith(color: UiColors.textSecondary), // Was bodySmall
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -199,7 +196,7 @@ class BankAccountPage extends StatelessWidget {
|
||||
width: 48,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: primaryColor.withOpacity(0.1),
|
||||
color: primaryColor.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
),
|
||||
child: const Center(
|
||||
@@ -216,10 +213,7 @@ class BankAccountPage extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
account.bankName,
|
||||
style: UiTypography.body2r.copyWith( // Was body2
|
||||
fontWeight: FontWeight.w500,
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
Text(
|
||||
strings.account_ending(
|
||||
@@ -227,9 +221,7 @@ class BankAccountPage extends StatelessWidget {
|
||||
? account.last4!
|
||||
: '----',
|
||||
),
|
||||
style: UiTypography.body2r.copyWith( // Was body2
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -239,7 +231,7 @@ class BankAccountPage extends StatelessWidget {
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: primaryColor.withOpacity(0.15),
|
||||
color: primaryColor.withValues(alpha: 0.15),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Row(
|
||||
@@ -248,10 +240,7 @@ class BankAccountPage extends StatelessWidget {
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
strings.primary,
|
||||
style: UiTypography.body3r.copyWith( // Was bodySmall
|
||||
fontWeight: FontWeight.w500,
|
||||
color: primaryColor,
|
||||
),
|
||||
style: UiTypography.body3m.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -43,7 +43,7 @@ class _AddAccountFormState extends State<AddAccountForm> {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
widget.strings.add_new_account,
|
||||
style: UiTypography.headline4m.copyWith(color: UiColors.textPrimary), // Was header4
|
||||
style: UiTypography.headline4m.textPrimary, // Was header4
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
UiTextField(
|
||||
@@ -71,8 +71,7 @@ class _AddAccountFormState extends State<AddAccountForm> {
|
||||
padding: const EdgeInsets.only(bottom: UiConstants.space2),
|
||||
child: Text(
|
||||
widget.strings.account_type,
|
||||
style: UiTypography.body2r.copyWith( // Was body2
|
||||
color: UiColors.textSecondary, fontWeight: FontWeight.w500),
|
||||
style: UiTypography.body2m.textSecondary,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
@@ -122,7 +121,7 @@ class _AddAccountFormState extends State<AddAccountForm> {
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? UiColors.primary.withOpacity(0.05)
|
||||
? UiColors.primary.withValues(alpha: 0.05)
|
||||
: UiColors.bgPopup, // Was surface
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
border: Border.all(
|
||||
@@ -133,8 +132,7 @@ class _AddAccountFormState extends State<AddAccountForm> {
|
||||
child: Center(
|
||||
child: Text(
|
||||
label,
|
||||
style: UiTypography.body2r.copyWith( // Was body2
|
||||
fontWeight: FontWeight.w600,
|
||||
style: UiTypography.body2b.copyWith(
|
||||
color: isSelected ? UiColors.primary : UiColors.textSecondary,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -40,9 +40,7 @@ class _TimeCardPageState extends State<TimeCardPage> {
|
||||
),
|
||||
title: Text(
|
||||
t.staff_time_card.title,
|
||||
style: UiTypography.headline4m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.headline4m.textPrimary,
|
||||
),
|
||||
bottom: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(1.0),
|
||||
|
||||
@@ -19,22 +19,22 @@ class TimesheetCard extends StatelessWidget {
|
||||
|
||||
switch (status) {
|
||||
case TimeCardStatus.approved:
|
||||
statusBg = UiColors.textSuccess.withOpacity(0.12);
|
||||
statusBg = UiColors.tagSuccess;
|
||||
statusColor = UiColors.textSuccess;
|
||||
statusText = t.staff_time_card.status.approved;
|
||||
break;
|
||||
case TimeCardStatus.disputed:
|
||||
statusBg = UiColors.destructive.withOpacity(0.12);
|
||||
statusBg = UiColors.destructive.withValues(alpha: 0.12);
|
||||
statusColor = UiColors.destructive;
|
||||
statusText = t.staff_time_card.status.disputed;
|
||||
break;
|
||||
case TimeCardStatus.paid:
|
||||
statusBg = UiColors.primary.withOpacity(0.12);
|
||||
statusBg = UiColors.primary.withValues(alpha: 0.12);
|
||||
statusColor = UiColors.primary;
|
||||
statusText = t.staff_time_card.status.paid;
|
||||
break;
|
||||
case TimeCardStatus.pending:
|
||||
statusBg = UiColors.textWarning.withOpacity(0.12);
|
||||
statusBg = UiColors.tagPending;
|
||||
statusColor = UiColors.textWarning;
|
||||
statusText = t.staff_time_card.status.pending;
|
||||
break;
|
||||
@@ -61,15 +61,11 @@ class TimesheetCard extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
timesheet.shiftTitle,
|
||||
style: UiTypography.body1m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.body1m.textPrimary,
|
||||
),
|
||||
Text(
|
||||
timesheet.clientName,
|
||||
style: UiTypography.body2r.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -116,13 +112,11 @@ class TimesheetCard extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
'${timesheet.totalHours.toStringAsFixed(1)} ${t.staff_time_card.hours} @ \$${timesheet.hourlyRate.toStringAsFixed(2)}${t.staff_time_card.per_hr}',
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
Text(
|
||||
'\$${timesheet.totalPay.toStringAsFixed(2)}',
|
||||
style: UiTypography.title2b.copyWith(
|
||||
color: UiColors.primary,
|
||||
),
|
||||
style: UiTypography.title2b.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -163,7 +157,7 @@ class _IconText extends StatelessWidget {
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
Text(
|
||||
text,
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -32,9 +32,7 @@ class AttirePage extends StatelessWidget {
|
||||
),
|
||||
title: Text(
|
||||
t.staff_profile_attire.title,
|
||||
style: UiTypography.headline3m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.headline3m.textPrimary,
|
||||
),
|
||||
bottom: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(1.0),
|
||||
|
||||
@@ -11,8 +11,8 @@ class AttireInfoCard extends StatelessWidget {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.primary.withOpacity(0.08),
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
color: UiColors.primary.withValues(alpha: 0.08),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -26,16 +26,12 @@ class AttireInfoCard extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
t.staff_profile_attire.info_card.title,
|
||||
style: UiTypography.body2m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
t.staff_profile_attire.info_card.description,
|
||||
style: UiTypography.body2r.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -23,12 +23,12 @@ class EmergencyContactScreen extends StatelessWidget {
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: Icon(UiIcons.chevronLeft, color: UiColors.textSecondary),
|
||||
icon: const Icon(UiIcons.chevronLeft, color: UiColors.textSecondary),
|
||||
onPressed: () => Modular.to.pop(),
|
||||
),
|
||||
title: Text(
|
||||
'Emergency Contact',
|
||||
style: UiTypography.title1m.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.title1m.textPrimary,
|
||||
),
|
||||
bottom: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(1.0),
|
||||
@@ -53,11 +53,11 @@ class EmergencyContactScreen extends StatelessWidget {
|
||||
children: [
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.all(UiConstants.space6),
|
||||
padding: const EdgeInsets.all(UiConstants.space6),
|
||||
child: Column(
|
||||
children: [
|
||||
const EmergencyContactInfoBanner(),
|
||||
SizedBox(height: UiConstants.space6),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
...state.contacts.asMap().entries.map(
|
||||
(entry) => EmergencyContactFormItem(
|
||||
index: entry.key,
|
||||
@@ -66,7 +66,7 @@ class EmergencyContactScreen extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const EmergencyContactAddButton(),
|
||||
SizedBox(height: UiConstants.space16),
|
||||
const SizedBox(height: UiConstants.space16),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -12,20 +12,20 @@ class EmergencyContactAddButton extends StatelessWidget {
|
||||
child: TextButton.icon(
|
||||
onPressed: () =>
|
||||
context.read<EmergencyContactBloc>().add(EmergencyContactAdded()),
|
||||
icon: Icon(UiIcons.add, size: 20.0),
|
||||
icon: const Icon(UiIcons.add, size: 20.0),
|
||||
label: Text(
|
||||
'Add Another Contact',
|
||||
style: UiTypography.title2b,
|
||||
),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: UiColors.primary,
|
||||
padding: EdgeInsets.symmetric(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space6,
|
||||
vertical: UiConstants.space3,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: UiConstants.radiusFull,
|
||||
side: BorderSide(color: UiColors.primary),
|
||||
side: const BorderSide(color: UiColors.primary),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -19,8 +19,8 @@ class EmergencyContactFormItem extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: EdgeInsets.only(bottom: UiConstants.space4),
|
||||
padding: EdgeInsets.all(UiConstants.space4),
|
||||
margin: const EdgeInsets.only(bottom: UiConstants.space4),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
@@ -30,33 +30,27 @@ class EmergencyContactFormItem extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildHeader(context),
|
||||
SizedBox(height: UiConstants.space4),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
_buildLabel('Full Name'),
|
||||
_buildTextField(
|
||||
initialValue: contact.name,
|
||||
hint: 'Contact name',
|
||||
icon: UiIcons.user,
|
||||
onChanged: (val) => context.read<EmergencyContactBloc>().add(
|
||||
EmergencyContactUpdated(
|
||||
index,
|
||||
contact.copyWith(name: val),
|
||||
),
|
||||
),
|
||||
EmergencyContactUpdated(index, contact.copyWith(name: val)),
|
||||
),
|
||||
),
|
||||
SizedBox(height: UiConstants.space4),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
_buildLabel('Phone Number'),
|
||||
_buildTextField(
|
||||
initialValue: contact.phone,
|
||||
hint: '+1 (555) 000-0000',
|
||||
icon: UiIcons.phone,
|
||||
onChanged: (val) => context.read<EmergencyContactBloc>().add(
|
||||
EmergencyContactUpdated(
|
||||
index,
|
||||
contact.copyWith(phone: val),
|
||||
),
|
||||
),
|
||||
EmergencyContactUpdated(index, contact.copyWith(phone: val)),
|
||||
),
|
||||
),
|
||||
SizedBox(height: UiConstants.space4),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
_buildLabel('Relationship'),
|
||||
_buildDropdown(
|
||||
context,
|
||||
@@ -65,11 +59,11 @@ class EmergencyContactFormItem extends StatelessWidget {
|
||||
onChanged: (val) {
|
||||
if (val != null) {
|
||||
context.read<EmergencyContactBloc>().add(
|
||||
EmergencyContactUpdated(
|
||||
index,
|
||||
contact.copyWith(relationship: val),
|
||||
),
|
||||
);
|
||||
EmergencyContactUpdated(
|
||||
index,
|
||||
contact.copyWith(relationship: val),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
@@ -85,7 +79,7 @@ class EmergencyContactFormItem extends StatelessWidget {
|
||||
required ValueChanged<RelationshipType?> onChanged,
|
||||
}) {
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space4,
|
||||
vertical: UiConstants.space2,
|
||||
),
|
||||
@@ -99,13 +93,13 @@ class EmergencyContactFormItem extends StatelessWidget {
|
||||
value: value,
|
||||
isExpanded: true,
|
||||
dropdownColor: UiColors.bgPopup,
|
||||
icon: Icon(UiIcons.chevronDown, color: UiColors.iconSecondary),
|
||||
icon: const Icon(UiIcons.chevronDown, color: UiColors.iconSecondary),
|
||||
items: items.map((type) {
|
||||
return DropdownMenuItem<RelationshipType>(
|
||||
value: type,
|
||||
child: Text(
|
||||
_formatRelationship(type),
|
||||
style: UiTypography.body1r.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.body1r.textPrimary,
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
@@ -116,11 +110,15 @@ class EmergencyContactFormItem extends StatelessWidget {
|
||||
}
|
||||
|
||||
String _formatRelationship(RelationshipType type) {
|
||||
switch(type) {
|
||||
case RelationshipType.family: return 'Family';
|
||||
case RelationshipType.spouse: return 'Spouse';
|
||||
case RelationshipType.friend: return 'Friend';
|
||||
case RelationshipType.other: return 'Other';
|
||||
switch (type) {
|
||||
case RelationshipType.family:
|
||||
return 'Family';
|
||||
case RelationshipType.spouse:
|
||||
return 'Spouse';
|
||||
case RelationshipType.friend:
|
||||
return 'Friend';
|
||||
case RelationshipType.other:
|
||||
return 'Other';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,22 +126,17 @@ class EmergencyContactFormItem extends StatelessWidget {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Contact ${index + 1}',
|
||||
style: UiTypography.title2m.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
),
|
||||
Text('Contact ${index + 1}', style: UiTypography.title2m.textPrimary),
|
||||
if (totalContacts > 1)
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
icon: const Icon(
|
||||
UiIcons.delete,
|
||||
color: UiColors.textError,
|
||||
size: 20.0,
|
||||
),
|
||||
onPressed: () => context
|
||||
.read<EmergencyContactBloc>()
|
||||
.add(EmergencyContactRemoved(index)),
|
||||
onPressed: () => context.read<EmergencyContactBloc>().add(
|
||||
EmergencyContactRemoved(index),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -151,13 +144,8 @@ class EmergencyContactFormItem extends StatelessWidget {
|
||||
|
||||
Widget _buildLabel(String label) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(bottom: UiConstants.space2),
|
||||
child: Text(
|
||||
label,
|
||||
style: UiTypography.body2m.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.only(bottom: UiConstants.space2),
|
||||
child: Text(label, style: UiTypography.body2m.textSecondary),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -169,16 +157,16 @@ class EmergencyContactFormItem extends StatelessWidget {
|
||||
}) {
|
||||
return TextFormField(
|
||||
initialValue: initialValue,
|
||||
style: UiTypography.body1r.copyWith(
|
||||
color: UiColors.textPrimary,
|
||||
),
|
||||
style: UiTypography.body1r.textPrimary,
|
||||
decoration: InputDecoration(
|
||||
hintText: hint,
|
||||
hintStyle: TextStyle(color: UiColors.textPlaceholder),
|
||||
hintStyle: const TextStyle(color: UiColors.textPlaceholder),
|
||||
prefixIcon: Icon(icon, color: UiColors.textSecondary, size: 20.0),
|
||||
filled: true,
|
||||
fillColor: UiColors.bgPopup,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: UiConstants.space4),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
vertical: UiConstants.space4,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
borderSide: BorderSide(color: UiColors.border),
|
||||
@@ -196,4 +184,3 @@ class EmergencyContactFormItem extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,14 +7,14 @@ class EmergencyContactInfoBanner extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(UiConstants.space4),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.accent.withOpacity(0.2),
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
color: UiColors.accent.withValues(alpha: 0.2),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
),
|
||||
child: Text(
|
||||
'Please provide at least one emergency contact. This information will only be used in case of an emergency during your shifts.',
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -30,19 +30,18 @@ class EmergencyContactSaveButton extends StatelessWidget {
|
||||
builder: (context, state) {
|
||||
final isLoading = state.status == EmergencyContactStatus.saving;
|
||||
return Container(
|
||||
padding: EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: const BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
border: Border(top: BorderSide(color: UiColors.border)),
|
||||
),
|
||||
child: SafeArea(
|
||||
child: UiButton.primary(
|
||||
fullWidth: true,
|
||||
onPressed: state.isValid && !isLoading
|
||||
? () => _onSave(context)
|
||||
: null,
|
||||
onPressed:
|
||||
state.isValid && !isLoading ? () => _onSave(context) : null,
|
||||
child: isLoading
|
||||
? SizedBox(
|
||||
? const SizedBox(
|
||||
height: 20.0,
|
||||
width: 20.0,
|
||||
child: CircularProgressIndicator(
|
||||
|
||||
@@ -73,16 +73,16 @@ class ExperiencePage extends StatelessWidget {
|
||||
children: [
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.all(UiConstants.space5),
|
||||
padding: const EdgeInsets.all(UiConstants.space5),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ExperienceSectionTitle(title: i18n.industries_title),
|
||||
Text(
|
||||
i18n.industries_subtitle,
|
||||
style: UiTypography.body2m.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body2m.textSecondary,
|
||||
),
|
||||
SizedBox(height: UiConstants.space3),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
Wrap(
|
||||
spacing: UiConstants.space2,
|
||||
runSpacing: UiConstants.space2,
|
||||
@@ -90,23 +90,26 @@ class ExperiencePage extends StatelessWidget {
|
||||
.map(
|
||||
(i) => UiChip(
|
||||
label: _getIndustryLabel(i18n.industries, i),
|
||||
isSelected: state.selectedIndustries.contains(i),
|
||||
onTap: () => BlocProvider.of<ExperienceBloc>(context)
|
||||
.add(ExperienceIndustryToggled(i)),
|
||||
variant: state.selectedIndustries.contains(i)
|
||||
? UiChipVariant.primary
|
||||
: UiChipVariant.secondary,
|
||||
isSelected:
|
||||
state.selectedIndustries.contains(i),
|
||||
onTap: () =>
|
||||
BlocProvider.of<ExperienceBloc>(context)
|
||||
.add(ExperienceIndustryToggled(i)),
|
||||
variant:
|
||||
state.selectedIndustries.contains(i)
|
||||
? UiChipVariant.primary
|
||||
: UiChipVariant.secondary,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
SizedBox(height: UiConstants.space6),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
ExperienceSectionTitle(title: i18n.skills_title),
|
||||
Text(
|
||||
i18n.skills_subtitle,
|
||||
style: UiTypography.body2m.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body2m.textSecondary,
|
||||
),
|
||||
SizedBox(height: UiConstants.space3),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
Wrap(
|
||||
spacing: UiConstants.space2,
|
||||
runSpacing: UiConstants.space2,
|
||||
@@ -114,19 +117,22 @@ class ExperiencePage extends StatelessWidget {
|
||||
.map(
|
||||
(s) => UiChip(
|
||||
label: _getSkillLabel(i18n.skills, s),
|
||||
isSelected: state.selectedSkills.contains(s.value),
|
||||
onTap: () => BlocProvider.of<ExperienceBloc>(context)
|
||||
.add(ExperienceSkillToggled(s.value)),
|
||||
variant: state.selectedSkills.contains(s.value)
|
||||
? UiChipVariant.primary
|
||||
: UiChipVariant.secondary,
|
||||
isSelected:
|
||||
state.selectedSkills.contains(s.value),
|
||||
onTap: () =>
|
||||
BlocProvider.of<ExperienceBloc>(context)
|
||||
.add(ExperienceSkillToggled(s.value)),
|
||||
variant:
|
||||
state.selectedSkills.contains(s.value)
|
||||
? UiChipVariant.primary
|
||||
: UiChipVariant.secondary,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
_buildSaveButton(context, state, i18n),
|
||||
],
|
||||
@@ -148,9 +154,9 @@ class ExperiencePage extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
i18n.custom_skills_title,
|
||||
style: UiTypography.body2m.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body2m.textSecondary,
|
||||
),
|
||||
SizedBox(height: UiConstants.space2),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
Wrap(
|
||||
spacing: UiConstants.space2,
|
||||
runSpacing: UiConstants.space2,
|
||||
@@ -165,10 +171,14 @@ class ExperiencePage extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSaveButton(BuildContext context, ExperienceState state, dynamic i18n) {
|
||||
Widget _buildSaveButton(
|
||||
BuildContext context,
|
||||
ExperienceState state,
|
||||
dynamic i18n,
|
||||
) {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: const BoxDecoration(
|
||||
color: UiColors.bgPopup,
|
||||
border: Border(top: BorderSide(color: UiColors.border)),
|
||||
),
|
||||
@@ -176,16 +186,21 @@ class ExperiencePage extends StatelessWidget {
|
||||
child: UiButton.primary(
|
||||
onPressed: state.status == ExperienceStatus.loading
|
||||
? null
|
||||
: () => BlocProvider.of<ExperienceBloc>(context).add(ExperienceSubmitted()),
|
||||
: () => BlocProvider.of<ExperienceBloc>(context)
|
||||
.add(ExperienceSubmitted()),
|
||||
fullWidth: true,
|
||||
text: state.status == ExperienceStatus.loading ? null : i18n.save_button,
|
||||
text: state.status == ExperienceStatus.loading
|
||||
? null
|
||||
: i18n.save_button,
|
||||
child: state.status == ExperienceStatus.loading
|
||||
? SizedBox(
|
||||
? const SizedBox(
|
||||
height: 20.0,
|
||||
width: 20.0,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(UiColors.white), // UiColors.primaryForeground is white mostly
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
UiColors.white,
|
||||
), // UiColors.primaryForeground is white mostly
|
||||
),
|
||||
)
|
||||
: null,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -52,13 +51,16 @@ class PersonalInfoPage extends StatelessWidget {
|
||||
backgroundColor: UiColors.bgPopup,
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: const Icon(UiIcons.chevronLeft, color: UiColors.textSecondary),
|
||||
icon: const Icon(
|
||||
UiIcons.chevronLeft,
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
onPressed: () => Modular.to.pop(),
|
||||
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
|
||||
),
|
||||
title: Text(
|
||||
i18n.title,
|
||||
style: UiTypography.title1m.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.title1m.textPrimary,
|
||||
),
|
||||
bottom: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(1.0),
|
||||
@@ -82,9 +84,7 @@ class PersonalInfoPage extends StatelessWidget {
|
||||
return Center(
|
||||
child: Text(
|
||||
'Failed to load personal information',
|
||||
style: UiTypography.body1r.copyWith(
|
||||
color: UiColors.textSecondary,
|
||||
),
|
||||
style: UiTypography.body1r.textSecondary,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ class _FieldLabel extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Text(
|
||||
text,
|
||||
style: UiTypography.body2m.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,6 @@ class _FieldLabel extends StatelessWidget {
|
||||
/// A read-only field widget for displaying non-editable information.
|
||||
/// A read-only field widget for displaying non-editable information.
|
||||
class _ReadOnlyField extends StatelessWidget {
|
||||
|
||||
const _ReadOnlyField({required this.value});
|
||||
final String value;
|
||||
|
||||
@@ -120,7 +119,7 @@ class _ReadOnlyField extends StatelessWidget {
|
||||
),
|
||||
child: Text(
|
||||
value,
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -129,7 +128,6 @@ class _ReadOnlyField extends StatelessWidget {
|
||||
/// An editable text field widget.
|
||||
/// An editable text field widget.
|
||||
class _EditableField extends StatelessWidget {
|
||||
|
||||
const _EditableField({
|
||||
required this.controller,
|
||||
required this.hint,
|
||||
@@ -150,10 +148,10 @@ class _EditableField extends StatelessWidget {
|
||||
enabled: enabled,
|
||||
keyboardType: keyboardType,
|
||||
autofillHints: autofillHints,
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textPrimary),
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
decoration: InputDecoration(
|
||||
hintText: hint,
|
||||
hintStyle: UiTypography.body2r.copyWith(color: UiColors.textSecondary),
|
||||
hintStyle: UiTypography.body2r.textSecondary,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space3,
|
||||
vertical: UiConstants.space3,
|
||||
|
||||
@@ -28,7 +28,8 @@ class ProfilePhotoWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final TranslationsStaffOnboardingPersonalInfoEn i18n = t.staff.onboarding.personal_info;
|
||||
final TranslationsStaffOnboardingPersonalInfoEn i18n =
|
||||
t.staff.onboarding.personal_info;
|
||||
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
@@ -41,7 +42,7 @@ class ProfilePhotoWidget extends StatelessWidget {
|
||||
height: 96,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: UiColors.primary.withOpacity(0.1),
|
||||
color: UiColors.primary.withValues(alpha: 0.1),
|
||||
),
|
||||
child: photoUrl != null
|
||||
? ClipOval(
|
||||
@@ -53,9 +54,7 @@ class ProfilePhotoWidget extends StatelessWidget {
|
||||
: Center(
|
||||
child: Text(
|
||||
fullName.isNotEmpty ? fullName[0].toUpperCase() : '?',
|
||||
style: UiTypography.displayL.copyWith(
|
||||
color: UiColors.primary,
|
||||
),
|
||||
style: UiTypography.displayL.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -71,7 +70,7 @@ class ProfilePhotoWidget extends StatelessWidget {
|
||||
border: Border.all(color: UiColors.border),
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: UiColors.textPrimary.withOpacity(0.1),
|
||||
color: UiColors.textPrimary.withValues(alpha: 0.1),
|
||||
blurRadius: UiConstants.space1,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -92,7 +91,7 @@ class ProfilePhotoWidget extends StatelessWidget {
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
Text(
|
||||
i18n.change_photo_hint,
|
||||
style: UiTypography.body2r.copyWith(color: UiColors.textSecondary),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user