policy tracker fix

This commit is contained in:
venbaittech 2025-12-24 17:46:51 +05:30
parent 10e5751367
commit 7a6ec262b7
5 changed files with 327 additions and 99 deletions

View File

@ -527,7 +527,7 @@ class _DateFilterRowState extends ConsumerState<DateFilterRowPayout> {
SizedBox(height: 5), SizedBox(height: 5),
SizedBox( SizedBox(
height: 35, height: 35,
width: MediaQuery.of(context).size.width * 0.42, width: MediaQuery.of(context).size.width * 0.4,
child: DropdownSearch<Map<String, dynamic>>.multiSelection( child: DropdownSearch<Map<String, dynamic>>.multiSelection(
key: dropDownKeyPartner, key: dropDownKeyPartner,
@ -567,7 +567,7 @@ class _DateFilterRowState extends ConsumerState<DateFilterRowPayout> {
decoratorProps: DropDownDecoratorProps( decoratorProps: DropDownDecoratorProps(
decoration: decoration:
AppInputDecorations.dropdownDecoration( AppInputDecorations.dropdownDecoration(
label: "Select Partner", label: "Select Referer",
).copyWith( ).copyWith(
hintStyle: GoogleFonts.inter( hintStyle: GoogleFonts.inter(
fontSize: 12, fontSize: 12,
@ -608,7 +608,7 @@ class _DateFilterRowState extends ConsumerState<DateFilterRowPayout> {
decoration: InputDecoration( decoration: InputDecoration(
filled: true, filled: true,
fillColor: Colors.white, fillColor: Colors.white,
hintText: "Search Partner...", hintText: "Search Referer...",
hintStyle: GoogleFonts.inter( hintStyle: GoogleFonts.inter(
fontSize: 11, fontSize: 11,
color: Colors.black, color: Colors.black,

View File

@ -15,6 +15,7 @@ import '../../layouts/responsive_layout.dart';
import '../../providers/manager_provider.dart'; import '../../providers/manager_provider.dart';
import '../../providers/userRoleProvider.dart'; import '../../providers/userRoleProvider.dart';
import '../../themes/indicators/input_field_decoration.dart'; import '../../themes/indicators/input_field_decoration.dart';
import '../../themes/indicators/search_field_theme.dart';
import 'FormFieldBox.dart'; import 'FormFieldBox.dart';
import 'custom_dateRange.dart'; import 'custom_dateRange.dart';
@ -44,6 +45,10 @@ class _PayOutScreenState extends ConsumerState<PayOutScreen> {
dynamic totalCommission = '0'; dynamic totalCommission = '0';
bool isEdit = false; bool isEdit = false;
List<Map<String, dynamic>> masterPolicies = [];
final TextEditingController _searchStaffController = TextEditingController();
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKeyPOS = final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKeyPOS =
GlobalKey<DropdownSearchState<Map<String, dynamic>>>(); GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
@ -136,6 +141,45 @@ class _PayOutScreenState extends ConsumerState<PayOutScreen> {
} }
} }
void filterPolicyData(String query) {
final lowerQuery = query.toLowerCase();
print('filterPolicyData - $lowerQuery');
print('filteredPolicies1 - $filteredPolicies');
setState(() {
if (query.trim().isEmpty) {
print('filteredPolicies2');
filteredPolicies = List.from(masterPolicies);
return;
}
print('filteredPolicies3');
filteredPolicies = masterPolicies.where((item) {
return (item['policy_no'] ?? '').toString().toLowerCase().contains(
lowerQuery,
) ||
(item['customer_name'] ?? '').toString().toLowerCase().contains(
lowerQuery,
) ||
(item['agent_name'] ?? '').toString().toLowerCase().contains(
lowerQuery,
) ||
(item['insurer_name'] ?? '').toString().toLowerCase().contains(
lowerQuery,
) ||
(item['premium_amount'] ?? '').toString().toLowerCase().contains(
lowerQuery,
) ||
(item['commission_amount'] ?? '').toString().toLowerCase().contains(
lowerQuery,
) ||
(_formatDate(item['issued_date']) ?? '').toLowerCase().contains(
lowerQuery,
);
}).toList();
});
}
Future<void> getPosList(int id) async { Future<void> getPosList(int id) async {
print('E104 => Fns called => $id'); print('E104 => Fns called => $id');
@ -224,6 +268,7 @@ class _PayOutScreenState extends ConsumerState<PayOutScreen> {
.map((e) => Map<String, dynamic>.from(e)) .map((e) => Map<String, dynamic>.from(e))
.toList(); .toList();
masterPolicies = List<Map<String, dynamic>>.from(response['data']);
filteredPolicies = List<Map<String, dynamic>>.from(response['data']); filteredPolicies = List<Map<String, dynamic>>.from(response['data']);
print("selectedPolicies → $filteredPolicies "); print("selectedPolicies → $filteredPolicies ");
@ -678,7 +723,8 @@ class _PayOutScreenState extends ConsumerState<PayOutScreen> {
), ),
), ),
// SizedBox(width: 10), // SizedBox(width: 10),
Spacer(), // Spacer(),
SizedBox(width: 10),
Text( Text(
'Status: ${isPending ? 'Pending' : 'Completed'}', 'Status: ${isPending ? 'Pending' : 'Completed'}',
style: GoogleFonts.inter( style: GoogleFonts.inter(
@ -690,6 +736,22 @@ class _PayOutScreenState extends ConsumerState<PayOutScreen> {
// : const Color(0xFF047857), // : const Color(0xFF047857),
), ),
), ),
Spacer(),
ThemedSearchField(
hintText: 'Search',
// backgroundColor: Color(0xFFF6F8F8),
onChanged: filterPolicyData,
controller: _searchStaffController,
backgroundColor: Color(0xFFFFFFFF),
txtHeight: 30,
txtwidth: ResponsiveLayout.isMobile(context)
? MediaQuery.of(context).size.width * 0.7
: MediaQuery.of(context).size.width * 0.15,
),
], ],
if (!isEdit) ...[ if (!isEdit) ...[

View File

@ -0,0 +1,92 @@
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';
import 'package:pdf_render/pdf_render_widgets.dart';
import 'dart:typed_data';
import 'package:flutter/services.dart';
// ============= KEY FIX: Separate PDF Viewer Widget =============
class PolicyPdfViewer extends StatefulWidget {
final String? pdfUrl;
const PolicyPdfViewer({Key? key, this.pdfUrl}) : super(key: key);
@override
State<PolicyPdfViewer> createState() => _PolicyPdfViewerState();
}
class _PolicyPdfViewerState extends State<PolicyPdfViewer>
with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true; // Prevents rebuilding
// Cache the loaded PDF bytes
Uint8List? _cachedPdfBytes;
String? _lastLoadedUrl;
Future<Uint8List> _loadPdf() async {
// Return cached bytes if URL hasn't changed
if (_cachedPdfBytes != null && _lastLoadedUrl == widget.pdfUrl) {
return _cachedPdfBytes!;
}
// Load new PDF
final response = await http.get(Uri.parse(widget.pdfUrl!));
if (response.statusCode == 200) {
_cachedPdfBytes = response.bodyBytes;
_lastLoadedUrl = widget.pdfUrl;
return _cachedPdfBytes!;
} else {
throw Exception('Failed to load PDF: ${response.statusCode}');
}
}
@override
Widget build(BuildContext context) {
super.build(context); // Required for AutomaticKeepAliveClientMixin
if (widget.pdfUrl == null) {
return const Center(child: CircularProgressIndicator());
}
return FutureBuilder<Uint8List>(
key: ValueKey(widget.pdfUrl), // Only rebuild if URL changes
future: _loadPdf(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
}
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
return PdfDocumentLoader.openData(
snapshot.data!,
documentBuilder: (context, pdfDocument, pageCount) {
return ListView.builder(
itemCount: pageCount,
itemBuilder: (context, index) {
return Container(
color: Colors.black12,
child: PdfPageView(
pdfDocument: pdfDocument,
pageNumber: index + 1,
),
);
},
);
},
);
},
);
}
}

View File

@ -866,7 +866,7 @@ class policylistState extends ConsumerState<policylist> {
? 'Verified' ? 'Verified'
: 'To Verify', : 'To Verify',
child: Container( child: Container(
width: 80, // FIXED WIDTH Equal in both states width: 30, // FIXED WIDTH Equal in both states
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 8, horizontal: 8,
vertical: 4, vertical: 4,

View File

@ -4,6 +4,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';
import 'package:nhance_partner/presentation/screens/staff/policy/policyPdf.dart';
import 'package:pdf_render/pdf_render_widgets.dart'; import 'package:pdf_render/pdf_render_widgets.dart';
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart'; import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
@ -41,6 +43,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
dynamic managerId; dynamic managerId;
dynamic userId; dynamic userId;
String? _cachedPdfUrl;
String? pdfUrl; // full file path from API String? pdfUrl; // full file path from API
// --- Controllers (all editable fields) // --- Controllers (all editable fields)
@ -110,6 +113,8 @@ class _policyValidationState extends ConsumerState<policyValidation> {
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKeyFuel = final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKeyFuel =
GlobalKey<DropdownSearchState<Map<String, dynamic>>>(); GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
bool _hasLoadedInitialData = false;
Map<String, dynamic> dataDetails() { Map<String, dynamic> dataDetails() {
return { return {
"rc_no": controllers["rcNo"]?.text, "rc_no": controllers["rcNo"]?.text,
@ -244,28 +249,50 @@ class _policyValidationState extends ConsumerState<policyValidation> {
for (final key in controllerKeys) key: TextEditingController(), for (final key in controllerKeys) key: TextEditingController(),
}; };
update(); update();
_loadInitialData();
// read providers + call APIs // read providers + call APIs
Future.microtask(() { // Future.microtask(() {
try { // try {
managerId = ref.read(managerIdProvider); // managerId = ref.read(managerIdProvider);
} catch (e) { // } catch (e) {
managerId = null; // managerId = null;
} // }
try { // try {
userId = ref.read(userIdProvider); // userId = ref.read(userIdProvider);
} catch (e) { // } catch (e) {
userId = null; // userId = null;
} // }
//
// getVehicleType();
// getFuelType();
// getFindPolicy();
// getPolicyFilePath();
// });
getFindPolicy(); // controllers['commission_amount']?.addListener(() {
getVehicleType(); // setState(() {});
getFuelType(); // });
getPolicyFilePath(); }
});
controllers['commission_amount']?.addListener(() { Future<void> _loadInitialData() async {
setState(() {}); print('_loadInitialData');
}); try {
managerId = ref.read(managerIdProvider);
} catch (e) {
managerId = null;
}
try {
userId = ref.read(userIdProvider);
} catch (e) {
userId = null;
}
await Future.wait([
getFindPolicy(),
getVehicleType(),
getFuelType(),
getPolicyFilePath(),
]);
} }
@override @override
@ -361,6 +388,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
setState(() { setState(() {
pdfUrl = "$url"; pdfUrl = "$url";
_cachedPdfUrl = pdfUrl;
}); });
print("FINAL PDF URL -> $pdfUrl"); print("FINAL PDF URL -> $pdfUrl");
} catch (e, st) { } catch (e, st) {
@ -416,7 +444,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
// controllers["startDate"]!.text = safeText(data['start_date']); // controllers["startDate"]!.text = safeText(data['start_date']);
// controllers["endDate"]!.text = safeText(data['end_date']); // controllers["endDate"]!.text = safeText(data['end_date']);
controllers["issueDate"]?.text = fixInvalidDate(data['issued_date']); controllers["issuedDate"]?.text = fixInvalidDate(data['issued_date']);
controllers["startDate"]?.text = fixInvalidDate(data['start_date']); controllers["startDate"]?.text = fixInvalidDate(data['start_date']);
controllers["endDate"]?.text = fixInvalidDate(data['end_date']); controllers["endDate"]?.text = fixInvalidDate(data['end_date']);
@ -451,6 +479,10 @@ class _policyValidationState extends ConsumerState<policyValidation> {
selectedInsuranceId = safeText(data['insurer_id']); selectedInsuranceId = safeText(data['insurer_id']);
selectedAgentRentionRate = safeText(data['agent_retention_rate']); selectedAgentRentionRate = safeText(data['agent_retention_rate']);
selectedManagerRentionRate = safeText(data['manager_retention_rate']); selectedManagerRentionRate = safeText(data['manager_retention_rate']);
controllers["commission_amount"]?.text = safeText(
data['commission_amount'],
);
}); });
debugPrint('findPolicyApi response3:'); debugPrint('findPolicyApi response3:');
@ -553,6 +585,15 @@ class _policyValidationState extends ConsumerState<policyValidation> {
} }
} }
DateTime? parseDate(String? value) {
if (value == null || value.isEmpty) return null;
try {
return DateFormat('dd-MM-yyyy').parse(value); // change format if required
} catch (_) {
return null;
}
}
Future<void> _fetchCommision() async { Future<void> _fetchCommision() async {
print('_fetchCommision IN'); print('_fetchCommision IN');
final policyId = widget.item?['policy_id']; final policyId = widget.item?['policy_id'];
@ -562,6 +603,17 @@ class _policyValidationState extends ConsumerState<policyValidation> {
return; return;
} }
final startDate = parseDate(controllers["startDate"]?.text);
final endDate = parseDate(controllers["endDate"]?.text);
if (startDate != null && endDate != null && startDate.isAfter(endDate)) {
ToastHelper.showWarningToast(
context,
'Start Date cannot be greater than End Date',
);
return;
}
if (!_formKey.currentState!.validate()) { if (!_formKey.currentState!.validate()) {
ToastHelper.showWarningToast(context, "Please fill all required fields"); ToastHelper.showWarningToast(context, "Please fill all required fields");
return; return;
@ -822,11 +874,11 @@ class _policyValidationState extends ConsumerState<policyValidation> {
onChanged: (val) { onChanged: (val) {
if (val != null) { if (val != null) {
setState(() { // setState(() {
selectedVehicleType = val; selectedVehicleType = val;
controllers['vehicleType']?.text = val; controllers['vehicleType']?.text = val;
}); // });
setState(() {});
print("Selected Vehicle Type: $val"); print("Selected Vehicle Type: $val");
} }
}, },
@ -927,11 +979,11 @@ class _policyValidationState extends ConsumerState<policyValidation> {
onChanged: (val) { onChanged: (val) {
if (val != null) { if (val != null) {
setState(() { // setState(() {
selectedFuelType = val; selectedFuelType = val;
controllers['fuelType']?.text = val; controllers['fuelType']?.text = val;
}); // });
setState(() {});
print("Selected Fuel Type: $val"); print("Selected Fuel Type: $val");
} }
}, },
@ -1187,60 +1239,62 @@ class _policyValidationState extends ConsumerState<policyValidation> {
), ),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Expanded( Expanded(
child: FutureBuilder<Uint8List>( child: PolicyPdfViewer(
future: loadNetworkPdfBytes(pdfUrl!), pdfUrl: pdfUrl,
builder: (context, snapshot) { ), // 👈 Use separate widget
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
final pdfBytes = snapshot.data!;
return PdfDocumentLoader.openData(
pdfBytes,
documentBuilder:
(context, pdfDocument, pageCount) {
return ListView.builder(
itemCount: pageCount,
itemBuilder: (context, index) {
return Container(
color: Colors.black12,
child: PdfPageView(
pdfDocument: pdfDocument,
pageNumber: index + 1,
),
);
},
);
},
);
},
),
), ),
// Expanded( // Expanded(
// child: PdfDocumentLoader.openAsset( // child: pdfUrl == null
// 'assets/pdfs/sample.pdf', // ? Center(child: CircularProgressIndicator())
// documentBuilder: (context, pdfDocument, pageCount) => LayoutBuilder( // : FutureBuilder<Uint8List>(
// builder: (context, constraints) => ListView.builder( // key: ValueKey(
// itemCount: pageCount, // _cachedPdfUrl,
// itemBuilder: (context, index) => Container( // ), // 👈 Add this key
// // margin: EdgeInsets.all(margin), // future: loadNetworkPdfBytes(
// // padding: EdgeInsets.all(padding), // _cachedPdfUrl!,
// color: Colors.black12, // ),
// child: PdfPageView( // // future: loadNetworkPdfBytes(pdfUrl!),
// pdfDocument: pdfDocument, // builder: (context, snapshot) {
// pageNumber: index + 1, // if (!snapshot.hasData) {
// ) // return const Center(
// ) // child:
// ) // CircularProgressIndicator(),
// ), // );
// ) // }
// ) //
// final pdfBytes = snapshot.data!;
//
// return PdfDocumentLoader.openData(
// pdfBytes,
// documentBuilder:
// (
// context,
// pdfDocument,
// pageCount,
// ) {
// return ListView.builder(
// itemCount: pageCount,
// itemBuilder:
// (context, index) {
// return Container(
// color:
// Colors.black12,
// child: PdfPageView(
// pdfDocument:
// pdfDocument,
// pageNumber:
// index + 1,
// ),
// );
// },
// );
// },
// );
// },
// ),
// ),
], ],
), ),
), ),
@ -1344,10 +1398,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
), ),
), ),
), ),
], const SizedBox(width: 8),
),
Row(
children: [
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'Premium Amount *', 'Premium Amount *',
@ -1362,16 +1413,34 @@ class _policyValidationState extends ConsumerState<policyValidation> {
decimalFormatter, decimalFormatter,
), ),
), ),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Remarks *',
required: false,
controllers['remarks']!,
),
),
], ],
), ),
// Row(
// children: [
// Expanded(
// child: _buildInput(
// 'Premium Amount *',
// controllers['premiumAmount']!,
//
// required: true,
// keyboardType:
// TextInputType.numberWithOptions(
// decimal: true,
// ),
// inputFormatters:
// decimalFormatter,
// ),
// ),
// const SizedBox(width: 8),
// // Expanded(
// // child: _buildInput(
// // 'Remarks *',
// // required: false,
// // controllers['remarks']!,
// // ),
// // ),
// ],
// ),
], ],
), ),
), ),
@ -1579,8 +1648,13 @@ class _policyValidationState extends ConsumerState<policyValidation> {
required: true, required: true,
keyboardType: keyboardType:
TextInputType.number, TextInputType.number,
inputFormatters: inputFormatters: [
digitsOnlyFormatter, FilteringTextInputFormatter
.digitsOnly, // only numbers
LengthLimitingTextInputFormatter(
4,
), // max 4 digits
],
), ),
), ),
], ],