import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:nhance_app_pwa/customAppBar/enrollmentAppBar.dart'; import 'package:nhance_app_pwa/pages/enrollment/service/api_service.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../customAppBar/customFooter.dart'; import '../../customAppBar/responsive.dart'; import '../../customAppBar/tabs.dart'; import '../../customAppBar/toastHelper.dart'; import 'package:jwt_decode/jwt_decode.dart'; import 'package:http/http.dart' as http; import 'package:flutter/widgets.dart'; import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; import 'dart:async'; import 'package:url_launcher/url_launcher.dart'; import '../service/SessionManager.dart'; import '../service/TokenService.dart'; import 'package:nhance_app_pwa/logger.dart'; class empDetails extends StatefulWidget { const empDetails({Key? key}) : super(key: key); @override State createState() => _empDetailsState(); } class _empDetailsState extends State { late ApiService apiService; bool isLoading = true; dynamic _token; dynamic enrollmentEmpCodeString; dynamic enrollmentEmpPrimaryId; dynamic enrollmentGpaEmpName; dynamic enrollmentClient_id; dynamic gpaPolicies; dynamic gpaPolicyName; dynamic gpaGridMaster; dynamic gpasumInsured; dynamic gpaClintPolicyId; dynamic gpaSlabRates = []; dynamic gpaMappedFamilyFloaters; dynamic gpaSelfName; dynamic gpaSelfDob; dynamic gpaSelfRelationship; dynamic gpaSelfDetails; dynamic gpaOpenForEnrollment; dynamic gpaECardDownload; dynamic gpaSumInsured; dynamic gmcPolicies; dynamic gmcSlabRates = []; dynamic getFalseObjects = []; dynamic gmcSelfName; dynamic gmcSelfDob; dynamic gmcSelfRelationship; dynamic gmcSelfDetails; dynamic gmcGridMaster; dynamic clientName; dynamic clientLogo; late TextEditingController _relationShipController; late TextEditingController _dobController; late TextEditingController _memberNameController; late DateTime? selectedDate; List> relationshipOptions = []; List> selectedRelationships = []; List> formDataList = []; late DateTime _selectedDate = DateTime.now(); // Define _selectedDate here dynamic mobileNumber; dynamic selfRelationship; dynamic selfName; dynamic selfMobile; dynamic selfDesignation; dynamic selfDob; dynamic selfDoj; dynamic selfGender; dynamic selfEmailCorporate; dynamic selfEmailPersonal; dynamic selfEmpCode; dynamic selfFamilyFloaterKey; dynamic selfEmpStatus; dynamic selfUnit; dynamic gmcDataIsEmpty = 1; dynamic gpaDataIsEmpty = 1; dynamic hrPrimaryId; dynamic empRefId; dynamic enrollmentEmpClientBranchId; bool isTokenAvailable = false; final session = SessionManager(); @override void initState() { super.initState(); apiService = ApiService(context); // Initialize ApiService here _dobController = TextEditingController(); _memberNameController = TextEditingController(); _relationShipController = TextEditingController(); _loadToken(); Future.delayed(Duration(seconds: 3), () { setState(() { isLoading = false; }); }); getTokenStatus(); } @override void dispose() { _dobController.dispose(); _memberNameController.dispose(); _relationShipController.dispose(); super.dispose(); } // Future getTokenStatus() async { // final SharedPreferences prefs = await SharedPreferences.getInstance(); // setState(() async { // isTokenAvailable = // (await TokenService.getPostToken())?.isNotEmpty ?? false; // logDebug('isTokenAvailable $isTokenAvailable'); // }); // } Future getTokenStatus() async { final token = await TokenService.getPostToken(); setState(() { isTokenAvailable = token != null && token.isNotEmpty; logDebug('isTokenAvailable $isTokenAvailable'); }); } Future _loadToken() async { logDebug('_loadToken'); final SharedPreferences prefs = await SharedPreferences.getInstance(); final String? token = await TokenService.getPreToken(); logDebug(token); if (token != null && token.isNotEmpty) { // Decode the JWT token received from the API response // Decode the JWT token received from the API response enrollmentEmpClientBranchId = session.enrollmentEmpClientBranchId; enrollmentEmpCodeString = session.enrollmentEmpCodeString; logDebug( 'enrollmentEmpCodeString : $enrollmentEmpCodeString'); // Check if emp_code is correct enrollmentEmpPrimaryId = session.enrollmentEmpPrimaryId; enrollmentGpaEmpName = session.enrollmentGpaEmpName; enrollmentClient_id = session.enrollmentClient_id; selfEmpStatus = prefs.getString('selfEmpStatus'); logDebug('client_id : $enrollmentClient_id'); final logo = await prefs.getString('clientLogo'); final name = await prefs.getString('clientName'); if (logo != null && logo.isNotEmpty && name != null && name.isNotEmpty) { setState(() { clientLogo = prefs.getString('clientLogo'); clientName = prefs.getString('clientName'); }); } else { logDebug('getClientLogoAndDetails()'); getClientLogoAndDetails(); } // Call the API when the page enters getSelfEmployeeProfile(); getGpaEmpPolicyDetails(enrollmentEmpPrimaryId); getGmcEmpPolicyDetails(enrollmentEmpPrimaryId); fetchRelationshipList(); } } // Future _loadToken() async { // logDebug('_loadToken'); // final SharedPreferences prefs = await SharedPreferences.getInstance(); // final String? token = prefs.getString('enrollToken'); // if (token != null && token.isNotEmpty) { // setState(() { // _token = token; // }); // // // Decode the JWT token received from the API response // Map? decodedToken = Jwt.parseJwt(token); // logDebug('decodedToken : $decodedToken'); // enrollmentEmpClientBranchId = // prefs.getString('enrollmentEmpClientBranchId'); // enrollmentEmpCodeString = prefs.getString('enrollmentEmpCodeString'); // logDebug( // 'enrollmentEmpCodeString : $enrollmentEmpCodeString'); // Check if emp_code is correct // enrollmentEmpPrimaryId = prefs.getString('enrollmentEmpPrimaryId'); // enrollmentGpaEmpName = prefs.getString('enrollmentGpaEmpName'); // enrollmentClient_id = prefs.getString('enrollmentClient_id'); // selfEmpStatus = prefs.getString('selfEmpStatus'); // logDebug('client_id : $enrollmentClient_id'); // // if (prefs.containsKey('clientLogo') && prefs.containsKey('clientName')) { // clientLogo = prefs.getString('clientLogo'); // clientName = prefs.getString('clientName'); // } else { // getClientLogoAndDetails(); // } // // // Call the API when the page enters // getSelfEmployeeProfile(); // getGpaEmpPolicyDetails(enrollmentEmpPrimaryId); // getGmcEmpPolicyDetails(enrollmentEmpPrimaryId); // fetchRelationshipList(); // } else { // // Token is empty or null, handle accordingly (e.g., navigate to login screen) // ToastHelper.showErrorToast(context, 'Session Out'); // context.go('/login'); // // Navigator.pushReplacementNamed(context, 'login'); // } // } Future getClientLogoAndDetails() async { try { final SharedPreferences prefs = await SharedPreferences.getInstance(); final empClientId = await session.client_id; final empClientBranchId = await session.empClientBranchId; // if (enrollmentClient_id == null || // enrollmentEmpCodeString == null || // enrollmentEmpClientBranchId == null) { // return; // } final response = await apiService.getClientLogoAndDetailsToApi( empClientId, empClientBranchId, enrollmentClient_id!, enrollmentEmpClientBranchId!); logDebug('check 1'); if (response['status'] == 'success') { if (response.containsKey('data')) { dynamic clientDetails = response['data']; final SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setString('clientLogo', clientDetails['client']['client_logo']); prefs.setString('clientName', clientDetails['client']['client_name']); setState(() { clientName = clientDetails['client']['client_name']; logDebug(clientName); clientLogo = clientDetails['client']['client_logo']; logDebug(clientLogo); }); } else { // Handle other status messages if needed logDebug('API request failed with status: ${response['status']}'); } } else { // Handle other status codes logDebug('Request failed with status: ${response['code']}'); } } catch (e) { // Handle exceptions logDebug('Exception occurred: $e'); } } Future getSelfEmployeeProfile() async { try { if (enrollmentClient_id == null || enrollmentEmpCodeString == null || enrollmentEmpClientBranchId == null) { return; } final response = await apiService.getSelfEmployeeProfileToApi( enrollmentClient_id!, enrollmentEmpCodeString!, enrollmentEmpClientBranchId!); if (response['status'] == 'success') { if (response.containsKey('data')) { setState(() { dynamic selfDetails = response['data']; logDebug(selfDetails); mobileNumber = selfDetails['relationship']; selfRelationship = selfDetails['relationship']; selfName = selfDetails['name']; selfMobile = selfDetails['mobile']; selfDesignation = selfDetails['designation']; selfDob = convertDateFormat(selfDetails['dob']); selfDoj = convertDateFormat(selfDetails['doj']); selfGender = selfDetails['gender']; selfEmailCorporate = selfDetails['email_corporate']; selfEmailPersonal = selfDetails['email_personal']; selfEmpCode = selfDetails['emp_code']; selfFamilyFloaterKey = selfDetails['family_floater_key']; // logDebug(clientDetails); selfEmpStatus = selfDetails['emp_status']; selfUnit = selfDetails['unit']; }); final SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setString('selfEmpStatus', selfEmpStatus); } else { // Handle other status messages if needed logDebug('API request failed with status: ${response['status']}'); } } else { // Handle other status codes logDebug('Request failed with status: ${response['code']}'); } } catch (e) { // Handle exceptions logDebug('Exception occurred: $e'); } } String convertDateFormat(String? date) { if (date == null || date.isEmpty) return ''; // Return empty string if date is null or empty // Parse the date string to DateTime DateTime dateTime = DateTime.parse(date); // Format the DateTime object to the desired format (DD-MM-YYYY) String formattedDate = '${dateTime.day.toString().padLeft(2, '0')}-${dateTime.month.toString().padLeft(2, '0')}-${dateTime.year}'; return formattedDate; } Future getGpaEmpPolicyDetails(enrollmentEmpPrimaryId) async { try { if (enrollmentClient_id == null || enrollmentEmpCodeString == null || enrollmentEmpClientBranchId == null) { return; } final response = await apiService.getGpaEmpPolicyDetailsToApi( enrollmentEmpPrimaryId, enrollmentEmpCodeString!, enrollmentClient_id!, 'GPA', enrollmentEmpClientBranchId!); if (response['status'] == 'success') { setState(() { gpaPolicies = response['data']; logDebug('gpaPolicies'); }); } else { setState(() { gpaDataIsEmpty = 0; }); // Handle other status codes ToastHelper.showWarningToast(context, 'Unable to process. Please try again later'); logDebug('Request failed with status: ${response['code']}'); } } catch (e) { // Handle exceptions logDebug('Exception occurred: $e'); } } Future getGmcEmpPolicyDetails(enrollmentEmpPrimaryId) async { try { if (enrollmentClient_id == null || enrollmentEmpCodeString == null || enrollmentEmpClientBranchId == null) { return; } final response = await apiService.getGmcEmpPolicyDetailsToApi( enrollmentEmpPrimaryId, enrollmentEmpCodeString!, enrollmentClient_id!, 'GMC', enrollmentEmpClientBranchId!); if (response['status'] == 'success') { setState(() { gmcPolicies = response['data']; logDebug('gmcPolicies'); }); // Assuming data is a List logDebug(gmcPolicies); } else { setState(() { gmcDataIsEmpty = 0; }); // Handle other status messages if needed logDebug('API request failed with status: ${response['status']}'); } } catch (e) { // Handle exceptions logDebug('Exception occurred: $e'); } } Future fetchRelationshipList() async { // Replace the URL with your API endpoint try { final response = await apiService.fetchRelationshipListToApi(); if (response['status'] == 'success') { for (var item in response['data']) { String relationshipName = item['relationship_name']; String dependent = item['dependent']; final id = item["id"]; relationshipOptions.add({ "id": id, 'relationship_name': relationshipName, 'dependent': dependent, }); } } else { throw Exception('Failed to fetch relationship list'); } } catch (error) { logDebug('Error fetching relationship list: $error'); } } Future _selectDate(BuildContext context, formType) async { logDebug(formType); var ageValidation = formType['age_validation']; logDebug(ageValidation); if (ageValidation is Map) { int min = ageValidation.containsKey('min') ? int.tryParse(ageValidation['min'].toString()) ?? 0 : 0; int max = ageValidation.containsKey('max') ? int.tryParse(ageValidation['max'].toString()) ?? 100 : 100; logDebug('Min age: $min'); logDebug('Max age: $max'); late DateTime minDate; late DateTime maxDate; final DateTime now = DateTime.now(); maxDate = DateTime(now.year - min, now.month, now.day); logDebug(maxDate); minDate = DateTime(now.year - max, now.month, now.day); logDebug(minDate); // Ensure initialDate is within the range of minDate and maxDate DateTime initialDate = _selectedDate ?? maxDate; // Use maxDate if _selectedDate is null initialDate = initialDate.isBefore(minDate) ? minDate : initialDate; initialDate = initialDate.isAfter(maxDate) ? maxDate : initialDate; final DateTime? picked = await showDatePicker( context: context, initialDate: initialDate, firstDate: minDate, lastDate: maxDate, selectableDayPredicate: (DateTime date) { return date.isAfter(minDate.subtract(const Duration(days: 1))) && date.isBefore(maxDate.add(const Duration(days: 1))); }, builder: (BuildContext context, Widget? child) { return Theme( data: ThemeData.light().copyWith( primaryColor: Color(0xFFE26728), // Header background color colorScheme: ColorScheme.light( primary: Color(0xFFE26728), secondary: Color(0xFFE26728)), buttonTheme: ButtonThemeData(textTheme: ButtonTextTheme.primary), iconTheme: IconThemeData(color: Color(0xFFE26728)), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( foregroundColor: Color(0xFFE26728)), // Button color ), ), child: child!, ); }, ); if (picked != null && picked != _selectedDate) { setState(() { _selectedDate = picked; _dobController.text = DateFormat('dd-MM-yyyy').format(_selectedDate); }); } } else { logDebug('Invalid age validation data'); } } String formatDate(String inputDate) { // Parse the input date string DateTime dateTime = DateFormat('dd-MM-yyyy').parse(inputDate); // Format the date to the desired format String formattedDate = DateFormat('dd MMM yyyy').format(dateTime); return formattedDate; } Future deleteItem(Map deletedItem,copyStatus,gmcClientPolicyId) async { logDebug(deletedItem); try { var id = deletedItem['employee_id']; final response = await apiService.deleteItemToApi(id,copyStatus,gmcClientPolicyId); // Check if the request was successful (status code 200) if (response['status'] == 'success') { formDataList.clear(); selectedRelationships.clear(); _relationShipController.clear(); _memberNameController.clear(); _dobController.clear(); relationshipOptions.clear(); getGpaEmpPolicyDetails(enrollmentEmpPrimaryId); getGmcEmpPolicyDetails(enrollmentEmpPrimaryId); fetchRelationshipList(); ToastHelper.showSuccessToast(context, 'Item deleted successfully'); logDebug('Item deleted successfully'); } else { // Handle errors ToastHelper.showErrorToast(context, 'Failed to delete item'); logDebug('Failed to delete item. Status code: ${response['code']}'); logDebug('Response body: ${response}'); } } catch (error) { // Handle network errors logDebug('Error deleting item: $error'); } } void saveFamilyMemberDetails(Map formData, Map floatedData, String action, gmcSumInsured) async { // Construct the array of objects logDebug(formData); logDebug('floatedData $floatedData'); logDebug(action); final SharedPreferences prefs = await SharedPreferences.getInstance(); dynamic primaryId; dynamic is_createdby_hr; if (prefs.containsKey('hrtoken')) { primaryId = hrPrimaryId; is_createdby_hr = 1; } else { primaryId = enrollmentEmpPrimaryId; is_createdby_hr = 0; } formDataList.add({ 'client_branch_id': enrollmentEmpClientBranchId, 'relationship': formData['relationship'], 'name': formData['memberName'], 'dob': formData['dateOfBirth'], 'emp_code': enrollmentEmpCodeString, 'client_id': enrollmentClient_id, 'client_policy_id': floatedData['client_policy_id'], 'created_by': primaryId, 'is_createdby_hr': is_createdby_hr, 'unit': selfUnit, 'basic_cover_si': gmcSumInsured, // Add the 'id' field only if action is 'Edit' if (action == 'Edit') 'id': floatedData['employee_id'], }); // Convert the list of objects to JSON // String formDataJson = jsonEncode(formDataList); // Prepare the API request final response = await apiService.saveFamilyMemberDetailsToApi(formDataList); // Check the response if (response['status'] == 'success') { formDataList.clear(); selectedRelationships.clear(); _relationShipController.clear(); _memberNameController.clear(); _dobController.clear(); relationshipOptions.clear(); // Request successful, handle response getGpaEmpPolicyDetails(enrollmentEmpPrimaryId); getGmcEmpPolicyDetails(enrollmentEmpPrimaryId); fetchRelationshipList(); ToastHelper.showSuccessToast(context, response['message']); logDebug('Form data sent successfully.'); } else { formDataList.clear(); selectedRelationships.clear(); _relationShipController.clear(); _memberNameController.clear(); _dobController.clear(); relationshipOptions.clear(); // Request failed, handle error ToastHelper.showErrorToast(context, response['message']); logDebug('Failed to send form data. Error: ${response}'); } } void cancelPopUp() { formDataList.clear(); selectedRelationships.clear(); _relationShipController.clear(); _memberNameController.clear(); _dobController.clear(); } 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 (gpaDataIsEmpty == 0 && gmcDataIsEmpty == 0) { logDebug('body if'); logDebug(gpaPolicies); return PopScope( canPop: false, onPopInvokedWithResult: (didPop, result) { if (didPop) return; _showExitConfirmation(context); }, child: Scaffold( appBar: CustomAppBar(), body: 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(10), color: Color(0xFFEFF3F6), child: Column( children: [ Card( elevation: 0, color: Colors.white, child: Container( width: double.infinity, height: 75, padding: Responsive.isDesktop(context) ? EdgeInsets.only( top: 20, bottom: 20, left: 30, right: 30) : EdgeInsets.only( top: 12, bottom: 12, left: 10, right: 10), // Add padding to the container child: Row( children: [ Expanded( flex: 6, child: Container( width: 150, height: 150, alignment: Alignment.centerLeft, child: Image.network( clientLogo ?? '', width: 80, // Set the width here height: 80, // Set the height here loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) { if (loadingProgress == null) return child; return Center( child: CircularProgressIndicator( value: loadingProgress .expectedTotalBytes != null ? loadingProgress .cumulativeBytesLoaded / loadingProgress .expectedTotalBytes! : null, ), ); }, errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { return Image.asset( 'assets/Solid_gray.png', width: 80, height: 80, fit: BoxFit.cover, ); }, ), ), ), Expanded( flex: 9, child: Text( clientName ?? '', textAlign: TextAlign.right, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 20 : 18, fontWeight: FontWeight.w600, ), ), ) ], ), ), ), SizedBox(height: 16), Card( elevation: 0, color: Colors.white, child: Container( width: double.infinity, height: MediaQuery.of(context).size.height, padding: Responsive.isDesktop(context) ? EdgeInsets.only( top: 20, bottom: 20, left: 30, right: 30) : EdgeInsets.only( top: 12, bottom: 12, left: 10, right: 10), child: Center( child: Text( 'No Active Current policies ', textAlign: TextAlign .center, // Align text center within the Card style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.w500, height: 5, ), ), ), ), ), ], ), ), ))); } else { return PopScope( canPop: false, onPopInvokedWithResult: (didPop, result) { if (didPop) return; _showExitConfirmation(context); }, child: Scaffold( backgroundColor: Color(0xFFFFFFFF), 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(10), color: Color(0xFFEFF3F6), child: Column( children: [ Card( elevation: 0, color: Colors.white, child: Container( width: double.infinity, height: 80, padding: Responsive.isDesktop(context) ? EdgeInsets.only( top: 20, bottom: 20, left: 30, right: 30) : EdgeInsets.only( top: 12, bottom: 12, left: 10, right: 10), // Add padding to the container child: Row( children: [ if(isTokenAvailable) InkWell( onTap: () { context.go('/home'); }, child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ // if (!Responsive.isDesktop(context)) Icon( Icons.chevron_left, color: Color(0xFF000000), size: 30, ), SizedBox( width: Responsive.isDesktop(context) ? 0 : 5), ], ), ), Expanded( flex: 6, child: Container( width: 200, height: 200, alignment: Alignment.centerLeft, child: Image.network( clientLogo ?? '', // width: 200, // Set the width here // height: 200, // Set the height here loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) { if (loadingProgress == null) return child; return Center( child: CircularProgressIndicator( value: loadingProgress .expectedTotalBytes != null ? loadingProgress .cumulativeBytesLoaded / loadingProgress .expectedTotalBytes! : null, ), ); }, errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { return Image.asset( 'assets/Solid_gray.png', // Replace 'default_image.png' with your default image asset path width: 80, height: 80, fit: BoxFit.cover, ); }, ), ), ), Expanded( flex: 9, child: Text( clientName ?? '', textAlign: TextAlign.right, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 20 : 18, fontWeight: FontWeight.w600, ), ), ) ], ), ), ), SizedBox(height: 16), if (gpaPolicies != null && gpaPolicies.length > 0) Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ ...generateGpaCards(gpaPolicies), ], ), SizedBox(height: 16), if (gmcPolicies != null && gmcPolicies.length > 0) Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ ...generateCards(gmcPolicies), ], ), SizedBox(height: 16), if (gmcPolicies != null && gmcPolicies.length > 0) Card( elevation: 0, color: Colors.white, child: Container( width: double.infinity, height: 75, padding: Responsive.isDesktop(context) ? EdgeInsets.only( top: 20, bottom: 20, left: 30, right: 30) : EdgeInsets.only( top: 10, bottom: 10, left: 10, right: 10), // Add padding to the container child: Row( children: [ Expanded( flex: 12, child: Container( width: 150, height: 150, alignment: Alignment.centerRight, child: ElevatedButton( onPressed: () { context.push('/addOnsDetails'); // Navigator.pushNamed( // context, 'addOnsDetails'); }, child: Text( 'Continue', style: GoogleFonts.poppins( color: Colors.white), ), style: ElevatedButton.styleFrom( backgroundColor: Color(0xFFE26728), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(5), ), ), ), )), ], ), ), ), SizedBox(height: 40), ], ), ), ), if (isLoading) 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) || (!Responsive.isDesktop(context) && !isTokenAvailable)) Align( alignment: Alignment.bottomCenter, child: Container( width: double.infinity, // Make the footer full width child: CustomFooter(), ), ), ]), // floatingActionButton: Responsive.isDesktop(context) // ? null // : isTokenAvailable // ? FloatingActionButton( // onPressed: () => Navigator.push( // context, // MaterialPageRoute(builder: (context) => chatbot()), // ), // child: Icon(Icons.chat), // ) // : null, floatingActionButtonLocation: Responsive.isDesktop(context) ? null : isTokenAvailable ? FloatingActionButtonLocation.miniEndFloat : null, bottomNavigationBar: Responsive.isDesktop(context) ? null : isTokenAvailable ? 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 ) : null, )); } } // Function to open URL in the default browser Future _launchURL(String url) async { final Uri uri = Uri.parse(url); // Parse the URL properly logDebug('_launchURL $uri'); if (uri != null) { logDebug('If $uri'); await launchUrl(uri, mode: LaunchMode.externalApplication); } else { logDebug('else $uri'); throw 'Could not launch $url'; } } // List> getMatchedRelationships() { // // 1. Get all empty floater slots // List available = gmcMappedFamilyFloaters // .where((e) => e['is_value_exist'] == false) // .map((e) => e['data']) // .toList(); // // List> matched = []; // // for (var item in relationshipOptions) { // String? dependent = item["dependent"]; // // bool exists = available.any((floater) => floater["form_type"] == dependent); // // if (exists) { // matched.add({ // "id": item["id"], // "relationship_name": item["relationship_name"], // "dependent": dependent, // }); // } // } // // return matched; // } void openAddFamilyMemberPopup( String action, Map? floaterData, String clientPolicyId, List relationshipList, dynamic sumInsured, ) { logDebug('gmcRelationShip : $relationshipList'); logDebug('editGmcRelationShip : $floaterData'); Map? selectedFloaterData; String? dropdownValue; // ============================ // NORMALIZE RELATIONSHIP LIST // ============================ List> relationshipObjects = []; // Case 1: List → convert to full object if (relationshipList.isNotEmpty && relationshipList.first is String) { relationshipObjects = relationshipList.map((r) { return { "relationship": r, "client_policy_id":r, "age_validation": {"min": "0", "max": "99"}, // default fallback }; }).toList(); } // Case 2: List> else if (relationshipList.isNotEmpty && relationshipList.first is Map) { relationshipObjects = List>.from(relationshipList); } logDebug("Normalized relationship list: $relationshipObjects"); Future showEditConfirmationDialog( BuildContext dialogContext, Map oldData, Map newData, bool relationshipEnabled, ) async { final oldRelationship = (oldData["relationship"] ?? "").toString().trim(); final oldName = (oldData["name"] ?? "").toString().trim(); final oldDob = (oldData["dob"] ?? "").toString().trim(); final newRelationship = (newData["relationship"] ?? "").toString().trim(); final newName = (newData["memberName"] ?? "").toString().trim(); final newDob = (newData["dateOfBirth"] ?? "").toString().trim(); final List> changedFields = []; if (oldRelationship != newRelationship) { changedFields.add({ "label": "Relationship", "old": oldRelationship, "new": newRelationship, }); } if (oldName != newName) { changedFields.add({ "label": "Member Name", "old": oldName, "new": newName, }); } if (oldDob != newDob) { changedFields.add({ "label": "Date of Birth", "old": oldDob, "new": newDob, }); } if (changedFields.isEmpty) { ToastHelper.showWarningToast( dialogContext, "No changes detected to save"); return false; } final List> reviewFields = []; if (relationshipEnabled || oldRelationship != newRelationship) { reviewFields.add({ "label": "Relationship", "old": oldRelationship, "new": newRelationship, }); } reviewFields.add({ "label": "Member Name", "old": oldName, "new": newName, }); reviewFields.add({ "label": "Date of Birth", "old": oldDob, "new": newDob, }); final bool? confirmed = await showDialog( context: dialogContext, barrierDismissible: false, builder: (confirmContext) { return AlertDialog( title: Text( "Confirm Changes", style: GoogleFonts.poppins(fontWeight: FontWeight.w600), ), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Please review old and new values before saving:", style: GoogleFonts.poppins(fontSize: 13), ), SizedBox(height: 12), ...reviewFields.map((field) { final oldValue = (field["old"] ?? '').trim().isEmpty ? '-' : (field["old"] ?? ''); final newValue = (field["new"] ?? '').trim().isEmpty ? '-' : (field["new"] ?? ''); return Padding( padding: const EdgeInsets.only(bottom: 12), child: Container( width: double.infinity, padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: const Color(0xFFF9F9F9), borderRadius: BorderRadius.circular(8), border: Border.all(color: const Color(0xFFE0E0E0)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( field["label"] ?? '', style: GoogleFonts.poppins( fontSize: 14, fontWeight: FontWeight.w700, color: const Color(0xFFE26728), ), ), const SizedBox(height: 8), RichText( text: TextSpan( style: GoogleFonts.poppins( fontSize: 13, color: const Color(0xFF232526), ), children: [ const TextSpan( text: "OLD: ", style: TextStyle( fontWeight: FontWeight.w700, color: Color(0xFFD32F2F), ), ), TextSpan(text: oldValue), ], ), ), const SizedBox(height: 4), RichText( text: TextSpan( style: GoogleFonts.poppins( fontSize: 13, color: const Color(0xFF232526), ), children: [ const TextSpan( text: "NEW: ", style: TextStyle( fontWeight: FontWeight.w700, color: Color(0xFF2E7D32), ), ), TextSpan(text: newValue), ], ), ), ], ), ), ); }).toList(), ], ), ), actions: [ TextButton( onPressed: () => Navigator.pop(confirmContext, false), child: Text("Cancel"), ), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Color(0xFFE26728), ), onPressed: () => Navigator.pop(confirmContext, true), child: Text("Confirm", style: TextStyle(color: Colors.white)), ), ], ); }, ); return confirmed == true; } // Reset UI Fields _relationShipController.clear(); _memberNameController.clear(); _dobController.clear(); // ============================ // EDIT MODE // ============================ if (action == "Edit" && floaterData != null) { logDebug('Edit Floater'); logDebug(floaterData); dropdownValue = floaterData["relationship"]; // Use REAL floaterData as selected data (IMPORTANT) selectedFloaterData = floaterData; // Insert into dropdown list only if needed if (!relationshipObjects.any((e) => e["relationship"] == dropdownValue)) { relationshipObjects.insert(0, { "relationship": dropdownValue, "client_policy_id": floaterData["client_policy_id"], }); } _relationShipController.text = floaterData["relationship"]; _memberNameController.text = floaterData["name"]; _dobController.text = floaterData["dob"]; } // if (action == "Edit" && floaterData != null) { // logDebug('Edit Floater'); // logDebug(floaterData); // String rel = floaterData["relationship"]; // // dropdownValue = rel; // // // Check if the relationship exists in normalized list // var exists = relationshipObjects.any((e) => e["relationship"] == rel); // // // If not found (rare case), insert it for dropdown display // if (!exists) { // relationshipObjects.insert(0, { // "relationship": rel, // "client_policy_id":floaterData["client_policy_id"], // "employee_id":floaterData["employee_id"], // "age_validation": floaterData["age_validation"] ?? {"min": "0", "max": "99"}, // }); // } // // selectedFloaterData = relationshipObjects.firstWhere( // (e) => e["relationship"] == rel, // orElse: () => { // "relationship": rel, // "client_policy_id":floaterData["client_policy_id"], // "employee_id":floaterData["employee_id"], // "age_validation": floaterData["age_validation"] ?? {"min": "0", "max": "99"}, // }); // // _relationShipController.text = rel; // _memberNameController.text = floaterData["name"]; // _dobController.text = floaterData["dob"]; // } // ============================ // SHOW POPUP // ============================ showDialog( context: context, barrierDismissible: false, builder: (context) { return AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), content: SizedBox( width: Responsive.isDesktop(context) ? 500 : 350, child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( action == "Edit" ? "Edit Family Member" : "Add Family Member", style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.bold, color: Color(0xFFE26728), ), ), SizedBox(height: 20), // RELATIONSHIP DROPDOWN DropdownButtonFormField( value: dropdownValue, decoration: InputDecoration( border: OutlineInputBorder(), labelText: "Relationship", ), items: relationshipObjects.map((item) { return DropdownMenuItem( value: item["relationship"], child: Text(item["relationship"]), ); }).toList(), onChanged: action == "Edit" ? null : (value) { dropdownValue = value!; _relationShipController.text = value; // assign selected relationship FULL OBJECT selectedFloaterData = relationshipObjects.firstWhere( (item) => item["relationship"] == value); }, ), SizedBox(height: 15), // FULL NAME FIELD TextFormField( controller: _memberNameController, decoration: InputDecoration( border: OutlineInputBorder(), labelText: "Member Name As Per Govt Id Proof", ), ), SizedBox(height: 15), // DOB → passes FULL SELECTED OBJECT TextFormField( controller: _dobController, readOnly: true, onTap: () { _selectDate(context, selectedFloaterData ?? floaterData); }, decoration: InputDecoration( border: OutlineInputBorder(), labelText: "Date of Birth", suffixIcon: IconButton( icon: Icon(Icons.calendar_today), onPressed: () { _selectDate(context, selectedFloaterData ?? floaterData); }, ), ), ), SizedBox(height: 20), // ACTION BUTTONS Row( children: [ Expanded( child: OutlinedButton( onPressed: () => Navigator.pop(context), child: Text("Cancel"), ), ), SizedBox(width: 10), Expanded( child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Color(0xFFE26728), ), onPressed: () async { if (_memberNameController.text.isEmpty || _dobController.text.isEmpty || dropdownValue == null) { ToastHelper.showWarningToast( context, "All fields are required"); return; } Map formData = { "relationship": dropdownValue!, "memberName": _memberNameController.text, "dateOfBirth": _dobController.text, }; logDebug('floaterDatafloaterData'); logDebug(floaterData); logDebug(selectedFloaterData); if (action == "Edit" && floaterData != null) { final shouldProceed = await showEditConfirmationDialog( context, floaterData, formData, action != "Edit", ); if (!shouldProceed) { return; } } saveFamilyMemberDetails( formData, selectedFloaterData ?? floaterData ?? {}, action, sumInsured, ); Navigator.pop(context); }, child: Text( "Save", style: TextStyle(color: Colors.white), ), ), ), ], ), ], ), ), ); }, ); } void openSelfForm(action) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30.0), ), elevation: 0, backgroundColor: Colors.transparent, content: SizedBox( width: Responsive.isDesktop(context) ? 1000 : 800, child: SingleChildScrollView( child: Card( color: Colors.white, elevation: 0, child: Padding( padding: Responsive.isDesktop(context) ? EdgeInsets.all(30) : EdgeInsets.all(15), child: Column( children: [ Container( child: Column( children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 12, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text('Member Details', style: GoogleFonts.poppins( fontSize: 16, fontWeight: FontWeight.w500, color: Color(0xFFE26728), )), ], ), ), ), ], ), SizedBox(height: 20), if (Responsive.isDesktop(context)) Row( children: [ Expanded( flex: 4, child: TextFormField( readOnly: true, initialValue: selfEmpCode ?? '', decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Employee ID', labelText: 'Employee ID', contentPadding: EdgeInsets.symmetric( vertical: 10, horizontal: 15), ), ), ), SizedBox(width: 10), Expanded( flex: 4, child: TextFormField( readOnly: true, initialValue: selfName ?? '', decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Employee Name', labelText: 'Employee Name', contentPadding: EdgeInsets.symmetric( vertical: 10, horizontal: 15), ), ), ), SizedBox(width: 10), Expanded( flex: 4, child: TextFormField( readOnly: true, initialValue: selfRelationship ?? '', decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Relationship', labelText: 'Relationship', contentPadding: EdgeInsets.symmetric( vertical: 10, horizontal: 15), ), ), ), ], ), SizedBox( height: Responsive.isDesktop(context) ? 30 : 0), if (Responsive.isDesktop(context)) Row( children: [ Expanded( flex: 4, child: TextFormField( readOnly: true, initialValue: selfMobile ?? '', decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Mobile No', labelText: 'Mobile No', contentPadding: EdgeInsets.symmetric( vertical: 10, horizontal: 15), ), ), ), // SizedBox(width: 10), // Expanded( // flex: 4, // child: TextFormField( // readOnly: true, // initialValue: selfEmailPersonal ?? '', // decoration: InputDecoration( // border: OutlineInputBorder(), // hintText: 'Email personal', // labelText: 'Email personal', // contentPadding: EdgeInsets.symmetric( // vertical: 10, horizontal: 15), // ), // ), // ), SizedBox(width: 10), Expanded( flex: 4, child: TextFormField( readOnly: true, initialValue: selfEmailCorporate ?? '', decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Email Corporate', labelText: 'Email Corporate', contentPadding: EdgeInsets.symmetric( vertical: 10, horizontal: 15), ), ), ), ], ), SizedBox( height: Responsive.isDesktop(context) ? 30 : 0), if (Responsive.isDesktop(context)) Row( children: [ Expanded( flex: 4, child: TextFormField( readOnly: true, initialValue: selfGender == 'M' ? 'Male' : 'Female', decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Gender', labelText: 'Gender', contentPadding: EdgeInsets.symmetric( vertical: 10, horizontal: 15), ), ), ), SizedBox(width: 10), Expanded( flex: 4, child: TextFormField( readOnly: true, initialValue: selfDob ?? '', decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Date of Birth', labelText: 'Date of Birth', contentPadding: EdgeInsets.symmetric( vertical: 10, horizontal: 15), ), ), ), SizedBox(width: 10), Expanded( flex: 4, child: TextFormField( readOnly: true, initialValue: selfDoj ?? '', decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Date of Joining', labelText: 'Date of Joining', contentPadding: EdgeInsets.symmetric( vertical: 10, horizontal: 15), ), ), ), ], ), SizedBox( height: Responsive.isDesktop(context) ? 30 : 0), if (!Responsive.isDesktop(context)) ListView(shrinkWrap: true, children: [ TextFormField( readOnly: true, initialValue: selfEmpCode ?? '', decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Employee ID', labelText: 'Employee ID', contentPadding: EdgeInsets.symmetric( vertical: 10, horizontal: 15), ), ), SizedBox(height: 15), TextFormField( readOnly: true, initialValue: selfName ?? '', decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Employee Name', labelText: 'Employee Name', contentPadding: EdgeInsets.symmetric( vertical: 10, horizontal: 15), ), ), SizedBox(height: 15), TextFormField( readOnly: true, initialValue: selfRelationship ?? '', decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Relationship', labelText: 'Relationship', contentPadding: EdgeInsets.symmetric( vertical: 10, horizontal: 15), ), ), SizedBox(height: 15), TextFormField( readOnly: true, initialValue: selfMobile ?? '', decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Mobile No', labelText: 'Mobile No', contentPadding: EdgeInsets.symmetric( vertical: 10, horizontal: 15), ), ), // SizedBox(height: 15), // TextFormField( // readOnly: true, // initialValue: selfEmailPersonal ?? '', // decoration: InputDecoration( // border: OutlineInputBorder(), // hintText: 'Email personal', // labelText: 'Email personal', // contentPadding: EdgeInsets.symmetric( // vertical: 10, horizontal: 15), // ), // ), SizedBox(height: 15), TextFormField( readOnly: true, initialValue: selfEmailCorporate ?? '', decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Email Corporate', labelText: 'Email Corporate', contentPadding: EdgeInsets.symmetric( vertical: 10, horizontal: 15), ), ), SizedBox(height: 15), TextFormField( readOnly: true, initialValue: selfGender == 'M' ? 'Male' : 'Female', decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Gender', labelText: 'Gender', contentPadding: EdgeInsets.symmetric( vertical: 10, horizontal: 15), ), ), SizedBox(height: 15), TextFormField( readOnly: true, initialValue: selfDob ?? '', decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Date of Birth', labelText: 'Date of Birth', contentPadding: EdgeInsets.symmetric( vertical: 10, horizontal: 15), ), ), SizedBox(height: 15), TextFormField( readOnly: true, initialValue: selfDoj ?? '', decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Date of Joining', labelText: 'Date of Joining', contentPadding: EdgeInsets.symmetric( vertical: 10, horizontal: 15), ), ), ]), SizedBox(height: 15), Row( children: [ Expanded( flex: 12, child: Container( alignment: Alignment.centerRight, child: ElevatedButton( onPressed: () { context.pop(); // Navigator.of(context).pop(); }, child: Text( 'Close', style: GoogleFonts.poppins( color: Colors.white), ), style: ElevatedButton.styleFrom( backgroundColor: Color(0xFFE26728), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(5), ), ), ), )), ], ), ], ), ), ], ), ), ), ), ), ); }, ); } List generateGpaCards(List data) { List cards = []; for (var item in data) { logDebug('item'); logDebug(item); String? gpaPolicyName = item['Policy_Name']; String? gpaPolicyType = item['type']; String? gpaECardDownload = item['eCardDownload']; String? gpaSumInsured = item['si_value']; double gpaGstValue = (item['si_gst_value'] ?? 0).toDouble(); double gpaSiPremiumValue = (item['si_premium_value'] ?? 0).toDouble(); double gpaTotalableValue = gpaSiPremiumValue + gpaGstValue; bool isValueValid = gpaSiPremiumValue != 0 && gpaGstValue != 0; final int premiumSummaryMode = parsePremiumSummaryMode(item['is_premium_summery']); // 0 = hide, 1 = full summary, 2 = total only final bool showFullPremiumSummary = premiumSummaryMode == 1 && isValueValid; final bool showPremiumTotalOnly = premiumSummaryMode == 2 && gpaTotalableValue != 0; List gpaMappedFamilyFloaters = []; if (item['mapped_family_floaters'] != null) { gpaMappedFamilyFloaters = [item['mapped_family_floaters']]; } dynamic getTrueObjects = gpaMappedFamilyFloaters .where((element) => element['is_value_exist'] == true) .toList(); // if (getTrueObjects.length > 0) { // gpaSumInsured = getTrueObjects[0]["data"]["basic_cover_si"]; // } else { // gpaSumInsured = item['Policy_Terms']['sumInsured2']; // } int gpaOpenForEnrollment = int.parse(item['OpenForEnrollment']); List familyFloaterContainers = []; for (var floater in gpaMappedFamilyFloaters) { bool isValueExist = floater['is_value_exist']; Map floaterData = floater['data']; final dobDate = floaterData['dob'] ?? ''; if (isValueExist) { familyFloaterContainers.add(Container( decoration: BoxDecoration( border: Border.all( color: Color(0xFF000000), width: 1, ), borderRadius: BorderRadius.circular(5), ), padding: Responsive.isDesktop(context) ? EdgeInsets.all(15) : EdgeInsets.only(top: 8, bottom: 8, left: 10, right: 10), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: Responsive.isDesktop(context) ? 1 : 2, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: Responsive.isDesktop(context) ? EdgeInsets.all(10) : EdgeInsets.all(5), decoration: BoxDecoration( color: Color(0xFF00989E), borderRadius: BorderRadius.circular(5), ), child: Icon( Icons.account_circle, color: Colors.white, size: 32, ), ), ], ), ), ), Expanded( flex: 8, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( floaterData['name'] ?? 'NA', textAlign: TextAlign.left, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 18 : 16, fontWeight: FontWeight.w600, ), ), Text( '${floaterData['relationship']} - ${dobDate}' ?? 'NA', textAlign: TextAlign.left, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 18 : 16, ), ), ], ), ), ), Expanded( flex: 2, child: Container( alignment: Alignment.topRight, child: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, children: [ MouseRegion( cursor: SystemMouseCursors.click, child: GestureDetector( onTap: () { openSelfForm('View'); }, child: Text( 'View', textAlign: TextAlign.left, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 16 : 15, color: Color(0xFFE26728), ), ), ), ) ], ), ), ), ], ), )); } familyFloaterContainers.add(SizedBox(height: 15)); } Widget card = Card( elevation: 0, color: Colors.white, child: Padding( padding: Responsive.isDesktop(context) ? EdgeInsets.all(30) : EdgeInsets.all(10), child: Column( children: [ Container( decoration: BoxDecoration( color: Color(0xFFFFF1DD), borderRadius: BorderRadius.circular(5), ), padding: EdgeInsets.all(10), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: Responsive.isDesktop(context) ? 9 : 7, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '', textAlign: TextAlign.left, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 18 : 13, ), ), Row( children: [ !Responsive.isDesktop(context) ? Tooltip( message: gpaPolicyType ?? 'NA', child: Text( gpaPolicyType ?? 'NA', textAlign: TextAlign.left, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 20 : 14, fontWeight: FontWeight.w600, ), ), ) : Text( gpaPolicyName ?? 'NA', textAlign: TextAlign.left, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 20 : 14, fontWeight: FontWeight.w600, ), ), if (item['eCardDownload'] != null) GestureDetector( onTap: () async { _launchURL(item['eCardDownload']); }, child: MouseRegion( cursor: SystemMouseCursors.click, child: Icon( Icons.file_download, color: Color(0xFFE26728), size: 25, ), ), ), ], ), ], ), ), ), Expanded( flex: Responsive.isDesktop(context) ? 3 : 5, child: Container( alignment: Alignment.centerRight, child: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( 'Sum Insured', textAlign: TextAlign.right, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 18 : 13, ), ), Text( '₹ ${gpaSumInsured != null ? gpaSumInsured : 'NA'}', textAlign: TextAlign.right, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 20 : 14, fontWeight: FontWeight.w600, ), ), ], ), ), ), ], ), ), SizedBox(height: 10), Column( children: familyFloaterContainers, ), if (Responsive.isDesktop(context) && (showFullPremiumSummary || showPremiumTotalOnly)) Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (showFullPremiumSummary) ...[ Expanded( flex: 5, child: Container( alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( 'Additional Premium', textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 20, fontWeight: FontWeight.w500, ), ), Text( (gpaSiPremiumValue ?? '').toString(), textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 18, ), ), ], ))), Expanded( flex: 2, child: Container( alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( 'GST', textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 20, fontWeight: FontWeight.w500, ), ), Text( (gpaGstValue ?? '').toString(), textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 18, ), ), ], ))), ], Expanded( flex: 5, child: Container( alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( 'Total Payable', textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 20, fontWeight: FontWeight.w500, ), ), Text( (gpaTotalableValue ?? '').toString(), textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 18, ), ), ], ))), ], ), if (!Responsive.isDesktop(context) && (showFullPremiumSummary || showPremiumTotalOnly)) Container( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (showFullPremiumSummary) ...[ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 6, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( 'Additional Premium', textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.w500, ), ), ], ))), Expanded( flex: 6, child: Container( alignment: Alignment.centerRight, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( (gpaSiPremiumValue ?? '').toString(), textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 16, ), ), ], ))), ], ), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 6, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( 'GST', textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.w500, ), ), ], ))), Expanded( flex: 6, child: Container( alignment: Alignment.centerRight, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( (gpaGstValue ?? '').toString(), textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 16, ), ), ], ))), ], ), ], Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 6, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( 'Total Payable', textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.w500, ), ), ], ))), Expanded( flex: 5, child: Container( alignment: Alignment.centerRight, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( (gpaTotalableValue ?? '').toString(), textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 16, ), ), ], ))), ], ), ])) ], ), ), ); cards.add(card); } return cards; } String formatAmount(double value) { return value % 1 == 0 ? value.toInt().toString() : value.toStringAsFixed(2); } /// 0 = hide premium summary, 1 = full summary, 2 = total only int parsePremiumSummaryMode(dynamic value) { if (value == null) return 0; if (value is bool) return value ? 1 : 0; if (value is num) return value.toInt(); final normalized = value.toString().trim().toLowerCase(); if (normalized == 'true' || normalized == 'yes') return 1; if (normalized == 'false' || normalized == 'no') return 0; return int.tryParse(normalized) ?? 0; } List generateCards(List data) { List cards = []; for (var item in data) { logDebug('item'); logDebug(item); String gmcPolicyName = item['Policy_Name']; logDebug('gmcPolicyName $gmcPolicyName'); String gmcPolicyType = item['type']; logDebug('gmcPolicyType $gmcPolicyType'); String gmcClientPolicyId = item['ClientPolicyId']; logDebug('gmcClientPolicyId $gmcClientPolicyId'); String gmcFloaterTextHeading = item['floter_text_heading']; logDebug('gmcFloaterTextHeading $gmcFloaterTextHeading'); String gmcFloaterTextDescription = item['floter_text_description']; logDebug('gmcFloaterTextDescription $gmcFloaterTextDescription'); String gmcNotes = item['notes']; logDebug('gmcNotes $gmcNotes'); String cleanedNotes = gmcNotes?.toString().toLowerCase().replaceAll(' ', '') ?? ''; logDebug('gmcNotes cleaned: $cleanedNotes'); dynamic gmcECardDownload = item['eCardDownload']; logDebug('gmcECardDownload $gmcECardDownload'); bool gmcCopyDependenceDataEnable = item['copy_dependence_data_enable']; logDebug('gmcCopyDependenceDataEnable $gmcCopyDependenceDataEnable'); // double gmcGstValue = (item['family_floaters_of_dependent_and_gst_value'] ?? 0).toDouble(); double gmcGstValue = double.tryParse(item['family_floaters_of_dependent_and_gst_value']?.toString() ?? '0') ?? 0.0; double gmcSiPremiumValue = double.tryParse(item['family_floaters_of_dependent_and_si_premium_value']?.toString() ?? '0') ?? 0.0; double gmcTotalableValue = gmcGstValue + gmcSiPremiumValue; bool gmcIsValueValid = (gmcSiPremiumValue > 0 && gmcGstValue > 0); final int gmcPremiumSummaryMode = parsePremiumSummaryMode(item['is_premium_summery']); // 0 = hide, 1 = full summary, 2 = total only final bool showFullGmcPremiumSummary = gmcPremiumSummaryMode == 1 && gmcIsValueValid; final bool showGmcPremiumTotalOnly = gmcPremiumSummaryMode == 2 && gmcTotalableValue != 0; List gmcRelationShip = item['relationship']; List gmcMappedFamilyFloaters = item['mapped_family_floaters']; logDebug('gmcMappedFamilyFloaters $gmcMappedFamilyFloaters'); List getTrueObjects = gmcMappedFamilyFloaters .where((element) => element['is_value_exist'] == true) .toList(); List getFalseObjects = gmcMappedFamilyFloaters .where((element) => element['is_value_exist'] == false) .toList(); logDebug('getTrueObjects'); logDebug(getTrueObjects); dynamic gmcSumInsured; if (getTrueObjects.length > 0) { logDebug('true'); gmcSumInsured = gmcMappedFamilyFloaters[0]["data"]["basic_cover_si"]; } else { logDebug('false'); gmcSumInsured = item['Policy_Terms']['sum_insured']; } String intOpenForEnrollment = item['OpenForEnrollment']; int gmcOpenForEnrollment = int.parse(intOpenForEnrollment); logDebug('gmcOpenForEnrollment $gmcOpenForEnrollment'); String gmcTypeName = item['type']; List familyFloaterContainers = []; for (var floater in gmcMappedFamilyFloaters) { bool isValueExist = floater['is_value_exist']; Map floaterData = floater['data']; logDebug('floaterData123456 $floaterData'); final dobDate = floaterData['dob'] ?? ''; if (isValueExist) { familyFloaterContainers.add( Container( decoration: BoxDecoration( border: Border.all( color: Color(0xFF000000), width: 1, ), borderRadius: BorderRadius.circular(5), ), padding: Responsive.isDesktop(context) ? EdgeInsets.all(15) : EdgeInsets.only(top: 8, bottom: 8, left: 10, right: 10), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: Responsive.isDesktop(context) ? 1 : 2, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: Responsive.isDesktop(context) ? EdgeInsets.all(10) : EdgeInsets.all(5), decoration: BoxDecoration( color: Color(0xFF00989E), borderRadius: BorderRadius.circular(5), ), child: Icon( Icons.account_circle, color: Colors.white, size: 32, ), ), ], ), ), ), SizedBox(width: Responsive.isDesktop(context) ? 5 : 0), Expanded( flex: Responsive.isDesktop(context) ? 9 : 6, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( floaterData['name'] ?? '', textAlign: TextAlign.left, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 18 : 16, fontWeight: FontWeight.w600, ), ), Text( '${floaterData['relationship']} - ${dobDate}', textAlign: TextAlign.left, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 18 : 16, ), ), ], ), ), ), // === RIGHT SIDE ACTION ICONS === if (gmcOpenForEnrollment != 0 && gmcECardDownload == null) Expanded( flex: Responsive.isDesktop(context) ? 2 : 3, child: Container( alignment: Alignment.topRight, child: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ // VIEW (Self Only) if (floaterData['relationship'] == 'Self') MouseRegion( cursor: SystemMouseCursors.click, child: GestureDetector( onTap: () => openSelfForm('View'), child: Tooltip( message: 'View', child: Icon( Icons.remove_red_eye, color: Color(0xFFE26728), ), ), ), ), // DELETE + EDIT (For others) if (floaterData['relationship'] != 'Self') ...[ // DELETE ICON MouseRegion( cursor: SystemMouseCursors.click, child: GestureDetector( onTap: () => deleteItem(floaterData,gmcCopyDependenceDataEnable,gmcClientPolicyId), child: Tooltip( message: 'Delete', child: Icon( Icons.delete, color: Color(0xFFE26728), ), ), ), ), SizedBox(height: 8), // EDIT ICON MouseRegion( cursor: SystemMouseCursors.click, child: GestureDetector( onTap: () { openAddFamilyMemberPopup( "Edit", floaterData, gmcClientPolicyId, gmcRelationShip, gmcSumInsured, ); }, child: Tooltip( message: 'Edit', child: Icon( Icons.edit, color: Color(0xFFE26728), ), ), ), ), ] ], ), ), ), // SizedBox(height: 10), ], ), ), ); } familyFloaterContainers.add(SizedBox(height: 10)); } Widget card = Card( elevation: 0, color: Colors.white, child: Padding( padding: Responsive.isDesktop(context) ? EdgeInsets.all(30) : EdgeInsets.all(10), child: Column( children: [ Container( decoration: BoxDecoration( color: Color( 0xFFFFF1DD), // Set background color for the container borderRadius: BorderRadius.circular( 5), // Set border radius for the container ), padding: Responsive.isDesktop(context) ? EdgeInsets.only( top: 15, bottom: 15, left: 25, right: 25) : EdgeInsets.only( top: 10, bottom: 10, left: 10, right: 10), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: Responsive.isDesktop(context) ? 9 : 7, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '', textAlign: TextAlign.left, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 18 : 13, ), ), Row( children: [ Text( Responsive.isDesktop(context) ? gmcPolicyName : gmcPolicyType, textAlign: TextAlign.left, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 20 : 14, fontWeight: FontWeight.w600, ), ), if (item['eCardDownload'] != null) GestureDetector( onTap: () async { _launchURL(item['eCardDownload']); }, child: MouseRegion( cursor: SystemMouseCursors.click, child: Icon( Icons.file_download, color: Color(0xFFE26728), size: 25, ), ), ), ], ), ], ))), Expanded( flex: Responsive.isDesktop(context) ? 3 : 5, child: Container( alignment: Alignment.centerRight, child: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( gmcFloaterTextHeading ?? '', textAlign: TextAlign.right, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 18 : 13, ), ), Text( '₹ ${gmcSumInsured != null ? gmcSumInsured : 'NA'}', textAlign: TextAlign.right, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 20 : 14, fontWeight: FontWeight.w600, ), ), ], ))), ], ), ), SizedBox(height: 10), Container( padding: EdgeInsets.only(top: 0, bottom: 0, left: 10, right: 10), child: Text(gmcFloaterTextDescription, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 14 : 11, color: Color(0xFF727272), )), ), SizedBox(height: 15), Container( decoration: BoxDecoration( color: Color( 0xFFF9F9FB), // Set background color for the container borderRadius: BorderRadius.circular( 5), // Set border radius for the container ), padding: Responsive.isDesktop(context) ? EdgeInsets.only( top: 15, bottom: 15, left: 25, right: 25) : EdgeInsets.only( top: 10, bottom: 10, left: 10, right: 10), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 12, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Please Note', textAlign: TextAlign.left, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 18 : 14, fontWeight: FontWeight.w600, ), ), Text( gmcNotes ?? '', textAlign: TextAlign.left, style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 18 : 15, ), ), ], ))), ], ), ), SizedBox(height: 15), Row( children: [ Expanded( child: Text( 'Please review your enrolled dependents. ', style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 18 : 16, color: Color(0xFF181818), fontWeight: FontWeight.w500, ), ), ), if(item['copy_dependence_data_enable']) GestureDetector( onTap:() => copyPreviousPolicy(item['mapped_family_floaters'],item['ClientPolicyId'],gmcSumInsured), child: Text( '( Copy From Previous Policy )', style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 18 : 16, color: Color(0xFFE26728), fontWeight: FontWeight.w600, ), ), ), ], ), SizedBox(height: 15), Column( children: familyFloaterContainers, ), // Add Family Member Button: // Show only when: // - enrollment is open // - e-card not generated // - there are still dependants left to add // - and the policy allows relationships beyond just "Self" // if (gmcOpenForEnrollment != 0 && // gmcECardDownload == null && // getFalseObjects.isNotEmpty && // gmcRelationShip.any((rel) => // (rel?.toString().toLowerCase() ?? '') != 'self')) ...[ // Builder(builder: (context) { // logDebug("*** Condition is TRUE"); // GestureDetector( // onTap: () { // if (getFalseObjects.length == 0) { // ToastHelper.showWarningToast(context, "No family member to add"); // return; // } // openAddFamilyMemberPopup( // "Add", // null, // gmcClientPolicyId, // gmcRelationShip, // gmcSumInsured, // ); // }, // child: Container( // margin: EdgeInsets.only(top: 10), // padding: EdgeInsets.all(15), // decoration: BoxDecoration( // border: Border.all(color: Colors.black, width: 1), // borderRadius: BorderRadius.circular(8), // ), // child: Row( // mainAxisAlignment: MainAxisAlignment.center, // children: [ // Icon(Icons.person_add, color: Colors.black), // SizedBox(width: 10), // Text( // "Add Family Member", // style: GoogleFonts.poppins( // fontSize: Responsive.isDesktop(context) ? 20 : 16, // fontWeight: FontWeight.w500, // ), // ), // ], // ), // ), // ), // ], if (cleanedNotes != 'allowedmembersself') ...[ if (gmcOpenForEnrollment != 0 && gmcECardDownload == null && getFalseObjects.isNotEmpty && gmcRelationShip.any((rel) => (rel is Map ? rel['relationship']?.toString().toLowerCase() : rel?.toString().toLowerCase() ?? '') != 'self')) ...[ Builder(builder: (context) { logDebug("*** IF - Condition is TRUE"); logDebug("*** gmcOpenForEnrollment: $gmcOpenForEnrollment"); logDebug("*** gmcECardDownload: $gmcECardDownload"); logDebug("*** getFalseObjects length: ${getFalseObjects.length}"); logDebug("*** gmcRelationShip full: $gmcRelationShip"); logDebug("*** gmcNotes original: $gmcNotes"); logDebug("*** gmcNotes cleaned: $cleanedNotes"); return GestureDetector( onTap: () { if (getFalseObjects.length == 0) { ToastHelper.showWarningToast(context, "No family member to add"); return; } openAddFamilyMemberPopup( "Add", null, gmcClientPolicyId, gmcRelationShip, gmcSumInsured, ); }, child: Container( margin: EdgeInsets.only(top: 10), padding: EdgeInsets.all(15), decoration: BoxDecoration( border: Border.all(color: Colors.black, width: 1), borderRadius: BorderRadius.circular(8), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.person_add, color: Colors.black), SizedBox(width: 10), Text( "Add Family Member", style: GoogleFonts.poppins( fontSize: Responsive.isDesktop(context) ? 20 : 16, fontWeight: FontWeight.w500, ), ), ], ), ), ); }), ] else ...[ Builder(builder: (context) { logDebug("*** ELSE - Condition is FALSE"); logDebug("*** gmcOpenForEnrollment: $gmcOpenForEnrollment → pass: ${gmcOpenForEnrollment != 0}"); logDebug("*** gmcECardDownload: $gmcECardDownload → pass: ${gmcECardDownload == null}"); logDebug("*** getFalseObjects length: ${getFalseObjects.length} → pass: ${getFalseObjects.isNotEmpty}"); logDebug("*** gmcRelationShip full list: $gmcRelationShip"); logDebug("*** gmcNotes original: $gmcNotes"); logDebug("*** gmcNotes cleaned: $cleanedNotes"); return SizedBox.shrink(); // no widget shown in else }), ], ]else ...[ Builder(builder: (context) { logDebug("*** OUTER ELSE - Condition is FALSE"); logDebug("*** gmcNotes original: $gmcNotes"); logDebug("*** gmcNotes cleaned: $cleanedNotes"); return SizedBox.shrink(); }), ], SizedBox(height: 15), if (Responsive.isDesktop(context) && (showFullGmcPremiumSummary || showGmcPremiumTotalOnly)) Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (showFullGmcPremiumSummary) ...[ Expanded( flex: 5, child: Container( alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( 'Additional Premium', textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 20, fontWeight: FontWeight.w500, ), ), Text( formatAmount(gmcSiPremiumValue), textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 18, ), ), ], ))), Expanded( flex: 2, child: Container( alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( 'GST', textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 20, fontWeight: FontWeight.w500, ), ), Text( formatAmount(gmcGstValue), textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 18, ), ), ], ))), ], Expanded( flex: 5, child: Container( alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( 'Total Payable', textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 20, fontWeight: FontWeight.w500, ), ), Text( formatAmount(gmcTotalableValue), textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 18, ), ), ], ))), ], ), if (!Responsive.isDesktop(context) && (showFullGmcPremiumSummary || showGmcPremiumTotalOnly)) Container( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (showFullGmcPremiumSummary) ...[ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 6, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( 'Additional Premium', textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.w500, ), ), ], ))), Expanded( flex: 6, child: Container( alignment: Alignment.centerRight, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( formatAmount(gmcSiPremiumValue), textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 16, ), ), ], ))), ], ), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 6, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( 'GST', textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.w500, ), ), ], ))), Expanded( flex: 6, child: Container( alignment: Alignment.centerRight, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( formatAmount(gmcGstValue), textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 16, ), ), ], ))), ], ), ], Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 6, child: Container( alignment: Alignment.centerLeft, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( 'Total Payable', textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.w500, ), ), ], ))), Expanded( flex: 5, child: Container( alignment: Alignment.centerRight, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( formatAmount(gmcTotalableValue), textAlign: TextAlign.start, style: GoogleFonts.poppins( fontSize: 16, ), ), ], ))), ], ), ])) ], ), )); cards.add(card); } return cards; } Future copyPreviousPolicy(gmcMappedFamilyFloaters,gmcClientPolicyId,sumInsured) async { logDebug('gmcClientPolicyId1234 $gmcClientPolicyId'); try { final response = await apiService.copyActivePolicy(enrollmentClient_id,enrollmentEmpCodeString,gmcClientPolicyId); logDebug('ABCDEF ${response['status']}'); if (response['status'] == 'success') { List dependents = response['data']; /// FILTER is_value_exist == true List getTrueObjects = gmcMappedFamilyFloaters .where((element) => element['is_value_exist'] == true) .toList(); /// MERGE & REMOVE DUPLICATES & REMOVE SELF List uniqueList = getNonMatchedDependents(getTrueObjects, dependents); ToastHelper.showSuccessToast(context, "Previous policy copied!"); /// OPEN POPUP showCopyPolicyPopup(context, uniqueList,sumInsured); } else { throw Exception('Failed to fetch relationship list'); } } catch (error) { logDebug('Error fetching relationship list: $error'); } } void showCopyPolicyPopup(BuildContext context, List uniqueList,sumInsured) { Map selected = {}; List> selectedDependents = []; for (int i = 0; i < uniqueList.length; i++) { selected[i] = false; } showDialog( context: context, barrierDismissible: true, builder: (context) { return StatefulBuilder( builder: (context, setState) { return Dialog( backgroundColor: Colors.white, insetPadding: EdgeInsets.symmetric( horizontal: Responsive.isDesktop(context) ? 350 : 20, vertical: 100, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: Container( padding: const EdgeInsets.all(20), width: double.maxFinite, child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( "Copy From Previous Policy", style: TextStyle( fontSize: Responsive.isDesktop(context) ? 24 : 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 20), SizedBox( height: 300, child: ListView.builder( itemCount: uniqueList.length, itemBuilder: (context, index) { final item = uniqueList[index]; final data = item["data"]; final relationship = data["relationship"].toString().toLowerCase(); bool isSelf = relationship == "self"; return Card( elevation: 3, margin: const EdgeInsets.symmetric(vertical: 8), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), child: ListTile( leading: isSelf ? const SizedBox(width: 24) // Empty space instead of checkbox : Checkbox( value: selected[index], onChanged: (val) { setState(() { selected[index] = val ?? false; if (val == true) { selectedDependents.add(data); } else { selectedDependents.removeWhere( (d) => d["employee_id"] == data["employee_id"]); } }); }, ), title: Text( "${data['relationship']} - ${data['name']}", style: const TextStyle(fontWeight: FontWeight.w600), ), subtitle: Text("DOB: ${data['dob']}"), ), ); }, ), ), const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // ❌ CANCEL BUTTON TextButton( onPressed: () => Navigator.pop(context), child: Text( "Cancel", style: TextStyle( fontSize: 16, color: Colors.red, fontWeight: FontWeight.w600), ), ), // ✔ SUBMIT BUTTON ElevatedButton( onPressed: () async { if (selectedDependents.isEmpty) { ToastHelper.showWarningToast(context, "Please select at least one member"); return; } Navigator.pop(context); // Send the full list in one API call await saveMultipleFamilyMembers(selectedDependents,sumInsured); }, child: Text( "Submit", style: TextStyle(fontSize: 16), ), ), ], ) ] ), ), ); }, ); }, ); } // List getNonMatchedDependents(List list1, List list2) { // List merged = [...list1, ...list2]; // // List unique = []; // // for (var item in merged) { // final data = item['data']; // // // ❌ SKIP SELF // // if (data['relationship'].toString().toLowerCase() == "self") { // // continue; // // } // // bool exists = unique.any((u) { // final ud = u['data']; // return ud['relationship'] == data['relationship'] && // ud['name'] == data['name'] && // ud['dob'] == data['dob']; // }); // // if (!exists) { // unique.add(item); // } // } // // return unique; // } List getNonMatchedDependents(List list1, List list2) { List nonMatched = []; for (var item2 in list2) { var d2 = item2['data']; // Always keep SELF — do NOT compare if (d2['relationship'].toString().toLowerCase() == "self") { nonMatched.add(item2); continue; } bool existsInList1 = false; for (var item1 in list1) { var d1 = item1['data']; // skip self in list1 also if (d1['relationship'].toString().toLowerCase() == "self") { continue; } if (d1['relationship'] == d2['relationship'] && d1['name'] == d2['name'] && d1['dob'] == d2['dob']) { existsInList1 = true; break; } } // If not found in list1 → keep the record if (!existsInList1) { nonMatched.add(item2); } } return nonMatched; } Future saveMultipleFamilyMembers( List> members, sumInsured) async { final SharedPreferences prefs = await SharedPreferences.getInstance(); dynamic primaryId; dynamic is_createdby_hr; if (prefs.containsKey('hrtoken')) { primaryId = hrPrimaryId; is_createdby_hr = 1; } else { primaryId = enrollmentEmpPrimaryId; is_createdby_hr = 0; } // LOOP and send ONE BY ONE for (var m in members) { Map body = { "client_branch_id": enrollmentEmpClientBranchId, "relationship": m["relationship"], "name": m["name"], "dob": m["dob"], "emp_code": enrollmentEmpCodeString, "client_id": enrollmentClient_id, "client_policy_id": m["client_policy_id"], "id": m["employee_id"], "created_by": primaryId, "is_createdby_hr": is_createdby_hr, "unit": selfUnit, "basic_cover_si": sumInsured, }; logDebug("SENDING TO API → $body"); final response = await apiService.saveFamilyMemberDetailsToApi([body]); // API expects a list if (response['status'] != 'success') { ToastHelper.showErrorToast(context, "Failed to save ${m['name']}"); return; // stop further calls on failure } } // ToastHelper.showSuccessToast(context, "Dependents copied successfully!"); formDataList.clear(); selectedRelationships.clear(); _relationShipController.clear(); _memberNameController.clear(); _dobController.clear(); relationshipOptions.clear(); // Refresh screens getGpaEmpPolicyDetails(enrollmentEmpPrimaryId); getGmcEmpPolicyDetails(enrollmentEmpPrimaryId); fetchRelationshipList(); } // Future saveMultipleFamilyMembers(List> members,sumInsured) async { // final SharedPreferences prefs = await SharedPreferences.getInstance(); // // dynamic primaryId; // dynamic is_createdby_hr; // // if (prefs.containsKey('hrtoken')) { // primaryId = hrPrimaryId; // is_createdby_hr = 1; // } else { // primaryId = enrollmentEmpPrimaryId; // is_createdby_hr = 0; // } // // // Add extra fields to each object // List> finalList = members.map((m) { // return { // "client_branch_id": enrollmentEmpClientBranchId, // "relationship": m["relationship"], // "name": m["name"], // "dob": m["dob"], // "emp_code": enrollmentEmpCodeString, // "client_id": enrollmentClient_id, // "id":m['employee_id'], // "client_policy_id": m["client_policy_id"], // "created_by": primaryId, // "is_createdby_hr": is_createdby_hr, // "unit": selfUnit, // "basic_cover_si": sumInsured, // }; // }).toList(); // // logDebug("FINAL JSON TO API:"); // logDebug(finalList); // // final response = await apiService.saveFamilyMemberDetailsToApi(finalList); // // if (response['status'] == 'success') { // ToastHelper.showSuccessToast(context, response['message']); // getGpaEmpPolicyDetails(enrollmentEmpPrimaryId); // getGmcEmpPolicyDetails(enrollmentEmpPrimaryId); // fetchRelationshipList(); // } else { // ToastHelper.showErrorToast(context, response['message']); // } // } }