feat: Enhance navigation robustness by redirecting to the appropriate home page on navigation errors or when popping the root route.

This commit is contained in:
Achintha Isuru
2026-02-28 17:02:44 -05:00
parent 76424b1b1f
commit c26128f1f2
4 changed files with 80 additions and 226 deletions

View File

@@ -1,6 +1,7 @@
import 'package:flutter_modular/flutter_modular.dart'; import 'package:flutter_modular/flutter_modular.dart';
import 'package:krow_domain/krow_domain.dart'; import 'package:krow_domain/krow_domain.dart';
import '../navigation_extensions.dart';
import 'route_paths.dart'; import 'route_paths.dart';
/// Typed navigation extension for the Client application. /// Typed navigation extension for the Client application.
@@ -33,14 +34,14 @@ extension ClientNavigator on IModularNavigator {
/// This effectively logs out the user by navigating to root. /// This effectively logs out the user by navigating to root.
/// Used when signing out or session expires. /// Used when signing out or session expires.
void toClientRoot() { void toClientRoot() {
navigate(ClientPaths.root); safeNavigate(ClientPaths.root);
} }
/// Navigates to the get started page. /// Navigates to the get started page.
/// ///
/// This is the landing page for unauthenticated users, offering login/signup options. /// This is the landing page for unauthenticated users, offering login/signup options.
void toClientGetStartedPage() { void toClientGetStartedPage() {
navigate(ClientPaths.getStarted); safeNavigate(ClientPaths.getStarted);
} }
/// Navigates to the client sign-in page. /// Navigates to the client sign-in page.
@@ -48,7 +49,7 @@ extension ClientNavigator on IModularNavigator {
/// This page allows existing clients to log in using email/password /// This page allows existing clients to log in using email/password
/// or social authentication providers. /// or social authentication providers.
void toClientSignIn() { void toClientSignIn() {
pushNamed(ClientPaths.signIn); safePush(ClientPaths.signIn);
} }
/// Navigates to the client sign-up page. /// Navigates to the client sign-up page.
@@ -56,7 +57,7 @@ extension ClientNavigator on IModularNavigator {
/// This page allows new clients to create an account and provides /// This page allows new clients to create an account and provides
/// the initial registration form. /// the initial registration form.
void toClientSignUp() { void toClientSignUp() {
pushNamed(ClientPaths.signUp); safePush(ClientPaths.signUp);
} }
/// Navigates to the client home dashboard. /// Navigates to the client home dashboard.
@@ -66,7 +67,7 @@ extension ClientNavigator on IModularNavigator {
/// ///
/// Uses pushNamed to avoid trailing slash issues with navigate(). /// Uses pushNamed to avoid trailing slash issues with navigate().
void toClientHome() { void toClientHome() {
navigate(ClientPaths.home); safeNavigate(ClientPaths.home);
} }
/// Navigates to the client main shell. /// Navigates to the client main shell.
@@ -74,7 +75,7 @@ extension ClientNavigator on IModularNavigator {
/// This is the container with bottom navigation. Usually you'd navigate /// This is the container with bottom navigation. Usually you'd navigate
/// to a specific tab instead (like [toClientHome]). /// to a specific tab instead (like [toClientHome]).
void toClientMain() { void toClientMain() {
navigate(ClientPaths.main); safeNavigate(ClientPaths.main);
} }
// ========================================================================== // ==========================================================================
@@ -85,43 +86,43 @@ extension ClientNavigator on IModularNavigator {
/// ///
/// Displays workforce coverage analytics and metrics. /// Displays workforce coverage analytics and metrics.
void toClientCoverage() { void toClientCoverage() {
navigate(ClientPaths.coverage); safeNavigate(ClientPaths.coverage);
} }
/// Navigates to the Billing tab. /// Navigates to the Billing tab.
/// ///
/// Access billing history, invoices, and payment methods. /// Access billing history, invoices, and payment methods.
void toClientBilling() { void toClientBilling() {
navigate(ClientPaths.billing); safeNavigate(ClientPaths.billing);
} }
/// Navigates to the Completion Review page. /// Navigates to the Completion Review page.
void toCompletionReview({Object? arguments}) { void toCompletionReview({Object? arguments}) {
pushNamed(ClientPaths.completionReview, arguments: arguments); safePush(ClientPaths.completionReview, arguments: arguments);
} }
/// Navigates to the full list of invoices awaiting approval. /// Navigates to the full list of invoices awaiting approval.
void toAwaitingApproval({Object? arguments}) { void toAwaitingApproval({Object? arguments}) {
navigate(ClientPaths.awaitingApproval, arguments: arguments); safeNavigate(ClientPaths.awaitingApproval, arguments: arguments);
} }
/// Navigates to the Invoice Ready page. /// Navigates to the Invoice Ready page.
void toInvoiceReady() { void toInvoiceReady() {
pushNamed(ClientPaths.invoiceReady); safePush(ClientPaths.invoiceReady);
} }
/// Navigates to the Orders tab. /// Navigates to the Orders tab.
/// ///
/// View and manage all shift orders with filtering and sorting. /// View and manage all shift orders with filtering and sorting.
void toClientOrders() { void toClientOrders() {
navigate(ClientPaths.orders); safeNavigate(ClientPaths.orders);
} }
/// Navigates to the Reports tab. /// Navigates to the Reports tab.
/// ///
/// Generate and view workforce reports and analytics. /// Generate and view workforce reports and analytics.
void toClientReports() { void toClientReports() {
navigate(ClientPaths.reports); safeNavigate(ClientPaths.reports);
} }
// ========================================================================== // ==========================================================================
@@ -132,12 +133,12 @@ extension ClientNavigator on IModularNavigator {
/// ///
/// Manage account settings, notifications, and app preferences. /// Manage account settings, notifications, and app preferences.
void toClientSettings() { void toClientSettings() {
pushNamed(ClientPaths.settings); safePush(ClientPaths.settings);
} }
/// Pushes the edit profile page. /// Pushes the edit profile page.
void toClientEditProfile() { void toClientEditProfile() {
pushNamed('${ClientPaths.settings}/edit-profile'); safePush('${ClientPaths.settings}/edit-profile');
} }
// ========================================================================== // ==========================================================================
@@ -148,12 +149,12 @@ extension ClientNavigator on IModularNavigator {
/// ///
/// View and manage physical locations/hubs where staff are deployed. /// View and manage physical locations/hubs where staff are deployed.
Future<void> toClientHubs() async { Future<void> toClientHubs() async {
await pushNamed(ClientPaths.hubs); await safePush(ClientPaths.hubs);
} }
/// Navigates to the details of a specific hub. /// Navigates to the details of a specific hub.
Future<bool?> toHubDetails(Hub hub) { Future<bool?> toHubDetails(Hub hub) {
return pushNamed<bool?>( return safePush<bool?>(
ClientPaths.hubDetails, ClientPaths.hubDetails,
arguments: <String, dynamic>{'hub': hub}, arguments: <String, dynamic>{'hub': hub},
); );
@@ -161,7 +162,7 @@ extension ClientNavigator on IModularNavigator {
/// Navigates to the page to add a new hub or edit an existing one. /// Navigates to the page to add a new hub or edit an existing one.
Future<bool?> toEditHub({Hub? hub}) async { Future<bool?> toEditHub({Hub? hub}) async {
return pushNamed<bool?>( return safePush<bool?>(
ClientPaths.editHub, ClientPaths.editHub,
arguments: <String, dynamic>{'hub': hub}, arguments: <String, dynamic>{'hub': hub},
// Some versions of Modular allow passing opaque here, but if not // Some versions of Modular allow passing opaque here, but if not
@@ -178,35 +179,35 @@ extension ClientNavigator on IModularNavigator {
/// ///
/// This is the starting point for all order creation flows. /// This is the starting point for all order creation flows.
void toCreateOrder({Object? arguments}) { void toCreateOrder({Object? arguments}) {
navigate(ClientPaths.createOrder, arguments: arguments); safeNavigate(ClientPaths.createOrder, arguments: arguments);
} }
/// Pushes the rapid order creation flow. /// Pushes the rapid order creation flow.
/// ///
/// Quick shift creation with simplified inputs for urgent needs. /// Quick shift creation with simplified inputs for urgent needs.
void toCreateOrderRapid({Object? arguments}) { void toCreateOrderRapid({Object? arguments}) {
pushNamed(ClientPaths.createOrderRapid, arguments: arguments); safePush(ClientPaths.createOrderRapid, arguments: arguments);
} }
/// Pushes the one-time order creation flow. /// Pushes the one-time order creation flow.
/// ///
/// Create a shift that occurs once at a specific date and time. /// Create a shift that occurs once at a specific date and time.
void toCreateOrderOneTime({Object? arguments}) { void toCreateOrderOneTime({Object? arguments}) {
pushNamed(ClientPaths.createOrderOneTime, arguments: arguments); safePush(ClientPaths.createOrderOneTime, arguments: arguments);
} }
/// Pushes the recurring order creation flow. /// Pushes the recurring order creation flow.
/// ///
/// Create shifts that repeat on a defined schedule (daily, weekly, etc.). /// Create shifts that repeat on a defined schedule (daily, weekly, etc.).
void toCreateOrderRecurring({Object? arguments}) { void toCreateOrderRecurring({Object? arguments}) {
pushNamed(ClientPaths.createOrderRecurring, arguments: arguments); safePush(ClientPaths.createOrderRecurring, arguments: arguments);
} }
/// Pushes the permanent order creation flow. /// Pushes the permanent order creation flow.
/// ///
/// Create a long-term or permanent staffing position. /// Create a long-term or permanent staffing position.
void toCreateOrderPermanent({Object? arguments}) { void toCreateOrderPermanent({Object? arguments}) {
pushNamed(ClientPaths.createOrderPermanent, arguments: arguments); safePush(ClientPaths.createOrderPermanent, arguments: arguments);
} }
// ========================================================================== // ==========================================================================
@@ -215,7 +216,7 @@ extension ClientNavigator on IModularNavigator {
/// Navigates to the order details page to a specific date. /// Navigates to the order details page to a specific date.
void toOrdersSpecificDate(DateTime date) { void toOrdersSpecificDate(DateTime date) {
navigate( safeNavigate(
ClientPaths.orders, ClientPaths.orders,
arguments: <String, DateTime>{'initialDate': date}, arguments: <String, DateTime>{'initialDate': date},
); );

View File

@@ -1,4 +1,6 @@
import 'package:flutter_modular/flutter_modular.dart'; import 'package:flutter_modular/flutter_modular.dart';
import 'client/route_paths.dart';
import 'staff/route_paths.dart';
/// Base navigation utilities extension for [IModularNavigator]. /// Base navigation utilities extension for [IModularNavigator].
/// ///
@@ -21,10 +23,7 @@ extension NavigationExtensions on IModularNavigator {
/// * [arguments] - Optional arguments to pass to the route /// * [arguments] - Optional arguments to pass to the route
/// ///
/// Returns `true` if navigation was successful, `false` otherwise. /// Returns `true` if navigation was successful, `false` otherwise.
Future<bool> safeNavigate( Future<bool> safeNavigate(String path, {Object? arguments}) async {
String path, {
Object? arguments,
}) async {
try { try {
navigate(path, arguments: arguments); navigate(path, arguments: arguments);
return true; return true;
@@ -32,6 +31,7 @@ extension NavigationExtensions on IModularNavigator {
// In production, you might want to log this to a monitoring service // In production, you might want to log this to a monitoring service
// ignore: avoid_print // ignore: avoid_print
print('Navigation error to $path: $e'); print('Navigation error to $path: $e');
navigateToHome();
return false; return false;
} }
} }
@@ -56,6 +56,7 @@ extension NavigationExtensions on IModularNavigator {
// In production, you might want to log this to a monitoring service // In production, you might want to log this to a monitoring service
// ignore: avoid_print // ignore: avoid_print
print('Push navigation error to $routeName: $e'); print('Push navigation error to $routeName: $e');
navigateToHome();
return null; return null;
} }
} }
@@ -68,14 +69,31 @@ extension NavigationExtensions on IModularNavigator {
navigate('/'); navigate('/');
} }
/// Pops the current route if possible. /// Pops the current route if possible, otherwise navigates to home.
/// ///
/// Returns `true` if a route was popped, `false` if already at root. /// Returns `true` if a route was popped, `false` if it navigated to home.
bool popSafe() { bool popSafe() {
if (canPop()) { if (canPop()) {
pop(); pop();
return true; return true;
} }
navigateToHome();
return false; return false;
} }
/// Navigates to the designated home page based on the current context.
///
/// Checks the current path to determine if the user is in the Client
/// or Staff portion of the application and routes to their respective home.
void navigateToHome() {
final String currentPath = Modular.to.path;
if (currentPath.contains('/client')) {
navigate(ClientPaths.home);
} else if (currentPath.contains('/worker') ||
currentPath.contains('/staff')) {
navigate(StaffPaths.home);
} else {
navigate('/');
}
}
} }

View File

@@ -1,6 +1,7 @@
import 'package:flutter_modular/flutter_modular.dart'; import 'package:flutter_modular/flutter_modular.dart';
import 'package:krow_domain/krow_domain.dart'; import 'package:krow_domain/krow_domain.dart';
import '../navigation_extensions.dart';
import 'route_paths.dart'; import 'route_paths.dart';
/// Typed navigation extension for the Staff application. /// Typed navigation extension for the Staff application.
@@ -33,76 +34,36 @@ extension StaffNavigator on IModularNavigator {
/// This effectively logs out the user by navigating to root. /// This effectively logs out the user by navigating to root.
/// Used when signing out or session expires. /// Used when signing out or session expires.
void toInitialPage() { void toInitialPage() {
navigate(StaffPaths.root); safeNavigate(StaffPaths.root);
} }
/// Navigates to the get started page.
///
/// This is the landing page for unauthenticated users, offering login/signup options.
void toGetStartedPage() { void toGetStartedPage() {
navigate(StaffPaths.getStarted); safeNavigate(StaffPaths.getStarted);
} }
/// Navigates to the phone verification page.
///
/// Used for both login and signup flows to verify phone numbers via OTP.
///
/// Parameters:
/// * [mode] - The authentication mode: 'login' or 'signup'
///
/// The mode is passed as an argument and used by the verification page
/// to determine the appropriate flow.
void toPhoneVerification(String mode) { void toPhoneVerification(String mode) {
pushNamed( safePush(
StaffPaths.phoneVerification, StaffPaths.phoneVerification,
arguments: <String, String>{'mode': mode}, arguments: <String, String>{'mode': mode},
); );
} }
/// Navigates to the profile setup page, replacing the current route.
///
/// This is typically called after successful phone verification for new
/// staff members. Uses pushReplacement to prevent going back to verification.
void toProfileSetup() { void toProfileSetup() {
pushNamed(StaffPaths.profileSetup); safePush(StaffPaths.profileSetup);
} }
// ==========================================================================
// MAIN NAVIGATION
// ==========================================================================
/// Navigates to the staff home dashboard.
///
/// This is the main landing page for authenticated staff members.
/// Displays shift cards, quick actions, and notifications.
void toStaffHome() { void toStaffHome() {
pushNamedAndRemoveUntil(StaffPaths.home, (_) => false); pushNamedAndRemoveUntil(StaffPaths.home, (_) => false);
} }
/// Navigates to the benefits overview page.
void toBenefits() { void toBenefits() {
pushNamed(StaffPaths.benefits); safePush(StaffPaths.benefits);
} }
/// Navigates to the staff main shell.
///
/// This is the container with bottom navigation. Navigates to home tab
/// by default. Usually you'd navigate to a specific tab instead.
void toStaffMain() { void toStaffMain() {
pushNamedAndRemoveUntil('${StaffPaths.main}/home/', (_) => false); pushNamedAndRemoveUntil('${StaffPaths.main}/home/', (_) => false);
} }
// ==========================================================================
// MAIN NAVIGATION TABS
// ==========================================================================
/// Navigates to the Shifts tab.
///
/// Browse available shifts, accepted shifts, and shift history.
///
/// Parameters:
/// * [selectedDate] - Optional date to pre-select in the shifts view
/// * [initialTab] - Optional initial tab (via query parameter)
void toShifts({ void toShifts({
DateTime? selectedDate, DateTime? selectedDate,
String? initialTab, String? initialTab,
@@ -118,94 +79,47 @@ extension StaffNavigator on IModularNavigator {
if (refreshAvailable == true) { if (refreshAvailable == true) {
args['refreshAvailable'] = true; args['refreshAvailable'] = true;
} }
navigate(StaffPaths.shifts, arguments: args.isEmpty ? null : args); safeNavigate(StaffPaths.shifts, arguments: args.isEmpty ? null : args);
} }
/// Navigates to the Payments tab.
///
/// View payment history, earnings breakdown, and tax information.
void toPayments() { void toPayments() {
pushNamedAndRemoveUntil(StaffPaths.payments, (_) => false); pushNamedAndRemoveUntil(StaffPaths.payments, (_) => false);
} }
/// Navigates to the Clock In tab.
///
/// Access time tracking interface for active shifts.
void toClockIn() { void toClockIn() {
pushNamedAndRemoveUntil(StaffPaths.clockIn, (_) => false); pushNamedAndRemoveUntil(StaffPaths.clockIn, (_) => false);
} }
/// Navigates to the Profile tab.
///
/// Manage personal information, documents, and preferences.
void toProfile() { void toProfile() {
navigate(StaffPaths.profile); safeNavigate(StaffPaths.profile);
} }
// ==========================================================================
// SHIFT MANAGEMENT
// ==========================================================================
/// Navigates to the shift details page for a specific shift.
///
/// Displays comprehensive information about a shift including location,
/// time, pay rate, and action buttons for accepting/declining/applying.
///
/// Parameters:
/// * [shift] - The shift entity to display details for
///
/// The shift object is passed as an argument and can be retrieved
/// in the details page.
void toShiftDetails(Shift shift) { void toShiftDetails(Shift shift) {
navigate(StaffPaths.shiftDetails(shift.id), arguments: shift); safeNavigate(StaffPaths.shiftDetails(shift.id), arguments: shift);
} }
// ==========================================================================
// ONBOARDING & PROFILE SECTIONS
// ==========================================================================
/// Pushes the personal information page.
///
/// Collect or edit basic personal information.
void toPersonalInfo() { void toPersonalInfo() {
pushNamed(StaffPaths.onboardingPersonalInfo); safePush(StaffPaths.onboardingPersonalInfo);
} }
/// Pushes the preferred locations editing page.
///
/// Allows staff to search and manage their preferred US work locations.
void toPreferredLocations() { void toPreferredLocations() {
pushNamed(StaffPaths.preferredLocations); safePush(StaffPaths.preferredLocations);
} }
/// Pushes the emergency contact page.
///
/// Manage emergency contact details for safety purposes.
void toEmergencyContact() { void toEmergencyContact() {
pushNamed(StaffPaths.emergencyContact); safePush(StaffPaths.emergencyContact);
} }
/// Pushes the work experience page.
///
/// Record previous work experience and qualifications.
void toExperience() { void toExperience() {
navigate(StaffPaths.experience); safeNavigate(StaffPaths.experience);
} }
/// Pushes the attire preferences page.
///
/// Record sizing and appearance information for uniform allocation.
void toAttire() { void toAttire() {
navigate(StaffPaths.attire); safeNavigate(StaffPaths.attire);
} }
/// Pushes the attire capture page.
///
/// Parameters:
/// * [item] - The attire item to capture
/// * [initialPhotoUrl] - Optional initial photo URL
void toAttireCapture({required AttireItem item, String? initialPhotoUrl}) { void toAttireCapture({required AttireItem item, String? initialPhotoUrl}) {
navigate( safeNavigate(
StaffPaths.attireCapture, StaffPaths.attireCapture,
arguments: <String, dynamic>{ arguments: <String, dynamic>{
'item': item, 'item': item,
@@ -214,24 +128,12 @@ extension StaffNavigator on IModularNavigator {
); );
} }
// ==========================================================================
// COMPLIANCE & DOCUMENTS
// ==========================================================================
/// Pushes the documents management page.
///
/// Upload and manage required documents like ID and work permits.
void toDocuments() { void toDocuments() {
navigate(StaffPaths.documents); safeNavigate(StaffPaths.documents);
} }
/// Pushes the document upload page.
///
/// Parameters:
/// * [document] - The document metadata to upload
/// * [initialUrl] - Optional initial document URL
void toDocumentUpload({required StaffDocument document, String? initialUrl}) { void toDocumentUpload({required StaffDocument document, String? initialUrl}) {
navigate( safeNavigate(
StaffPaths.documentUpload, StaffPaths.documentUpload,
arguments: <String, dynamic>{ arguments: <String, dynamic>{
'document': document, 'document': document,
@@ -240,124 +142,59 @@ extension StaffNavigator on IModularNavigator {
); );
} }
/// Pushes the certificates management page.
///
/// Manage professional certificates (e.g., food handling, CPR).
void toCertificates() { void toCertificates() {
pushNamed(StaffPaths.certificates); safePush(StaffPaths.certificates);
} }
// ==========================================================================
// FINANCIAL INFORMATION
// ==========================================================================
/// Pushes the bank account information page.
///
/// Manage banking details for direct deposit payments.
void toBankAccount() { void toBankAccount() {
pushNamed(StaffPaths.bankAccount); safePush(StaffPaths.bankAccount);
} }
/// Pushes the tax forms page.
///
/// Manage W-4, tax withholding, and related tax documents.
void toTaxForms() { void toTaxForms() {
pushNamed(StaffPaths.taxForms); safePush(StaffPaths.taxForms);
} }
/// Pushes the time card page.
///
/// View detailed time entries and timesheets.
void toTimeCard() { void toTimeCard() {
pushNamed(StaffPaths.timeCard); safePush(StaffPaths.timeCard);
} }
// ==========================================================================
// SCHEDULING & AVAILABILITY
// ==========================================================================
/// Pushes the availability management page.
///
/// Define when the staff member is available to work.
void toAvailability() { void toAvailability() {
pushNamed(StaffPaths.availability); safePush(StaffPaths.availability);
} }
// ==========================================================================
// ADDITIONAL FEATURES
// ==========================================================================
/// Pushes the KROW University page (placeholder).
///
/// Access training materials and educational courses.
void toKrowUniversity() { void toKrowUniversity() {
pushNamed(StaffPaths.krowUniversity); safePush(StaffPaths.krowUniversity);
} }
/// Pushes the trainings page (placeholder).
///
/// View and complete required training modules.
void toTrainings() { void toTrainings() {
pushNamed(StaffPaths.trainings); safePush(StaffPaths.trainings);
} }
/// Pushes the leaderboard page (placeholder).
///
/// View performance rankings and achievements.
void toLeaderboard() { void toLeaderboard() {
pushNamed(StaffPaths.leaderboard); safePush(StaffPaths.leaderboard);
} }
/// Pushes the FAQs page.
///
/// Access frequently asked questions and help resources.
void toFaqs() { void toFaqs() {
pushNamed(StaffPaths.faqs); safePush(StaffPaths.faqs);
} }
// ==========================================================================
// PRIVACY & SECURITY
// ==========================================================================
/// Navigates to the privacy and security settings page.
///
/// Manage privacy preferences including:
/// * Location sharing settings
/// * View terms of service
/// * View privacy policy
void toPrivacySecurity() { void toPrivacySecurity() {
pushNamed(StaffPaths.privacySecurity); safePush(StaffPaths.privacySecurity);
} }
/// Navigates to the Terms of Service page.
///
/// Display the full terms of service document in a dedicated page view.
void toTermsOfService() { void toTermsOfService() {
pushNamed(StaffPaths.termsOfService); safePush(StaffPaths.termsOfService);
} }
/// Navigates to the Privacy Policy page.
///
/// Display the full privacy policy document in a dedicated page view.
void toPrivacyPolicy() { void toPrivacyPolicy() {
pushNamed(StaffPaths.privacyPolicy); safePush(StaffPaths.privacyPolicy);
} }
// ==========================================================================
// MESSAGING & COMMUNICATION
// ==========================================================================
/// Pushes the messages page (placeholder).
///
/// Access internal messaging system.
void toMessages() { void toMessages() {
pushNamed(StaffPaths.messages); safePush(StaffPaths.messages);
} }
/// Pushes the settings page (placeholder).
///
/// General app settings and preferences.
void toSettings() { void toSettings() {
pushNamed(StaffPaths.settings); safePush(StaffPaths.settings);
} }
} }

View File

@@ -3,7 +3,6 @@ import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_modular/flutter_modular.dart'; import 'package:flutter_modular/flutter_modular.dart';
import 'package:krow_core/core.dart';
import '../blocs/billing_bloc.dart'; import '../blocs/billing_bloc.dart';
import '../blocs/billing_state.dart'; import '../blocs/billing_state.dart';
@@ -21,7 +20,6 @@ class PendingInvoicesPage extends StatelessWidget {
appBar: UiAppBar( appBar: UiAppBar(
title: t.client_billing.awaiting_approval, title: t.client_billing.awaiting_approval,
showBackButton: true, showBackButton: true,
onLeadingPressed: () => Modular.to.toClientBilling(),
), ),
body: _buildBody(context, state), body: _buildBody(context, state),
); );