import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:http/http.dart' as http; import 'package:pdf_render/pdf_render_widgets.dart'; import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart'; import '../../../../core/config/env.dart'; import '../../../../core/services/api_service.dart'; import '../../../../data/utils/toastNotification.dart'; import '../../../providers/manager_provider.dart'; import 'loadNetworkPdfBytes.dart'; import 'dart:typed_data'; // /// Represents Homepage for Navigation // class policyValidation extends ConsumerStatefulWidget { // final dynamic item; // const policyValidation({Key? key, this.item}) : super(key: key); // // @override // ConsumerState createState() => _policyValidationState(); // } // // class _policyValidationState extends ConsumerState { // final GlobalKey _pdfViewerKey = GlobalKey(); // // @override // void initState() { // super.initState(); // } // // @override // Widget build(BuildContext context) { // return Scaffold( // appBar: AppBar( // title: const Text('Syncfusion Flutter PDF Viewer'), // actions: [ // IconButton( // icon: const Icon( // Icons.bookmark, // color: Colors.white, // semanticLabel: 'Bookmark', // ), // onPressed: () { // _pdfViewerKey.currentState?.openBookmarkView(); // }, // ), // ], // ), // body: SfPdfViewer.asset( // 'assets/pdfs/sample.pdf', // key: _pdfViewerKey, // ) // ); // } // } import 'package:flutter/services.dart'; final digitsOnlyFormatter = [FilteringTextInputFormatter.digitsOnly]; final decimalFormatter = [ FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d{0,2}$')), ]; class policyValidation extends ConsumerStatefulWidget { final dynamic item; const policyValidation({Key? key, this.item}) : super(key: key); @override ConsumerState createState() => _policyValidationState(); } class _policyValidationState extends ConsumerState { // --- Api / state late ApiService apiService; bool isLoading = false; dynamic managerId; dynamic userId; String? pdfUrl; // full file path from API // --- Controllers (all editable fields) late TextEditingController policyNumberController; late TextEditingController insuredNameController; late TextEditingController premiumController; late TextEditingController remarksController; late TextEditingController rcNoController; late TextEditingController issuedDateController; late TextEditingController startDateController; late TextEditingController endDateController; late TextEditingController tpController; late TextEditingController odController; late TextEditingController paController; late TextEditingController cgstController; late TextEditingController sgstController; late TextEditingController igstController; late TextEditingController rtoStateCodeController; late TextEditingController rtoCityCodeController; late TextEditingController weightController; late TextEditingController fuelTypeController; late TextEditingController registrationDateController; late TextEditingController yomController; late TextEditingController engineNoController; late TextEditingController chassisNoController; late TextEditingController makeController; late TextEditingController modelController; late TextEditingController cubicCapacityController; late TextEditingController vehicleTypeController; late TextEditingController brokerNameController; late TextEditingController commissionAmountController; final GlobalKey _pdfViewerKey = GlobalKey(); final _formKey = GlobalKey(); @override void initState() { super.initState(); apiService = ApiService(); // instantiate controllers with defaults policyNumberController = TextEditingController(); insuredNameController = TextEditingController(); premiumController = TextEditingController(); remarksController = TextEditingController(); rcNoController = TextEditingController(); issuedDateController = TextEditingController(); startDateController = TextEditingController(); endDateController = TextEditingController(); tpController = TextEditingController(); odController = TextEditingController(); paController = TextEditingController(); cgstController = TextEditingController(); sgstController = TextEditingController(); igstController = TextEditingController(); rtoStateCodeController = TextEditingController(); rtoCityCodeController = TextEditingController(); weightController = TextEditingController(); fuelTypeController = TextEditingController(); registrationDateController = TextEditingController(); yomController = TextEditingController(); engineNoController = TextEditingController(); chassisNoController = TextEditingController(); makeController = TextEditingController(); modelController = TextEditingController(); cubicCapacityController = TextEditingController(); vehicleTypeController = TextEditingController(); brokerNameController = TextEditingController(); commissionAmountController = TextEditingController(); // Pre-fill controllers from initial `widget.item` (if available) final item = widget.item as Map? ?? {}; policyNumberController.text = item['policy_number']?.toString() ?? ''; insuredNameController.text = item['insured_name']?.toString() ?? ''; premiumController.text = item['premium_amount']?.toString() ?? ''; remarksController.text = item['remarks']?.toString() ?? ''; rcNoController.text = item['rc_no']?.toString() ?? ''; issuedDateController.text = item['issued_date']?.toString() ?? ''; startDateController.text = item['start_date']?.toString() ?? ''; endDateController.text = item['end_date']?.toString() ?? ''; tpController.text = item['tp']?.toString() ?? ''; odController.text = item['od']?.toString() ?? ''; paController.text = item['pa']?.toString() ?? ''; cgstController.text = item['cgst']?.toString() ?? ''; sgstController.text = item['sgst']?.toString() ?? ''; igstController.text = item['igst']?.toString() ?? ''; rtoStateCodeController.text = item['rto_state_code']?.toString() ?? ''; rtoCityCodeController.text = item['rto_city_code']?.toString() ?? ''; weightController.text = item['weight']?.toString() ?? ''; fuelTypeController.text = item['fuel_type']?.toString() ?? ''; registrationDateController.text = item['date_of_registration']?.toString() ?? ''; yomController.text = item['year_of_manufacture']?.toString() ?? ''; engineNoController.text = item['engine_no']?.toString() ?? ''; chassisNoController.text = item['chassis_no']?.toString() ?? ''; makeController.text = item['make']?.toString() ?? ''; modelController.text = item['model']?.toString() ?? ''; cubicCapacityController.text = item['cubic_capacity']?.toString() ?? ''; vehicleTypeController.text = item['vehicle_type']?.toString() ?? ''; brokerNameController.text = item['broker_name']?.toString() ?? ''; commissionAmountController.text = item['commission_amount']?.toString() ?? ''; // read providers + call APIs Future.microtask(() { try { managerId = ref.read(managerIdProvider); } catch (e) { managerId = null; } try { userId = ref.read(userIdProvider); } catch (e) { userId = null; } getFindPolicy(); getPolicyFilePath(); }); } @override void dispose() { policyNumberController.dispose(); insuredNameController.dispose(); premiumController.dispose(); remarksController.dispose(); rcNoController.dispose(); issuedDateController.dispose(); startDateController.dispose(); endDateController.dispose(); tpController.dispose(); odController.dispose(); paController.dispose(); cgstController.dispose(); sgstController.dispose(); igstController.dispose(); rtoStateCodeController.dispose(); rtoCityCodeController.dispose(); weightController.dispose(); fuelTypeController.dispose(); registrationDateController.dispose(); yomController.dispose(); engineNoController.dispose(); chassisNoController.dispose(); makeController.dispose(); modelController.dispose(); cubicCapacityController.dispose(); vehicleTypeController.dispose(); brokerNameController.dispose(); commissionAmountController.dispose(); super.dispose(); } Future getPolicyFilePath() async { _pdfViewerKey.currentState?.openBookmarkView(); final policyId = widget.item?['policy_id']; if (policyId == null) { debugPrint('policyValidation: policy id is null, skipping API call'); return; } if (!mounted) return; setState(() => isLoading = true); try { final url = Uri.parse( '${Env.apiUrl}policy/PolicyFilePath?policy_id=$policyId&file_type=policy_pdf', ); setState(() { pdfUrl = "$url"; }); print("FINAL PDF URL -> $pdfUrl"); } catch (e, st) { print('Exception in getPolicyFilePath: $e\n$st'); } finally { if (!mounted) return; setState(() => isLoading = false); } } Future getFindPolicy() async { final policyId = widget.item?['policy_id']; if (policyId == null) { debugPrint('policyValidation: policy id is null, skipping API call'); return; } if (!mounted) return; setState(() => isLoading = true); try { final response = await apiService.findPolicyApi(policyId); debugPrint('findPolicyApi response: $response'); if (response != null && response['status'] == 'success') { final data = (response['data'] ?? {}) as Map; if (!mounted) return; setState(() { // update controllers (overwrite with authoritative API values) policyNumberController.text = data['policy_number']?.toString() ?? policyNumberController.text; insuredNameController.text = data['insured_name']?.toString() ?? insuredNameController.text; premiumController.text = data['premium_amount']?.toString() ?? premiumController.text; remarksController.text = data['remarks']?.toString() ?? remarksController.text; rcNoController.text = data['rc_no']?.toString() ?? rcNoController.text; issuedDateController.text = data['issued_date']?.toString() ?? issuedDateController.text; startDateController.text = data['start_date']?.toString() ?? startDateController.text; endDateController.text = data['end_date']?.toString() ?? endDateController.text; tpController.text = data['tp']?.toString() ?? tpController.text; odController.text = data['od']?.toString() ?? odController.text; paController.text = data['pa']?.toString() ?? paController.text; cgstController.text = data['cgst']?.toString() ?? cgstController.text; sgstController.text = data['sgst']?.toString() ?? sgstController.text; igstController.text = data['igst']?.toString() ?? igstController.text; rtoStateCodeController.text = data['rto_state_code']?.toString() ?? rtoStateCodeController.text; rtoCityCodeController.text = data['rto_city_code']?.toString() ?? rtoCityCodeController.text; weightController.text = data['weight']?.toString() ?? weightController.text; fuelTypeController.text = data['fuel_type']?.toString() ?? fuelTypeController.text; registrationDateController.text = data['date_of_registration']?.toString() ?? registrationDateController.text; yomController.text = data['year_of_manufacture']?.toString() ?? yomController.text; engineNoController.text = data['engine_no']?.toString() ?? engineNoController.text; chassisNoController.text = data['chassis_no']?.toString() ?? chassisNoController.text; makeController.text = data['make']?.toString() ?? makeController.text; modelController.text = data['model']?.toString() ?? modelController.text; cubicCapacityController.text = data['cubic_capacity']?.toString() ?? cubicCapacityController.text; vehicleTypeController.text = data['vehicle_type']?.toString() ?? vehicleTypeController.text; brokerNameController.text = data['broker_name']?.toString() ?? brokerNameController.text; commissionAmountController.text = data['commission_amount']?.toString() ?? commissionAmountController.text; }); } else { debugPrint( 'findPolicyApi returned error: ${response?['message'] ?? 'unknown'}', ); } } catch (e, st) { debugPrint('Exception in getFindPolicy: $e\n$st'); } finally { if (!mounted) return; setState(() => isLoading = false); } } Future _pickDate( TextEditingController controller, BuildContext context, ) async { DateTime initial = DateTime.now(); try { if (controller.text.isNotEmpty) { // try parse dd-MM-yyyy final parts = controller.text.split('-'); if (parts.length == 3) { final d = int.tryParse(parts[0]) ?? initial.day; final m = int.tryParse(parts[1]) ?? initial.month; final y = int.tryParse(parts[2]) ?? initial.year; initial = DateTime(y, m, d); } } } catch (_) {} final picked = await showDatePicker( context: context, initialDate: initial, firstDate: DateTime(1900), lastDate: DateTime(2100), ); if (picked != null) { controller.text = "${picked.day.toString().padLeft(2, '0')}-${picked.month.toString().padLeft(2, '0')}-${picked.year}"; } } Future _save() async { final policyId = widget.item?['policy_id']; if (policyId == null) { ToastHelper.showWarningToast(context, 'Missing policy id'); return; } if (!_formKey.currentState!.validate()) { ToastHelper.showWarningToast(context, "Please fill all required fields"); return; } if (widget.item?['is_data_accuracy_checked'] == "1") { ToastHelper.showWarningToast(context, "Data already confirmed"); return; } final payload = { "id": policyId, "rc_no": rcNoController.text, "insured_name": insuredNameController.text, "issued_date": issuedDateController.text, "start_date": startDateController.text, "end_date": endDateController.text, "premium_amount": premiumController.text, "policy_number": policyNumberController.text, "tp": tpController.text.isEmpty ? null : tpController.text, "od": odController.text.isEmpty ? null : odController.text, "pa": paController.text.isEmpty ? null : paController.text, "cgst": cgstController.text.isEmpty ? null : cgstController.text, "sgst": sgstController.text.isEmpty ? null : sgstController.text, "igst": igstController.text.isEmpty ? null : igstController.text, "rto_state_code": rtoStateCodeController.text.isEmpty ? null : rtoStateCodeController.text, "rto_city_code": rtoCityCodeController.text.isEmpty ? null : rtoCityCodeController.text, "weight": weightController.text.isEmpty ? null : weightController.text, "fuel_type": fuelTypeController.text.isEmpty ? null : fuelTypeController.text, "date_of_registration": registrationDateController.text.isEmpty ? null : registrationDateController.text, "year_of_manufacture": yomController.text.isEmpty ? null : yomController.text, "engine_no": engineNoController.text.isEmpty ? null : engineNoController.text, "chassis_no": chassisNoController.text.isEmpty ? null : chassisNoController.text, "make": makeController.text.isEmpty ? null : makeController.text, "model": modelController.text.isEmpty ? null : modelController.text, "cubic_capacity": cubicCapacityController.text.isEmpty ? null : cubicCapacityController.text, "vehicle_type": vehicleTypeController.text.isEmpty ? null : vehicleTypeController.text, "broker_name": brokerNameController.text.isEmpty ? null : brokerNameController.text, "commission_amount": commissionAmountController.text.isEmpty ? null : commissionAmountController.text, "updated_by": userId, }; if (!mounted) return; setState(() => isLoading = true); try { debugPrint('FINAL SAVE PAYLOAD => $payload'); final result = await apiService.updatePolicyApi(payload); debugPrint('updatePolicy result => $result'); if (result != null && result['status'] == 'success') { if (!mounted) return; setState(() => isLoading = false); context.pop(); ToastHelper.showSuccessToast(context, "Policy updated successfully"); WidgetsBinding.instance.addPostFrameCallback((_) { // Now safe to do navigation + provider updates final container = ProviderScope.containerOf(context); container.read(policyDataAcurancyRefreshProvider.notifier).state = true; }); } else { if (!mounted) return; setState(() => isLoading = false); ToastHelper.showErrorToast( context, result?['message']?.toString() ?? 'Error updating policy', ); } } catch (e, st) { debugPrint('Exception in updatePolicy: $e\n$st'); if (!mounted) return; setState(() => isLoading = false); ToastHelper.showWarningToast(context, 'Exception: $e'); } } Future _fetchCommision() async { final policyId = widget.item?['policy_id']; if (policyId == null) { ToastHelper.showWarningToast(context, 'Missing policy id'); return; } if (!_formKey.currentState!.validate()) { ToastHelper.showWarningToast(context, "Please fill all required fields"); return; } // if (widget.item?['is_data_accuracy_checked'] == "1") { // ToastHelper.showWarningToast(context, "Data already confirmed"); // return; // } final payload = { "id": policyId, "rc_no": rcNoController.text, "insured_name": insuredNameController.text, "issued_date": issuedDateController.text, "start_date": startDateController.text, "end_date": endDateController.text, "premium_amount": premiumController.text, "policy_number": policyNumberController.text, "tp": tpController.text.isEmpty ? null : tpController.text, "od": odController.text.isEmpty ? null : odController.text, "pa": paController.text.isEmpty ? null : paController.text, "cgst": cgstController.text.isEmpty ? null : cgstController.text, "sgst": sgstController.text.isEmpty ? null : sgstController.text, "igst": igstController.text.isEmpty ? null : igstController.text, "rto_state_code": rtoStateCodeController.text.isEmpty ? null : rtoStateCodeController.text, "rto_city_code": rtoCityCodeController.text.isEmpty ? null : rtoCityCodeController.text, "weight": weightController.text.isEmpty ? null : weightController.text, "fuel_type": fuelTypeController.text.isEmpty ? null : fuelTypeController.text, "date_of_registration": registrationDateController.text.isEmpty ? null : registrationDateController.text, "year_of_manufacture": yomController.text.isEmpty ? null : yomController.text, "engine_no": engineNoController.text.isEmpty ? null : engineNoController.text, "chassis_no": chassisNoController.text.isEmpty ? null : chassisNoController.text, "make": makeController.text.isEmpty ? null : makeController.text, "model": modelController.text.isEmpty ? null : modelController.text, "cubic_capacity": cubicCapacityController.text.isEmpty ? null : cubicCapacityController.text, "vehicle_type": vehicleTypeController.text.isEmpty ? null : vehicleTypeController.text, "broker_name": brokerNameController.text.isEmpty ? null : brokerNameController.text, // "commission_amount": commissionAmountController.text.isEmpty // ? null // : commissionAmountController.text, "updated_by": userId, // "insurance_plan_type": }; if (!mounted) return; setState(() => isLoading = true); try { debugPrint('FINAL SAVE PAYLOAD => $payload'); final result = await apiService.calculateCommissionRequest(payload); debugPrint('updatePolicy result => $result'); if (result != null && result['status'] == 'success') { if (!mounted) return; setState(() => isLoading = false); // context.pop(); ToastHelper.showSuccessToast(context, "Policy updated successfully"); // WidgetsBinding.instance.addPostFrameCallback((_) { // // Now safe to do navigation + provider updates // final container = ProviderScope.containerOf(context); // container.read(policyDataAcurancyRefreshProvider.notifier).state = // true; // }); } else { if (!mounted) return; setState(() => isLoading = false); ToastHelper.showErrorToast( context, result?['message']?.toString() ?? 'Error updating policy', ); } } catch (e, st) { debugPrint('Exception in updatePolicy: $e\n$st'); if (!mounted) return; setState(() => isLoading = false); ToastHelper.showWarningToast(context, 'Exception: $e'); } } Widget _sectionHeader(String title, {IconData icon = Icons.info}) { return Container( padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 12), decoration: BoxDecoration( color: Color(0xFFE3F9F8), borderRadius: BorderRadius.circular(6), ), child: Row( children: [ Container( padding: const EdgeInsets.all(6), decoration: const BoxDecoration( color: Color(0xFF2E7D6E), shape: BoxShape.circle, ), child: Icon(icon, size: 16, color: Colors.white), ), const SizedBox(width: 10), Text( title, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600), ), ], ), ); } Widget _buildInput( String label, TextEditingController controller, { TextInputType keyboardType = TextInputType.text, bool readOnly = false, VoidCallback? onTap, bool required = false, List? inputFormatters, // 👈 ADD THIS }) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: const TextStyle(fontWeight: FontWeight.w500)), const SizedBox(height: 6), TextFormField( controller: controller, keyboardType: keyboardType, readOnly: readOnly, onTap: onTap, inputFormatters: inputFormatters, // 👈 USE HERE validator: (value) { if (required && (value == null || value.trim().isEmpty)) { return "$label is required"; } return null; }, decoration: InputDecoration( border: OutlineInputBorder(borderRadius: BorderRadius.circular(6)), isDense: true, // alignment fix helperText: ' ', helperStyle: const TextStyle(height: 1), errorMaxLines: 2, errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(6), borderSide: const BorderSide(color: Colors.red), ), focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(6), borderSide: const BorderSide(color: Colors.red), ), contentPadding: const EdgeInsets.all(10), ), ), ], ); } @override Widget build(BuildContext context) { // Ensure global AppHeader remains visible by pushing content down by 64px return SafeArea( child: Scaffold( backgroundColor: Color(0xffD9EBE8), // ⭐ FIXED BUTTON FOOTER bottomNavigationBar: Container( padding: const EdgeInsets.all(16), color: const Color(0xFFF7FBFA), child: Row( mainAxisAlignment: MainAxisAlignment.end, // 👉 move button to right children: [ ElevatedButton( onPressed: _fetchCommision, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF2E7D6E), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( vertical: 10, horizontal: 20, // 👉 smaller width ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: const Text( 'Fetch Commission', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600), ), ), SizedBox(width: 10), ElevatedButton( onPressed: widget.item?['is_data_accuracy_checked'] == '1' ? null : _save, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF2E7D6E), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( vertical: 10, horizontal: 20, // 👉 smaller width ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: const Text( 'Confirm Data Accuracy', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600), ), ), ], ), ), body: Container( // margin: const EdgeInsets.only(top: 64), // <-- keeps popup under global AppHeader width: double.infinity, // height: MediaQuery.of(context).size.height - 64, color: const Color(0xFFF7FBFA), child: Column( children: [ // In-body header Container( height: 56, color: Color(0xFFE3F9F8), padding: const EdgeInsets.symmetric(horizontal: 12), child: Row( children: [ IconButton( icon: const Icon(Icons.file_open), onPressed: () => context.pop(), ), const Expanded( child: Text( 'Insurance Policy Review', style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, ), ), ), if (isLoading) const SizedBox( width: 12, height: 12, child: CircularProgressIndicator(strokeWidth: 2), ), const SizedBox(width: 8), IconButton( icon: const Icon(Icons.close), onPressed: () => context.pop(), ), ], ), ), // Body: left PDF preview + right grouped form Expanded( child: Padding( padding: const EdgeInsets.all(16.0), child: Row( children: [ // LEFT - PDF placeholder Expanded( flex: 1, child: Container( margin: const EdgeInsets.only(right: 12), padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.grey.shade200), ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Text( 'Original Policy Document', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 8), Expanded( child: FutureBuilder( future: loadNetworkPdfBytes(pdfUrl!), builder: (context, snapshot) { 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( // child: PdfDocumentLoader.openAsset( // 'assets/pdfs/sample.pdf', // documentBuilder: (context, pdfDocument, pageCount) => LayoutBuilder( // builder: (context, constraints) => ListView.builder( // itemCount: pageCount, // itemBuilder: (context, index) => Container( // // margin: EdgeInsets.all(margin), // // padding: EdgeInsets.all(padding), // color: Colors.black12, // child: PdfPageView( // pdfDocument: pdfDocument, // pageNumber: index + 1, // ) // ) // ) // ), // ) // ) ], ), ), ), // RIGHT - Grouped Form Expanded( flex: 1, child: SingleChildScrollView( child: Form( key: _formKey, autovalidateMode: AutovalidateMode.onUserInteraction, child: Card( elevation: 2, color: Colors.white, margin: EdgeInsets.zero, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Policy Details Card( elevation: 5, color: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _sectionHeader( 'Policy Details', icon: Icons.policy, ), SizedBox(height: 10), Row( children: [ Expanded( child: _buildInput( 'Policy Number', policyNumberController, required: true, ), ), const SizedBox(width: 8), Expanded( child: _buildInput( 'Insured Name', insuredNameController, required: true, ), ), ], ), Row( children: [ Expanded( child: _buildInput( 'Issued Date', issuedDateController, readOnly: true, required: true, onTap: () => _pickDate( issuedDateController, context, ), ), ), const SizedBox(width: 8), Expanded( child: _buildInput( 'Start Date', startDateController, readOnly: true, required: true, onTap: () => _pickDate( startDateController, context, ), ), ), const SizedBox(width: 8), Expanded( child: _buildInput( 'End Date', endDateController, readOnly: true, required: true, onTap: () => _pickDate( endDateController, context, ), ), ), ], ), Row( children: [ Expanded( child: _buildInput( 'Premium Amount', premiumController, required: true, keyboardType: TextInputType.numberWithOptions( decimal: true, ), inputFormatters: decimalFormatter, ), ), const SizedBox(width: 8), Expanded( child: _buildInput( 'Remarks', remarksController, required: false, ), ), ], ), ], ), ), ), const SizedBox(height: 12), // Tax Details Card( elevation: 5, color: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _sectionHeader( 'Tax / Cover Details', icon: Icons.attach_money, ), SizedBox(height: 10), Row( children: [ Expanded( child: _buildInput( 'TP', tpController, required: true, keyboardType: TextInputType.numberWithOptions( decimal: true, ), inputFormatters: decimalFormatter, ), ), const SizedBox(width: 8), Expanded( child: _buildInput( 'OD', odController, required: true, keyboardType: TextInputType.numberWithOptions( decimal: true, ), inputFormatters: decimalFormatter, ), ), const SizedBox(width: 8), Expanded( child: _buildInput( 'PA', paController, required: true, keyboardType: TextInputType.numberWithOptions( decimal: true, ), inputFormatters: decimalFormatter, ), ), ], ), Row( children: [ Expanded( child: _buildInput( 'CGST', cgstController, required: true, keyboardType: TextInputType.numberWithOptions( decimal: true, ), inputFormatters: decimalFormatter, ), ), const SizedBox(width: 8), Expanded( child: _buildInput( 'SGST', sgstController, required: true, keyboardType: TextInputType.numberWithOptions( decimal: true, ), inputFormatters: decimalFormatter, ), ), const SizedBox(width: 8), Expanded( child: _buildInput( 'IGST', igstController, required: true, keyboardType: TextInputType.numberWithOptions( decimal: true, ), inputFormatters: decimalFormatter, ), ), ], ), ], ), ), ), const SizedBox(height: 12), // Vehicle Details Card( elevation: 5, color: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _sectionHeader( 'Vehicle Details', icon: Icons.directions_car, ), SizedBox(height: 10), Row( children: [ Expanded( child: _buildInput( 'RTO State Name', rtoStateCodeController, required: false, ), ), const SizedBox(width: 8), Expanded( child: _buildInput( 'RTO City Code', rtoCityCodeController, required: false, keyboardType: TextInputType.number, inputFormatters: digitsOnlyFormatter, ), ), const SizedBox(width: 8), Expanded( child: _buildInput( 'Weight', weightController, required: false, keyboardType: TextInputType.number, inputFormatters: digitsOnlyFormatter, ), ), ], ), Row( children: [ Expanded( child: _buildInput( 'Fuel Type', fuelTypeController, required: false, ), ), const SizedBox(width: 8), Expanded( child: _buildInput( 'Date of Registration', registrationDateController, required: false, readOnly: true, onTap: () => _pickDate( registrationDateController, context, ), ), ), const SizedBox(width: 8), Expanded( child: _buildInput( 'Year of Manufacture', yomController, required: false, keyboardType: TextInputType.number, inputFormatters: digitsOnlyFormatter, ), ), ], ), Row( children: [ Expanded( child: _buildInput( 'Engine No', engineNoController, required: false, ), ), const SizedBox(width: 8), Expanded( child: _buildInput( 'Chassis No', chassisNoController, required: false, ), ), const SizedBox(width: 8), Expanded( child: Expanded( child: _buildInput( 'Make', makeController, required: false, ), ), ), ], ), Row( children: [ Expanded( child: _buildInput( 'Model', modelController, required: false, ), ), const SizedBox(width: 8), Expanded( child: _buildInput( 'Cubic Capacity', cubicCapacityController, required: false, keyboardType: TextInputType.numberWithOptions( decimal: true, ), inputFormatters: decimalFormatter, ), ), const SizedBox(width: 8), Expanded( child: _buildInput( 'Vehicle Type', vehicleTypeController, required: false, ), ), ], ), ], ), ), ), const SizedBox(height: 12), // Broker Details Card( elevation: 5, color: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _sectionHeader( 'Broker / Commission', icon: Icons.person, ), SizedBox(height: 10), Row( children: [ Expanded( child: _buildInput( 'Broker Name', brokerNameController, required: false, ), ), const SizedBox(width: 8), Expanded( child: _buildInput( 'Commission Amount', commissionAmountController, required: false, keyboardType: TextInputType.numberWithOptions( decimal: true, ), inputFormatters: decimalFormatter, ), ), ], ), ], ), ), ), const SizedBox( height: 20, ), // spacing above fixed button ], ), ), ), ), ), ), ], ), ), ), ], ), ), ), ); } }