409 lines
13 KiB
Dart
Executable File
409 lines
13 KiB
Dart
Executable File
// 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/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/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 'dart:html' as html;
|
|
|
|
Future<void> main() async {
|
|
await startApp();
|
|
}
|
|
|
|
// === Splash (only for mobile) ===
|
|
class SplashScreen extends StatefulWidget {
|
|
const SplashScreen({super.key});
|
|
|
|
@override
|
|
State<SplashScreen> createState() => _SplashScreenState();
|
|
}
|
|
|
|
class _SplashScreenState extends State<SplashScreen> {
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_navigate();
|
|
}
|
|
|
|
Future<void> _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<String?> tokenRedirectLogic(
|
|
BuildContext context, GoRouterState state) async {
|
|
logDebug('ABCDEFGH');
|
|
const guestRoutes = [
|
|
'/login',
|
|
'/sso-login',
|
|
'/verify',
|
|
'/mailVerify',
|
|
'/pinPage',
|
|
'/splash',
|
|
];
|
|
|
|
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();
|
|
}
|
|
|
|
if (!kIsWeb && hasToken) {
|
|
final reauth = await _mobileReauthRedirectIfNeeded(location);
|
|
if (reauth != null) return reauth;
|
|
}
|
|
|
|
// Logged in on a guest route → home (only when mobile session is unlocked).
|
|
if (hasToken && guestRoutes.contains(location)) {
|
|
if (!kIsWeb && !session.isMobileAppSessionUnlocked) {
|
|
return null;
|
|
}
|
|
return '/home';
|
|
}
|
|
|
|
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<String?> _mobileReauthRedirectIfNeeded(String location) async {
|
|
const allowedWhileLocked = <String>{
|
|
'/login',
|
|
'/pinPage',
|
|
'/verify',
|
|
'/mailVerify',
|
|
'/sso-login',
|
|
'/pinSettingPage',
|
|
'/changePin',
|
|
};
|
|
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<void> startApp() async {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
_applyAppFlavorFromDartDefine();
|
|
|
|
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<String, dynamic>;
|
|
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<String, dynamic>?; // 👈 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<String, dynamic>?;
|
|
return ChatbotHost(child: planclaimsform(details: details));
|
|
},
|
|
),
|
|
GoRoute(
|
|
path: '/retailClaimForm',
|
|
builder: (context, state) {
|
|
final details = state.extra as Map<String, dynamic>?;
|
|
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),
|
|
);
|
|
|
|
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<MyApp> createState() => _MyAppState();
|
|
}
|
|
|
|
class _MyAppState extends State<MyApp> {
|
|
@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,
|
|
);
|
|
}
|
|
} |