post_enrollment_app/lib/pages/enrollment/empDetails.dart

3568 lines
148 KiB
Dart
Executable File

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<empDetails> createState() => _empDetailsState();
}
class _empDetailsState extends State<empDetails> {
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<Map<String, String>> relationshipOptions = [];
List<Map<String, String>> selectedRelationships = [];
List<Map<String, dynamic>> 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<void> getTokenStatus() async {
// final SharedPreferences prefs = await SharedPreferences.getInstance();
// setState(() async {
// isTokenAvailable =
// (await TokenService.getPostToken())?.isNotEmpty ?? false;
// logDebug('isTokenAvailable $isTokenAvailable');
// });
// }
Future<void> getTokenStatus() async {
final token = await TokenService.getPostToken();
setState(() {
isTokenAvailable = token != null && token.isNotEmpty;
logDebug('isTokenAvailable $isTokenAvailable');
});
}
Future<void> _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<void> _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<String, dynamic>? 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<void> 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<void> 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<void> 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<void> 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<void> 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<void> _selectDate(BuildContext context, formType) async {
logDebug(formType);
var ageValidation = formType['age_validation'];
logDebug(ageValidation);
if (ageValidation is Map<String, dynamic>) {
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<void> deleteItem(Map<String, dynamic> 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<String, dynamic> formData,
Map<String, dynamic> 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<void> _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<Map<String, dynamic>> getMatchedRelationships() {
// // 1. Get all empty floater slots
// List available = gmcMappedFamilyFloaters
// .where((e) => e['is_value_exist'] == false)
// .map((e) => e['data'])
// .toList();
//
// List<Map<String, dynamic>> 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<String, dynamic>? floaterData,
String clientPolicyId,
List relationshipList,
dynamic sumInsured,
) {
logDebug('gmcRelationShip : $relationshipList');
logDebug('editGmcRelationShip : $floaterData');
Map<String, dynamic>? selectedFloaterData;
String? dropdownValue;
// ============================
// NORMALIZE RELATIONSHIP LIST
// ============================
List<Map<String, dynamic>> relationshipObjects = [];
// Case 1: List<String> → 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<Map<String,dynamic>>
else if (relationshipList.isNotEmpty && relationshipList.first is Map) {
relationshipObjects = List<Map<String, dynamic>>.from(relationshipList);
}
logDebug("Normalized relationship list: $relationshipObjects");
Future<bool> showEditConfirmationDialog(
BuildContext dialogContext,
Map<String, dynamic> oldData,
Map<String, dynamic> 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<Map<String, String>> 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<Map<String, String>> 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<bool>(
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<String>(
value: dropdownValue,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: "Relationship",
),
items: relationshipObjects.map((item) {
return DropdownMenuItem<String>(
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<String, dynamic> 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<Widget> generateGpaCards(List<dynamic> data) {
List<Widget> 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<dynamic> 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<Widget> familyFloaterContainers = [];
for (var floater in gpaMappedFamilyFloaters) {
bool isValueExist = floater['is_value_exist'];
Map<String, dynamic> 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<Widget> generateCards(List<dynamic> data) {
List<Widget> 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<Widget> familyFloaterContainers = [];
for (var floater in gmcMappedFamilyFloaters) {
bool isValueExist = floater['is_value_exist'];
Map<String, dynamic> 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') ...<Widget>[
if (gmcOpenForEnrollment != 0 &&
gmcECardDownload == null &&
getFalseObjects.isNotEmpty &&
gmcRelationShip.any((rel) =>
(rel is Map
? rel['relationship']?.toString().toLowerCase()
: rel?.toString().toLowerCase() ?? '') != 'self')) ...<Widget>[
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 ...<Widget>[
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 ...<Widget>[
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<void> 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<dynamic> dependents = response['data'];
/// FILTER is_value_exist == true
List<dynamic> 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<dynamic> uniqueList,sumInsured) {
Map<int, bool> selected = {};
List<Map<String, dynamic>> 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<void> saveMultipleFamilyMembers(
List<Map<String, dynamic>> 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<String, dynamic> 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<void> saveMultipleFamilyMembers(List<Map<String, dynamic>> 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<Map<String, dynamic>> 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']);
// }
// }
}