diff --git a/lib/controller/auth/login_controller.dart b/lib/controller/auth/login_controller.dart index e7abe3a..6cc1bc1 100644 --- a/lib/controller/auth/login_controller.dart +++ b/lib/controller/auth/login_controller.dart @@ -81,7 +81,7 @@ class LoginController extends MyController { logSafe("Login successful for user: ${loginData['username']}"); - Get.toNamed('/select_tenant'); + Get.toNamed('/select-tenant'); } } catch (e, stacktrace) { logSafe("Exception during login", diff --git a/lib/controller/auth/mpin_controller.dart b/lib/controller/auth/mpin_controller.dart index 4a92691..a03b1f2 100644 --- a/lib/controller/auth/mpin_controller.dart +++ b/lib/controller/auth/mpin_controller.dart @@ -4,7 +4,6 @@ import 'package:marco/helpers/services/auth_service.dart'; import 'package:marco/helpers/services/storage/local_storage.dart'; import 'package:marco/helpers/widgets/my_form_validator.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; -import 'package:marco/view/dashboard/dashboard_screen.dart'; import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/helpers/services/firebase/firebase_messaging_service.dart'; import 'package:marco/controller/permission_controller.dart'; @@ -140,16 +139,17 @@ class MPINController extends GetxController { } /// Navigate to dashboard - void _navigateToDashboard({String? message}) { + /// Navigate to tenant selection after MPIN verification + void _navigateToTenantSelection({String? message}) { if (message != null) { - logSafe("Navigating to Dashboard with message: $message"); + logSafe("Navigating to Tenant Selection with message: $message"); showAppSnackbar( title: "Success", message: message, type: SnackbarType.success, ); } - Get.offAll(() => const DashboardScreen()); + Get.offAllNamed('/select-tenant'); } /// Clear the primary MPIN fields @@ -287,7 +287,7 @@ class MPINController extends GetxController { message: "MPIN Verified Successfully", type: SnackbarType.success, ); - _navigateToDashboard(); + _navigateToTenantSelection(); } else { final errorMessage = response["error"] ?? "Invalid MPIN"; logSafe("MPIN verification failed: $errorMessage", diff --git a/lib/controller/auth/otp_controller.dart b/lib/controller/auth/otp_controller.dart index 43c76ac..53cfeb5 100644 --- a/lib/controller/auth/otp_controller.dart +++ b/lib/controller/auth/otp_controller.dart @@ -109,7 +109,8 @@ class OTPController extends GetxController { } void onOTPChanged(String value, int index) { - logSafe("[OTPController] OTP field changed: index=$index", level: LogLevel.debug); + logSafe("[OTPController] OTP field changed: index=$index", + level: LogLevel.debug); if (value.isNotEmpty) { if (index < otpControllers.length - 1) { focusNodes[index + 1].requestFocus(); @@ -125,30 +126,24 @@ class OTPController extends GetxController { Future verifyOTP() async { final enteredOTP = otpControllers.map((c) => c.text).join(); - logSafe("[OTPController] Verifying OTP"); - final result = await AuthService.verifyOtp( email: email.value, otp: enteredOTP, ); if (result == null) { - logSafe("[OTPController] OTP verified successfully"); - showAppSnackbar( - title: "Success", - message: "OTP verified successfully", - type: SnackbarType.success, - ); - final bool isMpinEnabled = LocalStorage.getIsMpin(); - logSafe("[OTPController] MPIN Enabled: $isMpinEnabled"); + // ✅ Handle remember-me like in LoginController + final remember = LocalStorage.getBool('remember_me') ?? false; + if (remember) await LocalStorage.setToken('otp_email', email.value); - Get.offAllNamed('/home'); + // ✅ Enable remote logging + enableRemoteLogging(); + + Get.offAllNamed('/select-tenant'); } else { - final error = result['error'] ?? "Failed to verify OTP"; - logSafe("[OTPController] OTP verification failed", level: LogLevel.warning, error: error); showAppSnackbar( title: "Error", - message: error, + message: result['error']!, type: SnackbarType.error, ); } @@ -215,7 +210,8 @@ class OTPController extends GetxController { final savedEmail = LocalStorage.getToken('otp_email') ?? ''; emailController.text = savedEmail; email.value = savedEmail; - logSafe("[OTPController] Loaded saved email from local storage: $savedEmail"); + logSafe( + "[OTPController] Loaded saved email from local storage: $savedEmail"); } } } diff --git a/lib/controller/auth/reset_password_controller.dart b/lib/controller/auth/reset_password_controller.dart index efb1cce..842ca40 100644 --- a/lib/controller/auth/reset_password_controller.dart +++ b/lib/controller/auth/reset_password_controller.dart @@ -49,8 +49,8 @@ class ResetPasswordController extends MyController { basicValidator.clearErrors(); } - logSafe("[ResetPasswordController] Navigating to /home"); - Get.toNamed('/home'); + logSafe("[ResetPasswordController] Navigating to /dashboard"); + Get.toNamed('/dashboard'); update(); } else { logSafe("[ResetPasswordController] Form validation failed", level: LogLevel.warning); diff --git a/lib/helpers/services/auth_service.dart b/lib/helpers/services/auth_service.dart index 0ccb708..8bbe2da 100644 --- a/lib/helpers/services/auth_service.dart +++ b/lib/helpers/services/auth_service.dart @@ -1,9 +1,5 @@ import 'dart:convert'; -import 'package:get/get.dart'; import 'package:http/http.dart' as http; - -import 'package:marco/controller/permission_controller.dart'; -import 'package:marco/controller/project_controller.dart'; import 'package:marco/helpers/services/api_endpoints.dart'; import 'package:marco/helpers/services/storage/local_storage.dart'; import 'package:marco/helpers/services/app_logger.dart'; @@ -98,8 +94,8 @@ class AuthService { } static Future refreshToken() async { - final accessToken = await LocalStorage.getJwtToken(); - final refreshToken = await LocalStorage.getRefreshToken(); + final accessToken = LocalStorage.getJwtToken(); + final refreshToken = LocalStorage.getRefreshToken(); if ([accessToken, refreshToken].any((t) => t == null || t.isEmpty)) { logSafe("Missing access or refresh token.", level: LogLevel.warning); @@ -115,7 +111,7 @@ class AuthService { logSafe("Token refreshed successfully."); // 🔹 Retry FCM token registration after token refresh - final newFcmToken = await LocalStorage.getFcmToken(); + final newFcmToken = LocalStorage.getFcmToken(); if (newFcmToken?.isNotEmpty ?? false) { final success = await registerDeviceToken(newFcmToken!); logSafe( @@ -157,7 +153,7 @@ class AuthService { }) => _wrapErrorHandling( () async { - final token = await LocalStorage.getJwtToken(); + final token = LocalStorage.getJwtToken(); return _post( "/auth/generate-mpin", {"employeeId": employeeId, "mpin": mpin}, @@ -290,36 +286,6 @@ class AuthService { await LocalStorage.setIsMpin(false); await LocalStorage.removeMpinToken(); } - - // 🔹 Inject controllers only here, after login success - if (!Get.isRegistered()) { - Get.put(PermissionController()); - logSafe("✅ PermissionController injected after login."); - } - - if (!Get.isRegistered()) { - Get.put(ProjectController(), permanent: true); - logSafe("✅ ProjectController injected after login."); - } - - // 🔹 Load data - final token = data['token']; - await Future.wait([ - Get.find().loadData(token), - Get.find().fetchProjects(), - ]); - - // 🔹 Register FCM token after login - final fcmToken = await LocalStorage.getFcmToken(); - if (fcmToken?.isNotEmpty ?? false) { - final success = await registerDeviceToken(fcmToken!); - logSafe( - success - ? "✅ FCM token registered after login." - : "⚠️ Failed to register FCM token after login.", - level: success ? LogLevel.info : LogLevel.warning); - } - isLoggedIn = true; logSafe("✅ Login flow completed and controllers initialized."); } diff --git a/lib/helpers/services/firebase/firebase_messaging_service.dart b/lib/helpers/services/firebase/firebase_messaging_service.dart index 5cb98c5..1ac8c60 100644 --- a/lib/helpers/services/firebase/firebase_messaging_service.dart +++ b/lib/helpers/services/firebase/firebase_messaging_service.dart @@ -19,7 +19,7 @@ class FirebaseNotificationService { _registerMessageListeners(); _registerTokenRefreshListener(); - // Fetch token on app start (but only register with server if JWT available) + // Fetch token on app start (and register with server if JWT available) await getFcmToken(registerOnServer: true); } @@ -49,6 +49,7 @@ class FirebaseNotificationService { FirebaseMessaging.onMessageOpenedApp.listen(_handleNotificationTap); + // Background messages FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); } @@ -111,8 +112,6 @@ class FirebaseNotificationService { } } - - /// Handle tap on notification void _handleNotificationTap(RemoteMessage message) { _logger.i('📌 Notification tapped: ${message.data}'); @@ -129,7 +128,9 @@ class FirebaseNotificationService { } } -/// Background handler (required by Firebase) +/// 🔹 Background handler (required by Firebase) +/// Must be a top-level function and annotated for AOT +@pragma('vm:entry-point') Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { final logger = Logger(); logger diff --git a/lib/helpers/services/tenant_service.dart b/lib/helpers/services/tenant_service.dart index 83acfc6..3d9be30 100644 --- a/lib/helpers/services/tenant_service.dart +++ b/lib/helpers/services/tenant_service.dart @@ -129,6 +129,17 @@ class TenantService implements ITenantService { logSafe("⚠️ ProjectController not found while refreshing projects"); } + // 🔹 Register FCM token after tenant selection + final fcmToken = LocalStorage.getFcmToken(); + if (fcmToken?.isNotEmpty ?? false) { + final success = await AuthService.registerDeviceToken(fcmToken!); + logSafe( + success + ? "✅ FCM token registered after tenant selection." + : "⚠️ Failed to register FCM token after tenant selection.", + level: success ? LogLevel.info : LogLevel.warning); + } + return true; } diff --git a/lib/helpers/theme/app_theme.dart b/lib/helpers/theme/app_theme.dart index 8aa92e3..1d3e8bb 100644 --- a/lib/helpers/theme/app_theme.dart +++ b/lib/helpers/theme/app_theme.dart @@ -230,7 +230,7 @@ class AppStyle { containerRadius: AppStyle.containerRadius.medium, cardRadius: AppStyle.cardRadius.medium, buttonRadius: AppStyle.buttonRadius.medium, - defaultBreadCrumbItem: MyBreadcrumbItem(name: 'Marco', route: '/client/home'), + defaultBreadCrumbItem: MyBreadcrumbItem(name: 'Marco', route: '/client/dashboard'), )); bool isMobile = true; try { diff --git a/lib/routes.dart b/lib/routes.dart index a2f9362..4984fe1 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -45,7 +45,7 @@ getPageRoute() { page: () => DashboardScreen(), middlewares: [AuthMiddleware()]), GetPage( - name: '/home', + name: '/dashboard', page: () => DashboardScreen(), // or your actual home screen middlewares: [AuthMiddleware()], ), diff --git a/lib/view/layouts/left_bar.dart b/lib/view/layouts/left_bar.dart index 3c620d3..8b332cf 100644 --- a/lib/view/layouts/left_bar.dart +++ b/lib/view/layouts/left_bar.dart @@ -82,7 +82,7 @@ class _LeftBarState extends State child: Padding( padding: EdgeInsets.only(top: 50), child: InkWell( - onTap: () => Get.toNamed('/home'), + onTap: () => Get.toNamed('/dashboard'), child: Image.asset( (ThemeCustomizer.instance.theme == ThemeMode.light ? (widget.isCondensed diff --git a/lib/view/tenant/tenant_selection_screen.dart b/lib/view/tenant/tenant_selection_screen.dart index 2bf7acb..d3269b1 100644 --- a/lib/view/tenant/tenant_selection_screen.dart +++ b/lib/view/tenant/tenant_selection_screen.dart @@ -209,9 +209,6 @@ class TenantCardList extends StatelessWidget { ), ); } - if (controller.tenants.length == 1) { - return const SizedBox.shrink(); - } // Show tenant even if only 1 tenant return SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 24),