// import 'package:firebase_app_check/firebase_app_check.dart'; // import 'package:firebase_core/firebase_core.dart'; // import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:nhance_app_pwa/customAppBar/toastHelper.dart'; import 'package:nhance_app_pwa/features/chatbot/presentation/chatbot_host.dart'; import 'package:nhance_app_pwa/pages/changePassword.dart'; import 'package:nhance_app_pwa/pages/email_verify.dart'; import 'package:nhance_app_pwa/pages/enrollment/addons.dart'; import 'package:nhance_app_pwa/pages/enrollment/empDetails.dart'; import 'package:nhance_app_pwa/pages/enrollment/empReview.dart'; import 'package:nhance_app_pwa/pages/login.dart'; import 'package:nhance_app_pwa/pages/login_saml_auth.dart'; import 'package:nhance_app_pwa/pages/sso_login_return_page.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/AddPolicyScreen.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/claimprocess.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/claims.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/faqs.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/generalexclusionsdeductibles.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/help.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/home.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/planclaimsform.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/policies.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/privacypolicy.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/profile.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/raisedTicketList.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/retailClaimForm.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/service/api_service.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/termsofuse.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/tickets.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/tickettracklist.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/wellness.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/wellness_web_view.dart'; import 'package:nhance_app_pwa/pages/service/SessionManager.dart'; import 'package:nhance_app_pwa/pages/service/TokenService.dart'; import 'package:nhance_app_pwa/pages/service/data_manager.dart'; import 'package:nhance_app_pwa/pages/session/SetPinBiometric.dart'; import 'package:nhance_app_pwa/pages/session/changePin.dart'; import 'package:nhance_app_pwa/pages/session/settingUpPinAndBiometric.dart'; import 'package:nhance_app_pwa/pages/setPassword.dart'; import 'package:nhance_app_pwa/pages/helpers/app_permission_service.dart'; import 'package:nhance_app_pwa/pages/verify.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:flutter/foundation.dart'; import 'package:go_router/go_router.dart'; import 'config/environment.dart'; import 'logger.dart'; import 'router/app_router.dart'; // import 'dart:html' as html; Future main() async { await startApp(); } // === Splash (only for mobile) === class SplashScreen extends StatefulWidget { const SplashScreen({super.key}); @override State createState() => _SplashScreenState(); } class _SplashScreenState extends State { @override void initState() { super.initState(); _navigate(); } Future _navigate() async { await Future.delayed(const Duration(seconds: 3)); final prefs = await SharedPreferences.getInstance(); final isMpinSkipped = prefs.getString('is_mpin_skipped'); if (isMpinSkipped == '0') { if (mounted) context.go('/pinPage'); } else { if (mounted) context.go('/login'); } } @override Widget build(BuildContext context) { return Scaffold( body: Container( color: const Color(0x98FFFCE5), child: Center( child: Image.asset('assets/nhance-loader.gif', height: 60, width: 60), ), ), ); } } /// Middleware logic for tokens + mpin Future tokenRedirectLogic( BuildContext context, GoRouterState state) async { logDebug('ABCDEFGH'); final ssoLoginRedirect = redirectLoginWithSsoPayload(state); if (ssoLoginRedirect != null) return ssoLoginRedirect; const guestRoutes = [ '/login', '/sso-login', '/verify', '/mailVerify', '/pinPage', '/splash', '/privacypolicy', '/termsofuse', ]; final hasToken = await TokenService.hasValidToken(); logDebug('hasToken : $hasToken'); final location = state.matchedLocation; final session = SessionManager(); logDebug('Location: $location'); logDebug('hasToken: $hasToken'); if (hasToken) { await session.restoreSession(); final destination = await TokenService.defaultRouteForStoredTokens(); if (location == '/home' && destination == '/empDetails') { return '/empDetails'; } } if (!kIsWeb && hasToken) { final reauth = await _mobileReauthRedirectIfNeeded(location); if (reauth != null) return reauth; } // Logged in on a guest route → home or enrollment (pre-only). if (hasToken && guestRoutes.contains(location)) { if (!kIsWeb && !session.isMobileAppSessionUnlocked) { return null; } return await TokenService.defaultRouteForStoredTokens(); } if (!hasToken && guestRoutes.contains(location)) { return null; } if (!hasToken && !guestRoutes.contains(location)) { WidgetsBinding.instance.addPostFrameCallback((_) { ToastHelper.showErrorToast( context, 'Session expired. Please login again.'); }); return '/login'; } return null; } /// After a full app restart (new process), require MPIN or password login before /// protected routes. Tokens remain in secure storage. Minimizing does not lock. Future _mobileReauthRedirectIfNeeded(String location) async { const allowedWhileLocked = { '/login', '/pinPage', '/verify', '/mailVerify', '/sso-login', '/pinSettingPage', '/changePin', '/privacypolicy', '/termsofuse', }; final session = SessionManager(); if (session.isMobileAppSessionUnlocked) return null; if (allowedWhileLocked.contains(location)) return null; final prefs = await SharedPreferences.getInstance(); final skip = prefs.getString('is_mpin_skipped'); return skip == '0' ? '/pinPage' : '/login'; } /// When not using `-t lib/config/main_uat.dart`, pass e.g. `--dart-define=APP_FLAVOR=uat` /// so [Environment.flavor] (and logger UAT rules) match the build. void _applyAppFlavorFromDartDefine() { const fromDefine = String.fromEnvironment('APP_FLAVOR', defaultValue: ''); switch (fromDefine.toLowerCase()) { case 'uat': Environment.flavor = Flavor.uat; break; case 'prod': Environment.flavor = Flavor.prod; break; case 'prod1': Environment.flavor = Flavor.prod1; break; case 'dev': Environment.flavor = Flavor.dev; break; default: break; } } Future startApp() async { WidgetsFlutterBinding.ensureInitialized(); _applyAppFlavorFromDartDefine(); await AppPermissionService.requestInitialPermissions(); await TokenService.clearLegacyWebAuthFromSharedPreferences(); // await dotenv.load(fileName: Environment.fileName); // Initialize prefs before router final prefs = await SharedPreferences.getInstance(); // ✅ Initial route for mobile vs web final initialLocation = kIsWeb ? '/login' : '/splash'; // === GoRouter Setup === final router = GoRouter( initialLocation: initialLocation, routes: [ GoRoute( path: '/splash', builder: (context, state) => const SplashScreen()), GoRoute(path: '/login', builder: (context, state) => const login()), GoRoute( path: '/sso-login', builder: (context, state) => const SsoLoginReturnPage(), ), GoRoute( path: '/mailVerify', builder: (context, state) { final data = state.extra as Map; final type = data['type'] as String; final value = data['value'] as String; return MyEmailVerify(type: type, value: value); }, ), GoRoute(path: '/pinPage', builder: (context, state) => pinPage()), GoRoute( path: '/pinSettingPage', builder: (context, state) => pinSettingPage()), GoRoute( path: '/changePin', builder: (context, state) => changePin(), ), GoRoute( path: '/home', builder: (context, state) => ChatbotHost( child: Home(), triggerIntroOnHome: true, ), ), GoRoute( path: '/profile', builder: (context, state) => ChatbotHost(child: profile()), ), GoRoute( path: '/help', builder: (context, state) => ChatbotHost(child: help()), ), GoRoute( path: '/claimprocess', builder: (context, state) => ChatbotHost(child: claimprocess()), ), GoRoute(path: '/wellness', builder: (context, state) => ChatbotHost(child:wellness()), ), GoRoute( path: '/privacypolicy', builder: (context, state) => privacypolicy()), GoRoute(path: '/termsofuse', builder: (context, state) => termsofuse()), GoRoute( path: '/generalExclusionsDeductibles', builder: (context, state) => ChatbotHost(child:generalExclusionsDeductibles()), ), GoRoute(path: '/tickets', builder: (context, state) => ChatbotHost(child:tickets()), ), GoRoute( path: '/policies', builder: (context, state) { final arguments = state.extra as Map?; // 👈 receive here return ChatbotHost(child:policies(arguments: arguments)); }, ), GoRoute( path: '/claims', builder: (context, state) { final int tabIndex = state.extra as int? ?? 0; // default to 0 return ChatbotHost(child: claims(initialTab: tabIndex)); }, ), GoRoute( path: '/planclaimsform', builder: (context, state) { final details = state.extra as Map?; return ChatbotHost(child: planclaimsform(details: details)); }, ), GoRoute( path: '/retailClaimForm', builder: (context, state) { final details = state.extra as Map?; return ChatbotHost(child:retailClaimForm(details: details)); }, ), GoRoute( path: '/raisedTicketHistory', builder: (context, state) => ChatbotHost(child:raisedTicketHistory()), ), GoRoute( path: '/tickettracklist/:ticketID', builder: (context, state) { final ticketID = state.pathParameters['ticketID']!; return ChatbotHost(child:tickettracklist(ticketID: ticketID)); }, ), // GoRoute( // path: '/tickettracklist', // builder: (context, state) { // final ticketID = state.extra as String; // cast to correct type // return tickettracklist(ticketID: ticketID); // }, // ), GoRoute( path: '/empDetails', builder: (context, state) => empDetails(), ), GoRoute( path: '/faqs', builder: (context, state) => ChatbotHost(child: faqs()), ), GoRoute( path: '/addOnsDetails', builder: (context, state) => addOnsDetails()), GoRoute( path: '/empReviewDetails', builder: (context, state) => empReviewDetails()), GoRoute( path: '/AddPolicyScreen', builder: (context, state) => AddPolicyScreen()), GoRoute( path: '/changePassword', name: 'changePassword', builder: (context, state) { final email = state.uri.queryParameters['email'] ?? ''; final clientId = state.uri.queryParameters['client_id'] ?? ''; return changesPassword( email: email, client_id: clientId, ); }, ), GoRoute( path: '/setPassword', name: 'setPassword', builder: (context, state) { final email = state.uri.queryParameters['email'] ?? ''; final clientId = state.uri.queryParameters['client_id'] ?? ''; final route = state.uri.queryParameters['route'] ?? ''; return setPassword( email: email, client_id: clientId, route: route, ); }, ), GoRoute( path: '/wellnessWebView', builder: (context, state) { final url = state.extra as String; // receiving URL return WellnessWebView(url: url); }, ), ], // ✅ Middleware hook redirect: (context, state) async => await tokenRedirectLogic(context, state), ); registerAppGoRouter(router); runApp( ProviderScope( child: MyApp(router: router), ), ); } class MyApp extends StatefulWidget { final GoRouter router; // ✅ define router as a field const MyApp({super.key, required this.router}); @override State createState() => _MyAppState(); } class _MyAppState extends State { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { final apiService = ApiService(context); DataManager().init(apiService); // DataManager().loadAdvertisementImages(); }); } @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: widget.router, // ✅ this now works debugShowCheckedModeBanner: false, ); } }