fix login and add notifications

This commit is contained in:
Phuoc Nguyen
2025-11-26 17:46:09 +07:00
parent 88ac2f2f07
commit dc8e60f589
14 changed files with 517 additions and 33 deletions

View File

@@ -569,7 +569,7 @@ Future<AuthInterceptor> authInterceptor(Ref ref, Dio dio) async {
@riverpod
LoggingInterceptor loggingInterceptor(Ref ref) {
// Only enable logging in debug mode
const bool isDebug = true; // TODO: Replace with kDebugMode from Flutter
const bool isDebug = false; // TODO: Replace with kDebugMode from Flutter
return LoggingInterceptor(
enableRequestLogging: false,

View File

@@ -65,14 +65,21 @@ final routerProvider = Provider<GoRouter>((ref) {
redirect: (context, state) {
final isLoading = authState.isLoading;
final isLoggedIn = authState.value != null;
final isOnSplashPage = state.matchedLocation == RouteNames.splash;
final isOnLoginPage = state.matchedLocation == RouteNames.login;
final isOnForgotPasswordPage =
state.matchedLocation == RouteNames.forgotPassword;
final isOnRegisterPage = state.matchedLocation == RouteNames.register;
final isOnBusinessUnitPage =
state.matchedLocation == RouteNames.businessUnitSelection;
final isOnOtpPage = state.matchedLocation == RouteNames.otpVerification;
final currentPath = state.matchedLocation;
final targetPath = state.uri.toString();
// Log redirect attempts for debugging
print('🔄 Router redirect check:');
print(' Current: $currentPath');
print(' Target: $targetPath');
print(' isLoading: $isLoading, isLoggedIn: $isLoggedIn');
final isOnSplashPage = currentPath == RouteNames.splash;
final isOnLoginPage = currentPath == RouteNames.login;
final isOnForgotPasswordPage = currentPath == RouteNames.forgotPassword;
final isOnRegisterPage = currentPath == RouteNames.register;
final isOnBusinessUnitPage = currentPath == RouteNames.businessUnitSelection;
final isOnOtpPage = currentPath == RouteNames.otpVerification;
final isOnAuthPage =
isOnLoginPage ||
isOnForgotPasswordPage ||
@@ -82,25 +89,35 @@ final routerProvider = Provider<GoRouter>((ref) {
// While loading auth state, show splash screen
if (isLoading) {
return RouteNames.splash;
if (!isOnSplashPage) {
print(' ➡️ Redirecting to splash (loading)');
return RouteNames.splash;
}
print(' ✓ Already on splash (loading)');
return null;
}
// After loading, redirect from splash to appropriate page
if (isOnSplashPage && !isLoading) {
return isLoggedIn ? RouteNames.home : RouteNames.login;
if (isOnSplashPage) {
final destination = isLoggedIn ? RouteNames.home : RouteNames.login;
print(' ➡️ Redirecting from splash to $destination');
return destination;
}
// If not logged in and not on auth/splash pages, redirect to login
if (!isLoggedIn && !isOnAuthPage && !isOnSplashPage) {
if (!isLoggedIn && !isOnAuthPage) {
print(' ➡️ Redirecting to login (not authenticated)');
return RouteNames.login;
}
// If logged in and on login page, redirect to home
if (isLoggedIn && isOnLoginPage) {
print(' ➡️ Redirecting to home (already logged in)');
return RouteNames.home;
}
// No redirect needed
print(' ✓ No redirect needed');
return null;
},
@@ -549,7 +566,7 @@ final routerProvider = Provider<GoRouter>((ref) {
),
// Debug logging (disable in production)
debugLogDiagnostics: true,
debugLogDiagnostics: false, // Using custom logs instead
);
});

View File

@@ -88,10 +88,8 @@ class Auth extends _$Auth {
@override
Future<User?> build() async {
// Simple initialization - just check if user is logged in
// Don't call getSession() here to avoid ref disposal issues
// Do this ONCE on app startup and don't rebuild
try {
final secureStorage = ref.read(secureStorageProvider);
// Check if "Remember Me" was enabled
final rememberMe = await _localDataSource.getRememberMe();
@@ -101,6 +99,7 @@ class Auth extends _$Auth {
}
// Check if we have a stored session
final secureStorage = ref.read(secureStorageProvider);
final sid = await secureStorage.read(key: 'frappe_sid');
final userId = await secureStorage.read(key: 'frappe_user_id');
final fullName = await secureStorage.read(key: 'frappe_full_name');

View File

@@ -4,6 +4,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:onesignal_flutter/onesignal_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:worker/app.dart';
@@ -29,6 +30,10 @@ void main() async {
// Initialize app with error handling
await _initializeApp();
// Enable verbose logging for debugging (remove in production)
}
/// Initialize all app dependencies with comprehensive error handling
@@ -40,6 +45,55 @@ Future<void> _initializeApp() async {
// Initialize core dependencies in parallel for faster startup
await Future.wait([_initializeHive(), _initializeSharedPreferences()]);
// Initialize OneSignal with verbose logging for debugging
OneSignal.Debug.setLogLevel(OSLogLevel.verbose);
// Initialize with your OneSignal App ID
OneSignal.initialize("778ca22d-c719-4ec8-86cb-a6b911166066");
debugPrint('🔔 OneSignal initialized');
// Add observer BEFORE requesting permission to catch the subscription event
OneSignal.User.pushSubscription.addObserver((state) {
debugPrint('🔔 Push subscription state changed:');
debugPrint(' Previous - optedIn: ${state.previous.optedIn}, id: ${state.previous.id}');
debugPrint(' Current - optedIn: ${state.current.optedIn}, id: ${state.current.id}');
debugPrint(' Subscription ID: ${state.current.id}');
debugPrint(' Push Token: ${state.current.token}');
// Save subscription info when available
if (state.current.id != null) {
debugPrint('🔔 ✅ Device successfully subscribed!');
}
});
// Add notification permission observer
OneSignal.Notifications.addPermissionObserver((isGranted) {
debugPrint('🔔 Notification permission changed: $isGranted');
});
// Request permission - TRUE to show the native permission prompt
final accepted = await OneSignal.Notifications.requestPermission(true);
debugPrint('🔔 Permission request result: $accepted');
// Give OneSignal SDK time to complete initialization and server registration
// This is necessary because the subscription happens asynchronously
await Future.delayed(const Duration(seconds: 2));
// Check current subscription status after initialization completes
final optedIn = OneSignal.User.pushSubscription.optedIn;
final id = OneSignal.User.pushSubscription.id;
final token = OneSignal.User.pushSubscription.token;
debugPrint('🔔 Current subscription status (after delay):');
debugPrint(' Opted In: $optedIn');
debugPrint(' Subscription ID: $id');
debugPrint(' Push Token: $token');
if (id == null) {
debugPrint('🔔 ⚠️ Subscription ID is still null - check device connectivity and OneSignal app ID');
}
// Run the app with Riverpod ProviderScope
runApp(const ProviderScope(child: WorkerApp()));
} catch (error, stackTrace) {