FIX_Minor Issues Fixes and Excel api changes in polict report and Audit History Modal
This commit is contained in:
parent
4dd43e1ed1
commit
a52b8d6c04
@ -1971,4 +1971,117 @@ class ApiService {
|
||||
final response = await _makeGetRequest(url, headers);
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
Future<void> generatePolicyExcel(managerId,fromDate,toDate) async {
|
||||
|
||||
final url = Uri.parse('${Env.apiUrl}reports/policy-excel?manager_id=$managerId&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}',);
|
||||
|
||||
print('getPdfDownload policy-excel - $url');
|
||||
await _initializeToken();
|
||||
|
||||
if (_token == null) throw Exception('Token not found. Please log in.');
|
||||
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $_token',
|
||||
// 'App-Signature': Env.App_Signature,
|
||||
'app-signature': Env.App_Signature,
|
||||
};
|
||||
|
||||
final response = await _makeGethttpRequest(url, headers);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final contentType = response.headers['content-type'] ?? '';
|
||||
if (contentType.contains('application/json')) {
|
||||
final jsonResponse = jsonDecode(response.body);
|
||||
if (jsonResponse['code'] == 404 || jsonResponse['code'] == 500) {
|
||||
ToastHelper.show('File Not Found', Colors.red);
|
||||
} else {
|
||||
ToastHelper.show('No File Found', Colors.red);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
final blob = html.Blob([response.bodyBytes]);
|
||||
final blobUrl = html.Url.createObjectUrlFromBlob(blob);
|
||||
print('getPdfDownload $blobUrl');
|
||||
final contentDisp = response.headers['content-disposition'];
|
||||
print('getPdfDownloadcontentDisp $contentDisp');
|
||||
|
||||
String fileName = extractFileName(contentDisp, "policy_excel");
|
||||
print('Resolved fileName: $fileName');
|
||||
final anchor = html.AnchorElement(href: blobUrl)
|
||||
..setAttribute('download', fileName)
|
||||
..click();
|
||||
|
||||
html.Url.revokeObjectUrl(blobUrl);
|
||||
}
|
||||
} else if (response.statusCode == 404) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('File not found.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: const Text('OK'),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else if (response.statusCode == 403) {
|
||||
await clearLocalStorageAndRedirect();
|
||||
} else if (response.statusCode == 500) {
|
||||
ToastHelper.show('No File Found', Colors.red);
|
||||
} else if (response.statusCode == 302) {
|
||||
print('getPdfDownload 3-PP-302');
|
||||
ToastHelper.show('No File Found', Colors.red);
|
||||
} else {
|
||||
ToastHelper.show('No File Found', Colors.red);
|
||||
throw Exception('Failed to download file');
|
||||
}
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> fetchAuditHistory(id) async {
|
||||
|
||||
print( "fetchAuditHistory - $id " );
|
||||
|
||||
if (_token == null) {
|
||||
await _initializeToken();
|
||||
}
|
||||
// final url = Uri.parse('${Env.apiUrl}audit/history?table_name=partner_policy&pk=80',);
|
||||
final url = Uri.parse('${Env.apiUrl}audit/history?table_name=partner_policy&pk=${id ?? ''}',);
|
||||
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $_token' ?? '',
|
||||
'app-signature': Env.App_Signature,
|
||||
};
|
||||
|
||||
final response = await _makeGetRequest(url, headers);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
// Future<Map<String, dynamic>> fetchPolicyExcel(managerId,fromDate,toDate) async {
|
||||
//
|
||||
// print( "fetchPolicyExcel - mangerID- $managerId - Dated - $fromDate - $toDate " );
|
||||
//
|
||||
// if (_token == null) {
|
||||
// await _initializeToken();
|
||||
// }
|
||||
//
|
||||
// final String query;
|
||||
//
|
||||
// query = 'manager_id=$managerId';
|
||||
//
|
||||
// final url = Uri.parse('${Env.apiUrl}reports/policy-excel?$query&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}',);
|
||||
//
|
||||
// final headers = {
|
||||
// 'Authorization': 'Bearer $_token' ?? '',
|
||||
// 'app-signature': Env.App_Signature,
|
||||
// };
|
||||
//
|
||||
// final response = await _makeGetRequest(url, headers);
|
||||
//
|
||||
// return response;
|
||||
// }
|
||||
}
|
||||
|
||||
@ -227,7 +227,8 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
|
||||
// late Timer timer;
|
||||
Timer? timer;
|
||||
int selectedSeconds = 30;
|
||||
bool isActionable = false;
|
||||
bool isActionable = false; // current UI state
|
||||
bool userPreference = false; // memory of what the user chose
|
||||
bool _listened = false;
|
||||
|
||||
//---------------------- Assign Staff Ends -------------------------------- //
|
||||
@ -311,11 +312,25 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
|
||||
getInsuranceType();
|
||||
}
|
||||
|
||||
// Future<void> loadPreferences() async {
|
||||
// final prefs = await SharedPreferences.getInstance();
|
||||
//
|
||||
// setState(() {
|
||||
// isActionable = prefs.getBool('isActionable') ?? false;
|
||||
// selectedSeconds = prefs.getInt('selectedSeconds') ?? 30;
|
||||
//
|
||||
// _showFilterRow = true;
|
||||
// });
|
||||
//
|
||||
// startTimer(); // restart timer using stored value
|
||||
// }
|
||||
Future<void> loadPreferences() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
|
||||
setState(() {
|
||||
isActionable = prefs.getBool('isActionable') ?? false;
|
||||
bool savedValue = prefs.getBool('isActionable') ?? false;
|
||||
isActionable = savedValue;
|
||||
userPreference = savedValue; // Initialize the backup
|
||||
selectedSeconds = prefs.getInt('selectedSeconds') ?? 30;
|
||||
|
||||
_showFilterRow = true;
|
||||
@ -1719,8 +1734,10 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
|
||||
value: !isActionable,
|
||||
onChanged: (v) async {
|
||||
bool newValue = !v;
|
||||
setState(() => isActionable = newValue);
|
||||
|
||||
setState(() {
|
||||
isActionable = newValue;
|
||||
userPreference = newValue; // Save this as the new "normal"
|
||||
});
|
||||
final prefs =
|
||||
await SharedPreferences.getInstance();
|
||||
await prefs.setBool(
|
||||
@ -1780,27 +1797,41 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
|
||||
SizedBox(width: 10),
|
||||
MouseRegion(
|
||||
onEnter: (_) {
|
||||
setState(() {
|
||||
isActionable = true;
|
||||
});
|
||||
// setState(() {
|
||||
// isActionable = true;
|
||||
// });
|
||||
},
|
||||
onExit: (_) {
|
||||
setState(() {
|
||||
// isActionable = false;
|
||||
isActionable = _searchStaffController.text.isNotEmpty;
|
||||
});
|
||||
// setState(() {
|
||||
// // isActionable = false;
|
||||
// isActionable = _searchStaffController.text.isNotEmpty;
|
||||
// });
|
||||
},
|
||||
child: ThemedSearchField(
|
||||
hintText: 'Search',
|
||||
backgroundColor: Color(0xFFFFFFFF),
|
||||
txtHeight: 30,
|
||||
// backgroundColor: Colors.white,
|
||||
onChanged: filterData,
|
||||
|
||||
controller: _searchStaffController,
|
||||
txtwidth: ResponsiveLayout.isMobile(context)
|
||||
? MediaQuery.of(context).size.width * 0.7
|
||||
: MediaQuery.of(context).size.width * 0.13,
|
||||
|
||||
// Combine the logic into one function block
|
||||
onChanged: (value) {
|
||||
// 1. Call your existing filter function
|
||||
filterData(value);
|
||||
|
||||
// 2. Perform the logic to toggle the switch UI
|
||||
setState(() {
|
||||
if (value.isNotEmpty) {
|
||||
// CASE 1: Searching -> Force switch to "OFF" (isActionable = true)
|
||||
isActionable = true;
|
||||
} else {
|
||||
// CASE 2: Search cleared -> Restore the status from memory
|
||||
isActionable = userPreference;
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
|
||||
@ -39,6 +39,8 @@ class policylistState extends ConsumerState<policylist> {
|
||||
List<Map<String, dynamic>> getStaffData = [];
|
||||
List<Map<String, dynamic>> originalData = [];
|
||||
List<Map<String, dynamic>> filteredData = [];
|
||||
List<Map<String, dynamic>> excelResponseData = [];
|
||||
List<Map<String, dynamic>> auditHistoryResponseData = [];
|
||||
bool isLoading = false;
|
||||
dynamic roleId;
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
@ -292,6 +294,34 @@ class policylistState extends ConsumerState<policylist> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> fetchPolicyExcelReport() async {
|
||||
|
||||
final String fromDate = controllers['startDate']!.text; // "11-01-2025"
|
||||
final String toDate = controllers['endDate']!.text; // "20-01-2025"
|
||||
final response = await apiService.generatePolicyExcel(managerId,fromDate,toDate);
|
||||
// Map your controllers and IDs to the API parameters
|
||||
// final String fromDate = controllers['startDate']!.text; // "11-01-2025"
|
||||
// final String toDate = controllers['endDate']!.text; // "20-01-2025"
|
||||
// print("fetchPolicyExcelReport function called here.");
|
||||
//
|
||||
// try {
|
||||
// // Assuming you have a generic _makeGetRequest method
|
||||
// final response = await apiService.fetchPolicyExcel(managerId,fromDate,toDate);
|
||||
//
|
||||
// if (response != null && response['status'] == 200) {
|
||||
// setState(() {
|
||||
// // Store the list of data in your variable
|
||||
// excelResponseData = response['data'];
|
||||
// });
|
||||
// print("Data fetched. Ready to export.");
|
||||
// }
|
||||
// } catch (e) {
|
||||
// debugPrint("Export Error: $e");
|
||||
// print("Failed to fetch report data.");
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MainLayout(
|
||||
@ -465,35 +495,63 @@ class policylistState extends ConsumerState<policylist> {
|
||||
ResponsiveLayout.isMobile(context)
|
||||
? Spacer()
|
||||
: SizedBox(width: 10),
|
||||
ExportBtn(
|
||||
sheetName: "Policy",
|
||||
fileName: "Policy_list",
|
||||
data: filteredData,
|
||||
txt: !ResponsiveLayout.isMobile(context) ? true : false,
|
||||
displayHeaders: [
|
||||
// "Received Date & Time",
|
||||
"Assigned To",
|
||||
"Partner",
|
||||
|
||||
"Insurer",
|
||||
"Vehicle.No.",
|
||||
"Insured Name",
|
||||
"Premium",
|
||||
"Payment Mode",
|
||||
"Policy Number",
|
||||
],
|
||||
keys: [
|
||||
// "updated_on",
|
||||
"assigned_to_name",
|
||||
"agent_name",
|
||||
"insurer_short_name",
|
||||
"reg_no",
|
||||
"insured_name",
|
||||
"premium_amount",
|
||||
"payment_mode_value",
|
||||
"policy_number",
|
||||
],
|
||||
// ExportBtn(
|
||||
// sheetName: "Policy",
|
||||
// fileName: "Policy_list",
|
||||
// data: filteredData,
|
||||
// txt: !ResponsiveLayout.isMobile(context) ? true : false,
|
||||
// displayHeaders: [
|
||||
// // "Received Date & Time",
|
||||
// "Assigned To",
|
||||
// "Partner",
|
||||
//
|
||||
// "Insurer",
|
||||
// "Vehicle.No.",
|
||||
// "Insured Name",
|
||||
// "Premium",
|
||||
// "Payment Mode",
|
||||
// "Policy Number",
|
||||
// ],
|
||||
// keys: [
|
||||
// // "updated_on",
|
||||
// "assigned_to_name",
|
||||
// "agent_name",
|
||||
// "insurer_short_name",
|
||||
// "reg_no",
|
||||
// "insured_name",
|
||||
// "premium_amount",
|
||||
// "payment_mode_value",
|
||||
// "policy_number",
|
||||
// ],
|
||||
// ),
|
||||
// SizedBox(width: 10),
|
||||
Tooltip(
|
||||
message: 'Export Excel',
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
await fetchPolicyExcelReport();
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF2E7D6E),
|
||||
// color: const Color(0xFF425B5B),
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Image.asset(
|
||||
"assets/miscellaneous/export.png",
|
||||
height: 15,
|
||||
width: 15,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -763,6 +821,33 @@ class policylistState extends ConsumerState<policylist> {
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
showAuditHistoryModal(context,item['id']);
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5.4),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF2E7D6E),
|
||||
// color: Color(0xFF425B5B),
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
),
|
||||
child: Row(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Tooltip(
|
||||
message: 'Audit History Information',
|
||||
child: Icon(
|
||||
Icons.file_open_outlined,
|
||||
color: Colors.white,
|
||||
size: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -1039,3 +1124,163 @@ class policylistState extends ConsumerState<policylist> {
|
||||
fontSize: 12,
|
||||
);
|
||||
}
|
||||
|
||||
void showAuditHistoryModal(BuildContext context, dynamic policyId) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AuditHistoryModal(policyId: policyId), // Pass ID here
|
||||
);
|
||||
}
|
||||
|
||||
class AuditHistoryModal extends ConsumerStatefulWidget {
|
||||
final dynamic policyId; // Add this
|
||||
const AuditHistoryModal({super.key, required this.policyId}); // Update constructor
|
||||
|
||||
@override
|
||||
ConsumerState<AuditHistoryModal> createState() => AuditHistoryModalState();
|
||||
}
|
||||
|
||||
class AuditHistoryModalState extends ConsumerState<AuditHistoryModal> {
|
||||
late ApiService apiService;
|
||||
bool isLoading = true; // Start with loading true
|
||||
List<Map<String, dynamic>> getAuditHistoryData = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
apiService = ApiService();
|
||||
|
||||
// Fetch the audit history as soon as the modal opens
|
||||
fetchAuditHistory();
|
||||
}
|
||||
|
||||
Future<void> fetchAuditHistory() async {
|
||||
setState(() => isLoading = true);
|
||||
try {
|
||||
// Use widget.policyId here!
|
||||
final response = await apiService.fetchAuditHistory(widget.policyId.toString());
|
||||
|
||||
if (response != null && response['status'] == "success") {
|
||||
setState(() {
|
||||
getAuditHistoryData = List<Map<String, dynamic>>.from(response['data']);
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("Audit History Error: $e");
|
||||
} finally {
|
||||
if (mounted) setState(() => isLoading = false);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
backgroundColor: Colors.white,
|
||||
content: Container(
|
||||
width: MediaQuery.of(context).size.width * 0.55,
|
||||
height: MediaQuery.of(context).size.height * 0.7,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
"Audit History",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Color(0xFF50A398),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
Tooltip(
|
||||
message: 'Close',
|
||||
child: IconButton(
|
||||
icon: const Icon(
|
||||
Icons.close,
|
||||
size: 18,
|
||||
// color: Color(0xFF425B5B),
|
||||
color: Color(0xFF2E7D6E),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
splashRadius: 28,
|
||||
hoverColor: Colors.black12,
|
||||
padding: const EdgeInsets.all(8),
|
||||
constraints: const BoxConstraints(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Expanded(
|
||||
child: isLoading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: getAuditHistoryData.isEmpty
|
||||
? const Center(child: Text("No Audit History Data Found"))
|
||||
: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
dividerColor: Colors.grey.shade200,
|
||||
),
|
||||
child: DataTable(
|
||||
headingRowColor: WidgetStateProperty.all(Color(0xFFF8FAFC)),
|
||||
columnSpacing: 20,
|
||||
columns: [
|
||||
DataColumn(label: Text("Column Name", style: _headerStyle())),
|
||||
DataColumn(label: Text("Message", style: _headerStyle())),
|
||||
DataColumn(label: Text("Changed On", style: _headerStyle())),
|
||||
DataColumn(label: Text("Changed By", style: _headerStyle())),
|
||||
],
|
||||
// Inside your build method's DataTable
|
||||
rows: getAuditHistoryData.map((data) {
|
||||
return DataRow(cells: [
|
||||
DataCell(Text(data['column_name'] ?? "-", style: _cellStyle())),
|
||||
DataCell(
|
||||
SizedBox(
|
||||
width: 300, // Give message more width
|
||||
child: Text(
|
||||
data['message'] ?? "-",
|
||||
style: _cellStyle(),
|
||||
softWrap: true, // Ensure text wraps to next line
|
||||
),
|
||||
)
|
||||
),
|
||||
DataCell(Text(
|
||||
formatIndianDate(data['changed_on'] ?? ""),
|
||||
style: _cellStyle(),
|
||||
)),
|
||||
DataCell(Text(data['changed_by'] ?? "-", style: _cellStyle())),
|
||||
]);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper styles to keep code clean
|
||||
TextStyle _headerStyle() => GoogleFonts.poppins(
|
||||
fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF475569));
|
||||
|
||||
TextStyle _cellStyle() => GoogleFonts.poppins(
|
||||
fontSize: 11, color: Color(0xFF1E293B));
|
||||
|
||||
String formatIndianDate(String dateStr) {
|
||||
try {
|
||||
DateTime dateTime = DateTime.parse(dateStr);
|
||||
// Format: Day-Month-Year Hour:Minute AM/PM
|
||||
return DateFormat('dd-MM-yyyy hh:mm a').format(dateTime);
|
||||
} catch (e) {
|
||||
return dateStr; // Fallback to original string if parsing fails
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user