import 'dart:convert'; import 'dart:io'; import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_image_slideshow/flutter_image_slideshow.dart'; import 'package:flutter_svg/svg.dart'; import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; import 'package:jwt_decode/jwt_decode.dart'; import 'package:nhance_app_pwa/customAppBar/customAppBar.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/service/api_service.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/service/svg_service.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:http/http.dart' as http; import 'package:url_launcher/url_launcher.dart'; import 'package:webview_flutter/webview_flutter.dart'; import '../../customAppBar/customFooter.dart'; import '../../customAppBar/responsive.dart'; import '../../customAppBar/tabs.dart'; import '../../customAppBar/toastHelper.dart'; import '../service/BlinkingCard.dart'; import '../service/popup_widget.dart'; import '../service/SessionManager.dart'; import '../service/TokenService.dart'; import '../service/data_manager.dart'; import '../service/popup_helper.dart'; // import 'dart:js' as js; // import 'dart:html' as html; import 'package:carousel_slider/carousel_slider.dart'; import '/pages/helpers/botman_stub.dart' if (dart.library.html) '/pages/helpers/botman_web.dart'; import '/../pages/helpers/mobile_helpers.dart' if (dart.library.html) '/../pages/helpers/web_helpers.dart'; import 'package:webview_flutter_android/webview_flutter_android.dart'; import 'package:carousel_slider/carousel_slider.dart'; import 'package:nhance_app_pwa/logger.dart'; class Home extends StatefulWidget { const Home({Key? key}) : super(key: key); @override State createState() => _HomeState(); } class _HomeState extends State { final CarouselSliderController _carouselController = CarouselSliderController(); bool _dialogShown = false; bool isLoadingGif = false; bool showProfileAlert = false; late ApiService apiService; int _currentIndex = 0; bool isActive = true; dynamic _token; dynamic empCodeString; dynamic empName; dynamic empPrimaryId; dynamic client_id; dynamic emailId; List policyList = []; List retailPolicyDetails = []; dynamic activePoliciesDetails; dynamic policyDataIsEmpty = 1; dynamic policyHeading; dynamic policyName; dynamic EmployeePolicy; dynamic emp_name; dynamic pre_policy_count; dynamic emp_not_enrolled_count; dynamic wellnessURL; dynamic client_branch_id; dynamic mobileNo; List advertisementImages = []; bool isLoading = true; int currentIndex = 0; int displayIndex = 0; bool isRetailLoggedIn = false; // dynamic policyCount; bool isTokenAvailable = false; // Default: button disabled void _onTabChanged(int index) { setState(() { _currentIndex = index; }); } final session = SessionManager(); final dataManager = DataManager(); late final WebViewController _controller; dynamic selfDetails; @override void initState() { super.initState(); apiService = ApiService(context); // Initialize ApiService here dataManager.init(apiService); if (session.client_id == null || session.client_id!.isEmpty || session.empCodeString == null || session.empCodeString!.isEmpty || session.empClientBranchId == null || session.empClientBranchId!.isEmpty) { setState(() { isRetailLoggedIn = true; }); } _loadToken(); // if (kIsWeb) { getAdvertisementSliderImage(); // } else { // advertisementImages = DataManager().advertisementImages; // } if(!isRetailLoggedIn){ checkEnrollToken(); // 🔹 Load ads // dataManager.loadAdvertisementImages(); // Load self profile → AFTER loading, check mobile number dataManager .loadSelfEmployeeProfile( clientId: session.client_id!, empCode: session.empCodeString!, clientBranchId: session.empClientBranchId!, ) .then((_) { final selfDetails = dataManager.selfProfile; final mobile = selfDetails?["mobile"]?.toString().trim() ?? ''; setState(() { showProfileAlert = mobile.isEmpty; }); }); logDebug('starts'); logDebug(advertisementImages); logDebug('Ends'); // // 🔹 Load policies (Active ones) // activePoliciesDetails = dataManager.loadPolicies( // clientId: session.client_id, // empCode: session.empCodeString, // status: "Active", // clientBranchId: session.empClientBranchId, // mobileNo: session.mobileNo ?? '', // ); // // logDebug('activePoliciesDetails'); // logDebug(activePoliciesDetails); // if (kIsWeb) { // openBotmanChat(); // } } } @override void dispose() { super.dispose(); } // void openBotmanChat() { // logDebug('openBotmanChat'); // if (kIsWeb) { // js.context // .callMethod('openBotmanChat'); // Correct way to call JS function // } // } // // void repositionBotman() { // if (kIsWeb) { // js.context.callMethod('repositionBotmanWidget'); // } // } void _showBackConfirmationDialog() { _dialogShown = true; showDialog( context: context, builder: (context) => AlertDialog( title: Text("Confirm"), content: Text("Do you want to logout?"), actions: [ TextButton( onPressed: () { context.pop(); // Close dialog _dialogShown = false; }, child: Text("Cancel"), ), TextButton( onPressed: () { // Logout logic here context.pop(); // Close dialog _logoutAndRedirect(); }, child: Text("Logout"), ), ], ), ); } void _logoutAndRedirect() { // Clear session if any // Navigate to login page context.go('/login'); } Future checkEnrollToken() async { final preToken = TokenService.getPreToken(); logDebug('preToken'); logDebug(preToken); setState(() { isTokenAvailable = preToken != null; }); } // void _loadChatbot() async { // String chatbotHtml = await DefaultAssetBundle.of(context) // .loadString("assets/botman_chat.html"); // _controller.loadUrl(Uri.dataFromString(chatbotHtml, // mimeType: 'text/html', encoding: Encoding.getByName('utf-8')) // .toString()); // } Future _loadToken() async { logDebug('_loadToken'); final String? token = await TokenService.getPostToken(); if (token != null && token.isNotEmpty) { // Decode the JWT token received from the API response Map? decodedToken = Jwt.parseJwt(token); logDebug(decodedToken); mobileNo = session.mobileNo ?? ''; client_branch_id = session.empClientBranchId ?? null; empCodeString = session.empCodeString?? null; empName = session.gpaEmpName?? null; logDebug(empCodeString); // Check if emp_code is correct empPrimaryId = session.empPrimaryId?? null; client_id = session.client_id?? null; logDebug(client_id); emailId = session.empEmailCorporate?? null; // getAdvertisementSliderImage(); getActiveAndInactivePolicyDetails('Active'); } } Future getActiveAndInactivePolicyDetails(String status) async { logDebug(getActiveAndInactivePolicyDetails); // if (client_id == null || empCodeString == null) { // return; // } setState(() { isLoadingGif = true; }); logDebug('check 1'); final response = await apiService.getActiveAndInactivePolicyDetails( client_id, empCodeString, status, client_branch_id, mobileNo,emailId); logDebug('check 1'); setState(() { isLoadingGif = false; }); if (response['status'] == 'success') { emp_name = response['emp_name']; policyList = List.from(response['data'] ?? []); retailPolicyDetails = List.from(response['retail_policy_data'] ?? []); logDebug('policyList $policyList'); pre_policy_count = response['pre_policy_count'] ?? ''; final empNotEnrolledCount = response['emp_not_enrolled_count'] ?? ''; final wellnessStatus = response['wellness_data']['status'] ?? 'failed'; logDebug('wellnessStatus $wellnessStatus'); if (wellnessStatus == 'success') { wellnessURL = response['wellness_data']['data']; } setState(() { isTokenAvailable = pre_policy_count != 0; emp_not_enrolled_count = empNotEnrolledCount != 0; }); if (emp_not_enrolled_count) { final prefs = await SharedPreferences.getInstance(); bool? cancelFlag = prefs.getBool('cancel_flag'); logDebug('cancelFlag $cancelFlag'); // Show popup only when flag is NOT true if (cancelFlag != true) { showBlurPopup(context, emp_name); } } logDebug(policyList); } else { setState(() { policyDataIsEmpty = 0; }); logDebug('API request failed with status: ${response['status']}'); } } Future getAdvertisementSliderImage() async { final response = await apiService.getAdvertisementImageToApi(session.client_id); logDebug('check 1'); if (response['status'] == 'success') { setState(() { advertisementImages = List.from(response['data']); logDebug('advertisementImages'); logDebug(advertisementImages); isLoading = false; }); // logDebug(policyList); } else { logDebug('API request failed with status: ${response['status']}'); setState(() { isLoading = false; }); } } String formatToCroresLakhsAndThousands(String value) { double numValue = double.parse(value); if (numValue >= 10000000) { return "₹ ${(numValue / 10000000).toStringAsFixed(2)} Crores"; } else if (numValue >= 100000) { return "₹ ${(numValue / 100000).toStringAsFixed(2)} Lakhs"; } else if (numValue >= 1000) { return "₹ ${(numValue / 1000).toStringAsFixed(2)} Thousands"; } else { return "₹ $numValue"; } } // String formatToCroresLakhsAndThousands(String value) { // double numValue = double.parse(value); // // if (numValue >= 10000000) { // // 1 crore is 10,000,000 // return "₹ ${(numValue / 10000000).toStringAsFixed(0)} Crores"; // } else if (numValue >= 100000) { // // 1 lakh is 100,000 // return "₹ ${(numValue / 100000).toStringAsFixed(0)} Lakhs"; // } else if (numValue >= 1000) { // // 1 thousand is 1,000 // return "₹ ${(numValue / 1000).toStringAsFixed(0)} Thousands"; // } else { // return "₹ $numValue"; // This handles the case where value is less than 1 thousand // } // } String generateSessionId([int length = 15]) { const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; final random = Random.secure(); return List.generate( length, (index) => characters[random.nextInt(characters.length)]) .join(); } void _showExitConfirmation(BuildContext context) { double myheight = MediaQuery.of(context).size.height; showDialog( context: context, barrierDismissible: false, // User must tap a button to dismiss dialog builder: (dialogContext) => AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(5.0), // Rounded corners ), backgroundColor: Colors.white, contentPadding: EdgeInsets.zero, title: Text( 'Log Out Confirmation', textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.black, ), ), content: Padding( padding: const EdgeInsets.all(20.0), child: Text( 'Are you sure you want to log out?', textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 18, color: Color(0xFF898C81), ), ), ), actions: [ Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, // Space buttons evenly children: [ SizedBox( width: MediaQuery.of(context).size.width * 0.3, // Set button width child: TextButton( onPressed: () => Navigator.pop(dialogContext), style: TextButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), ), side: BorderSide( color: Color(0xFFE26728), // Border color width: 1, ), ), child: Text( 'Cancel', style: GoogleFonts.poppins( color: Color(0xFFE26728), fontSize: 16, ), ), ), ), SizedBox( width: MediaQuery.of(context).size.width * 0.3, // Set button width child: TextButton( onPressed: () => TokenService().logout(context), style: TextButton.styleFrom( backgroundColor: Color(0xFFE26728), // Background color foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), ), ), child: FittedBox( fit: BoxFit.scaleDown, // Prevents wrapping while adjusting text size child: Text( 'Log Out', style: GoogleFonts.poppins( color: Colors.white, fontSize: 16, ), textAlign: TextAlign.center, ), ), ), ), ], ), SizedBox(height: 10), // Add spacing below buttons ], ), ); } @override Widget build(BuildContext context) { if (!Responsive.isDesktop(context)) SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( statusBarColor: Color(0xFFFFFBDE), // Status bar color statusBarIconBrightness: Brightness.dark, // Light icons for status bar )); return PopScope( canPop: false, onPopInvokedWithResult: (didPop, result) { if (didPop) return; _showExitConfirmation(context); }, child: Scaffold( backgroundColor: Colors.white, appBar: CustomAppBar(), body: Stack(children: [ SingleChildScrollView( child: Container( padding: Responsive.isDesktop(context) ? EdgeInsets.symmetric( horizontal: MediaQuery.of(context).size.width * 0.2, // 30% of screen width as horizontal padding vertical: MediaQuery.of(context).size.height * 0.03, // 5% of screen height as vertical padding ) : EdgeInsets.all(15), color: Colors.white, child: Column(children: [ // Card( // elevation: 2, // color: Color(0xFFDDF3FF), // shape: RoundedRectangleBorder( // borderRadius: // BorderRadius.circular(10), // Set the border radius here // ), // child: ClipRRect( // borderRadius: BorderRadius.circular( // 10), // Apply border radius to the container // child: Column( // children: [ // Container( // decoration: BoxDecoration( // color: Color( // 0xFFDDF3FF), // Set background color for the container // borderRadius: BorderRadius.circular( // 10), // Set border radius for the container // ), // padding: Responsive.isDesktop(context) // ? EdgeInsets.only( // top: 10, bottom: 10, left: 10, right: 10) // : EdgeInsets.only( // top: 10, bottom: 10, left: 10, right: 10), // child: Row( // crossAxisAlignment: CrossAxisAlignment.center, // children: [ // Expanded( // flex: 7, // child: Row( // mainAxisAlignment: MainAxisAlignment.start, // children: [ // Text( // 'Update Mobile Number', // textAlign: TextAlign.center, // style: GoogleFonts.poppins( // fontSize: // Responsive.isDesktop(context) ? 18 : 12, // fontWeight: FontWeight.w500, // color: Color(0xFF404040), // ), // ).animate( // delay: 1000.ms, // this delay only happens once at the very start // onPlay: (controller) => controller.repeat(), // loop // ).fadeIn(delay: 500.ms) // inherits the delay & duration from move // ], // ), // ), // Expanded( // flex: 5, // child: Row( // mainAxisAlignment: MainAxisAlignment.end, // children: [ // ElevatedButton( // onPressed: showProfileAlert // ? () { // // } // : null, // child: Text('View Details'), // ), // ], // ), // ), // ], // ), // ), // ], // ), // ), // ), Container( child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 12, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text( 'Hello, $emp_name!', textAlign: TextAlign.left, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 20 : 20, fontWeight: FontWeight.w500, color: Color(0xFF000000), ), ), ], ), // Text( // 'Lorem ipsum dolor sit amet', // textAlign: TextAlign.left, // style: GoogleFonts.poppins( // fontSize: // Responsive.isDesktop(context) ? 12 : 14, // fontWeight: FontWeight.w400, // color: Color(0xFF7A7A7A), // ), // ), ], ))), ], ), ), if (showProfileAlert) BlinkingCard( onUpdated: () { setState(() { dataManager .loadSelfEmployeeProfile( clientId: session.client_id!, empCode: session.empCodeString!, clientBranchId: session.empClientBranchId!, ) .then((_) { final selfDetails = dataManager.selfProfile; final mobile = selfDetails?["mobile"]?.toString().trim() ?? ''; setState(() { showProfileAlert = mobile.isEmpty; }); }); }); }, ), SizedBox(height: 15), if(!isRetailLoggedIn && isTokenAvailable) Card( elevation: 2, color: Color(0xFFDDF3FF), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), // Set the border radius here ), child: ClipRRect( borderRadius: BorderRadius.circular( 10), // Apply border radius to the container child: Column( children: [ Container( decoration: BoxDecoration( color: Color(0xFFDDF3FF), // Set background color for the container borderRadius: BorderRadius.circular( 10), // Set border radius for the container ), padding: Responsive.isDesktop(context) ? EdgeInsets.only( top: 10, bottom: 10, left: 10, right: 10) : EdgeInsets.only( top: 10, bottom: 10, left: 10, right: 10), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( flex: 7, child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Text( 'Policies for enrollment : $pre_policy_count', textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 18 : 12, fontWeight: FontWeight.w500, color: Color(0xFF404040), ), ), ], ), ), Expanded( flex: 5, child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ ElevatedButton( onPressed: isTokenAvailable ? () { context.go('/empDetails'); } : null, child: Text('View Details'), ), ], ), ), ], ), ), ], ), ), ), SizedBox(height: 15), if (advertisementImages != null) Container( child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 12, child: Container( alignment: Alignment.centerLeft, child: advertisementImages.isEmpty ? Center(child: Text("No images available")) : Container( child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 12, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( child: ImageSlideshow( /// Width of the [ImageSlideshow]. width: double.infinity, /// Height of the [ImageSlideshow]. height: Responsive.isDesktop( context) ? 200 : 150, /// The page to show when first creating the [ImageSlideshow]. initialPage: 0, /// The color to paint the indicator. indicatorColor: Color(0xFFE26728), /// The color to paint behind the indicator. indicatorBackgroundColor: Colors.grey, /// The widgets to display in the [ImageSlideshow]. children: advertisementImages .map( (imageUrl) => ClipRRect( borderRadius: BorderRadius .circular( 8), child: Image .network( imageUrl, fit: BoxFit .cover, ), ), ) .toList(), /// Called whenever the page in the center of the viewport changes. onPageChanged: (value) { logDebug( 'Page changed: $value'); }, /// Auto scroll interval. /// Do not auto scroll with null or 0. autoPlayInterval: 3000, /// Loops back to the first slide. isLoop: true, ), ), ], ), ), ), ], ), ), ), ), ], ), ), SizedBox(height: 15), Container( child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 12, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text( 'Your Policies', textAlign: TextAlign.left, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 18 : 18, fontWeight: FontWeight.w500, color: Color(0xFF000000), ), ), ], ), // Text( // 'Lorem ipsum dolor sit amet', // textAlign: TextAlign.left, // style: GoogleFonts.poppins( // fontSize: // Responsive.isDesktop(context) ? 12 : 14, // fontWeight: FontWeight.w400, // color: Color(0xFF7A7A7A), // ), // ), ], ))), ], ), ), SizedBox(height: 15), Container( decoration: BoxDecoration( color: Color(0xFFEEF5FF), // Set background color for the container borderRadius: BorderRadius.circular( 5), // Set border radius for the container ), padding: Responsive.isDesktop(context) ? EdgeInsets.only( top: 10, bottom: 10, left: 25, right: 25) : EdgeInsets.only( top: 10, bottom: 10, left: 10, right: 10), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( flex: 12, child: Container( alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( flex: 6, child: Container( alignment: Alignment.center, child: GestureDetector( onTap: () { setState(() { isActive = true; policyList.clear(); }); getActiveAndInactivePolicyDetails( 'Active'); }, child: isActive ? Material( elevation: 5, borderRadius: BorderRadius.circular( 10), color: Colors.white, child: SizedBox( width: Responsive .isDesktop( context) ? 400 : 150, // Set the width here child: TextButton( onPressed: () {}, style: TextButton .styleFrom( padding: EdgeInsets .symmetric( vertical: Responsive .isDesktop( context) ? 12 : 5, ), ), child: Text( 'Active', style: GoogleFonts .poppins( fontSize: Responsive .isDesktop( context) ? 18 : 13, fontWeight: FontWeight .w500, color: Color( 0xFF593AFF), ), ), ), ), ) : Text( 'Active', style: GoogleFonts.poppins( fontSize: Responsive .isDesktop( context) ? 18 : 13, fontWeight: FontWeight.w400, color: Color(0xFF636363), ), ), ), )), Expanded( flex: 6, child: Container( alignment: Alignment.center, child: GestureDetector( onTap: () { setState(() { isActive = false; policyList.clear(); retailPolicyDetails.clear(); }); getActiveAndInactivePolicyDetails( 'Inactive'); }, child: !isActive ? Material( elevation: 5, borderRadius: BorderRadius.circular( 10), color: Colors.white, child: SizedBox( width: Responsive .isDesktop( context) ? 400 : 150, // Set the width here child: TextButton( onPressed: () {}, style: TextButton .styleFrom( padding: EdgeInsets .symmetric( vertical: Responsive .isDesktop( context) ? 12 : 5, ), ), child: Text( 'Inactive', style: GoogleFonts .poppins( fontSize: Responsive .isDesktop( context) ? 18 : 13, fontWeight: FontWeight .w500, color: Color( 0xFF593AFF), ), ), ), ), ) : Text( 'Inactive', style: GoogleFonts.poppins( fontSize: Responsive .isDesktop( context) ? 18 : 13, fontWeight: FontWeight.w400, color: Color(0xFF636363), ), ), ), )) ], ) ], ))), ], ), ), SizedBox(height: 15), // if (policyList != null && policyList.length > 0) Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ buildCarousel() // ...generateCards(policyList) // CarouselSlider( // options: CarouselOptions( // aspectRatio: 2.0, // enlargeCenterPage: true, // enableInfiniteScroll: false, // 👈 NO LOOP // initialPage: 2, // 👈 START FROM MIDDLE // autoPlay: false, // ), // items: imgList.map((item) { // return Container( // width: double.infinity, // decoration: BoxDecoration( // image: DecorationImage( // image: NetworkImage(item), // fit: BoxFit.cover, // ), // ), // ); // }).toList(), // ), ], ), SizedBox(height: 15), if (wellnessURL != null && wellnessURL.toString().isNotEmpty && isActive) Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [_buildWellnessCard()], ), SizedBox(height: Responsive.isDesktop(context) ? 40 : 70), ]), )), // Positioned( // bottom: 25, // right: 15, // child: GestureDetector( // onTap: () async { // // Navigator.of(context).push( // // MaterialPageRoute(builder: (context) => const ChatPage()), // // ); // final sessionId = generateSessionId(); // final SharedPreferences prefs = await SharedPreferences.getInstance(); // final empClientBranchId = prefs.getString('empClientBranchId') ?? ''; // final empCodeString = prefs.getString('empCode') ?? ''; // final empPrimaryId = prefs.getString('empPrimaryId') ?? ''; // final client_id = prefs.getString('client_id') ?? ''; // final gpaEmpName = prefs.getString('gpaEmpName') ?? ''; // // logDebug('param check from home'); // logDebug(gpaEmpName); // logDebug(empCodeString); // logDebug(empClientBranchId); // logDebug(client_id); // logDebug(empPrimaryId); // // Navigator.of(context).push( // MaterialPageRoute( // builder: (context) => BotmanChatScreen( // // builder: (context) => ChatPage( // sessionId: sessionId, // employeeId: empPrimaryId, // empCode: empCodeString, // clientId: client_id, // clientBranchId: empClientBranchId, // empName: gpaEmpName, // ), // ), // ); // // }, // child: Container( // width: 60, // height: 60, // decoration: BoxDecoration( // color: Colors.blue, // borderRadius: BorderRadius.circular(30), // boxShadow: [ // BoxShadow( // color: Colors.black26, // blurRadius: 5, // offset: Offset(2, 2), // ), // ], // ), // alignment: Alignment.center, // child: const Icon( // Icons.chat, // you can change this to any icon you like // color: Colors.white, // size: 20, // ), // ), // ), // ), if (isLoadingGif) Container( color: Color(0x98FFFCE5), // Semi-transparent background child: Center( child: // Your GIF loader widget Image.asset( height: 60, width: 60, 'assets/nhance-loader.gif'), // Adjust path to your GIF loader ), ), if (Responsive.isDesktop(context)) Align( alignment: Alignment.bottomCenter, child: Container( width: double.infinity, // Make the footer full width child: CustomFooter(), ), ), ]), // floatingActionButton: Responsive.isDesktop(context) // ? null // : FloatingActionButton( // // onPressed: () => push(chatbot()), // onPressed: () => { // // Navigator.push( // // context, // // MaterialPageRoute( // // builder: (context) => MyWebViewPage( // // url: 'https://venbait.in/nhance/dev/chatbot?employee_id=${empPrimaryId}&emp_code=${empCodeString}&origin=mob&name=${empName}&client_id=${client_id}&client_branch_id=${client_branch_id}', // // ), // // ), // // ) // // context.go( // // '/chatbot', // // extra: { // // 'client_branch_id': client_branch_id, // // 'empCodeString': empCodeString, // // 'empName': empName, // // 'empPrimaryId': empPrimaryId, // // 'client_id': client_id, // // }, // // ) // Navigator.push( // context, // // MaterialPageRoute(builder: (context) => const BotmanChatPage()), // MaterialPageRoute( // builder: (context) => ChatbotWebViewPage( // client_branch_id: client_branch_id, // empCodeString: empCodeString, // empName: empName, // empPrimaryId: empPrimaryId, // client_id: client_id, // )), // ) // }, // child: Icon(Icons.chat), // ), floatingActionButtonLocation: Responsive.isDesktop(context) ? null : FloatingActionButtonLocation.miniEndFloat, bottomNavigationBar: Responsive.isDesktop(context) ? null : CustomBottomNavigationBar( onTabChanged: (index) { // Add your navigation logic here // repositionBotman(); if (index == 0) { context.push('/home'); } else if (index == 1) { context.push('/claims'); } else if (index == 2) { context.push('/faqs'); } else if (index == 3) { context.push('/profile'); } else if (index == 4) { context.push('/help'); } // else if (index == 4) { // // context.push('/wellness'); // // Wellness tab clicked → show popup // if(!isRetailLoggedIn) // PopupHelper.showRedirectPopup( // context: context, // apiService: apiService, // empPrimaryId: session.empPrimaryId, // ); // } }, icons: [ Icons.home_outlined, Icons.sticky_note_2_outlined, Icons.question_answer_outlined, Icons.person_outline_outlined, Icons.headset_mic_outlined, ], labels: ["Home", "Claims", "FAQs", "Profile","Help"], initialIndex: 0, // Initial index of the bottom navigation bar ), )); } // String getMemberNames(List employeePolicy) { // List names = []; // for (var member in employeePolicy) { // if (member['name'] != null) { // names.add(member['name']); // } // } // return names.join(' ~ '); // } String formatMemberNames(List memberList) { if (memberList.isEmpty) return ""; // Extract only the names List names = memberList .map((item) => item["name"]?.toString() ?? "") .where((name) => name.isNotEmpty) .toList(); if (names.length <= 2) { return names.join(" ~ "); } final remaining = names.length - 2; return "${names[0]} ~ ${names[1]} ~ + $remaining Members"; } // List generateCards(List data) { // logDebug('generateCards'); // logDebug(data); // return [ // GridView.builder( // shrinkWrap: true, // physics: NeverScrollableScrollPhysics(), // gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( // crossAxisCount: Responsive.isDesktop(context) ? 2 : 1, // crossAxisSpacing: 20.0, // mainAxisSpacing: 20.0, // childAspectRatio: Responsive.isDesktop(context) ? 2.2 : 2.6), // itemCount: data.length, // itemBuilder: (BuildContext context, int index) { // var item = data[index]; // String policyHeading = item['heading']; // String policyName = item['policy_name']; // // String si_value = item['si_value']; // String siValueStr = item['si_value'] ?? '0'; // String settledStr = item['total_settled_amount']?.toString() ?? '0'; // // double siValue = double.tryParse(siValueStr) ?? 0; // double settled = double.tryParse(settledStr) ?? 0; // // // Main logic // double finalValue = (settled == 0) ? siValue : (siValue - settled); // // logDebug("Final Value: $finalValue"); // String policyEndDate = item['policy_end_date']; // List employeePolicy = item['EmployeePolicy']; // String memberNames = getMemberNames(employeePolicy); // // DateTime parsedDate = DateFormat('dd-MMM-yyyy').parse(policyEndDate); // String formattedDate = DateFormat('d MMM yyyy').format(parsedDate); // // return GestureDetector( // onTap: () { // context.go( // '/policies', // extra: item, // 👈 pass arguments here // ); // }, // child: MouseRegion( // cursor: SystemMouseCursors.click, // child: Card( // elevation: 5, // shape: RoundedRectangleBorder( // borderRadius: // BorderRadius.circular(15.0), // Set border radius here // ), // child: Container( // decoration: BoxDecoration( // color: Colors.white, // Set background color to white // borderRadius: BorderRadius.circular( // 15.0), // Set border radius for Container // ), // padding: Responsive.isDesktop(context) // ? EdgeInsets.only( // top: 15, bottom: 15, left: 15, right: 15) // : EdgeInsets.only( // top: 10, // bottom: 10, // left: 10, // right: 10), // Add padding to the container // child: Row( // children: [ // Expanded( // flex: 12, // child: Container( // alignment: Alignment.centerLeft, // child: Column( // mainAxisAlignment: MainAxisAlignment.start, // crossAxisAlignment: // CrossAxisAlignment.start, // children: [ // Row( // children: [ // Expanded( // flex: 7, // child: Column( // crossAxisAlignment: // CrossAxisAlignment.start, // children: [ // Text( // policyHeading ?? '', // textAlign: TextAlign.left, // style: GoogleFonts.poppins( // fontSize: // Responsive.isDesktop( // context) // ? 10 // : 10, // fontWeight: FontWeight.w400, // color: Color(0xFF785EFF), // ), // ), // ], // ), // ), // Expanded( // flex: 5, // child: Column( // crossAxisAlignment: // CrossAxisAlignment.end, // children: [ // Text( // 'Expires on $formattedDate', // textAlign: TextAlign.right, // style: GoogleFonts.poppins( // fontSize: // Responsive.isDesktop( // context) // ? 10 // : 10, // fontWeight: FontWeight.w400, // color: Color(0xFF747474), // ), // ), // ], // ), // ), // ], // ), // SizedBox(height: 7), // Row( // children: [ // Expanded( // flex: 6, // child: Column( // crossAxisAlignment: // CrossAxisAlignment.start, // children: [ // Text( // policyName ?? '', // textAlign: TextAlign.left, // style: GoogleFonts.poppins( // fontSize: // Responsive.isDesktop( // context) // ? 14 // : 13, // fontWeight: FontWeight.w500, // color: Color(0xFF000000), // ), // ), // ], // ), // ), // Expanded( // flex: 5, // child: Column( // crossAxisAlignment: // CrossAxisAlignment.end, // children: [ // Text( // formatToCroresLakhsAndThousands( // siValueStr), // textAlign: TextAlign.left, // style: GoogleFonts.poppins( // fontSize: // Responsive.isDesktop( // context) // ? 14 // : 13, // fontWeight: FontWeight.w500, // color: Color(0xFF000000), // ), // ), // ], // ), // ), // Expanded( // flex: 1, // child: Container( // alignment: // Alignment.centerRight, // child: Icon( // Icons.chevron_right, // color: Color( // 0xFFE26728), // Replace with your desired icon // size: Responsive.isDesktop( // context) // ? 30 // : 26, // ), // )) // ], // ), // SizedBox(height: 7), // Row( // children: [ // Expanded( // flex: 12, // child: Column( // crossAxisAlignment: // CrossAxisAlignment.start, // children: [ // Text( // memberNames ?? '', // textAlign: TextAlign.left, // style: GoogleFonts.poppins( // fontSize: // Responsive.isDesktop( // context) // ? 14 // : 13, // fontWeight: FontWeight.w400, // color: Color(0xFF000000), // ), // ), // ], // ), // ), // ], // ), // SizedBox(height: 20), // Row( // children: [ // Expanded( // flex: 12, // child: Column( // crossAxisAlignment: // CrossAxisAlignment.end, // children: [ // Text( // 'Remaining Amount: ${finalValue}', // textAlign: TextAlign.right, // style: GoogleFonts.poppins( // fontSize: // Responsive.isDesktop( // context) // ? 10 // : 10, // fontWeight: FontWeight.w400, // color: Color(0xFF747474), // ), // ), // ], // ), // ), // ], // ), // // SizedBox(height: 7), // ], // ))), // ], // ), // ), // ))); // }, // ), // ]; // } // Widget _creditCardDesign({ // required String policyHeading, // required String policyName, // required String siValue, // required String memberNames, // required String expiresOn, // required double remainingAmount, // }) { // return Container( // width: double.infinity, // margin: const EdgeInsets.symmetric(vertical: 8), // padding: const EdgeInsets.all(15), // decoration: BoxDecoration( // color: const Color(0xFFF4F8FF), // Light background like image // borderRadius: BorderRadius.circular(16), // ), // child: Row( // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // // ======================= // // LEFT LOGO // // ======================= // Container( // height: 50, // width: 50, // decoration: BoxDecoration( // color: Colors.white, // borderRadius: BorderRadius.circular(12), // boxShadow: [ // BoxShadow( // color: Colors.black12, // blurRadius: 4, // offset: Offset(0, 2), // ) // ], // ), // child: Center( // child: Image.asset( // "assets/company_logo.png", // <--- change logo here // height: 35, // fit: BoxFit.contain, // ), // ), // ), // // const SizedBox(width: 15), // // // ======================= // // RIGHT SIDE CONTENT // // ======================= // Expanded( // child: Column( // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // // 🔹 Small category heading // Text( // "• Health Insurance", // style: GoogleFonts.poppins( // fontSize: 11, // color: const Color(0xFF5370F0), // fontWeight: FontWeight.w500, // ), // ), // // const SizedBox(height: 5), // // // 🔹 Main title (SI + policy name) // Text( // "${formatToCroresLakhsAndThousands(siValue)} health policy", // style: GoogleFonts.poppins( // fontSize: 15, // fontWeight: FontWeight.w600, // color: Colors.black, // ), // ), // // const SizedBox(height: 5), // // // 🔹 Members // Text( // memberNames, // style: GoogleFonts.poppins( // fontSize: 13, // color: Colors.black87, // ), // ), // // const SizedBox(height: 10), // // // 🔹 Expires On // Text( // "Expires on $expiresOn", // style: GoogleFonts.poppins( // fontSize: 11, // color: Colors.black54, // ), // ), // ], // ), // ), // // const SizedBox(width: 10), // // // ======================= // // ARROW ICON // // ======================= // Icon( // Icons.chevron_right, // color: const Color(0xFF5370F0), // size: 24, // ), // ], // ), // ); // } // List generateCardWidgets(List data, BuildContext context) { // return data.map((item) { // String policyHeading = item['heading']; // String policyName = item['policy_name']; // String siValueStr = item['si_value'] ?? '0'; // String settledStr = item['total_settled_amount']?.toString() ?? '0'; // // double siValue = double.tryParse(siValueStr) ?? 0; // double settled = double.tryParse(settledStr) ?? 0; // // double finalValue = (settled == 0) ? siValue : (siValue - settled); // // String policyEndDate = item['policy_end_date']; // List employeePolicy = item['EmployeePolicy']; // String memberNames = getMemberNames(employeePolicy); // // DateTime parsedDate = DateFormat('dd-MMM-yyyy').parse(policyEndDate); // String formattedDate = DateFormat('d MMM yyyy').format(parsedDate); // // return GestureDetector( // onTap: () { // context.go( // '/policies', // extra: item, // ); // }, // child: MouseRegion( // cursor: SystemMouseCursors.click, // child: Card( // elevation: 5, // shape: RoundedRectangleBorder( // borderRadius: BorderRadius.circular(15.0), // ), // child: Container( // padding: const EdgeInsets.all(15), // decoration: BoxDecoration( // color: Colors.white, // borderRadius: BorderRadius.circular(15.0), // ), // child: _buildCardContent( // context, // policyHeading, // formattedDate, // policyName, // siValueStr, // memberNames, // finalValue, // ), // ), // ), // ), // ); // }).toList(); // } // // Widget _buildCardContent( // BuildContext context, // String policyHeading, // String formattedDate, // String policyName, // String siValueStr, // String memberNames, // double finalValue, // ) { // return Column( // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // Row( // mainAxisAlignment: MainAxisAlignment.spaceBetween, // children: [ // Text( // policyHeading, // style: GoogleFonts.poppins( // fontSize: 10, // fontWeight: FontWeight.w400, // color: Color(0xFF785EFF), // ), // ), // Text( // 'Expires on $formattedDate', // style: GoogleFonts.poppins( // fontSize: 10, // fontWeight: FontWeight.w400, // color: Color(0xFF747474), // ), // ), // ], // ), // // const SizedBox(height: 7), // // Row( // children: [ // Expanded( // flex: 6, // child: Text( // policyName, // style: GoogleFonts.poppins( // fontSize: 14, // fontWeight: FontWeight.w500, // color: Color(0xFF000000), // ), // ), // ), // Expanded( // flex: 5, // child: Text( // formatToCroresLakhsAndThousands(siValueStr), // textAlign: TextAlign.right, // style: GoogleFonts.poppins( // fontSize: 14, // fontWeight: FontWeight.w500, // color: Color(0xFF000000), // ), // ), // ), // const Icon(Icons.chevron_right, color: Color(0xFFE26728), size: 28), // ], // ), // // const SizedBox(height: 7), // // Text( // memberNames, // style: GoogleFonts.poppins( // fontSize: 13, // fontWeight: FontWeight.w400, // color: Color(0xFF000000), // ), // ), // // const SizedBox(height: 20), // // Align( // alignment: Alignment.centerRight, // child: Text( // "Remaining Amount: $finalValue", // style: GoogleFonts.poppins( // fontSize: 10, // color: Color(0xFF747474), // ), // ), // ), // ], // ); // } // List generateCardWidgets(BuildContext context) { return policyList.map((item) { String policyHeading = item['heading']; String policyName = item['policy_name']; String policyType = item['policy_type']; String sumInsuredLabel = item['sum_insured_label']; String siValueStr = item['si_value'] ?? '0'; String settledStr = item['total_settled_amount']?.toString() ?? '0'; double siValue = double.tryParse(siValueStr) ?? 0; double settled = double.tryParse(settledStr) ?? 0; // double finalValue = (settled == 0) ? settled : (siValue - settled); double finalValue = (settled == 0) ? siValue : (siValue - settled); String policyEndDate = item['policy_end_date']; List employeePolicy = item['EmployeePolicy']; logDebug('employeePolicy $employeePolicy'); String memberNames = formatMemberNames(employeePolicy); DateTime parsedDate = DateFormat('dd-MMM-yyyy').parse(policyEndDate); String formattedDate = DateFormat('d MMM yyyy').format(parsedDate); return GestureDetector( onTap: () { context.push('/policies', extra: item); }, child: MouseRegion( cursor: SystemMouseCursors.click, child: _creditCardDesign( policyHeading: policyHeading, policyName: policyName, siValue: siValueStr, memberNames: memberNames, expiresOn: formattedDate, remainingAmount: finalValue, sumInsuredLabel: sumInsuredLabel, policyType: policyType, ), ), ); }).toList(); } Widget buildCarousel() { final List cards = []; // ========================================== // CASE 1: Retail logged in → Show ONLY retail cards // ========================================== if (isRetailLoggedIn == true) { for (var retail in retailPolicyDetails) { cards.add( GestureDetector( onTap: () { logDebug("Retail policy clicked: ${retail['policy_no']}"); }, child: _buildRetailPolicyCard(retail), ), ); } return _buildCarouselSlider(cards); // return without add-card } // ========================================== // CASE 2: Normal flow → Add policy cards // ========================================== if (policyList.isNotEmpty) { cards.addAll(generateCardWidgets(context)); } // final cards = generateCardWidgets(data, context); // ====================== // ADD RETAIL POLICIES // ====================== if (retailPolicyDetails.isNotEmpty) { for (var retail in retailPolicyDetails) { cards.add( GestureDetector( onTap: () { // TODO: navigate to retail policy details page logDebug("Retail policy clicked: ${retail['policy_no']}"); }, child: _buildRetailPolicyCard(retail), ), ); } } // // ====================== // // ADD WELLNESS CARD // // ====================== // if (wellnessURL != null && wellnessURL.toString().isNotEmpty) { // cards.add(_buildWellnessCard()); // <-- add card // } // ====================== // ADD EMPTY "ADD CARD" // ====================== if(isActive){ cards.add(_buildAddCard()); // <-- always add this card } // ✅ NEW: Show empty state when inactive tab has no policies if (!isActive && cards.isEmpty) { return _buildEmptyState("No inactive policies available"); } return _buildCarouselSlider(cards); } Widget _buildEmptyState(String message) { return Container( width: double.infinity, margin: const EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.symmetric(vertical: 40, horizontal: 20), decoration: BoxDecoration( color: const Color(0xFFF7F7F7), borderRadius: BorderRadius.circular(20), border: Border.all(color: const Color(0xFFE0E0E0), width: 1.5), ), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.folder_off_outlined, size: 48, color: Colors.grey[400]), const SizedBox(height: 12), Text( message, textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 14, fontWeight: FontWeight.w500, color: Colors.grey[600], ), ), ], ), ); } Widget _buildCarouselSlider(List cards) { final int totalCards = cards.length; final bool hasAddCard = isActive; // because you add AddCard only when isActive final int displayCardCount = hasAddCard ? totalCards - 1 : totalCards; return Stack( alignment: Alignment.center, children: [ CarouselSlider( carouselController: _carouselController, items: cards, options: CarouselOptions( height: Responsive.isDesktop(context) ? 200 : 170, enlargeCenterPage: true, enableInfiniteScroll: false, autoPlay: false, viewportFraction: Responsive.isDesktop(context) ? 0.45 : 0.85, aspectRatio: 2.0, initialPage: 0, onPageChanged: (index, reason) { setState(() { currentIndex = index; // Counter should not include Add Policy card if (index >= displayCardCount) { displayIndex = displayCardCount - 1; } else { displayIndex = index; } }); }, ), ), // 🔵 CARD COUNTER (4/10) if(isActive && displayCardCount > 0) Positioned( bottom: 10, child: Container( padding: EdgeInsets.symmetric(horizontal: 12, vertical: 5), decoration: BoxDecoration( color: Colors.black.withOpacity(0.45), borderRadius: BorderRadius.circular(12), ), child: Text( "${displayIndex + 1} / $displayCardCount", style: TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.w600, ), ), ), ), // Arrows only on Desktop if (Responsive.isDesktop(context)) ...[ if(isActive) Positioned( left: 0, child: IconButton( icon: Icon(Icons.arrow_back_ios, color: Colors.black, size: 22), onPressed: currentIndex > 0 ? () { _carouselController.animateToPage( currentIndex - 1, duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); } : null, ), ), if(isActive) Positioned( right: 0, child: IconButton( icon: Icon(Icons.arrow_forward_ios, color: Colors.black54, size: 22), onPressed: currentIndex < cards.length - 1 ? () { _carouselController.animateToPage( currentIndex + 1, duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); } : null, ), ), ] ], ); } Widget _creditCardDesign({ required String policyHeading, required String policyName, required String siValue, required String memberNames, required String expiresOn, required double remainingAmount, required String sumInsuredLabel, required String policyType, }) { return Container( margin: const EdgeInsets.symmetric(vertical: 8), height: Responsive.isDesktop(context) ? 170 : Responsive.isTablet(context) ? 150 : 135, // You can adjust decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.15), blurRadius: 10, offset: const Offset(0, 4), ) ], ), child: ClipRRect( borderRadius: BorderRadius.circular(20), child: Stack( children: [ /// 🔵 BACKGROUND IMAGE Positioned.fill( child: Image.asset( "assets/nhance.png", // <-- REMOVE leading slash fit: BoxFit.cover, ), ), // /// 🔵 SEMI-TRANSPARENT GRADIENT OVERLAY // Positioned.fill( // child: Container( // decoration: BoxDecoration( // gradient: LinearGradient( // colors: [ // const Color(0xFF00989e).withOpacity(0.50), // 70% visible // const Color(0xFF7fcbce).withOpacity(0.70), // ], // begin: Alignment.topLeft, // end: Alignment.bottomRight, // ), // ), // ), // ), /// 🔵 MAIN CARD CONTENT Padding( padding: const EdgeInsets.all(14), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ /// 🔹 ROW 1: Policy Heading Text( policyHeading, style: GoogleFonts.poppins( fontSize: fontSize(context, 12, 14, 16), fontWeight: FontWeight.w600, color: Colors.black87, ), ), SizedBox(height: 6), /// 🔹 ROW 3: Details + SVG Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ /// LEFT TEXT BLOCK Expanded( flex: 8, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( memberNames, style: GoogleFonts.poppins( fontSize: fontSize(context, 11, 13, 14), fontWeight: FontWeight.w500, color: Colors.black87, ), ), SizedBox(height: 6), Text( "${formatToCroresLakhsAndThousands(siValue)} ($sumInsuredLabel)", style: GoogleFonts.poppins( fontSize: fontSize(context, 11, 13, 14), fontWeight: FontWeight.w600, color: Colors.black87, ), ), SizedBox(height: 6), if (remainingAmount > 0) Text( "Available: ${remainingAmount.toStringAsFixed(0)}", style: GoogleFonts.poppins( fontSize: fontSize(context, 10, 12, 13), color: Colors.black87, ), ), SizedBox(height: 6), Text( "Expires: $expiresOn", style: GoogleFonts.poppins( fontSize: fontSize(context, 10, 12, 13), color: Colors.black87, ), ), ], ), ), /// RIGHT SVG BLOCK Expanded( flex: 2, child: Align( alignment: Alignment.bottomRight, child: SizedBox( height: Responsive.isDesktop(context) ? 100 : Responsive.isTablet(context) ? 100 : 90, child: SvgPicture.string( SvgService.getSvg(_mapPolicyTypeToSvg(policyType)), fit: BoxFit.fitHeight, ), ), ), ), ], ) ], ), ) ], ), ), ); } Widget _buildWellnessCard() { return GestureDetector( onTap: () { // OPEN WELLNESS URL launchUrl(Uri.parse(wellnessURL)); }, child: Container( width: double.infinity, margin: const EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.all(18), decoration: BoxDecoration( gradient: const LinearGradient( colors: [Color(0xFFFF7E5F), Color(0xFFFFB88C)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(20), // border: Border.all(color: Color(0xFF00999E), width: 2), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 6, offset: const Offset(0, 3), ) ], ), child: Row( children: [ Icon(Icons.health_and_safety, color: Color(0xFF00999E), size: 40), const SizedBox(width: 15), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "OPD & Wellness", style: GoogleFonts.poppins( fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white, ), ), ], ), ), Icon(Icons.chevron_right, color: Color(0xFF00999E)) ], ), ), ); } Widget _buildAddCard() { return GestureDetector( onTap: () { context.go('/AddPolicyScreen'); }, child: Container( width: double.infinity, margin: const EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), border: Border.all(color: Color(0xFFFF7E5F), width: 2), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 6, offset: Offset(0, 3), ) ], ), child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Icon(Icons.add_circle_outline, color: Color(0xFFFF7E5F), size: 32), const SizedBox(width: 6), Text( "Add Policy", style: GoogleFonts.poppins( fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xFFFF7E5F), ), ), ], ), const SizedBox(height: 4), // 🔶 SUBTITLE Text( "Add and manage all your insurance policies taken anywhere for value added services and renewal reminders", maxLines: 3, softWrap: true, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w400, color: Colors.black87, ), ), ], ), ), ], ), ), ); } Widget _buildRetailPolicyCard(Map item) { return Container( margin: const EdgeInsets.symmetric(vertical: 8), height: Responsive.isDesktop(context) ? 170 : Responsive.isTablet(context) ? 150 : 135, // You can adjust decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.15), blurRadius: 10, offset: const Offset(0, 4), ) ], ), child: ClipRRect( borderRadius: BorderRadius.circular(20), child: Stack( children: [ /// 🔵 BACKGROUND IMAGE Positioned.fill( child: Image.asset( "assets/retail.png", // <-- REMOVE leading slash fit: BoxFit.cover, ), ), // /// 🔵 SEMI-TRANSPARENT GRADIENT OVERLAY // Positioned.fill( // child: Container( // decoration: BoxDecoration( // gradient: LinearGradient( // colors: [ // const Color(0xFFFF7E5F).withOpacity(0.50), // 70% visible // const Color(0xFFFFB88C).withOpacity(0.70), // ], // begin: Alignment.topLeft, // end: Alignment.bottomRight, // ), // ), // ), // ), Padding( padding: const EdgeInsets.all(14), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ /// 🔹 ROW 1: Policy Heading Text( item['policy_type_long_name'] ?? item['policy_type'], style: GoogleFonts.poppins( fontSize: fontSize(context, 12, 14, 16), fontWeight: FontWeight.w600, color: Colors.black87, ), ), SizedBox(height: 6), /// 🔹 ROW 3: Details + SVG Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ /// LEFT TEXT BLOCK Expanded( flex: 8, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item['insurer_name'] ?? "-", style: GoogleFonts.poppins( fontSize: fontSize(context, 11, 13, 14), fontWeight: FontWeight.w500, color: Colors.black87, ), ), SizedBox(height: 6), Text( "Policy No: ${item['policy_no'] ?? '-'}", style: GoogleFonts.poppins( fontSize: fontSize(context, 10, 12, 13), color: Colors.black87, ), ), SizedBox(height: 6), Text( "Expires: ${item['policy_end_date'] ?? '-'}", style: GoogleFonts.poppins( fontSize: fontSize(context, 10, 12, 13), color: Colors.black87, ), ), ], ), ), /// RIGHT SVG BLOCK Expanded( flex: 2, child: Align( alignment: Alignment.bottomRight, child: SizedBox( height: Responsive.isDesktop(context) ? 100 : Responsive.isTablet(context) ? 100 : 90, child: SvgPicture.string( SvgService.getSvg(_mapPolicyTypeToSvg(item['policy_type'])), fit: BoxFit.fitHeight, ), ), ), ), ], ) ], ), ) ], ), ), ); } String _mapPolicyTypeToSvg(String? type) { if (type == null) return 'InsuranceSvg'; // default icon switch (type.trim()) { case 'Motor': return 'motorPolicy'; case 'Householders Policy': return 'HouseholdersPolicy'; case 'Individual Health': return 'individualHealthPolicy'; case 'Individual Term Life': return 'individualTermLifePolicy'; case 'Travel Policy': return 'travelPolicy'; case 'GPA': return 'GPA'; case 'GMC': return 'GMC'; case 'GMC - Parents': return 'GMCPARENT'; case 'GMC - TOPUP': return 'InsuranceSvg'; case 'GMC - Topup(Parents)': return 'InsuranceSvg'; case 'EDLI': return 'InsuranceSvg'; case 'GTLI': return 'InsuranceSvg'; default: return 'InsuranceSvg'; // fallback } } double fontSize(BuildContext context, double mobile, double tablet, double desktop) { final width = MediaQuery.of(context).size.width; if (Responsive.isMobile(context)) return mobile; // Mobile if (Responsive.isTablet(context)) return tablet; // Tablet return desktop; // Desktop } void push(Widget page) { Navigator.of(context).push( MaterialPageRoute( builder: (BuildContext context) { return page; }, ), ); } }