merged policy validation

This commit is contained in:
Surendiran 2025-12-12 17:01:25 +05:30
commit 7a07b0f3bd
21 changed files with 1218 additions and 623 deletions

File diff suppressed because one or more lines are too long

View File

@ -771,46 +771,15 @@ class ApiService {
// ----------------------------------- ENQUIRY -------------------------------------------------
Future<Map<String, dynamic>> fetchEnquiryList1(int id, role) async {
// print(_token);
if (_token == null) {
await _initializeToken();
}
final url;
if (role == 'manager') {
url = Uri.parse(
'${Env.apiUrl}enquiry/enquiryList?manager_id=$id&from_date=&to_date=',
);
} else if (role == 'staff') {
url = Uri.parse(
'${Env.apiUrl}enquiry/enquiryList?staff_id=$id&from_date=&to_date=',
);
} else {
url = Uri.parse(
'${Env.apiUrl}enquiry/enquiryList?agent_id=$id&from_date=&to_date=',
);
}
// final url = Uri.parse(
// 'https://venbait.in/nhance/partner/dev/api/agent/agentList?manager_id=${managerId}',
// );
final headers = {
'Authorization': 'Bearer $_token' ?? '',
'app-signature': Env.App_Signature,
};
final response = await _makeGetRequest(url, headers);
return response;
}
Future<Map<String, dynamic>> fetchEnquiryList(int managerid,
int id,
String role, {
String? fromDate,
String? toDate,
String? selectedStatus,
String? selectedStaffId,
}) async {
Future<Map<String, dynamic>> fetchEnquiryList(
int managerid,
int id,
String role, {
String? fromDate,
String? toDate,
String? selectedStatus,
String? selectedStaffId,
}) async {
print("selectedStatusselectedStatus - $selectedStatus");
if (_token == null) {
await _initializeToken();
@ -1166,23 +1135,67 @@ class ApiService {
// ----------------------------------- CLAIMS -------------------------------------------------
Future<Map<String, dynamic>> fetchClaimList(int id, role) async {
Future<Map<String, dynamic>> fetchPolicySearch(val) async {
// print(_token);
// print('rolemanagerId - $managerId');
if (_token == null) {
await _initializeToken();
}
dynamic url;
url = Uri.parse('${Env.apiUrl}policy/searchThePolicies?policy_number=$val');
final headers = {
'Authorization': 'Bearer $_token' ?? '',
'app-signature': Env.App_Signature,
};
final response = await _makeGetRequest(url, headers);
return response;
}
Future<Map<String, dynamic>> fetchVehicleSearch(val) async {
// print(_token);
// print('rolemanagerId - $managerId');
if (_token == null) {
await _initializeToken();
}
dynamic url;
url = Uri.parse(
'${Env.apiUrl}policy/searchThePolicies?vehicle_number=$val',
);
final headers = {
'Authorization': 'Bearer $_token' ?? '',
'app-signature': Env.App_Signature,
};
final response = await _makeGetRequest(url, headers);
return response;
}
Future<Map<String, dynamic>> fetchClaimList(
managerId,
int userId,
role,
) async {
// print(_token);
if (_token == null) {
await _initializeToken();
}
final userId = '1';
final url;
if (role == 'manager') {
url = Uri.parse('${Env.apiUrl}claim/ClaimList?manager_id=$id');
url = Uri.parse('${Env.apiUrl}claim/ClaimList?manager_id=$managerId');
} else if (role == 'agent') {
url = Uri.parse('${Env.apiUrl}claim/ClaimList?agent_id=$id');
url = Uri.parse('${Env.apiUrl}claim/ClaimList?agent_id=$userId');
} else if (role == 'handler') {
url = Uri.parse('${Env.apiUrl}claim/ClaimList?handler_id=$id');
url = Uri.parse('${Env.apiUrl}claim/ClaimList?handler_id=$userId');
} else {
url = Uri.parse('${Env.apiUrl}claim/ClaimList?staff_id=$id');
url = Uri.parse('${Env.apiUrl}claim/ClaimList?staff_id=$userId');
}
// final url = Uri.parse(
@ -1213,18 +1226,21 @@ class ApiService {
// ----------------------------------- ENDORSEMENT -------------------------------------------------
Future<Map<String, dynamic>> fetchEndorsementList(int id, role) async {
Future<Map<String, dynamic>> fetchEndorsementList(
managerId,
int id,
role,
) async {
// print(_token);
if (_token == null) {
await _initializeToken();
}
final userId = '1';
final url;
if (role == 'manager') {
url = Uri.parse(
'${Env.apiUrl}endorsement/endorsementList?manager_id=$id',
'${Env.apiUrl}endorsement/endorsementList?manager_id=$managerId',
);
} else if (role == 'agent') {
url = Uri.parse('${Env.apiUrl}endorsement/endorsementList?agent_id=$id');
@ -1323,8 +1339,11 @@ class ApiService {
return response;
}
Future<Map<String, dynamic>> fetchStaffListForEnquiryAssignDropDown(id,
role,) async {
Future<Map<String, dynamic>> fetchStaffListForEnquiryAssignDropDown(
managerId,
id,
role,
) async {
print('fetchHandlerNameDropDown');
if (_token == null) {
await _initializeToken();
@ -1335,7 +1354,7 @@ class ApiService {
if (role == 'manager') {
url = Uri.parse(
'${Env.apiUrl}staff/staffListForEnquiryAssignDropdown?manager_id=$id',
'${Env.apiUrl}staff/staffListForEnquiryAssignDropdown?manager_id=$managerId',
);
} else {
url = Uri.parse(

View File

@ -706,11 +706,11 @@ class _HoverableContainerState extends State<_HoverableContainer> {
color: Colors.black87,
),
),
Icon(
Icons.arrow_forward_ios_rounded,
size: 10,
color: Colors.grey.shade600,
),
// Icon(
// Icons.arrow_forward_ios_rounded,
// size: 10,
// color: Colors.grey.shade600,
// ),
],
),
),

View File

@ -16,3 +16,4 @@ final staffIndiviualAttendanceNameIdProvider = StateProvider<String?>(
final dashboardKeyProvider = StateProvider<int?>((ref) => null);
final dashboardStatusProvider = StateProvider<String?>((ref) => null);
final dashboardStaffIdProvider = StateProvider<String?>((ref) => null);
final enquiryRefreshProvider = StateProvider<bool>((ref) => false);

View File

@ -26,7 +26,7 @@ class AddDialog extends StatefulWidget {
final dynamic managerId;
final dynamic role;
final void Function(String value) onSubmit;
final dynamic policyNumber;
// final dynamic policyNumber;
const AddDialog({
super.key,
required this.title,
@ -34,7 +34,7 @@ class AddDialog extends StatefulWidget {
required this.userId,
required this.managerId,
required this.role,
this.policyNumber,
// this.policyNumber,
});
@override
@ -69,6 +69,10 @@ class _AddDialogState extends State<AddDialog> {
List<String> tabHeader = ['policyNum', 'claimsDesc', 'remarks'];
final TextEditingController _vehicleSearchController =
TextEditingController();
final TextEditingController _policySearchController = TextEditingController();
final TextEditingController _searchStaffController = TextEditingController();
List<Map<String, dynamic>> getClaimsTypeData = [];
@ -86,6 +90,14 @@ class _AddDialogState extends State<AddDialog> {
List<Map<String, dynamic>> originalData = [];
List<Map<String, dynamic>> filteredData = [];
List<Map<String, dynamic>> getPolicyListData = [];
List<Map<String, dynamic>> originalPolicyData = [];
List<Map<String, dynamic>> filteredPolicyData = [];
List<Map<String, dynamic>> getVehicleListData = [];
List<Map<String, dynamic>> originalVehicleData = [];
List<Map<String, dynamic>> filteredVehicleData = [];
Map<String, dynamic> claimsDetails() {
final data = {
"policy_number": controllers["policyNum"]?.text,
@ -116,7 +128,7 @@ class _AddDialogState extends State<AddDialog> {
controllers[field] = TextEditingController();
}
controllers["policyNum"]?.text = widget.policyNumber;
// controllers["policyNum"]?.text = widget.policyNumber;
print('userIFF - ${widget.userId}');
print('roleIFF - ${widget.role}');
@ -136,6 +148,107 @@ class _AddDialogState extends State<AddDialog> {
getEnroementType();
}
Future<void> getPolicyListSearchData(String val) async {
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchPolicySearch(val);
if (response['status'] == 'success' && response['data'] != null) {
final dataList = List<Map<String, dynamic>>.from(response['data']);
setState(() {
getPolicyListData = dataList;
originalPolicyData = dataList;
filteredPolicyData = List.from(originalPolicyData);
});
} else {
setState(() {
getPolicyListData = [];
originalPolicyData = [];
filteredPolicyData = [];
});
}
} catch (e) {
print('Exception occurred: $e');
setState(() {
getPolicyListData = [];
originalPolicyData = [];
filteredPolicyData = [];
});
} finally {
setState(() {
isLoading = false;
});
}
}
Future<void> getPolicyListSearchData1(val) async {
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchPolicySearch(val);
if (response['status'] == 'success') {
print('E113 => getStaffListData => ${response['data']}');
setState(() {
getPolicyListData = List<Map<String, dynamic>>.from(response['data']);
// filteredData = getPolicyData.where((item) {
// return (item['agent_name'] ?? '-').toLowerCase() ||
// (item['reg_no'] ?? '-').toLowerCase;
// }).toList();
originalPolicyData = getPolicyListData;
filteredPolicyData = List.from(originalPolicyData);
// print('originalData - $getClaimPolicies');
});
} else {
getPolicyListData = [];
originalPolicyData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
Future<void> getVehicleListSearchData(String val) async {
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchVehicleSearch(val);
if (response['status'] == 'success') {
print('E113 => getStaffListData => ${response['data']}');
setState(() {
getVehicleListData = List<Map<String, dynamic>>.from(
response['data'],
);
originalVehicleData = getVehicleListData;
filteredVehicleData = List.from(originalVehicleData);
// print('originalData - $getClaimPolicies');
});
} else {
getVehicleListData = [];
originalVehicleData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
Future<void> getStaffList(
dynamic managerId,
role, {
@ -473,20 +586,160 @@ class _AddDialogState extends State<AddDialog> {
),
const SizedBox(height: 16),
ThemedSearchField(
hintText: 'Search',
// backgroundColor: Color(0xFFF6F8F8),
backgroundColor: Color(0xFFFFFFFF),
txtHeight: 30,
onChanged: filterData,
controller: _searchStaffController,
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
// txtwidth: ResponsiveLayout.isMobile(context)
// ? MediaQuery.of(context).size.width * 0.7
// : MediaQuery.of(context).size.width * 0.15,
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
ThemedSearchField(
hintText: 'Search By Vehicle Number',
backgroundColor: Color(0xFFFFFFFF),
txtHeight: 30,
controller: _vehicleSearchController,
onChanged: (val) async {
if (val.isNotEmpty) {
await getVehicleListSearchData(val);
} else {
setState(() {
// filteredVehicleData = List.from(originalVehicleData);
filteredVehicleData.clear();
});
}
},
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
// Vehicle Search Results
if (filteredVehicleData.isNotEmpty)
Container(
width:
MediaQuery.of(context).size.width * 0.26, // optional
height: 150,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.blueGrey.shade100),
borderRadius: BorderRadius.circular(5),
),
child: ListView.builder(
itemCount: filteredVehicleData.length,
itemBuilder: (context, index) {
final vehicle = filteredVehicleData[index];
return InkWell(
onTap: () {
setState(() {
controllers['policyNum']?.text =
vehicle['policy_number'];
filteredVehicleData.clear();
});
},
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 3,
horizontal: 8,
),
// color: Colors.amber,
child: Text(
vehicle['policy_number'] ?? '-',
style: _textStyle1,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
);
},
),
),
],
),
SizedBox(width: 15),
Column(
children: [
ThemedSearchField(
hintText: 'Search By Policy Number',
backgroundColor: Color(0xFFFFFFFF),
txtHeight: 30,
controller: _policySearchController,
onChanged: (val) async {
if (val.isNotEmpty) {
await getPolicyListSearchData(val);
} else {
setState(() {
// filteredPolicyData = List.from(originalPolicyData);
filteredPolicyData.clear();
});
}
},
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
// Policy Search Results
if (filteredPolicyData.isNotEmpty)
Container(
width:
MediaQuery.of(context).size.width * 0.26, // optional
height: 150,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.blueGrey.shade100),
borderRadius: BorderRadius.circular(5),
),
child: ListView.builder(
itemCount: filteredPolicyData.length,
itemBuilder: (context, index) {
final policy = filteredPolicyData[index];
return InkWell(
onTap: () {
setState(() {
controllers['policyNum']?.text =
policy['policy_number'];
filteredPolicyData.clear();
});
},
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 3,
horizontal: 8,
),
// color: Colors.amber,
child: Text(
policy['policy_number'] ?? '-',
style: _textStyle1,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
);
// ListTile(
// dense: true, // reduces row height
// contentPadding: EdgeInsets.symmetric(
// horizontal: 10,
// vertical: 2,
// ),
// subtitle: Text(
//
// style: _textStyle1,
// ),
// onTap: () {
// setState(() {
//
// // populate other fields as needed
// });
// },
// );
},
),
),
],
),
],
),
const SizedBox(height: 10),
const SizedBox(height: 16),
// 🔹 Switch content dynamically
@ -519,10 +772,24 @@ class _AddDialogState extends State<AddDialog> {
key: _formKeyClaims,
child: Column(
children: [
buildClaimType(context),
buildPolicyNumber(context),
buildUploadDocumentClaims(context),
buildClaimsDesc(context),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
buildClaimType(context),
SizedBox(width: 15),
buildPolicyNumber(context),
],
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
buildUploadDocumentClaims(context),
SizedBox(width: 15),
buildClaimsDesc(context),
],
),
],
),
);
@ -534,9 +801,24 @@ class _AddDialogState extends State<AddDialog> {
key: _formKeyEndrosment,
child: Column(
children: [
buildEndrosType(context),
buildUploadDocumentEndorsment(context),
buildEndrosRemarks(context),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
buildEndrosType(context),
SizedBox(width: 15),
buildPolicyNumber(context),
],
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
buildUploadDocumentClaims(context),
SizedBox(width: 15),
buildEndrosRemarks(context),
],
),
],
),
);
@ -547,7 +829,7 @@ class _AddDialogState extends State<AddDialog> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Policy Number", style: _textStyle),
Text("Policy Number *", style: _textStyle),
SizedBox(height: 10),
ThemedFormField(
controller: controllers['policyNum']!,
@ -566,11 +848,12 @@ class _AddDialogState extends State<AddDialog> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Claims Description *", style: _textStyle),
SizedBox(height: 10),
Text("Claims Description ", style: _textStyle),
// SizedBox(height: 10),
ThemedFormField(
backgroundColor: Color(0xFFEDF6F5),
controller: controllers['claimsDesc']!,
txtheight: 45,
validator: (value) => Validators.requiredField(value, "claimsDesc"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
@ -860,6 +1143,7 @@ class _AddDialogState extends State<AddDialog> {
? null
: MediaQuery.of(context).size.width * 0.26,
keyboardType: TextInputType.multiline,
txtheight: 45,
),
],
);
@ -952,4 +1236,8 @@ class _AddDialogState extends State<AddDialog> {
fontSize: 12,
fontWeight: FontWeight.w600,
);
static final TextStyle _textStyle1 = TextStyle(
fontSize: 9,
fontWeight: FontWeight.w400,
);
}

View File

@ -581,7 +581,7 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
role: null,
managerId: null,
title: "Endorsement",
policyNumber: selectedPolicyNumber,
// policyNumber: selectedPolicyNumber,
onSubmit: (value) {
debugPrint("New Endorsement: $value");
enrollKey.currentState?.getEndrosmentList(selectedPolicyNumber);
@ -608,7 +608,7 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
title: "Claims",
role: null,
managerId: null,
policyNumber: selectedPolicyNumber,
// policyNumber: selectedPolicyNumber,
onSubmit: (value) {
debugPrint("New Claim: $value");
claimsKey.currentState?.getClaimsList(selectedPolicyNumber);

View File

@ -51,23 +51,23 @@ class claimListState extends ConsumerState<claimList> {
// roleId = ref.read(userRoleProvider);
// roleId = ref.read(userRoleProvider);
roleId = ref.read(userRoleProvider);
userId = ref.read(userIdProvider);
print("G47 => r : $roleId | mId: $id | uId: $userId ");
if (userId != null) {
getStaffList(id!, userId);
getStaffList(managerId, userId, roleId);
}
});
}
Future<void> getStaffList(int managerId, role) async {
Future<void> getStaffList(int managerId, int userId, role) async {
print('G54 => Fns called => $managerId | $role');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchClaimList(managerId, role);
final response = await apiService.fetchClaimList(managerId, userId, role);
if (response['status'] == 'success') {
final data = response['data'];
@ -175,6 +175,10 @@ class claimListState extends ConsumerState<claimList> {
];
}
void refresh() {
getStaffList(managerId, userId, roleId);
}
@override
Widget build(BuildContext context) {
return MainLayout(
@ -303,10 +307,12 @@ class claimListState extends ConsumerState<claimList> {
userId: userId,
role: roleId,
title: "Claims",
policyNumber: 'POC_n1',
// policyNumber: 'POC_n1',
// policyNumber: selectedPolicyNumber,
onSubmit: (value) {
debugPrint("New Claims: $value");
refresh();
// enrollKey.currentState?.getEndrosmentList(selectedPolicyNumber);
// Update claim list or call API

View File

@ -49,19 +49,23 @@ class endosementState extends ConsumerState<endosement> {
userId = ref.read(userIdProvider);
print("F46 => r : $roleId | mId: $id | uId: $userId ");
if (userId != null) {
getStaffList(userId, roleId);
getStaffList(managerId, userId, roleId);
}
});
}
Future<void> getStaffList(int managerId, role) async {
Future<void> getStaffList(int managerId, userId, role) async {
print('F53 => Fns called => $managerId | $role');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchEndorsementList(managerId, role);
final response = await apiService.fetchEndorsementList(
managerId,
userId,
role,
);
if (response['status'] == 'success') {
final data = response['data'];
@ -111,6 +115,10 @@ class endosementState extends ConsumerState<endosement> {
return sortedData.sublist(startIndex, endIndex);
}
void refresh() {
getStaffList(managerId, userId, roleId);
}
void filterData(String query) {
print("FilterDAta - $query");
setState(() {
@ -171,7 +179,7 @@ class endosementState extends ConsumerState<endosement> {
@override
Widget build(BuildContext context) {
return MainLayout(
title: "Endosement",
title: "Endorsement",
body: Container(
// color: Colors.yellow.shade50,
width: MediaQuery.of(context).size.width,
@ -293,12 +301,12 @@ class endosementState extends ConsumerState<endosement> {
userId: userId,
role: roleId,
title: "Endorsement",
policyNumber: '1',
// policyNumber: '1',
// policyNumber: selectedPolicyNumber,
onSubmit: (value) {
debugPrint("New Endorsement: $value");
// enrollKey.currentState?.getEndrosmentList(selectedPolicyNumber);
refresh();
// Update claim list or call API
},
),

View File

@ -239,62 +239,74 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
),
),
const SizedBox(height: 26),
Row(
children: [
const Icon(
Icons.phone_outlined,
size: 20,
color: Colors.black,
),
const SizedBox(width: 8),
Text(
profileData?['mobile'] ?? '-',
style: _dataBold,
),
],
),
const SizedBox(height: 8),
Row(
children: [
const Icon(
Icons.email_outlined,
size: 18,
color: Colors.black,
),
const SizedBox(width: 8),
Text(
profileData?['email'] ?? '-',
style: _dataBold,
),
],
),
const SizedBox(height: 16),
if ((roleId != 1) &&
(roleId != 2) &&
(roleId != 3)) ...[
if (profileData?['mobile'] != null ||
profileData?['mobile'] != '') ...[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Icon(
Icons.location_on_outlined,
Icons.phone_outlined,
size: 20,
color: Colors.black,
),
const SizedBox(width: 8),
Text(
profileData?['mobile'] ?? '-',
style: _dataBold,
),
],
),
const SizedBox(height: 8),
],
if (profileData?['email'] != null ||
profileData?['email'] != '') ...[
Row(
children: [
const Icon(
Icons.email_outlined,
size: 18,
color: Colors.black,
),
const SizedBox(width: 8),
Expanded(
child: Text(
profileData?['address'] ?? '-',
style: _dataBold,
softWrap: true,
),
Text(
profileData?['email'] ?? '-',
style: _dataBold,
),
],
),
const SizedBox(height: 20),
const SizedBox(height: 16),
],
if ((roleId != 2) && (roleId != 3)) ...[
if (profileData?['address'] != null ||
profileData?['address'] != '') ...[
if ((roleId != 1) &&
(roleId != 2) &&
(roleId != 3)) ...[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Icon(
Icons.location_on_outlined,
size: 18,
color: Colors.black,
),
const SizedBox(width: 8),
Expanded(
child: Text(
profileData?['address'] ?? '-',
style: _dataBold,
softWrap: true,
),
),
],
),
const SizedBox(height: 20),
],
],
if ((roleId != 1) &&
(roleId != 2) &&
(roleId != 3)) ...[
// Staff, Handler doesn't have this part Only Manager and agent have
Container(
padding: const EdgeInsets.all(6),

View File

@ -93,8 +93,8 @@ class _DashboardState extends ConsumerState<PartnerDashboard> {
final prefroleId = ref.read(userRoleProvider);
print("B81 => roleId: $prefroleId | userId: $prefuserid ");
if (prefuserid != null) {
getParnterDashBrdList(prefuserid);
if (prefmanagerid != null) {
getParnterDashBrdList(prefmanagerid);
// getStaffList(prefmanagerid!, prefroleId, prefuserid);
}
});
@ -324,39 +324,46 @@ class _DashboardState extends ConsumerState<PartnerDashboard> {
),
child: Column(
children: [
Row(
children: [
Expanded(
child: Text(
'Performing Partner ( Top 50 )',
style: _chartHeader,
Padding(
padding: const EdgeInsets.only(
top: 8.0,
bottom: 16.0,
),
child: Row(
children: [
Expanded(
child: Text(
'Performing Partner ( Top 50 )',
style: _chartHeader,
),
),
),
Text(
isPerfomingAgntPolicy
? "Policies"
: "Premium",
style: _styleSmall1,
),
Transform.scale(
scale: 0.5,
child: Switch(
value: isPerfomingAgntPolicy,
activeColor: Colors.teal,
activeTrackColor: Colors.grey.shade200,
inactiveThumbColor: Colors.orange,
inactiveTrackColor: Colors.white,
onChanged: (val) {
setState(
() => isPerfomingAgntPolicy = val,
);
},
),
),
],
// Text(
// isPerfomingAgntPolicy
// ? "Policies"
// : "Premium",
// style: _styleSmall1,
// ),
//
// Transform.scale(
// scale: 0.5,
// child: Switch(
// value: isPerfomingAgntPolicy,
// activeColor: Colors.teal,
// activeTrackColor: Colors.grey.shade200,
// inactiveThumbColor: Colors.orange,
// inactiveTrackColor: Colors.white,
// onChanged: (val) {
// setState(
// () => isPerfomingAgntPolicy = val,
// );
// },
// ),
// ),
],
),
),
Expanded(
child: Performance(
title: "Performing Partner",
@ -497,7 +504,7 @@ class _PerformanceState extends State<Performance> {
Expanded(
flex: 1,
child: Text(
"S.NO",
"S.no.",
textAlign: TextAlign.left,
style: _headerStyle,
),
@ -518,20 +525,24 @@ class _PerformanceState extends State<Performance> {
style: _headerStyle,
),
),
(widget.title == 'Performing Partner')
? Expanded(
flex: 1,
child: Text(
widget.isPerfomingAgntPolicy
? "Policy Count"
: "Premium Count",
textAlign: TextAlign.center,
style: _headerStyle,
),
)
: SizedBox(),
if (widget.title == 'Performing Partner') ...[
Expanded(
flex: 1,
child: Text(
"Policy Count",
textAlign: TextAlign.center,
style: _headerStyle,
),
),
Expanded(
flex: 1,
child: Text(
"Premium Amount",
textAlign: TextAlign.center,
style: _headerStyle,
),
),
],
],
),
),
@ -586,30 +597,47 @@ class _PerformanceState extends State<Performance> {
),
),
(widget.title == 'Performing Partner')
? Expanded(
flex: 1,
child: Text(
isPerfomingAgntPolicy
? (row['policy_count']?.toString() ?? "0")
: (row['total_premium_amount']
?.toString() ??
"0"),
textAlign: TextAlign.center,
style: GoogleFonts.inter(
fontSize: 11,
fontWeight: FontWeight.w500,
// color: isPerfomingAgntPolicy
// ? Colors.black
// : (row['status']?.toString().toLowerCase() ==
// "active"
// ? Colors.green
// : Colors.red),
),
),
)
: SizedBox(),
if (widget.title == 'Performing Partner') ...[
Expanded(
flex: 1,
child: Text(
row['policy_count'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
),
Expanded(
flex: 1,
child: Text(
row['total_premium_amount'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
),
],
// (widget.title == 'Performing Partner')
// ? Expanded(
// flex: 1,
// child: Text(
// isPerfomingAgntPolicy
// ? (row['policy_count']?.toString() ?? "0")
// : (row['total_premium_amount']
// ?.toString() ??
// "0"),
// textAlign: TextAlign.center,
// style: GoogleFonts.inter(
// fontSize: 11,
// fontWeight: FontWeight.w500,
// // color: isPerfomingAgntPolicy
// // ? Colors.black
// // : (row['status']?.toString().toLowerCase() ==
// // "active"
// // ? Colors.green
// // : Colors.red),
// ),
// ),
// )
// : SizedBox(),
],
),
);

View File

@ -43,9 +43,14 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
bool showStaff = true;
bool showProduct = true;
int selectedStaffIndex = 0;
List<List<String>> staffVehicleTypeNames =
[]; // 👈 Add this at the top with other state variables
Map<String, Color> vehicleColors = {};
List<String> staffLabels = [];
// List<List<List<dynamic>>> staffChartData = [];
List<List<List<dynamic>>> staffChartData = [];
double maxPremium = 0;
int selectedView = 0;
@ -74,137 +79,171 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
});
}
// Add this helper method:
double _getSmartMaxValue() {
if (maxPremium <= 0) return 10;
// For policies (small numbers), ensure minimum scale
if (isInsureWisePolicy) {
if (maxPremium < 10) {
return 12; // Minimum scale of 10 for policies
}
// Round up to nearest 5
return ((maxPremium / 5).ceil() * 5).toDouble();
}
// For premium (large numbers)
return (maxPremium * 1.15).ceilToDouble(); // 15% headroom
}
Color _generateColorForVehicle(String vehicleType, int index) {
// Predefined colors for common vehicle types
const predefinedColors = [
Colors.blue,
Colors.green,
Colors.orange,
Colors.purple,
Colors.red,
Colors.teal,
Colors.pink,
Colors.indigo,
Colors.amber,
Colors.cyan,
Colors.lime,
Colors.deepOrange,
];
// If within predefined range, use those
if (index < predefinedColors.length) {
return predefinedColors[index];
}
// Otherwise generate using HSL for infinite colors
final hue = (index * 137.5) % 360; // Golden angle for distribution
return HSLColor.fromAHSL(1.0, hue, 0.6, 0.5).toColor();
}
Future<void> getProductivityDashBrdList(id) async {
// print('getClaimList called MagId - $managerId - $role');
setState(() {
isLoading = true;
});
// dynamic id = widget.policyNumber;
print('getProductivityDshID - $id');
try {
final response = await apiService.findProductivityDashboardData(
id,
SelctdProductivityproduct,
);
if (response['status'] == 'success') {
final data = response['data'];
print('getProductivityDshBdData - ${response['data']}');
if (response['status'] != 'success') {
setState(() {
if (data is Map<String, dynamic>) {
staffLabels.clear();
staffChartData.clear();
maxPremium = 0;
final staffWise = (data['StaffWise'] ?? []) as List<dynamic>;
staffLabels.clear();
staffChartData.clear();
maxPremium = 0.0;
double _toDouble(dynamic v) {
if (v == null) return 0.0;
if (v is double) return v;
if (v is int) return v.toDouble();
return double.tryParse(v.toString()) ?? 0.0;
}
for (var staff in staffWise) {
final name = staff['sales_executive_name']?.toString() ?? '';
staffLabels.add(name);
double totalPre = 0.0;
double totalCur = 0.0;
final products = (staff['products_list'] ?? []) as List<dynamic>;
for (var p in products) {
totalPre += _toDouble(p['total_premium_pre_month']);
totalCur += _toDouble(p['total_premium_current_month']);
}
// build 3 stacks: preMonth, currentMonth (stacked after pre), extra (difference optional)
final preStart = 0.0;
final preEnd = totalPre;
final curStart = preEnd;
final curEnd = preEnd + totalCur;
// optional extra stack (here zero, but kept for structure)
final extraStart = curEnd;
final extraEnd = curEnd; // no extra by default
// update chart max
maxPremium = [maxPremium, curEnd].reduce((a, b) => a > b ? a : b);
staffChartData.add([
[preStart, preEnd, Colors.cyan],
[curStart, curEnd, Colors.blueAccent],
// include extra only if needed >0
if ((extraEnd - extraStart) > 0)
[extraStart, extraEnd, Colors.grey],
]);
}
// use setState to save and pass to chart
setState(() {
originalStaffWise = List.from(staffWise); // if you need
staffLabels = staffLabels;
staffChartData = staffChartData;
// choose a little padding for maxY
final chartMax = (maxPremium * 1.1).ceilToDouble();
// store chartMax somewhere e.g. chartMaxY
});
setState(() {});
}
// if (data is List) {
// // Already a list of maps
// getProductivityDshBdData = List<Map<String, dynamic>>.from(data);
// } else if (data is Map) {
// // Single object, wrap in a list
// getProductivityDshBdData = [Map<String, dynamic>.from(data)];
// } else {
// getProductivityDshBdData = [];
// }
// // getProductivityDshBdData = List<Map<String, dynamic>>.from(response['data']);
// originalData = getProductivityDshBdData;
// filteredData = List.from(originalData);
// // print('originalData - $getClaimPolicies');
isLoading = false;
});
if (data is Map<String, dynamic>) {
setState(() {
// Store BrokerWise
productWise = List<Map<String, dynamic>>.from(
data['productWise'] ?? [],
);
// Store ProductWise
productWise = List<Map<String, dynamic>>.from(
data['productWise'] ?? [],
);
print('productWise - ${productWise}');
originalProductWise = List.from(productWise);
filteredProductWise = List.from(productWise);
// Store StaffWise
insurerWise = List<Map<String, dynamic>>.from(
data['insurerWise'] ?? [],
);
print('insurerWise - ${insurerWise}');
originalStaffWise = List.from(insurerWise);
filteredStaffWise = List.from(insurerWise);
});
} else {
// fallback
productWise = [];
productWise = [];
insurerWise = [];
}
} else {
getProductivityDshBdData = [];
originalData = [];
return;
}
final data = response['data'];
final staffWise = (data['StaffWise'] ?? []) as List<dynamic>;
print('data - $data');
print('staffWise - $staffWise');
// 🎨 STEP 1: Collect ALL unique vehicle types across all staff
Set<String> allVehicleTypes = {};
for (var staff in staffWise) {
final products = (staff['products_list'] ?? []) as List<dynamic>;
for (var p in products) {
final vehicleType = p['vechile_type']?.toString() ?? 'Unknown';
allVehicleTypes.add(vehicleType);
}
}
// 🎨 STEP 2: Generate dynamic colors for all vehicle types
Map<String, Color> dynamicVehicleColors = {};
int colorIndex = 0;
for (var vehicleType in allVehicleTypes) {
dynamicVehicleColors[vehicleType] = _generateColorForVehicle(
vehicleType,
colorIndex++,
);
}
print('Dynamic Vehicle Colors: $dynamicVehicleColors');
List<String> newLabels = [];
List<List<List<dynamic>>> newChartData = [];
List<List<String>> vehicleNames = [];
double newMax = 0.0;
double _toDouble(dynamic v) {
if (v == null) return 0.0;
if (v is double) return v;
if (v is int) return v.toDouble();
return double.tryParse(v.toString()) ?? 0.0;
}
for (var staff in staffWise) {
final name =
(staff['sales_executive_name'] ?? staff['short_name'])
?.toString() ??
'';
newLabels.add(name);
final products = (staff['products_list'] ?? []) as List<dynamic>;
List<List<dynamic>> currentRod = [];
List<List<dynamic>> previousRod = [];
List<String> staffVehicleNames = [];
double curStart = 0.0;
double preStart = 0.0;
for (var p in products) {
final cur = isInsureWisePolicy
? _toDouble(p['total_policies_current_month'])
: _toDouble(p['total_premium_current_month']);
final pre = isInsureWisePolicy
? _toDouble(p['total_policies_pre_month'])
: _toDouble(p['total_premium_pre_month']);
// Get vehicle type and its DYNAMIC color
final vehicleType = p['vechile_type']?.toString() ?? 'Unknown';
final color = dynamicVehicleColors[vehicleType] ?? Colors.grey;
staffVehicleNames.add(vehicleType);
// Add to current month rod with vehicle-specific color
currentRod.add([curStart, curStart + cur, color]);
curStart += cur;
// Add to previous month rod with lighter shade (60% opacity)
previousRod.add([preStart, preStart + pre, color.withOpacity(0.6)]);
preStart += pre;
}
newChartData.add([currentRod, previousRod]);
vehicleNames.add(staffVehicleNames);
newMax = [newMax, curStart, preStart].reduce((a, b) => a > b ? a : b);
}
setState(() {
originalStaffWise = staffWise
.map((e) => Map<String, dynamic>.from(e))
.toList();
filteredStaffWise = List<Map<String, dynamic>>.from(originalStaffWise);
staffLabels = newLabels;
staffChartData = newChartData;
staffVehicleTypeNames = vehicleNames;
vehicleColors = dynamicVehicleColors; // Save for legend
maxPremium = newMax;
productWise = List<Map<String, dynamic>>.from(
data['productWise'] ?? [],
);
insurerWise = List<Map<String, dynamic>>.from(
data['insurerWise'] ?? [],
);
});
} catch (e) {
print('Exception occurred: $e');
} finally {
@ -214,6 +253,31 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
}
}
List<String> buildStaffLabels() {
return filteredStaffWise.map<String>((item) {
final name = item['sales_executive_name'] ?? item['short_name'];
if (name != null && name.toString().trim().isNotEmpty) {
return name.toString();
} else {
return item['sales_executive_name']?.toString() ?? '';
}
}).toList();
}
List<Map<String, dynamic>> convertToProductList(List<dynamic> rawList) {
return rawList.map<Map<String, dynamic>>((item) {
return {
"vehicle_type": item[0],
"current_month": double.tryParse(item[1].toString()) ?? 0.0,
"previous_month": double.tryParse(item[2].toString()) ?? 0.0,
};
}).toList();
}
// In insurerContainer() you are passing staffLabels (which we now populate).
// Also set the chart maxY to some headroom:
// CustomStackedBarChart(..., maxY: (maxPremium * 1.1).ceilToDouble(), ...)
List<BarData> buildStaffBarData() {
double parseDouble(dynamic value) {
if (value == null) return 0.0;
@ -241,17 +305,6 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
}).toList();
}
List<String> buildStaffLabels() {
return filteredStaffWise.map<String>((item) {
final name = item['short_name'];
if (name != null && name.toString().trim().isNotEmpty) {
return name.toString();
} else {
return item['short_name']?.toString() ?? '';
}
}).toList();
}
List<BarData> buildProductBarData() {
double parseDouble(dynamic value) {
if (value == null) return 0.0;
@ -297,52 +350,53 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
// color: Colors.amber.shade100,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Hide and Show Charts : ', style: _styleSmall1),
Row(
children: [
Transform.scale(
scale: 0.75,
child: Checkbox(
value: showStaff,
onChanged: (val) {
setState(() => showStaff = val!);
},
),
),
Text(
// showStaff ? "Staff" : "Staff Hidden",
"Staff",
style: _styleSmall2,
),
],
),
// SizedBox(width: 10),
//
// Row(
// children: [
// Transform.scale(
// scale: 0.75,
// child: Checkbox(
// value: showProduct,
// onChanged: (val) {
// setState(() => showProduct = val!);
// },
// ),
// ),
// Text(
// // showBroker ? "Broker" : "Broker Hidden",
// "Product",
// style: _styleSmall2,
// ),
// ],
// ),
],
),
// Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Text('Hide and Show Charts : ', style: _styleSmall1),
//
// Row(
// children: [
// Transform.scale(
// scale: 0.75,
// child: Checkbox(
// value: showStaff,
// onChanged: (val) {
// setState(() => showStaff = val!);
// },
// ),
// ),
// Text(
// // showStaff ? "Staff" : "Staff Hidden",
// "Staff",
// style: _styleSmall2,
// ),
// ],
// ),
//
// // SizedBox(width: 10),
// //
// // Row(
// // children: [
// // Transform.scale(
// // scale: 0.75,
// // child: Checkbox(
// // value: showProduct,
// // onChanged: (val) {
// // setState(() => showProduct = val!);
// // },
// // ),
// // ),
// // Text(
// // // showBroker ? "Broker" : "Broker Hidden",
// // "Product",
// // style: _styleSmall2,
// // ),
// // ],
// // ),
// ],
// ),
SizedBox(height: 10),
Expanded(
child: Row(
@ -361,8 +415,7 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
Widget insurerContainer() {
final chartStaffData = buildStaffBarData();
final chartStaffLabels = buildStaffLabels();
print('chartStaffData - $chartStaffData');
print('chartStaffLabels - $chartStaffLabels');
return Container(
padding: EdgeInsets.all(10),
margin: EdgeInsets.only(right: 20),
@ -378,7 +431,7 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
children: [
Expanded(
child: Text(
'Staff Wise (Previous / Current Month)',
'Sales Executive Product Wise (Previous / Current Month)',
style: _chartHeader,
),
),
@ -390,99 +443,119 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
scale: 0.5,
child: Switch(
value: isInsureWisePolicy,
onChanged: (val) => setState(() => isInsureWisePolicy = val),
onChanged: (val) {
setState(() {
isInsureWisePolicy = val;
});
// 👇 ADD THIS: Rebuild chart data with new toggle value
getProductivityDashBrdList(managerId);
},
),
),
],
),
SizedBox(height: 10),
// Expanded(
// child: Container(
// clipBehavior: Clip.none,
// // color: Colors.red.shade100,
// child: CustomStackedBarChart(
// labels: staffLabels, // 👈 staff names
// maxY: maxPremium + 5000, // avoid touching border
// data: staffChartData,
// ),
// ),
// ),
Expanded(
child: CustomStackedBarChart(
labels: staffLabels,
data: staffChartData,
maxY: (maxPremium * 1.1).ceilToDouble(), // a bit of headroom
// maxY: (maxPremium * 1.1).ceilToDouble(),
maxY: _getSmartMaxValue(),
initialRotation: 1,
dataList: [],
productsList: staffChartData,
vehicleTypeNames:
staffVehicleTypeNames, // 👈 NEW: Pass vehicle names
),
),
legendWidget(),
Row(children: [Expanded(child: legendWidget())]),
],
),
);
}
Widget productContainer() {
final chartProductData = buildProductBarData();
final chartProductLabels = buildProductLabels();
print('chartProductData - $chartProductData');
print('chartProductLabels - $chartProductLabels');
return Container(
padding: EdgeInsets.all(10),
margin: EdgeInsets.only(right: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
'Staff Product Wise (Previous / Current Month)',
style: _chartHeader,
),
),
Text(
isProductWisePolicy ? "Policies" : "Premium",
style: _styleSmall1,
),
Transform.scale(
scale: 0.5,
child: Switch(
value: isProductWisePolicy,
onChanged: (val) => setState(() => isProductWisePolicy = val),
),
),
],
),
SizedBox(height: 10),
Expanded(
child: CustomBarChart(
dataList: chartProductData,
labels: chartProductLabels,
),
),
legendWidget(),
],
),
);
}
// Widget productContainer() {
// final chartProductData = buildProductBarData();
// final chartProductLabels = buildProductLabels();
// print('chartProductData - $chartProductData');
// print('chartProductLabels - $chartProductLabels');
// return Container(
// padding: EdgeInsets.all(10),
// margin: EdgeInsets.only(right: 20),
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius: BorderRadius.circular(10),
// ),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Row(
// children: [
// Expanded(
// child: Text(
// 'Sales Executive Product Wise (Previous / Current Month)',
// style: _chartHeader,
// ),
// ),
// Text(
// isProductWisePolicy ? "Policies" : "Premium",
// style: _styleSmall1,
// ),
// Transform.scale(
// scale: 0.5,
// child: Switch(
// value: isProductWisePolicy,
// onChanged: (val) => setState(() => isProductWisePolicy = val),
// ),
// ),
// ],
// ),
// SizedBox(height: 10),
// Expanded(
// child: CustomBarChart(
// dataList: chartProductData,
// labels: chartProductLabels,
// ),
// ),
// legendWidget(),
// ],
// ),
// );
// }
Widget legendWidget() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
return Wrap(
spacing: 8,
runSpacing: 5,
alignment: WrapAlignment.center,
children: [
Icon(Icons.circle, size: 10, color: Colors.cyan.shade300),
SizedBox(width: 2),
Text('Current Month', style: _styleSmall1),
SizedBox(width: 5),
Icon(Icons.circle, size: 10, color: Colors.orange.shade300),
SizedBox(width: 2),
Text('Previous Month', style: _styleSmall1),
// Vehicle type legends (dynamically generated)
...vehicleColors.entries.map((entry) {
return _legendItem(entry.key, entry.value);
}),
// Separator
SizedBox(width: 10),
Container(height: 12, width: 1, color: Colors.grey.shade300),
SizedBox(width: 10),
// // Month legends
// _legendItem('Current (Solid)', Colors.black87),
// _legendItem('Previous (Light)', Colors.black38),
],
);
}
Widget _legendItem(String label, Color color) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 10,
height: 10,
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
),
SizedBox(width: 4),
Text(label, style: _styleSmall1),
],
);
}

View File

@ -369,6 +369,7 @@ class EnquiryHandlerState extends ConsumerState<EnquiryListHandler> {
try {
// final response = await apiService.fetchStaffUserList(id, role);
final response = await apiService.fetchStaffListForEnquiryAssignDropDown(
managerId,
id,
roleId,
);

View File

@ -639,7 +639,9 @@ class CreateProposal_QuickFormState
print("Response: ${response.body}");
// ToastHelper.showErrorToast(context, 'Proposal Created');
reset();
getQuickQuotationList(managerId);
// Navigator.of(context).pop();
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
@ -699,8 +701,17 @@ class CreateProposal_QuickFormState
print("tre1");
selectedId = null; // just update field
Navigator.of(context).pop();
// final prefs = await SharedPreferences.getInstance();
// await prefs.setString('QuoteKeyProvider', 'fromQuickQuote');
WidgetsBinding.instance.addPostFrameCallback((_) {
// Now safe to do navigation + provider updates
final container = ProviderScope.containerOf(context);
container.read(enquiryRefreshProvider.notifier).state = true;
context.go('/enquiryForStaff');
});
context.go('/enquiryForStaff');
print("tre11");
getQuickQuotationList(managerId);
} else if (response.statusCode == 403) {
@ -1559,7 +1570,8 @@ class CreateProposal_QuickFormState
bordedRad: 5,
// backgroundColor: Color(0xFFEDF6F5),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')),
// FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')),
FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d{0,2}$')),
],
// validator: (value) =>
// Validators.doubleNumber(value, "PremiumAmount"),

View File

@ -369,6 +369,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInlineTST> {
try {
// final response = await apiService.fetchStaffUserList(id, role);
final response = await apiService.fetchStaffListForEnquiryAssignDropDown(
managerId,
id,
roleId,
);

View File

@ -484,6 +484,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
try {
// final response = await apiService.fetchStaffUserList(id, role);
final response = await apiService.fetchStaffListForEnquiryAssignDropDown(
managerId,
id,
roleId,
);

View File

@ -59,6 +59,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
dynamic idPrimary;
dynamic managerId;
dynamic dashboardKey;
dynamic quickQuotationKey;
dynamic SelectedStatus;
dynamic SelectedStaffId;
String? selectedFileNames;
@ -79,6 +80,14 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
List<Map<String, dynamic>> originalData = [];
List<Map<String, dynamic>> filteredData = [];
bool isLoading = false;
bool isLoadingInsurers = false;
bool isLoadingInsuranceType = false;
bool isLoadingBroker = false;
bool isLoadingPaymentMode = false;
bool isLoadingStaffEnqAssign = false;
bool isLoadingStaffList = false;
bool isLoadingVehicleType = false;
bool isLoadingAgentList = false;
dynamic roleId;
bool _showFilterRow = false;
@ -100,6 +109,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
Map<int, bool> isEditingRow = {};
Map<int, Map<String, TextEditingController>> rowControllers = {};
late ProviderSubscription<bool> refreshSub;
//---------------------- Enquiry TAB Initializations Starts -------------------------------- //
@ -139,6 +149,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
String? selectedId;
// int selectedIndex = 1;
int selectedIndex = 0;
int autoRefreshIndex = 0;
@ -213,6 +224,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
Timer? timer;
int selectedSeconds = 30;
bool isActionable = false;
bool _listened = false;
//---------------------- Assign Staff Ends -------------------------------- //
//---------------------- Enquiry TAB Initializations Ends -------------------------------- //
@ -238,11 +250,13 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
final prefs = await SharedPreferences.getInstance();
dashboardKey = prefs.getString('dashboardKeyProvider');
quickQuotationKey = prefs.getString('QuoteKeyProvider');
final dashboardStatus = prefs.getString('dashboardStatusProvider');
final dashboardStaffId = prefs.getString('dashboardStaffIdProvider');
print('handlerIdENQ - $handlerId');
print("C72 => r : $roleId | uId: $userId !mID : $managerId ");
print('quickQuotationKey');
print('dashboardKey - $dashboardKey');
print('dashboardStatus - $dashboardStatus');
@ -277,6 +291,15 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
print('hansles');
getStaffDetailsForEnquiryAssignment(userID);
}
ref.listen(enquiryRefreshProvider, (prev, next) {
print('quickQuotationKey1');
if (next == true) {
print('quickQuotationKey2 - $next');
callRefresh();
ref.read(enquiryRefreshProvider.notifier).state = false; // reset
}
});
});
getVehicleType();
@ -284,6 +307,18 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
getInsuranceType();
getBroker();
getPaymentMode();
refreshSub = ref.listenManual<bool>(enquiryRefreshProvider, (
previous,
next,
) {
if (next == true) {
print('refresh triggered Quick Creation');
callRefresh();
ref.read(enquiryRefreshProvider.notifier).state = false;
}
});
}
Future<void> loadPreferences() async {
@ -359,6 +394,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
@override
void dispose() {
refreshSub.close();
_horizontalScrollController.dispose();
// ... dispose other controllers ...
super.dispose();
@ -421,7 +457,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
Future<void> getInsurers() async {
print('Insurers called');
setState(() {
isLoading = true;
isLoadingInsurers = true;
});
try {
@ -444,7 +480,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
isLoadingInsurers = false;
});
}
}
@ -452,7 +488,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
Future<void> getInsuranceType() async {
print('getClaimList called');
setState(() {
isLoading = true;
isLoadingInsuranceType = true;
});
try {
@ -477,7 +513,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
isLoadingInsuranceType = false;
});
}
}
@ -485,7 +521,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
Future<void> getBroker() async {
print('getBroker called');
setState(() {
isLoading = true;
isLoadingBroker = true;
});
try {
@ -508,7 +544,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
isLoadingBroker = false;
});
}
}
@ -516,7 +552,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
Future<void> getPaymentMode() async {
print('getPaymentMode called');
setState(() {
isLoading = true;
isLoadingPaymentMode = true;
});
try {
@ -541,7 +577,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
isLoadingPaymentMode = false;
});
}
}
@ -549,12 +585,13 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
Future<void> getStaffDetailsForEnquiryAssignment(int id) async {
print('getStaffDetailsForEnquiryAssignment called By handler');
setState(() {
isLoading = true;
isLoadingStaffEnqAssign = true;
});
try {
// final response = await apiService.fetchStaffUserList(id, role);
final response = await apiService.fetchStaffListForEnquiryAssignDropDown(
managerId,
id,
roleId,
);
@ -578,7 +615,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
isLoadingStaffEnqAssign = false;
});
}
}
@ -593,7 +630,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
}) async {
print('DAJJshA72 => Fns called => $managerId | $role');
setState(() {
isLoading = true;
isLoadingStaffList = true;
});
dynamic fromDt;
@ -612,7 +649,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
final yesterday = today.subtract(Duration(days: 1));
fromDt = dateFormat.format(yesterday.subtract(Duration(days: 5)));
fromDt = dateFormat.format(yesterday.subtract(Duration(days: 2)));
toDt = dateFormat.format(yesterday);
print('PrevPending FROM TO - $fromDt - $toDt');
@ -635,7 +672,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
print("ENQ LIST PAGE");
final today = DateTime.now();
fromDt = dateFormat.format(today.subtract(Duration(days: 5)));
fromDt = dateFormat.format(today.subtract(Duration(days: 2)));
// fromDt = dateFormat.format(today);
toDt = dateFormat.format(today);
@ -694,13 +731,13 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
print('ToDate : $toDate');
setState(() {
if (SelectedStatus == 'Completed' || autoRefreshIndex == 1) {
selectedIndex = 1;
SelectedStatus = 'Completed';
} else {
selectedIndex = 0;
SelectedStatus = 'OtherThenCompleted';
}
// if (SelectedStatus == 'Completed' || autoRefreshIndex == 1) {
// selectedIndex = 1;
// SelectedStatus = 'Completed';
// } else {
// selectedIndex = 0;
// SelectedStatus = 'OtherThenCompleted';
// }
controllers['startDate']?.text = fromDate;
controllers['endDate']?.text = toDate;
if (data is List) {
@ -721,7 +758,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
isLoadingStaffList = false;
});
}
}
@ -1516,7 +1553,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
Future<void> getVehicleType() async {
print('getClaimList called');
setState(() {
isLoading = true;
isLoadingVehicleType = true;
});
try {
@ -1541,7 +1578,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
isLoadingVehicleType = false;
});
}
}
@ -1549,7 +1586,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
Future<void> getAgentList(id) async {
print('getAgentListData called');
setState(() {
isLoading = true;
isLoadingAgentList = true;
});
try {
@ -1573,7 +1610,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
isLoadingAgentList = false;
});
}
}
@ -3472,7 +3509,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
"created_on",
"agent_name",
"assigned_to_name",
"insurer_name",
"insurer_short_name",
"reg_no",
"insured_name",
"updated_on",
@ -4003,6 +4040,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
item['insurer_short_name'] != null
? item['insurer_short_name']
: '-',
style: _dataBoldthm2,
),
),
@ -4012,6 +4050,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
item['broker_name'] != null
? _truncateText(item['broker_name'], 8)
: '-',
style: _dataBoldthm4,
),
),
@ -4093,7 +4132,11 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
border: Border.all(color: Color(0xFFE2E8F0)),
borderRadius: BorderRadius.circular(5),
),
child: Text(item['reg_no'] ?? '-', style: _dataBoldthm3),
child: Text(
item['reg_no'] ?? '-',
textAlign: TextAlign.center,
style: _dataBoldthm3,
),
),
// ),
// child: Text(item['reg_no'] ?? '-', style: _dataBold),
@ -4267,40 +4310,40 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
Material(
color: Colors.white,
child: InkWell(
onTap: null,
// hoverColor: Color(0xFFEAF6F4),
// onTap: (item['enquiry_status'] == 'Completed')
// ? () async {
// final prefs =
// await SharedPreferences.getInstance();
//
// // Remove old value (if any)
// await prefs.remove('enqStaffDataId');
//
// // Save the new id
// await prefs.setString(
// 'enqStaffDataId',
// id.toString(),
// );
//
// // Read it back if needed
// final dynamic? enqStaffDataId = prefs.getString(
// 'enqStaffDataId',
// );
//
// // Update provider too
// ref
// .read(quotationStaffIdProvider.notifier)
// .state =
// enqStaffDataId;
//
// buildPolicyCreatedStatusActions(
// context,
// status,
// item['id'],
// );
// }
// : null,
// onTap: null,
hoverColor: Color(0xFFEAF6F4),
onTap: (item['enquiry_status'] == 'Completed')
? () async {
final prefs =
await SharedPreferences.getInstance();
// Remove old value (if any)
await prefs.remove('enqStaffDataId');
// Save the new id
await prefs.setString(
'enqStaffDataId',
id.toString(),
);
// Read it back if needed
final dynamic? enqStaffDataId = prefs.getString(
'enqStaffDataId',
);
// Update provider too
ref
.read(quotationStaffIdProvider.notifier)
.state =
enqStaffDataId;
buildPolicyCreatedStatusActions(
context,
status,
item['id'],
);
}
: null,
child: Container(
padding: EdgeInsets.symmetric(vertical: 2.0),
margin: EdgeInsets.symmetric(vertical: 2),
@ -4963,6 +5006,10 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
print(
"❌ Cancel clicked. Ignoring old file.",
);
ToastHelper.showErrorToast(
context,
'Please upload a new file. No previous file exists.',
);
setState(() {
print('Clear Fields');
selectedFileNames =
@ -5257,15 +5304,15 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
setState(() {
selectedIndex = index;
if (selectedIndex == '1') {
getStaffList(
managerId,
roleId,
SelectedStatus: 'Completed',
);
} else {
getStaffList(managerId, roleId);
}
// if (selectedIndex == '1') {
// getStaffList(
// managerId,
// roleId,
// SelectedStatus: 'Completed',
// );
// } else {
// getStaffList(managerId, roleId);
// }
});
},
child: AnimatedContainer(

View File

@ -367,6 +367,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
try {
// final response = await apiService.fetchStaffUserList(id, role);
final response = await apiService.fetchStaffListForEnquiryAssignDropDown(
managerId,
id,
roleId,
);

View File

@ -351,6 +351,7 @@ class RaiseEnqFormState extends ConsumerState<RaiseEnqForm> {
try {
// final response = await apiService.fetchStaffUserList(id, role);
final response = await apiService.fetchStaffListForEnquiryAssignDropDown(
managerId,
id,
roleId,
);
@ -413,9 +414,8 @@ class RaiseEnqFormState extends ConsumerState<RaiseEnqForm> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
buildAgentName(context, fromHeader: true),
if (roleId != 'staff') ...[buildSelectStaffMem(context)],
buildAgentName(context, fromHeader: true),
buildBroker(context),
buildInsurer(context, fromHeader: true),

View File

@ -76,6 +76,8 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
String? selectedRegNum;
String? selectedStaffName;
dynamic managerId;
Map<String, dynamic> dataDetails() {
final data = {
"id": widget.enquiryPrimaryId,
@ -104,7 +106,7 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
getInsurers();
getBroker();
Future.microtask(() {
final managerId = ref.watch(managerIdProvider);
managerId = ref.watch(managerIdProvider);
// final handlerId = ref.watch(handlerIdProvider);
role = ref.watch(userRoleProvider);
final userID = ref.watch(userIdProvider);
@ -193,6 +195,7 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
try {
// final response = await apiService.fetchStaffUserList(id, role);
final response = await apiService.fetchStaffListForEnquiryAssignDropDown(
managerId,
id,
role,
);

View File

@ -1,20 +1,38 @@
// custom_stacked_bar_chart.dart
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import '../../../data/models/bar_data.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'appChartColors.dart';
class CustomStackedBarChart extends StatefulWidget {
final List<String> labels;
final List<List<List<dynamic>>>
data; // data[group][stackIndex] = [start, end, color]
final List<dynamic> dataList;
final double maxY;
final int initialRotation;
final List<List<List<dynamic>>> productsList;
final List<List<String>>? vehicleTypeNames;
final Map<String, Color>? vehicleColorMap; // Dynamic color mapping
const CustomStackedBarChart({
super.key,
required this.labels,
required this.data,
required this.dataList,
this.maxY = 100.0,
this.initialRotation = 1,
required this.productsList,
this.vehicleTypeNames,
this.vehicleColorMap,
});
@override
@ -30,89 +48,50 @@ class _CustomStackedBarChartState extends State<CustomStackedBarChart> {
rotationTurns = widget.initialRotation;
}
double _toDouble(dynamic v) {
if (v == null) return 0.0;
if (v is double) return v;
if (v is int) return v.toDouble();
return double.tryParse(v.toString()) ?? 0.0;
}
BarChartGroupData _generateGroup(int xIndex) {
// Each group is a single stacked rod (one staff)
final stacks = widget.data[xIndex];
final rodStackItems = <BarChartRodStackItem>[];
for (var s in stacks) {
// s expected: [start, end, color]
final start = _toDouble(s[0]);
final end = _toDouble(s[1]);
final color = (s.length > 2 && s[2] is Color)
? s[2] as Color
: Colors.grey;
rodStackItems.add(BarChartRodStackItem(start, end, color));
}
final maxEnd = rodStackItems.isNotEmpty
? rodStackItems.map((r) => r.toY).reduce((a, b) => a > b ? a : b)
: 0.0;
return BarChartGroupData(
x: xIndex,
groupVertically: false,
barRods: [
BarChartRodData(
toY: maxEnd,
width: 12,
borderRadius: BorderRadius.zero,
rodStackItems: rodStackItems,
),
BarChartRodData(
toY: maxEnd,
width: 12,
borderRadius: BorderRadius.zero,
rodStackItems: rodStackItems,
),
],
);
}
@override
Widget build(BuildContext context) {
final maxY = widget.maxY;
final maxY = widget.maxY <= 0 ? 100.0 : widget.maxY;
return AspectRatio(
aspectRatio: 1.6,
child: BarChart(
BarChartData(
alignment: BarChartAlignment.center,
alignment: BarChartAlignment.spaceAround,
rotationQuarterTurns: rotationTurns,
// gridData: FlGridData(
// show: true,
// checkToShowHorizontalLine: (value) {
// final step = maxY / 5;
// if (step == 0) return false;
// return (value % step).abs() < 0.0001;
// },
// getDrawingHorizontalLine: (value) =>
// FlLine(color: Colors.grey.withOpacity(0.12), strokeWidth: 0.8),
// drawVerticalLine: false,
//
// ),
gridData: FlGridData(
show: true,
checkToShowHorizontalLine: (value) => value % (maxY / 5) == 0,
getDrawingHorizontalLine: (value) =>
FlLine(color: Colors.grey.withOpacity(0.12), strokeWidth: 0.8),
// drawVerticalLine: true,
drawVerticalLine: false,
getDrawingHorizontalLine: (value) => FlLine(
// color: AppColors.gridLinesColor.withValues(alpha: 0.2),
color: Colors.blueGrey.shade100,
// color: Colors.black,
// color: AppColors.borderColor,
strokeWidth: 0.3,
),
),
borderData: FlBorderData(show: false),
barTouchData: BarTouchData(
enabled: true,
touchTooltipData: BarTouchTooltipData(
tooltipRoundedRadius: 6,
tooltipPadding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 6,
// borderData: FlBorderData(show: false),
borderData: FlBorderData(
show: true,
border: Border(
bottom: BorderSide(
color: AppColors.contentColorBlack,
width: 0.1,
),
fitInsideHorizontally: true,
fitInsideVertically: true,
getTooltipItem: (group, groupIndex, rod, rodIndex) {
return BarTooltipItem(
'${rod.toY.toStringAsFixed(2)}',
GoogleFonts.poppins(
color: Colors.black,
fontSize: 12,
fontWeight: FontWeight.w600,
),
);
},
right: BorderSide(color: AppColors.contentColorBlack, width: 0.1),
),
),
titlesData: FlTitlesData(
@ -122,8 +101,9 @@ class _CustomStackedBarChartState extends State<CustomStackedBarChart> {
reservedSize: 56,
getTitlesWidget: (value, meta) {
final i = value.toInt();
if (i < 0 || i >= widget.labels.length)
if (i < 0 || i >= widget.labels.length) {
return const SizedBox();
}
return SideTitleWidget(
meta: meta,
child: Text(
@ -141,11 +121,18 @@ class _CustomStackedBarChartState extends State<CustomStackedBarChart> {
rightTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 40,
reservedSize: 50,
getTitlesWidget: (value, meta) {
return Text(
value.toInt().toString(),
style: GoogleFonts.inter(fontSize: 9),
return Transform.rotate(
angle: -3,
child: Padding(
padding: const EdgeInsets.only(right: 3.0),
child: Text(
value.toInt().toString(),
textAlign: TextAlign.end,
style: GoogleFonts.inter(fontSize: 10),
),
),
);
},
),
@ -153,10 +140,115 @@ class _CustomStackedBarChartState extends State<CustomStackedBarChart> {
leftTitles: const AxisTitles(),
topTitles: const AxisTitles(),
),
barGroups: List.generate(
widget.data.length,
(i) => _generateGroup(i),
barTouchData: BarTouchData(
enabled: true,
touchTooltipData: BarTouchTooltipData(
tooltipRoundedRadius: 8,
tooltipPadding: const EdgeInsets.all(8),
tooltipMargin: 8,
fitInsideHorizontally: true,
fitInsideVertically: true,
getTooltipItem: (group, groupIndex, rod, rodIndex) {
// Determine if this is current or previous month
final isCurrentMonth = rodIndex == 0;
final monthLabel = isCurrentMonth ? 'Current' : 'Previous';
// Calculate total for this rod
final total = rod.rodStackItems.isNotEmpty
? rod.rodStackItems
.map((s) => s.toY - s.fromY)
.reduce((a, b) => a + b)
: 0.0;
// Build detailed breakdown
String breakdown = '';
if (rod.rodStackItems.isNotEmpty) {
for (int i = 0; i < rod.rodStackItems.length; i++) {
final item = rod.rodStackItems[i];
final value = item.toY - item.fromY;
if (value > 0) {
// Try to get vehicle type name if provided
String vehicleName = 'Item ${i + 1}';
if (widget.vehicleTypeNames != null &&
groupIndex < widget.vehicleTypeNames!.length &&
i < widget.vehicleTypeNames![groupIndex].length) {
vehicleName = widget.vehicleTypeNames![groupIndex][i];
}
breakdown +=
'\n$vehicleName: ${value.toStringAsFixed(0)}';
}
}
}
return BarTooltipItem(
'$monthLabel Month\nTotal: ${total.toStringAsFixed(0)}$breakdown',
textAlign: TextAlign.start,
GoogleFonts.poppins(
color: Colors.white,
fontSize: 11,
fontWeight: FontWeight.w500,
),
);
},
),
),
barGroups: widget.productsList.asMap().entries.map((entry) {
int x = entry.key;
List<List<dynamic>> rods = entry.value;
List<BarChartRodStackItem> currentStack = [];
List<BarChartRodStackItem> previousStack = [];
double cumCurrent = 0;
// double cumPrev = 25000;
double cumPrev = 0;
// Current month
for (var item in rods[0]) {
double value = (item[1] - item[0]).toDouble();
currentStack.add(
BarChartRodStackItem(
cumCurrent,
cumCurrent + value,
item[2] as Color? ?? Colors.grey,
),
);
cumCurrent += value;
}
// Previous month
for (var item in rods[1]) {
double value = (item[1] - item[0]).toDouble();
previousStack.add(
BarChartRodStackItem(
cumPrev,
cumPrev + value,
item[2] as Color? ?? Colors.grey,
),
);
cumPrev += value;
}
return BarChartGroupData(
x: x,
groupVertically: false,
barRods: [
BarChartRodData(
toY: cumCurrent,
width: 16,
rodStackItems: currentStack,
borderRadius: BorderRadius.zero,
),
BarChartRodData(
toY: cumPrev,
width: 16,
rodStackItems: previousStack,
borderRadius: BorderRadius.zero,
),
],
);
}).toList(),
maxY: maxY,
),
),

View File

@ -80,6 +80,7 @@ class _DateFilterRowState extends ConsumerState<DateFilterRow> {
String? selectedStaff;
String? selectedStaffName;
dynamic role;
dynamic managerId;
bool isLoading = false;
@ -89,7 +90,7 @@ class _DateFilterRowState extends ConsumerState<DateFilterRow> {
apiService = ApiService();
Future.microtask(() {
final managerId = ref.watch(managerIdProvider);
managerId = ref.watch(managerIdProvider);
final userID = ref.watch(userIdProvider);
// final handlerId = ref.watch(handlerIdProvider);
role = ref.watch(userRoleProvider);
@ -118,6 +119,7 @@ class _DateFilterRowState extends ConsumerState<DateFilterRow> {
try {
// final response = await apiService.fetchStaffUserList(id, role);
final response = await apiService.fetchStaffListForEnquiryAssignDropDown(
managerId,
id,
role,
);