diff --git a/apps/mobile/packages/features/client/billing/lib/src/presentation/pages/completion_review_page.dart b/apps/mobile/packages/features/client/billing/lib/src/presentation/pages/completion_review_page.dart index 99bd872a..3856857f 100644 --- a/apps/mobile/packages/features/client/billing/lib/src/presentation/pages/completion_review_page.dart +++ b/apps/mobile/packages/features/client/billing/lib/src/presentation/pages/completion_review_page.dart @@ -1,20 +1,20 @@ import 'package:core_localization/core_localization.dart'; import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_modular/flutter_modular.dart'; -import 'package:krow_core/core.dart'; + import '../blocs/billing_bloc.dart'; import '../blocs/billing_event.dart'; import '../models/billing_invoice_model.dart'; class ShiftCompletionReviewPage extends StatefulWidget { const ShiftCompletionReviewPage({this.invoice, super.key}); - + final BillingInvoice? invoice; @override - State createState() => _ShiftCompletionReviewPageState(); + State createState() => + _ShiftCompletionReviewPageState(); } class _ShiftCompletionReviewPageState extends State { @@ -31,99 +31,62 @@ class _ShiftCompletionReviewPageState extends State { @override Widget build(BuildContext context) { - final List filteredWorkers = invoice.workers.where((BillingWorkerRecord w) { + final List filteredWorkers = invoice.workers.where(( + BillingWorkerRecord w, + ) { if (searchQuery.isEmpty) return true; return w.workerName.toLowerCase().contains(searchQuery.toLowerCase()) || - w.roleName.toLowerCase().contains(searchQuery.toLowerCase()); + w.roleName.toLowerCase().contains(searchQuery.toLowerCase()); }).toList(); return Scaffold( - backgroundColor: const Color(0xFFF8FAFC), + appBar: UiAppBar( + title: invoice.title, + subtitle: invoice.clientName, + showBackButton: true, + ), body: SafeArea( - child: Column( - children: [ - _buildHeader(context), - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.symmetric(horizontal: UiConstants.space5), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: UiConstants.space4), - _buildInvoiceInfoCard(), - const SizedBox(height: UiConstants.space4), - _buildAmountCard(), - const SizedBox(height: UiConstants.space6), - _buildWorkersHeader(), - const SizedBox(height: UiConstants.space4), - _buildSearchAndTabs(), - const SizedBox(height: UiConstants.space4), - ...filteredWorkers.map((BillingWorkerRecord worker) => _buildWorkerCard(worker)), - const SizedBox(height: UiConstants.space6), - _buildActionButtons(context), - const SizedBox(height: UiConstants.space4), - _buildDownloadLink(), - const SizedBox(height: UiConstants.space8), - ], + child: Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: UiConstants.space5), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: UiConstants.space4), + _buildInvoiceInfoCard(), + const SizedBox(height: UiConstants.space4), + _buildAmountCard(), + const SizedBox(height: UiConstants.space6), + _buildWorkersHeader(), + const SizedBox(height: UiConstants.space4), + _buildSearchAndTabs(), + const SizedBox(height: UiConstants.space4), + ...filteredWorkers.map( + (BillingWorkerRecord worker) => _buildWorkerCard(worker), ), - ), + const SizedBox(height: UiConstants.space6), + _buildActionButtons(context), + const SizedBox(height: UiConstants.space4), + _buildDownloadLink(), + const SizedBox(height: UiConstants.space8), + ], ), - ], + ), ), ), ); } - Widget _buildHeader(BuildContext context) { - return Container( - padding: const EdgeInsets.fromLTRB(UiConstants.space5, UiConstants.space4, UiConstants.space5, UiConstants.space4), - decoration: const BoxDecoration( - color: Colors.white, - border: Border(bottom: BorderSide(color: UiColors.border)), - ), - child: Column( - children: [ - Container( - width: 40, - height: 4, - decoration: BoxDecoration( - color: UiColors.border, - borderRadius: UiConstants.radiusFull, - ), - ), - const SizedBox(height: UiConstants.space4), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(t.client_billing.invoice_ready, style: UiTypography.headline4b.textPrimary), - Text(t.client_billing.review_and_approve_subtitle, style: UiTypography.body2r.textSecondary), - ], - ), - UiIconButton.secondary( - icon: UiIcons.close, - onTap: () => Navigator.of(context).pop(), - ), - ], - ), - ], - ), - ); - } - Widget _buildInvoiceInfoCard() { return Column( crossAxisAlignment: CrossAxisAlignment.start, + spacing: UiConstants.space1, children: [ - Text(invoice.title, style: UiTypography.headline4b.textPrimary), - Text(invoice.clientName, style: UiTypography.body2r.textSecondary), - const SizedBox(height: UiConstants.space4), _buildInfoRow(UiIcons.calendar, invoice.date), - const SizedBox(height: UiConstants.space2), - _buildInfoRow(UiIcons.clock, '${invoice.startTime ?? "--"} - ${invoice.endTime ?? "--"}'), - const SizedBox(height: UiConstants.space2), + _buildInfoRow( + UiIcons.clock, + '${invoice.startTime ?? "--"} - ${invoice.endTime ?? "--"}', + ), _buildInfoRow(UiIcons.mapPin, invoice.locationAddress), ], ); @@ -194,7 +157,11 @@ class _ShiftCompletionReviewPageState extends State { child: TextField( onChanged: (String val) => setState(() => searchQuery = val), decoration: InputDecoration( - icon: const Icon(UiIcons.search, size: 18, color: UiColors.iconSecondary), + icon: const Icon( + UiIcons.search, + size: 18, + color: UiColors.iconSecondary, + ), hintText: t.client_billing.workers_tab.search_hint, hintStyle: UiTypography.body2r.textSecondary, border: InputBorder.none, @@ -205,11 +172,17 @@ class _ShiftCompletionReviewPageState extends State { Row( children: [ Expanded( - child: _buildTabButton(t.client_billing.workers_tab.needs_review(count: 0), 0), + child: _buildTabButton( + t.client_billing.workers_tab.needs_review(count: 0), + 0, + ), ), const SizedBox(width: UiConstants.space3), Expanded( - child: _buildTabButton(t.client_billing.workers_tab.all(count: invoice.workersCount), 1), + child: _buildTabButton( + t.client_billing.workers_tab.all(count: invoice.workersCount), + 1, + ), ), ], ), @@ -226,7 +199,9 @@ class _ShiftCompletionReviewPageState extends State { decoration: BoxDecoration( color: isSelected ? const Color(0xFF2563EB) : Colors.white, borderRadius: UiConstants.radiusMd, - border: Border.all(color: isSelected ? const Color(0xFF2563EB) : UiColors.border), + border: Border.all( + color: isSelected ? const Color(0xFF2563EB) : UiColors.border, + ), ), child: Center( child: Text( @@ -257,24 +232,44 @@ class _ShiftCompletionReviewPageState extends State { CircleAvatar( radius: 20, backgroundColor: UiColors.bgSecondary, - backgroundImage: worker.workerAvatarUrl != null ? NetworkImage(worker.workerAvatarUrl!) : null, - child: worker.workerAvatarUrl == null ? const Icon(UiIcons.user, size: 20, color: UiColors.iconSecondary) : null, + backgroundImage: worker.workerAvatarUrl != null + ? NetworkImage(worker.workerAvatarUrl!) + : null, + child: worker.workerAvatarUrl == null + ? const Icon( + UiIcons.user, + size: 20, + color: UiColors.iconSecondary, + ) + : null, ), const SizedBox(width: UiConstants.space3), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(worker.workerName, style: UiTypography.body1b.textPrimary), - Text(worker.roleName, style: UiTypography.footnote2r.textSecondary), + Text( + worker.workerName, + style: UiTypography.body1b.textPrimary, + ), + Text( + worker.roleName, + style: UiTypography.footnote2r.textSecondary, + ), ], ), ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ - Text('\$${worker.totalAmount.toStringAsFixed(2)}', style: UiTypography.body1b.textPrimary), - Text('${worker.hours}h x \$${worker.rate.toStringAsFixed(2)}/hr', style: UiTypography.footnote2r.textSecondary), + Text( + '\$${worker.totalAmount.toStringAsFixed(2)}', + style: UiTypography.body1b.textPrimary, + ), + Text( + '${worker.hours}h x \$${worker.rate.toStringAsFixed(2)}/hr', + style: UiTypography.footnote2r.textSecondary, + ), ], ), ], @@ -283,17 +278,26 @@ class _ShiftCompletionReviewPageState extends State { Row( children: [ Container( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 4, + ), decoration: BoxDecoration( color: Colors.white, borderRadius: UiConstants.radiusMd, border: Border.all(color: UiColors.border), ), - child: Text('${worker.startTime} - ${worker.endTime}', style: UiTypography.footnote2b.textPrimary), + child: Text( + '${worker.startTime} - ${worker.endTime}', + style: UiTypography.footnote2b.textPrimary, + ), ), const SizedBox(width: UiConstants.space2), Container( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 4, + ), decoration: BoxDecoration( color: Colors.white, borderRadius: UiConstants.radiusMd, @@ -301,22 +305,23 @@ class _ShiftCompletionReviewPageState extends State { ), child: Row( children: [ - const Icon(UiIcons.coffee, size: 12, color: UiColors.iconSecondary), + const Icon( + UiIcons.coffee, + size: 12, + color: UiColors.iconSecondary, + ), const SizedBox(width: 4), - Text('${worker.breakMinutes} ${t.client_billing.workers_tab.min_break}', style: UiTypography.footnote2r.textSecondary), + Text( + '${worker.breakMinutes} ${t.client_billing.workers_tab.min_break}', + style: UiTypography.footnote2r.textSecondary, + ), ], ), ), const Spacer(), - UiIconButton.secondary( - icon: UiIcons.edit, - onTap: () {}, - ), + UiIconButton.secondary(icon: UiIcons.edit, onTap: () {}), const SizedBox(width: UiConstants.space2), - UiIconButton.secondary( - icon: UiIcons.warning, - onTap: () {}, - ), + UiIconButton.secondary(icon: UiIcons.warning, onTap: () {}), ], ), ], @@ -333,9 +338,15 @@ class _ShiftCompletionReviewPageState extends State { text: t.client_billing.actions.approve_pay, leadingIcon: UiIcons.checkCircle, onPressed: () { - Modular.get().add(BillingInvoiceApproved(invoice.id)); + Modular.get().add( + BillingInvoiceApproved(invoice.id), + ); Modular.to.pop(); - UiSnackbar.show(context, message: t.client_billing.approved_success, type: UiSnackbarType.success); + UiSnackbar.show( + context, + message: t.client_billing.approved_success, + type: UiSnackbarType.success, + ); }, size: UiButtonSize.large, style: ElevatedButton.styleFrom( @@ -350,8 +361,8 @@ class _ShiftCompletionReviewPageState extends State { width: double.infinity, child: Container( decoration: BoxDecoration( - borderRadius: UiConstants.radiusMd, - border: Border.all(color: Colors.orange, width: 2), + borderRadius: UiConstants.radiusMd, + border: Border.all(color: Colors.orange, width: 2), ), child: UiButton.secondary( text: t.client_billing.actions.flag_review, @@ -409,7 +420,11 @@ class _ShiftCompletionReviewPageState extends State { ); Navigator.pop(dialogContext); Modular.to.pop(); - UiSnackbar.show(context, message: t.client_billing.flagged_success, type: UiSnackbarType.warning); + UiSnackbar.show( + context, + message: t.client_billing.flagged_success, + type: UiSnackbarType.warning, + ); } }, child: Text(t.client_billing.flag_dialog.button), diff --git a/apps/mobile/packages/features/client/billing/lib/src/presentation/pages/invoice_ready_page.dart b/apps/mobile/packages/features/client/billing/lib/src/presentation/pages/invoice_ready_page.dart index 8e6469f1..7ae7b9bf 100644 --- a/apps/mobile/packages/features/client/billing/lib/src/presentation/pages/invoice_ready_page.dart +++ b/apps/mobile/packages/features/client/billing/lib/src/presentation/pages/invoice_ready_page.dart @@ -2,6 +2,7 @@ import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_modular/flutter_modular.dart'; + import '../blocs/billing_bloc.dart'; import '../blocs/billing_event.dart'; import '../blocs/billing_state.dart'; @@ -14,7 +15,7 @@ class InvoiceReadyPage extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider.value( value: Modular.get()..add(const BillingLoadStarted()), - child: const InvoiceReadyView(), + child: const Placeholder(), ); } } @@ -25,13 +26,7 @@ class InvoiceReadyView extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: const Text('Invoices Ready'), - leading: UiIconButton.secondary( - icon: UiIcons.arrowLeft, - onTap: () => Modular.to.pop(), - ), - ), + appBar: const UiAppBar(title: 'Invoices Ready', showBackButton: true), body: BlocBuilder( builder: (context, state) { if (state.status == BillingStatus.loading) { @@ -43,12 +38,16 @@ class InvoiceReadyView extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon(UiIcons.file, size: 64, color: UiColors.iconSecondary), - const SizedBox(height: UiConstants.space4), - Text( - 'No invoices ready yet', - style: UiTypography.body1m.textSecondary, - ), + const Icon( + UiIcons.file, + size: 64, + color: UiColors.iconSecondary, + ), + const SizedBox(height: UiConstants.space4), + Text( + 'No invoices ready yet', + style: UiTypography.body1m.textSecondary, + ), ], ), ); @@ -96,26 +95,31 @@ class _InvoiceSummaryCard extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 4, + ), decoration: BoxDecoration( color: UiColors.success.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(20), ), child: Text( 'READY', - style: UiTypography.titleUppercase4b.copyWith(color: UiColors.success), + style: UiTypography.titleUppercase4b.copyWith( + color: UiColors.success, + ), ), ), - Text( - invoice.date, - style: UiTypography.footnote2r.textTertiary, - ), + Text(invoice.date, style: UiTypography.footnote2r.textTertiary), ], ), const SizedBox(height: 16), Text(invoice.title, style: UiTypography.title2b.textPrimary), const SizedBox(height: 8), - Text(invoice.locationAddress, style: UiTypography.body2r.textSecondary), + Text( + invoice.locationAddress, + style: UiTypography.body2r.textSecondary, + ), const Divider(height: 32), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -123,8 +127,14 @@ class _InvoiceSummaryCard extends StatelessWidget { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('TOTAL AMOUNT', style: UiTypography.titleUppercase4m.textSecondary), - Text('\$${invoice.totalAmount.toStringAsFixed(2)}', style: UiTypography.title2b.primary), + Text( + 'TOTAL AMOUNT', + style: UiTypography.titleUppercase4m.textSecondary, + ), + Text( + '\$${invoice.totalAmount.toStringAsFixed(2)}', + style: UiTypography.title2b.primary, + ), ], ), UiButton.primary( diff --git a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/actions_widget.dart b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/actions_widget.dart index 74c38c2e..468d6b85 100644 --- a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/actions_widget.dart +++ b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/actions_widget.dart @@ -25,7 +25,7 @@ class ActionsWidget extends StatelessWidget { title: i18n.rapid, subtitle: i18n.rapid_subtitle, icon: UiIcons.zap, - color: UiColors.tagError, + color: UiColors.tagError.withValues(alpha: 0.5), borderColor: UiColors.borderError.withValues(alpha: 0.3), iconBgColor: UiColors.white, iconColor: UiColors.textError, diff --git a/apps/mobile/packages/features/client/orders/create_order/lib/src/presentation/utils/constants/order_types.dart b/apps/mobile/packages/features/client/orders/create_order/lib/src/presentation/utils/constants/order_types.dart index 68b48b75..67fd318b 100644 --- a/apps/mobile/packages/features/client/orders/create_order/lib/src/presentation/utils/constants/order_types.dart +++ b/apps/mobile/packages/features/client/orders/create_order/lib/src/presentation/utils/constants/order_types.dart @@ -12,18 +12,16 @@ class UiOrderType { /// Order type constants for the create order feature const List orderTypes = [ - /// TODO: FEATURE_NOT_YET_IMPLEMENTED - // UiOrderType( - // id: 'rapid', - // titleKey: 'client_create_order.types.rapid', - // descriptionKey: 'client_create_order.types.rapid_desc', - // ), + UiOrderType( + id: 'rapid', + titleKey: 'client_create_order.types.rapid', + descriptionKey: 'client_create_order.types.rapid_desc', + ), UiOrderType( id: 'one-time', titleKey: 'client_create_order.types.one_time', descriptionKey: 'client_create_order.types.one_time_desc', ), - UiOrderType( id: 'recurring', titleKey: 'client_create_order.types.recurring',