diff --git a/lib/helpers/services/app_initializer.dart b/lib/helpers/services/app_initializer.dart index acd9b88..88b7f73 100644 --- a/lib/helpers/services/app_initializer.dart +++ b/lib/helpers/services/app_initializer.dart @@ -1,6 +1,7 @@ import 'package:flutter/services.dart'; import 'package:url_strategy/url_strategy.dart'; import 'package:firebase_core/firebase_core.dart'; + import 'package:marco/helpers/services/storage/local_storage.dart'; import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/helpers/services/auth_service.dart'; @@ -20,7 +21,7 @@ Future initializeApp() async { ]); await _setupDeviceInfo(); - await _handleAuthTokens(); + await _handleAuthTokens(); await _setupTheme(); await _setupFirebaseMessaging(); @@ -38,23 +39,10 @@ Future initializeApp() async { } } -Future _handleAuthTokens() async { - final refreshToken = await LocalStorage.getRefreshToken(); - if (refreshToken?.isNotEmpty ?? false) { - logSafe("🔁 Refresh token found. Attempting to refresh JWT..."); - final success = await AuthService.refreshToken(); - if (!success) { - logSafe("⚠️ Refresh token invalid or expired. User must login again."); - } - } else { - logSafe("❌ No refresh token found. Skipping refresh."); - } -} - Future _setupUI() async { setPathUrlStrategy(); await SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); - logSafe("💡 UI setup completed with default system behavior."); + logSafe("💡 UI setup completed."); } Future _setupFirebase() async { @@ -77,6 +65,19 @@ Future _setupDeviceInfo() async { logSafe("📱 Device Info: ${deviceInfoService.deviceData}"); } +Future _handleAuthTokens() async { + final refreshToken = LocalStorage.getRefreshToken(); + if (refreshToken?.isNotEmpty ?? false) { + logSafe("🔁 Refresh token found. Attempting refresh..."); + final success = await AuthService.refreshToken(); + if (!success) { + logSafe("⚠️ Refresh failed — user must login again."); + } + } else { + logSafe("❌ No refresh token — skipping refresh."); + } +} + Future _setupTheme() async { await ThemeCustomizer.init(); logSafe("💡 Theme customizer initialized."); @@ -84,10 +85,10 @@ Future _setupTheme() async { Future _setupFirebaseMessaging() async { await FirebaseNotificationService().initialize(); - logSafe("💡 Firebase Messaging initialized."); + logSafe("💬 Firebase Messaging initialized."); } void _finalizeAppStyle() { AppStyle.init(); - logSafe("💡 AppStyle initialized."); + logSafe("🎨 AppStyle initialized."); } diff --git a/lib/main.dart b/lib/main.dart index 77307e9..3bc0d24 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -12,20 +12,15 @@ import 'package:marco/helpers/services/storage/local_storage.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - // Initialize logging system + // --- Logging setup --- await initLogging(); - logSafe("App starting..."); - - // ✅ Ensure local storage is ready before enabling remote logging + logSafe("🚀 App starting..."); await LocalStorage.init(); - logSafe("💡 Local storage initialized (early init for logging)."); - - // Now safe to enable remote logging enableRemoteLogging(); try { await initializeApp(); - logSafe("App initialized successfully."); + logSafe("✅ App fully initialized"); runApp( ChangeNotifierProvider( diff --git a/lib/routes.dart b/lib/routes.dart index 37a166e..6edb62a 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -2,26 +2,29 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:marco/helpers/services/auth_service.dart'; import 'package:marco/helpers/services/tenant_service.dart'; -import 'package:marco/view/auth/forgot_password_screen.dart'; +// Auth import 'package:marco/view/auth/login_screen.dart'; +import 'package:marco/view/auth/login_option_screen.dart'; import 'package:marco/view/auth/register_account_screen.dart'; +import 'package:marco/view/auth/forgot_password_screen.dart'; import 'package:marco/view/auth/reset_password_screen.dart'; -import 'package:marco/view/error_pages/coming_soon_screen.dart'; -import 'package:marco/view/error_pages/error_404_screen.dart'; -import 'package:marco/view/error_pages/error_500_screen.dart'; +import 'package:marco/view/auth/mpin_screen.dart'; +import 'package:marco/view/auth/mpin_auth_screen.dart'; +// Dashboard + Modules import 'package:marco/view/dashboard/dashboard_screen.dart'; +import 'package:marco/view/tenant/tenant_selection_screen.dart'; import 'package:marco/view/Attendence/attendance_screen.dart'; import 'package:marco/view/taskPlanning/daily_task_planning.dart'; import 'package:marco/view/taskPlanning/daily_progress_report.dart'; import 'package:marco/view/employees/employees_screen.dart'; -import 'package:marco/view/auth/login_option_screen.dart'; -import 'package:marco/view/auth/mpin_screen.dart'; -import 'package:marco/view/auth/mpin_auth_screen.dart'; import 'package:marco/view/directory/directory_main_screen.dart'; import 'package:marco/view/expense/expense_screen.dart'; import 'package:marco/view/document/user_document_screen.dart'; -import 'package:marco/view/tenant/tenant_selection_screen.dart'; - +// Error +import 'package:marco/view/error_pages/coming_soon_screen.dart'; +import 'package:marco/view/error_pages/error_404_screen.dart'; +import 'package:marco/view/error_pages/error_500_screen.dart'; +/// Middleware to enforce authentication and tenant selection class AuthMiddleware extends GetMiddleware { @override RouteSettings? redirect(String? route) { @@ -38,88 +41,99 @@ class AuthMiddleware extends GetMiddleware { } } -getPageRoute() { - var routes = [ +/// Returns the list of all app routes +List getPageRoute() { + final List routes = [ + // ========== AUTH ROUTES ========== + GetPage(name: '/auth/login', page: () => LoginScreen()), + GetPage(name: '/auth/login-option', page: () => LoginOptionScreen()), + GetPage(name: '/auth/register_account', page: () => const RegisterAccountScreen()), + GetPage(name: '/auth/forgot_password', page: () => ForgotPasswordScreen()), + GetPage(name: '/auth/reset_password', page: () => const ResetPasswordScreen()), + GetPage(name: '/auth/mpin', page: () => MPINScreen()), + GetPage(name: '/auth/mpin-auth', page: () => MPINAuthScreen()), + + // ========== MAIN DASHBOARD ROUTES ========== GetPage( - name: '/', - page: () => DashboardScreen(), - middlewares: [AuthMiddleware()]), - GetPage( - name: '/dashboard', - page: () => DashboardScreen(), // or your actual home screen + name: '/', + page: () => DashboardScreen(), middlewares: [AuthMiddleware()], ), GetPage( - name: '/select-tenant', - page: () => const TenantSelectionScreen(), - middlewares: [AuthMiddleware()]), + name: '/dashboard', + page: () => DashboardScreen(), + middlewares: [AuthMiddleware()], + ), + GetPage( + name: '/select-tenant', + page: () => const TenantSelectionScreen(), + middlewares: [AuthMiddleware()], + ), - // Dashboard + // ========== DASHBOARD SUBMODULES ========== GetPage( - name: '/dashboard/attendance', - page: () => AttendanceScreen(), - middlewares: [AuthMiddleware()]), + name: '/dashboard/attendance', + page: () => AttendanceScreen(), + middlewares: [AuthMiddleware()], + ), GetPage( - name: '/dashboard', - page: () => DashboardScreen(), - middlewares: [AuthMiddleware()]), + name: '/dashboard/employees', + page: () => EmployeesScreen(), + middlewares: [AuthMiddleware()], + ), GetPage( - name: '/dashboard/employees', - page: () => EmployeesScreen(), - middlewares: [AuthMiddleware()]), - // Daily Task Planning + name: '/dashboard/daily-task-Planning', + page: () => DailyTaskPlanningScreen(), + middlewares: [AuthMiddleware()], + ), GetPage( - name: '/dashboard/daily-task-Planning', - page: () => DailyTaskPlanningScreen(), - middlewares: [AuthMiddleware()]), + name: '/dashboard/daily-task-progress', + page: () => DailyProgressReportScreen(), + middlewares: [AuthMiddleware()], + ), GetPage( - name: '/dashboard/daily-task-progress', - page: () => DailyProgressReportScreen(), - middlewares: [AuthMiddleware()]), + name: '/dashboard/directory-main-page', + page: () => DirectoryMainScreen(), + middlewares: [AuthMiddleware()], + ), GetPage( - name: '/dashboard/directory-main-page', - page: () => DirectoryMainScreen(), - middlewares: [AuthMiddleware()]), - // Expense + name: '/dashboard/expense-main-page', + page: () => ExpenseMainScreen(), + middlewares: [AuthMiddleware()], + ), GetPage( - name: '/dashboard/expense-main-page', - page: () => ExpenseMainScreen(), - middlewares: [AuthMiddleware()]), - // Documents + name: '/dashboard/document-main-page', + page: () => UserDocumentsPage(), + middlewares: [AuthMiddleware()], + ), + + // ========== ERROR SCREENS ========== GetPage( - name: '/dashboard/document-main-page', - page: () => UserDocumentsPage(), - middlewares: [AuthMiddleware()]), - // Authentication - GetPage(name: '/auth/login', page: () => LoginScreen()), - GetPage(name: '/auth/login-option', page: () => LoginOptionScreen()), - GetPage(name: '/auth/mpin', page: () => MPINScreen()), - GetPage(name: '/auth/mpin-auth', page: () => MPINAuthScreen()), + name: '/error/coming_soon', + page: () => ComingSoonScreen(), + middlewares: [AuthMiddleware()], + ), GetPage( - name: '/auth/register_account', - page: () => const RegisterAccountScreen()), - GetPage(name: '/auth/forgot_password', page: () => ForgotPasswordScreen()), + name: '/error/500', + page: () => Error500Screen(), + middlewares: [AuthMiddleware()], + ), GetPage( - name: '/auth/reset_password', page: () => const ResetPasswordScreen()), - // Error - GetPage( - name: '/error/coming_soon', - page: () => ComingSoonScreen(), - middlewares: [AuthMiddleware()]), - GetPage( - name: '/error/500', - page: () => Error500Screen(), - middlewares: [AuthMiddleware()]), - GetPage( - name: '/error/404', - page: () => Error404Screen(), - middlewares: [AuthMiddleware()]), + name: '/error/404', + page: () => Error404Screen(), + middlewares: [AuthMiddleware()], + ), ]; + + // ✅ Force uniform transition for all pages return routes - .map((e) => GetPage( + .map( + (e) => GetPage( name: e.name, page: e.page, middlewares: e.middlewares, - transition: Transition.noTransition)) + transition: Transition.noTransition, + ), + ) .toList(); } diff --git a/lib/view/my_app.dart b/lib/view/my_app.dart index 5b4a66a..5786214 100644 --- a/lib/view/my_app.dart +++ b/lib/view/my_app.dart @@ -4,7 +4,6 @@ import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; import 'package:marco/helpers/services/app_logger.dart'; -import 'package:marco/helpers/extensions/app_localization_delegate.dart'; import 'package:marco/helpers/services/localizations/language.dart'; import 'package:marco/helpers/services/navigation_services.dart'; import 'package:marco/helpers/services/storage/local_storage.dart'; @@ -16,25 +15,26 @@ import 'package:marco/routes.dart'; class MyApp extends StatelessWidget { const MyApp({super.key}); - Future _getInitialRoute() async { + Future _resolveInitialRoute() async { try { final token = LocalStorage.getJwtToken(); + if (token == null || token.isEmpty) { - logSafe("User not logged in. Routing to /auth/login-option"); + logSafe("👤 No token — going to login option"); return "/auth/login-option"; } final bool hasMpin = LocalStorage.getIsMpin(); if (hasMpin) { await LocalStorage.setBool("mpin_verified", false); - logSafe("Routing to /auth/mpin-auth"); + logSafe("🔐 MPIN found — going to MPIN auth"); return "/auth/mpin-auth"; } - logSafe("No MPIN. Routing to /dashboard"); + logSafe("🏠 Routing to dashboard"); return "/dashboard"; } catch (e, stacktrace) { - logSafe("Error determining initial route", + logSafe("❌ Error resolving initial route", level: LogLevel.error, error: e, stackTrace: stacktrace); return "/auth/login-option"; } @@ -45,29 +45,35 @@ class MyApp extends StatelessWidget { return Consumer( builder: (_, notifier, __) { return FutureBuilder( - future: _getInitialRoute(), + future: _resolveInitialRoute(), builder: (context, snapshot) { - if (snapshot.hasError) { - logSafe("FutureBuilder snapshot error", - level: LogLevel.error, error: snapshot.error); + if (snapshot.connectionState == ConnectionState.waiting) { return const MaterialApp( - home: Center(child: Text("Error determining route")), + home: Scaffold( + body: Center(child: CircularProgressIndicator()), + ), ); } - if (!snapshot.hasData) { + if (snapshot.hasError) { + logSafe("❌ Error while determining initial route: ${snapshot.error}"); return const MaterialApp( - home: Center(child: CircularProgressIndicator()), + home: Scaffold( + body: Center(child: Text("Error determining route")), + ), ); } + final initialRoute = snapshot.data ?? "/auth/login-option"; + logSafe("🚦 Launching app with initial route: $initialRoute"); + return GetMaterialApp( debugShowCheckedModeBanner: false, theme: AppTheme.lightTheme, darkTheme: AppTheme.darkTheme, themeMode: ThemeCustomizer.instance.theme, navigatorKey: NavigationService.navigatorKey, - initialRoute: snapshot.data!, + initialRoute: initialRoute, getPages: getPageRoute(), builder: (context, child) { NavigationService.registerContext(context); @@ -76,8 +82,7 @@ class MyApp extends StatelessWidget { child: child ?? const SizedBox(), ); }, - localizationsDelegates: [ - AppLocalizationsDelegate(context), + localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate,