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,39 +771,8 @@ class ApiService {
// ----------------------------------- ENQUIRY ------------------------------------------------- // ----------------------------------- ENQUIRY -------------------------------------------------
Future<Map<String, dynamic>> fetchEnquiryList1(int id, role) async { Future<Map<String, dynamic>> fetchEnquiryList(
// print(_token); int managerid,
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, int id,
String role, { String role, {
String? fromDate, String? fromDate,
@ -1166,23 +1135,67 @@ class ApiService {
// ----------------------------------- CLAIMS ------------------------------------------------- // ----------------------------------- 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); // print(_token);
if (_token == null) { if (_token == null) {
await _initializeToken(); await _initializeToken();
} }
final userId = '1';
final url; final url;
if (role == 'manager') { 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') { } 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') { } 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 { } 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( // final url = Uri.parse(
@ -1213,18 +1226,21 @@ class ApiService {
// ----------------------------------- ENDORSEMENT ------------------------------------------------- // ----------------------------------- ENDORSEMENT -------------------------------------------------
Future<Map<String, dynamic>> fetchEndorsementList(int id, role) async { Future<Map<String, dynamic>> fetchEndorsementList(
managerId,
int id,
role,
) async {
// print(_token); // print(_token);
if (_token == null) { if (_token == null) {
await _initializeToken(); await _initializeToken();
} }
final userId = '1';
final url; final url;
if (role == 'manager') { if (role == 'manager') {
url = Uri.parse( url = Uri.parse(
'${Env.apiUrl}endorsement/endorsementList?manager_id=$id', '${Env.apiUrl}endorsement/endorsementList?manager_id=$managerId',
); );
} else if (role == 'agent') { } else if (role == 'agent') {
url = Uri.parse('${Env.apiUrl}endorsement/endorsementList?agent_id=$id'); url = Uri.parse('${Env.apiUrl}endorsement/endorsementList?agent_id=$id');
@ -1323,8 +1339,11 @@ class ApiService {
return response; return response;
} }
Future<Map<String, dynamic>> fetchStaffListForEnquiryAssignDropDown(id, Future<Map<String, dynamic>> fetchStaffListForEnquiryAssignDropDown(
role,) async { managerId,
id,
role,
) async {
print('fetchHandlerNameDropDown'); print('fetchHandlerNameDropDown');
if (_token == null) { if (_token == null) {
await _initializeToken(); await _initializeToken();
@ -1335,7 +1354,7 @@ class ApiService {
if (role == 'manager') { if (role == 'manager') {
url = Uri.parse( url = Uri.parse(
'${Env.apiUrl}staff/staffListForEnquiryAssignDropdown?manager_id=$id', '${Env.apiUrl}staff/staffListForEnquiryAssignDropdown?manager_id=$managerId',
); );
} else { } else {
url = Uri.parse( url = Uri.parse(

View File

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

View File

@ -16,3 +16,4 @@ final staffIndiviualAttendanceNameIdProvider = StateProvider<String?>(
final dashboardKeyProvider = StateProvider<int?>((ref) => null); final dashboardKeyProvider = StateProvider<int?>((ref) => null);
final dashboardStatusProvider = StateProvider<String?>((ref) => null); final dashboardStatusProvider = StateProvider<String?>((ref) => null);
final dashboardStaffIdProvider = 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 managerId;
final dynamic role; final dynamic role;
final void Function(String value) onSubmit; final void Function(String value) onSubmit;
final dynamic policyNumber; // final dynamic policyNumber;
const AddDialog({ const AddDialog({
super.key, super.key,
required this.title, required this.title,
@ -34,7 +34,7 @@ class AddDialog extends StatefulWidget {
required this.userId, required this.userId,
required this.managerId, required this.managerId,
required this.role, required this.role,
this.policyNumber, // this.policyNumber,
}); });
@override @override
@ -69,6 +69,10 @@ class _AddDialogState extends State<AddDialog> {
List<String> tabHeader = ['policyNum', 'claimsDesc', 'remarks']; List<String> tabHeader = ['policyNum', 'claimsDesc', 'remarks'];
final TextEditingController _vehicleSearchController =
TextEditingController();
final TextEditingController _policySearchController = TextEditingController();
final TextEditingController _searchStaffController = TextEditingController(); final TextEditingController _searchStaffController = TextEditingController();
List<Map<String, dynamic>> getClaimsTypeData = []; List<Map<String, dynamic>> getClaimsTypeData = [];
@ -86,6 +90,14 @@ class _AddDialogState extends State<AddDialog> {
List<Map<String, dynamic>> originalData = []; List<Map<String, dynamic>> originalData = [];
List<Map<String, dynamic>> filteredData = []; 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() { Map<String, dynamic> claimsDetails() {
final data = { final data = {
"policy_number": controllers["policyNum"]?.text, "policy_number": controllers["policyNum"]?.text,
@ -116,7 +128,7 @@ class _AddDialogState extends State<AddDialog> {
controllers[field] = TextEditingController(); controllers[field] = TextEditingController();
} }
controllers["policyNum"]?.text = widget.policyNumber; // controllers["policyNum"]?.text = widget.policyNumber;
print('userIFF - ${widget.userId}'); print('userIFF - ${widget.userId}');
print('roleIFF - ${widget.role}'); print('roleIFF - ${widget.role}');
@ -136,6 +148,107 @@ class _AddDialogState extends State<AddDialog> {
getEnroementType(); 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( Future<void> getStaffList(
dynamic managerId, dynamic managerId,
role, { role, {
@ -473,20 +586,160 @@ class _AddDialogState extends State<AddDialog> {
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
ThemedSearchField( ThemedSearchField(
hintText: 'Search', hintText: 'Search By Vehicle Number',
// backgroundColor: Color(0xFFF6F8F8),
backgroundColor: Color(0xFFFFFFFF), backgroundColor: Color(0xFFFFFFFF),
txtHeight: 30, txtHeight: 30,
onChanged: filterData, controller: _vehicleSearchController,
controller: _searchStaffController, onChanged: (val) async {
if (val.isNotEmpty) {
await getVehicleListSearchData(val);
} else {
setState(() {
// filteredVehicleData = List.from(originalVehicleData);
filteredVehicleData.clear();
});
}
},
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
: MediaQuery.of(context).size.width * 0.26, : 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,
), ),
// 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), const SizedBox(height: 16),
// 🔹 Switch content dynamically // 🔹 Switch content dynamically
@ -518,13 +771,27 @@ class _AddDialogState extends State<AddDialog> {
return Form( return Form(
key: _formKeyClaims, key: _formKeyClaims,
child: Column( child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
buildClaimType(context), buildClaimType(context),
SizedBox(width: 15),
buildPolicyNumber(context), buildPolicyNumber(context),
],
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
buildUploadDocumentClaims(context), buildUploadDocumentClaims(context),
SizedBox(width: 15),
buildClaimsDesc(context), buildClaimsDesc(context),
], ],
), ),
],
),
); );
} }
@ -533,12 +800,27 @@ class _AddDialogState extends State<AddDialog> {
return Form( return Form(
key: _formKeyEndrosment, key: _formKeyEndrosment,
child: Column( child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
buildEndrosType(context), buildEndrosType(context),
buildUploadDocumentEndorsment(context), SizedBox(width: 15),
buildPolicyNumber(context),
],
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
buildUploadDocumentClaims(context),
SizedBox(width: 15),
buildEndrosRemarks(context), buildEndrosRemarks(context),
], ],
), ),
],
),
); );
} }
@ -547,7 +829,7 @@ class _AddDialogState extends State<AddDialog> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text("Policy Number", style: _textStyle), Text("Policy Number *", style: _textStyle),
SizedBox(height: 10), SizedBox(height: 10),
ThemedFormField( ThemedFormField(
controller: controllers['policyNum']!, controller: controllers['policyNum']!,
@ -566,11 +848,12 @@ class _AddDialogState extends State<AddDialog> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text("Claims Description *", style: _textStyle), Text("Claims Description ", style: _textStyle),
SizedBox(height: 10), // SizedBox(height: 10),
ThemedFormField( ThemedFormField(
backgroundColor: Color(0xFFEDF6F5), backgroundColor: Color(0xFFEDF6F5),
controller: controllers['claimsDesc']!, controller: controllers['claimsDesc']!,
txtheight: 45,
validator: (value) => Validators.requiredField(value, "claimsDesc"), validator: (value) => Validators.requiredField(value, "claimsDesc"),
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
@ -860,6 +1143,7 @@ class _AddDialogState extends State<AddDialog> {
? null ? null
: MediaQuery.of(context).size.width * 0.26, : MediaQuery.of(context).size.width * 0.26,
keyboardType: TextInputType.multiline, keyboardType: TextInputType.multiline,
txtheight: 45,
), ),
], ],
); );
@ -952,4 +1236,8 @@ class _AddDialogState extends State<AddDialog> {
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, 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, role: null,
managerId: null, managerId: null,
title: "Endorsement", title: "Endorsement",
policyNumber: selectedPolicyNumber, // policyNumber: selectedPolicyNumber,
onSubmit: (value) { onSubmit: (value) {
debugPrint("New Endorsement: $value"); debugPrint("New Endorsement: $value");
enrollKey.currentState?.getEndrosmentList(selectedPolicyNumber); enrollKey.currentState?.getEndrosmentList(selectedPolicyNumber);
@ -608,7 +608,7 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
title: "Claims", title: "Claims",
role: null, role: null,
managerId: null, managerId: null,
policyNumber: selectedPolicyNumber, // policyNumber: selectedPolicyNumber,
onSubmit: (value) { onSubmit: (value) {
debugPrint("New Claim: $value"); debugPrint("New Claim: $value");
claimsKey.currentState?.getClaimsList(selectedPolicyNumber); 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); // roleId = ref.read(userRoleProvider);
roleId = ref.read(userRoleProvider);
userId = ref.read(userIdProvider); userId = ref.read(userIdProvider);
print("G47 => r : $roleId | mId: $id | uId: $userId "); print("G47 => r : $roleId | mId: $id | uId: $userId ");
if (userId != null) { 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'); print('G54 => Fns called => $managerId | $role');
setState(() { setState(() {
isLoading = true; isLoading = true;
}); });
try { try {
final response = await apiService.fetchClaimList(managerId, role); final response = await apiService.fetchClaimList(managerId, userId, role);
if (response['status'] == 'success') { if (response['status'] == 'success') {
final data = response['data']; final data = response['data'];
@ -175,6 +175,10 @@ class claimListState extends ConsumerState<claimList> {
]; ];
} }
void refresh() {
getStaffList(managerId, userId, roleId);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MainLayout( return MainLayout(
@ -303,10 +307,12 @@ class claimListState extends ConsumerState<claimList> {
userId: userId, userId: userId,
role: roleId, role: roleId,
title: "Claims", title: "Claims",
policyNumber: 'POC_n1', // policyNumber: 'POC_n1',
// policyNumber: selectedPolicyNumber, // policyNumber: selectedPolicyNumber,
onSubmit: (value) { onSubmit: (value) {
debugPrint("New Claims: $value"); debugPrint("New Claims: $value");
refresh();
// enrollKey.currentState?.getEndrosmentList(selectedPolicyNumber); // enrollKey.currentState?.getEndrosmentList(selectedPolicyNumber);
// Update claim list or call API // Update claim list or call API

View File

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

View File

@ -239,6 +239,8 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
), ),
), ),
const SizedBox(height: 26), const SizedBox(height: 26),
if (profileData?['mobile'] != null ||
profileData?['mobile'] != '') ...[
Row( Row(
children: [ children: [
const Icon( const Icon(
@ -254,6 +256,9 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
], ],
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
],
if (profileData?['email'] != null ||
profileData?['email'] != '') ...[
Row( Row(
children: [ children: [
const Icon( const Icon(
@ -269,6 +274,10 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
], ],
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
],
if (profileData?['address'] != null ||
profileData?['address'] != '') ...[
if ((roleId != 1) && if ((roleId != 1) &&
(roleId != 2) && (roleId != 2) &&
(roleId != 3)) ...[ (roleId != 3)) ...[
@ -293,8 +302,11 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
], ],
],
if ((roleId != 2) && (roleId != 3)) ...[ if ((roleId != 1) &&
(roleId != 2) &&
(roleId != 3)) ...[
// Staff, Handler doesn't have this part Only Manager and agent have // Staff, Handler doesn't have this part Only Manager and agent have
Container( Container(
padding: const EdgeInsets.all(6), padding: const EdgeInsets.all(6),

View File

@ -93,8 +93,8 @@ class _DashboardState extends ConsumerState<PartnerDashboard> {
final prefroleId = ref.read(userRoleProvider); final prefroleId = ref.read(userRoleProvider);
print("B81 => roleId: $prefroleId | userId: $prefuserid "); print("B81 => roleId: $prefroleId | userId: $prefuserid ");
if (prefuserid != null) { if (prefmanagerid != null) {
getParnterDashBrdList(prefuserid); getParnterDashBrdList(prefmanagerid);
// getStaffList(prefmanagerid!, prefroleId, prefuserid); // getStaffList(prefmanagerid!, prefroleId, prefuserid);
} }
}); });
@ -324,7 +324,12 @@ class _DashboardState extends ConsumerState<PartnerDashboard> {
), ),
child: Column( child: Column(
children: [ children: [
Row( Padding(
padding: const EdgeInsets.only(
top: 8.0,
bottom: 16.0,
),
child: Row(
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
@ -333,30 +338,32 @@ class _DashboardState extends ConsumerState<PartnerDashboard> {
), ),
), ),
Text( // Text(
isPerfomingAgntPolicy // isPerfomingAgntPolicy
? "Policies" // ? "Policies"
: "Premium", // : "Premium",
style: _styleSmall1, // style: _styleSmall1,
), // ),
//
Transform.scale( // Transform.scale(
scale: 0.5, // scale: 0.5,
child: Switch( // child: Switch(
value: isPerfomingAgntPolicy, // value: isPerfomingAgntPolicy,
activeColor: Colors.teal, // activeColor: Colors.teal,
activeTrackColor: Colors.grey.shade200, // activeTrackColor: Colors.grey.shade200,
inactiveThumbColor: Colors.orange, // inactiveThumbColor: Colors.orange,
inactiveTrackColor: Colors.white, // inactiveTrackColor: Colors.white,
onChanged: (val) { // onChanged: (val) {
setState( // setState(
() => isPerfomingAgntPolicy = val, // () => isPerfomingAgntPolicy = val,
); // );
}, // },
), // ),
), // ),
], ],
), ),
),
Expanded( Expanded(
child: Performance( child: Performance(
title: "Performing Partner", title: "Performing Partner",
@ -497,7 +504,7 @@ class _PerformanceState extends State<Performance> {
Expanded( Expanded(
flex: 1, flex: 1,
child: Text( child: Text(
"S.NO", "S.no.",
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: _headerStyle, style: _headerStyle,
), ),
@ -518,20 +525,24 @@ class _PerformanceState extends State<Performance> {
style: _headerStyle, style: _headerStyle,
), ),
), ),
if (widget.title == 'Performing Partner') ...[
(widget.title == 'Performing Partner') Expanded(
? Expanded(
flex: 1, flex: 1,
child: Text( child: Text(
widget.isPerfomingAgntPolicy "Policy Count",
? "Policy Count"
: "Premium Count",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: _headerStyle, style: _headerStyle,
), ),
) ),
: SizedBox(), 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') if (widget.title == 'Performing Partner') ...[
? Expanded( Expanded(
flex: 1, flex: 1,
child: Text( child: Text(
isPerfomingAgntPolicy row['policy_count'] ?? "",
? (row['policy_count']?.toString() ?? "0")
: (row['total_premium_amount']
?.toString() ??
"0"),
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: GoogleFonts.inter( style: _tableDataStyle,
fontSize: 11,
fontWeight: FontWeight.w500,
// color: isPerfomingAgntPolicy
// ? Colors.black
// : (row['status']?.toString().toLowerCase() ==
// "active"
// ? Colors.green
// : Colors.red),
), ),
), ),
) Expanded(
: SizedBox(), 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 showStaff = true;
bool showProduct = 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<String> staffLabels = [];
// List<List<List<dynamic>>> staffChartData = [];
List<List<List<dynamic>>> staffChartData = []; List<List<List<dynamic>>> staffChartData = [];
double maxPremium = 0; double maxPremium = 0;
int selectedView = 0; int selectedView = 0;
@ -74,33 +79,100 @@ 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 { Future<void> getProductivityDashBrdList(id) async {
// print('getClaimList called MagId - $managerId - $role');
setState(() { setState(() {
isLoading = true; isLoading = true;
}); });
// dynamic id = widget.policyNumber;
print('getProductivityDshID - $id');
try { try {
final response = await apiService.findProductivityDashboardData( final response = await apiService.findProductivityDashboardData(
id, id,
SelctdProductivityproduct, SelctdProductivityproduct,
); );
if (response['status'] == 'success') { if (response['status'] != 'success') {
final data = response['data'];
print('getProductivityDshBdData - ${response['data']}');
setState(() { setState(() {
if (data is Map<String, dynamic>) { isLoading = false;
staffLabels.clear(); });
staffChartData.clear(); return;
maxPremium = 0; }
final data = response['data'];
final staffWise = (data['StaffWise'] ?? []) as List<dynamic>; final staffWise = (data['StaffWise'] ?? []) as List<dynamic>;
staffLabels.clear(); print('data - $data');
staffChartData.clear(); print('staffWise - $staffWise');
maxPremium = 0.0;
// 🎨 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) { double _toDouble(dynamic v) {
if (v == null) return 0.0; if (v == null) return 0.0;
@ -110,101 +182,68 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
} }
for (var staff in staffWise) { for (var staff in staffWise) {
final name = staff['sales_executive_name']?.toString() ?? ''; final name =
staffLabels.add(name); (staff['sales_executive_name'] ?? staff['short_name'])
?.toString() ??
double totalPre = 0.0; '';
double totalCur = 0.0; newLabels.add(name);
final products = (staff['products_list'] ?? []) as List<dynamic>; 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) { for (var p in products) {
totalPre += _toDouble(p['total_premium_pre_month']); final cur = isInsureWisePolicy
totalCur += _toDouble(p['total_premium_current_month']); ? _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;
} }
// build 3 stacks: preMonth, currentMonth (stacked after pre), extra (difference optional) newChartData.add([currentRod, previousRod]);
final preStart = 0.0; vehicleNames.add(staffVehicleNames);
final preEnd = totalPre; newMax = [newMax, curStart, preStart].reduce((a, b) => a > b ? a : b);
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(() { setState(() {
originalStaffWise = List.from(staffWise); // if you need originalStaffWise = staffWise
staffLabels = staffLabels; .map((e) => Map<String, dynamic>.from(e))
staffChartData = staffChartData; .toList();
// choose a little padding for maxY filteredStaffWise = List<Map<String, dynamic>>.from(originalStaffWise);
final chartMax = (maxPremium * 1.1).ceilToDouble();
// store chartMax somewhere e.g. chartMaxY
});
setState(() {}); staffLabels = newLabels;
} staffChartData = newChartData;
staffVehicleTypeNames = vehicleNames;
vehicleColors = dynamicVehicleColors; // Save for legend
maxPremium = newMax;
// 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');
});
if (data is Map<String, dynamic>) {
setState(() {
// Store BrokerWise
productWise = List<Map<String, dynamic>>.from( productWise = List<Map<String, dynamic>>.from(
data['productWise'] ?? [], 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( insurerWise = List<Map<String, dynamic>>.from(
data['insurerWise'] ?? [], data['insurerWise'] ?? [],
); );
print('insurerWise - ${insurerWise}');
originalStaffWise = List.from(insurerWise);
filteredStaffWise = List.from(insurerWise);
}); });
} else {
// fallback
productWise = [];
productWise = [];
insurerWise = [];
}
} else {
getProductivityDshBdData = [];
originalData = [];
}
} catch (e) { } catch (e) {
print('Exception occurred: $e'); print('Exception occurred: $e');
} finally { } 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() { List<BarData> buildStaffBarData() {
double parseDouble(dynamic value) { double parseDouble(dynamic value) {
if (value == null) return 0.0; if (value == null) return 0.0;
@ -241,17 +305,6 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
}).toList(); }).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() { List<BarData> buildProductBarData() {
double parseDouble(dynamic value) { double parseDouble(dynamic value) {
if (value == null) return 0.0; if (value == null) return 0.0;
@ -297,52 +350,53 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
// color: Colors.amber.shade100, // color: Colors.amber.shade100,
child: Column( child: Column(
children: [ children: [
Row( // Row(
mainAxisAlignment: MainAxisAlignment.center, // mainAxisAlignment: MainAxisAlignment.center,
children: [ // children: [
Text('Hide and Show Charts : ', style: _styleSmall1), // 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( // Row(
// children: [ // children: [
// Transform.scale( // Transform.scale(
// scale: 0.75, // scale: 0.75,
// child: Checkbox( // child: Checkbox(
// value: showProduct, // value: showStaff,
// onChanged: (val) { // onChanged: (val) {
// setState(() => showProduct = val!); // setState(() => showStaff = val!);
// }, // },
// ), // ),
// ), // ),
// Text( // Text(
// // showBroker ? "Broker" : "Broker Hidden", // // showStaff ? "Staff" : "Staff Hidden",
// "Product", // "Staff",
// style: _styleSmall2, // 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( Expanded(
child: Row( child: Row(
@ -361,8 +415,7 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
Widget insurerContainer() { Widget insurerContainer() {
final chartStaffData = buildStaffBarData(); final chartStaffData = buildStaffBarData();
final chartStaffLabels = buildStaffLabels(); final chartStaffLabels = buildStaffLabels();
print('chartStaffData - $chartStaffData');
print('chartStaffLabels - $chartStaffLabels');
return Container( return Container(
padding: EdgeInsets.all(10), padding: EdgeInsets.all(10),
margin: EdgeInsets.only(right: 20), margin: EdgeInsets.only(right: 20),
@ -378,7 +431,7 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
'Staff Wise (Previous / Current Month)', 'Sales Executive Product Wise (Previous / Current Month)',
style: _chartHeader, style: _chartHeader,
), ),
), ),
@ -390,99 +443,119 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
scale: 0.5, scale: 0.5,
child: Switch( child: Switch(
value: isInsureWisePolicy, 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), 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( Expanded(
child: CustomStackedBarChart( child: CustomStackedBarChart(
labels: staffLabels, labels: staffLabels,
data: staffChartData, // maxY: (maxPremium * 1.1).ceilToDouble(),
maxY: (maxPremium * 1.1).ceilToDouble(), // a bit of headroom maxY: _getSmartMaxValue(),
initialRotation: 1, initialRotation: 1,
dataList: [],
productsList: staffChartData,
vehicleTypeNames:
staffVehicleTypeNames, // 👈 NEW: Pass vehicle names
), ),
), ),
Row(children: [Expanded(child: legendWidget())]),
legendWidget(),
], ],
), ),
); );
} }
Widget productContainer() { // Widget productContainer() {
final chartProductData = buildProductBarData(); // final chartProductData = buildProductBarData();
final chartProductLabels = buildProductLabels(); // final chartProductLabels = buildProductLabels();
print('chartProductData - $chartProductData'); // print('chartProductData - $chartProductData');
print('chartProductLabels - $chartProductLabels'); // print('chartProductLabels - $chartProductLabels');
return Container( // return Container(
padding: EdgeInsets.all(10), // padding: EdgeInsets.all(10),
margin: EdgeInsets.only(right: 20), // margin: EdgeInsets.only(right: 20),
decoration: BoxDecoration( // decoration: BoxDecoration(
color: Colors.white, // color: Colors.white,
borderRadius: BorderRadius.circular(10), // borderRadius: BorderRadius.circular(10),
), // ),
child: Column( // child: Column(
crossAxisAlignment: CrossAxisAlignment.start, // crossAxisAlignment: CrossAxisAlignment.start,
children: [ // children: [
Row( // Row(
children: [ // children: [
Expanded( // Expanded(
child: Text( // child: Text(
'Staff Product Wise (Previous / Current Month)', // 'Sales Executive Product Wise (Previous / Current Month)',
style: _chartHeader, // style: _chartHeader,
), // ),
), // ),
Text( // Text(
isProductWisePolicy ? "Policies" : "Premium", // isProductWisePolicy ? "Policies" : "Premium",
style: _styleSmall1, // style: _styleSmall1,
), // ),
Transform.scale( // Transform.scale(
scale: 0.5, // scale: 0.5,
child: Switch( // child: Switch(
value: isProductWisePolicy, // value: isProductWisePolicy,
onChanged: (val) => setState(() => isProductWisePolicy = val), // onChanged: (val) => setState(() => isProductWisePolicy = val),
), // ),
), // ),
], // ],
), // ),
SizedBox(height: 10), // SizedBox(height: 10),
Expanded( // Expanded(
child: CustomBarChart( // child: CustomBarChart(
dataList: chartProductData, // dataList: chartProductData,
labels: chartProductLabels, // labels: chartProductLabels,
), // ),
), // ),
legendWidget(), // legendWidget(),
], // ],
), // ),
); // );
} // }
Widget legendWidget() { Widget legendWidget() {
return Row( return Wrap(
mainAxisAlignment: MainAxisAlignment.center, spacing: 8,
runSpacing: 5,
alignment: WrapAlignment.center,
children: [ children: [
Icon(Icons.circle, size: 10, color: Colors.cyan.shade300), // Vehicle type legends (dynamically generated)
SizedBox(width: 2), ...vehicleColors.entries.map((entry) {
Text('Current Month', style: _styleSmall1), return _legendItem(entry.key, entry.value);
SizedBox(width: 5), }),
Icon(Icons.circle, size: 10, color: Colors.orange.shade300),
SizedBox(width: 2), // Separator
Text('Previous Month', style: _styleSmall1), 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 { try {
// final response = await apiService.fetchStaffUserList(id, role); // final response = await apiService.fetchStaffUserList(id, role);
final response = await apiService.fetchStaffListForEnquiryAssignDropDown( final response = await apiService.fetchStaffListForEnquiryAssignDropDown(
managerId,
id, id,
roleId, roleId,
); );

View File

@ -639,7 +639,9 @@ class CreateProposal_QuickFormState
print("Response: ${response.body}"); print("Response: ${response.body}");
// ToastHelper.showErrorToast(context, 'Proposal Created'); // ToastHelper.showErrorToast(context, 'Proposal Created');
reset(); reset();
getQuickQuotationList(managerId); getQuickQuotationList(managerId);
// Navigator.of(context).pop(); // Navigator.of(context).pop();
} else if (response.statusCode == 403) { } else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect(); await apiService.clearLocalStorageAndRedirect();
@ -699,8 +701,17 @@ class CreateProposal_QuickFormState
print("tre1"); print("tre1");
selectedId = null; // just update field selectedId = null; // just update field
Navigator.of(context).pop(); 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"); print("tre11");
getQuickQuotationList(managerId); getQuickQuotationList(managerId);
} else if (response.statusCode == 403) { } else if (response.statusCode == 403) {
@ -1559,7 +1570,8 @@ class CreateProposal_QuickFormState
bordedRad: 5, bordedRad: 5,
// backgroundColor: Color(0xFFEDF6F5), // backgroundColor: Color(0xFFEDF6F5),
inputFormatters: [ inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')), // FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')),
FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d{0,2}$')),
], ],
// validator: (value) => // validator: (value) =>
// Validators.doubleNumber(value, "PremiumAmount"), // Validators.doubleNumber(value, "PremiumAmount"),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,20 +1,38 @@
// custom_stacked_bar_chart.dart
import 'package:fl_chart/fl_chart.dart'; import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.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 { class CustomStackedBarChart extends StatefulWidget {
final List<String> labels; final List<String> labels;
final List<List<List<dynamic>>> final List<dynamic> dataList;
data; // data[group][stackIndex] = [start, end, color]
final double maxY; final double maxY;
final int initialRotation; final int initialRotation;
final List<List<List<dynamic>>> productsList;
final List<List<String>>? vehicleTypeNames;
final Map<String, Color>? vehicleColorMap; // Dynamic color mapping
const CustomStackedBarChart({ const CustomStackedBarChart({
super.key, super.key,
required this.labels, required this.labels,
required this.data, required this.dataList,
this.maxY = 100.0, this.maxY = 100.0,
this.initialRotation = 1, this.initialRotation = 1,
required this.productsList,
this.vehicleTypeNames,
this.vehicleColorMap,
}); });
@override @override
@ -30,89 +48,50 @@ class _CustomStackedBarChartState extends State<CustomStackedBarChart> {
rotationTurns = widget.initialRotation; 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final maxY = widget.maxY; final maxY = widget.maxY <= 0 ? 100.0 : widget.maxY;
return AspectRatio( return AspectRatio(
aspectRatio: 1.6, aspectRatio: 1.6,
child: BarChart( child: BarChart(
BarChartData( BarChartData(
alignment: BarChartAlignment.center, alignment: BarChartAlignment.spaceAround,
rotationQuarterTurns: rotationTurns, 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( gridData: FlGridData(
show: true, show: true,
checkToShowHorizontalLine: (value) => value % (maxY / 5) == 0, // drawVerticalLine: true,
getDrawingHorizontalLine: (value) =>
FlLine(color: Colors.grey.withOpacity(0.12), strokeWidth: 0.8),
drawVerticalLine: false, 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,
), ),
fitInsideHorizontally: true, // borderData: FlBorderData(show: false),
fitInsideVertically: true, borderData: FlBorderData(
getTooltipItem: (group, groupIndex, rod, rodIndex) { show: true,
return BarTooltipItem( border: Border(
'${rod.toY.toStringAsFixed(2)}', bottom: BorderSide(
GoogleFonts.poppins( color: AppColors.contentColorBlack,
color: Colors.black, width: 0.1,
fontSize: 12,
fontWeight: FontWeight.w600,
), ),
); right: BorderSide(color: AppColors.contentColorBlack, width: 0.1),
},
), ),
), ),
titlesData: FlTitlesData( titlesData: FlTitlesData(
@ -122,8 +101,9 @@ class _CustomStackedBarChartState extends State<CustomStackedBarChart> {
reservedSize: 56, reservedSize: 56,
getTitlesWidget: (value, meta) { getTitlesWidget: (value, meta) {
final i = value.toInt(); final i = value.toInt();
if (i < 0 || i >= widget.labels.length) if (i < 0 || i >= widget.labels.length) {
return const SizedBox(); return const SizedBox();
}
return SideTitleWidget( return SideTitleWidget(
meta: meta, meta: meta,
child: Text( child: Text(
@ -141,11 +121,18 @@ class _CustomStackedBarChartState extends State<CustomStackedBarChart> {
rightTitles: AxisTitles( rightTitles: AxisTitles(
sideTitles: SideTitles( sideTitles: SideTitles(
showTitles: true, showTitles: true,
reservedSize: 40, reservedSize: 50,
getTitlesWidget: (value, meta) { getTitlesWidget: (value, meta) {
return Text( return Transform.rotate(
angle: -3,
child: Padding(
padding: const EdgeInsets.only(right: 3.0),
child: Text(
value.toInt().toString(), value.toInt().toString(),
style: GoogleFonts.inter(fontSize: 9), textAlign: TextAlign.end,
style: GoogleFonts.inter(fontSize: 10),
),
),
); );
}, },
), ),
@ -153,10 +140,115 @@ class _CustomStackedBarChartState extends State<CustomStackedBarChart> {
leftTitles: const AxisTitles(), leftTitles: const AxisTitles(),
topTitles: const AxisTitles(), topTitles: const AxisTitles(),
), ),
barGroups: List.generate( barTouchData: BarTouchData(
widget.data.length, enabled: true,
(i) => _generateGroup(i), 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, maxY: maxY,
), ),
), ),

View File

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