diff --git a/apps/mobile/packages/core/lib/src/routing/client/navigator.dart b/apps/mobile/packages/core/lib/src/routing/client/navigator.dart index a7ce7150..dc057029 100644 --- a/apps/mobile/packages/core/lib/src/routing/client/navigator.dart +++ b/apps/mobile/packages/core/lib/src/routing/client/navigator.dart @@ -1,6 +1,7 @@ import 'package:flutter_modular/flutter_modular.dart'; import 'package:krow_domain/krow_domain.dart'; +import '../navigation_extensions.dart'; import 'route_paths.dart'; /// 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. /// Used when signing out or session expires. void toClientRoot() { - navigate(ClientPaths.root); + safeNavigate(ClientPaths.root); } /// Navigates to the get started page. /// /// This is the landing page for unauthenticated users, offering login/signup options. void toClientGetStartedPage() { - navigate(ClientPaths.getStarted); + safeNavigate(ClientPaths.getStarted); } /// 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 /// or social authentication providers. void toClientSignIn() { - pushNamed(ClientPaths.signIn); + safePush(ClientPaths.signIn); } /// 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 /// the initial registration form. void toClientSignUp() { - pushNamed(ClientPaths.signUp); + safePush(ClientPaths.signUp); } /// Navigates to the client home dashboard. @@ -66,7 +67,7 @@ extension ClientNavigator on IModularNavigator { /// /// Uses pushNamed to avoid trailing slash issues with navigate(). void toClientHome() { - navigate(ClientPaths.home); + safeNavigate(ClientPaths.home); } /// 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 /// to a specific tab instead (like [toClientHome]). void toClientMain() { - navigate(ClientPaths.main); + safeNavigate(ClientPaths.main); } // ========================================================================== @@ -85,43 +86,43 @@ extension ClientNavigator on IModularNavigator { /// /// Displays workforce coverage analytics and metrics. void toClientCoverage() { - navigate(ClientPaths.coverage); + safeNavigate(ClientPaths.coverage); } /// Navigates to the Billing tab. /// /// Access billing history, invoices, and payment methods. void toClientBilling() { - navigate(ClientPaths.billing); + safeNavigate(ClientPaths.billing); } /// Navigates to the Completion Review page. void toCompletionReview({Object? arguments}) { - pushNamed(ClientPaths.completionReview, arguments: arguments); + safePush(ClientPaths.completionReview, arguments: arguments); } /// Navigates to the full list of invoices awaiting approval. void toAwaitingApproval({Object? arguments}) { - navigate(ClientPaths.awaitingApproval, arguments: arguments); + safeNavigate(ClientPaths.awaitingApproval, arguments: arguments); } /// Navigates to the Invoice Ready page. void toInvoiceReady() { - pushNamed(ClientPaths.invoiceReady); + safePush(ClientPaths.invoiceReady); } /// Navigates to the Orders tab. /// /// View and manage all shift orders with filtering and sorting. void toClientOrders() { - navigate(ClientPaths.orders); + safeNavigate(ClientPaths.orders); } /// Navigates to the Reports tab. /// /// Generate and view workforce reports and analytics. void toClientReports() { - navigate(ClientPaths.reports); + safeNavigate(ClientPaths.reports); } // ========================================================================== @@ -132,12 +133,12 @@ extension ClientNavigator on IModularNavigator { /// /// Manage account settings, notifications, and app preferences. void toClientSettings() { - pushNamed(ClientPaths.settings); + safePush(ClientPaths.settings); } /// Pushes the edit profile page. 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. Future toClientHubs() async { - await pushNamed(ClientPaths.hubs); + await safePush(ClientPaths.hubs); } /// Navigates to the details of a specific hub. Future toHubDetails(Hub hub) { - return pushNamed( + return safePush( ClientPaths.hubDetails, arguments: {'hub': hub}, ); @@ -161,7 +162,7 @@ extension ClientNavigator on IModularNavigator { /// Navigates to the page to add a new hub or edit an existing one. Future toEditHub({Hub? hub}) async { - return pushNamed( + return safePush( ClientPaths.editHub, arguments: {'hub': hub}, // 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. void toCreateOrder({Object? arguments}) { - navigate(ClientPaths.createOrder, arguments: arguments); + safeNavigate(ClientPaths.createOrder, arguments: arguments); } /// Pushes the rapid order creation flow. /// /// Quick shift creation with simplified inputs for urgent needs. void toCreateOrderRapid({Object? arguments}) { - pushNamed(ClientPaths.createOrderRapid, arguments: arguments); + safePush(ClientPaths.createOrderRapid, arguments: arguments); } /// Pushes the one-time order creation flow. /// /// Create a shift that occurs once at a specific date and time. void toCreateOrderOneTime({Object? arguments}) { - pushNamed(ClientPaths.createOrderOneTime, arguments: arguments); + safePush(ClientPaths.createOrderOneTime, arguments: arguments); } /// Pushes the recurring order creation flow. /// /// Create shifts that repeat on a defined schedule (daily, weekly, etc.). void toCreateOrderRecurring({Object? arguments}) { - pushNamed(ClientPaths.createOrderRecurring, arguments: arguments); + safePush(ClientPaths.createOrderRecurring, arguments: arguments); } /// Pushes the permanent order creation flow. /// /// Create a long-term or permanent staffing position. 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. void toOrdersSpecificDate(DateTime date) { - navigate( + safeNavigate( ClientPaths.orders, arguments: {'initialDate': date}, ); diff --git a/apps/mobile/packages/core/lib/src/routing/navigation_extensions.dart b/apps/mobile/packages/core/lib/src/routing/navigation_extensions.dart index 697e3ed8..f520b823 100644 --- a/apps/mobile/packages/core/lib/src/routing/navigation_extensions.dart +++ b/apps/mobile/packages/core/lib/src/routing/navigation_extensions.dart @@ -1,4 +1,6 @@ import 'package:flutter_modular/flutter_modular.dart'; +import 'client/route_paths.dart'; +import 'staff/route_paths.dart'; /// Base navigation utilities extension for [IModularNavigator]. /// @@ -21,10 +23,7 @@ extension NavigationExtensions on IModularNavigator { /// * [arguments] - Optional arguments to pass to the route /// /// Returns `true` if navigation was successful, `false` otherwise. - Future safeNavigate( - String path, { - Object? arguments, - }) async { + Future safeNavigate(String path, {Object? arguments}) async { try { navigate(path, arguments: arguments); return true; @@ -32,6 +31,7 @@ extension NavigationExtensions on IModularNavigator { // In production, you might want to log this to a monitoring service // ignore: avoid_print print('Navigation error to $path: $e'); + navigateToHome(); return false; } } @@ -56,6 +56,7 @@ extension NavigationExtensions on IModularNavigator { // In production, you might want to log this to a monitoring service // ignore: avoid_print print('Push navigation error to $routeName: $e'); + navigateToHome(); return null; } } @@ -68,14 +69,31 @@ extension NavigationExtensions on IModularNavigator { 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() { if (canPop()) { pop(); return true; } + navigateToHome(); 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('/'); + } + } } diff --git a/apps/mobile/packages/core/lib/src/routing/staff/navigator.dart b/apps/mobile/packages/core/lib/src/routing/staff/navigator.dart index d3c1bfdd..f07a7fba 100644 --- a/apps/mobile/packages/core/lib/src/routing/staff/navigator.dart +++ b/apps/mobile/packages/core/lib/src/routing/staff/navigator.dart @@ -1,6 +1,7 @@ import 'package:flutter_modular/flutter_modular.dart'; import 'package:krow_domain/krow_domain.dart'; +import '../navigation_extensions.dart'; import 'route_paths.dart'; /// 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. /// Used when signing out or session expires. 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() { - 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) { - pushNamed( + safePush( StaffPaths.phoneVerification, arguments: {'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() { - 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() { pushNamedAndRemoveUntil(StaffPaths.home, (_) => false); } - /// Navigates to the benefits overview page. 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() { 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({ DateTime? selectedDate, String? initialTab, @@ -118,94 +79,47 @@ extension StaffNavigator on IModularNavigator { if (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() { pushNamedAndRemoveUntil(StaffPaths.payments, (_) => false); } - /// Navigates to the Clock In tab. - /// - /// Access time tracking interface for active shifts. void toClockIn() { pushNamedAndRemoveUntil(StaffPaths.clockIn, (_) => false); } - /// Navigates to the Profile tab. - /// - /// Manage personal information, documents, and preferences. 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) { - 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() { - 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() { - pushNamed(StaffPaths.preferredLocations); + safePush(StaffPaths.preferredLocations); } - /// Pushes the emergency contact page. - /// - /// Manage emergency contact details for safety purposes. void toEmergencyContact() { - pushNamed(StaffPaths.emergencyContact); + safePush(StaffPaths.emergencyContact); } - /// Pushes the work experience page. - /// - /// Record previous work experience and qualifications. void toExperience() { - navigate(StaffPaths.experience); + safeNavigate(StaffPaths.experience); } - /// Pushes the attire preferences page. - /// - /// Record sizing and appearance information for uniform allocation. 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}) { - navigate( + safeNavigate( StaffPaths.attireCapture, arguments: { '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() { - 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}) { - navigate( + safeNavigate( StaffPaths.documentUpload, arguments: { '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() { - pushNamed(StaffPaths.certificates); + safePush(StaffPaths.certificates); } - // ========================================================================== - // FINANCIAL INFORMATION - // ========================================================================== - - /// Pushes the bank account information page. - /// - /// Manage banking details for direct deposit payments. void toBankAccount() { - pushNamed(StaffPaths.bankAccount); + safePush(StaffPaths.bankAccount); } - /// Pushes the tax forms page. - /// - /// Manage W-4, tax withholding, and related tax documents. void toTaxForms() { - pushNamed(StaffPaths.taxForms); + safePush(StaffPaths.taxForms); } - /// Pushes the time card page. - /// - /// View detailed time entries and timesheets. 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() { - pushNamed(StaffPaths.availability); + safePush(StaffPaths.availability); } - // ========================================================================== - // ADDITIONAL FEATURES - // ========================================================================== - - /// Pushes the KROW University page (placeholder). - /// - /// Access training materials and educational courses. void toKrowUniversity() { - pushNamed(StaffPaths.krowUniversity); + safePush(StaffPaths.krowUniversity); } - /// Pushes the trainings page (placeholder). - /// - /// View and complete required training modules. void toTrainings() { - pushNamed(StaffPaths.trainings); + safePush(StaffPaths.trainings); } - /// Pushes the leaderboard page (placeholder). - /// - /// View performance rankings and achievements. void toLeaderboard() { - pushNamed(StaffPaths.leaderboard); + safePush(StaffPaths.leaderboard); } - /// Pushes the FAQs page. - /// - /// Access frequently asked questions and help resources. 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() { - 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() { - 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() { - pushNamed(StaffPaths.privacyPolicy); + safePush(StaffPaths.privacyPolicy); } - // ========================================================================== - // MESSAGING & COMMUNICATION - // ========================================================================== - - /// Pushes the messages page (placeholder). - /// - /// Access internal messaging system. void toMessages() { - pushNamed(StaffPaths.messages); + safePush(StaffPaths.messages); } - /// Pushes the settings page (placeholder). - /// - /// General app settings and preferences. void toSettings() { - pushNamed(StaffPaths.settings); + safePush(StaffPaths.settings); } } diff --git a/apps/mobile/packages/features/client/billing/lib/src/presentation/pages/pending_invoices_page.dart b/apps/mobile/packages/features/client/billing/lib/src/presentation/pages/pending_invoices_page.dart index d76b6d1a..246e2d08 100644 --- a/apps/mobile/packages/features/client/billing/lib/src/presentation/pages/pending_invoices_page.dart +++ b/apps/mobile/packages/features/client/billing/lib/src/presentation/pages/pending_invoices_page.dart @@ -3,7 +3,6 @@ import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_modular/flutter_modular.dart'; -import 'package:krow_core/core.dart'; import '../blocs/billing_bloc.dart'; import '../blocs/billing_state.dart'; @@ -21,7 +20,6 @@ class PendingInvoicesPage extends StatelessWidget { appBar: UiAppBar( title: t.client_billing.awaiting_approval, showBackButton: true, - onLeadingPressed: () => Modular.to.toClientBilling(), ), body: _buildBody(context, state), );