policy validation

This commit is contained in:
Surendiran 2025-12-15 12:17:00 +05:30
parent dda10c8d91
commit 5482d76788
3 changed files with 434 additions and 381 deletions

File diff suppressed because one or more lines are too long

View File

@ -55,6 +55,15 @@ import 'dart:typed_data';
// );
// }
// }
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;
@ -109,6 +118,8 @@ class _policyValidationState extends ConsumerState<policyValidation> {
late TextEditingController commissionAmountController;
final GlobalKey<SfPdfViewerState> _pdfViewerKey = GlobalKey();
final _formKey = GlobalKey<FormState>();
@override
void initState() {
@ -437,11 +448,24 @@ class _policyValidationState extends ConsumerState<policyValidation> {
Future<void> _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,
@ -560,33 +584,58 @@ class _policyValidationState extends ConsumerState<policyValidation> {
}
Widget _buildInput(
String label,
TextEditingController controller, {
TextInputType keyboardType = TextInputType.text,
bool readOnly = false,
VoidCallback? onTap,
}) {
String label,
TextEditingController controller, {
TextInputType keyboardType = TextInputType.text,
bool readOnly = false,
VoidCallback? onTap,
bool required = false,
List<TextInputFormatter>? inputFormatters, // 👈 ADD THIS
}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: const TextStyle(fontWeight: FontWeight.w500)),
const SizedBox(height: 6),
TextField(
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),
),
),
const SizedBox(height: 12),
],
);
}
@override
Widget build(BuildContext context) {
// Ensure global AppHeader remains visible by pushing content down by 64px
@ -755,388 +804,392 @@ class _policyValidationState extends ConsumerState<policyValidation> {
Expanded(
flex: 1,
child: SingleChildScrollView(
child: Card(
elevation: 2,
color: Colors.white,
margin: EdgeInsets.zero, // flush with container
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,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Insured Name',
insuredNameController,
),
),
],
),
Row(
children: [
Expanded(
child: _buildInput(
'Issued Date',
issuedDateController,
readOnly: true,
onTap: () => _pickDate(
issuedDateController,
context,
),
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Start Date',
startDateController,
readOnly: true,
onTap: () => _pickDate(
startDateController,
context,
),
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'End Date',
endDateController,
readOnly: true,
onTap: () => _pickDate(
endDateController,
context,
),
),
),
],
),
Row(
children: [
Expanded(
child: _buildInput(
'Premium Amount',
premiumController,
keyboardType:
TextInputType.number,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Remarks',
remarksController,
),
),
],
),
],
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),
),
),
),
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,
keyboardType:
TextInputType.number,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'OD',
odController,
keyboardType:
TextInputType.number,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'PA',
paController,
keyboardType:
TextInputType.number,
),
),
],
),
Row(
children: [
Expanded(
child: _buildInput(
'CGST',
cgstController,
keyboardType:
TextInputType.number,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'SGST',
sgstController,
keyboardType:
TextInputType.number,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'IGST',
igstController,
keyboardType:
TextInputType.number,
),
),
],
),
],
),
),
),
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,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'RTO City Code',
rtoCityCodeController,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Weight',
weightController,
keyboardType:
TextInputType.number,
),
),
],
),
Row(
children: [
Expanded(
child: _buildInput(
'Fuel Type',
fuelTypeController,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Date of Registration',
registrationDateController,
readOnly: true,
onTap: () => _pickDate(
registrationDateController,
context,
),
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Year of Manufacture',
yomController,
keyboardType:
TextInputType.number,
),
),
],
),
Row(
children: [
Expanded(
child: _buildInput(
'Engine No',
engineNoController,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Chassis No',
chassisNoController,
),
),
const SizedBox(width: 8),
Expanded(
child: Expanded(
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(
'Make',
makeController,
'Policy Number',
policyNumberController, required: true,
),
),
),
],
),
Row(
children: [
Expanded(
child: _buildInput(
'Model',
modelController,
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Insured Name',
insuredNameController, required: true
),
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Cubic Capacity',
cubicCapacityController,
keyboardType:
TextInputType.number,
],
),
Row(
children: [
Expanded(
child: _buildInput(
'Issued Date',
issuedDateController,
readOnly: true, required: true,
onTap: () => _pickDate(
issuedDateController,
context,
),
),
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Vehicle Type',
vehicleTypeController,
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: true
),
),
],
),
],
),
),
),
),
const SizedBox(height: 12),
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,
// 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(
'Commission Amount',
commissionAmountController,
keyboardType:
TextInputType.number,
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: 20,
), // spacing above fixed button
],
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: true,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'RTO City Code',
rtoCityCodeController,required: true,
keyboardType: TextInputType.number,
inputFormatters: digitsOnlyFormatter,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Weight',
weightController,required: true,
keyboardType: TextInputType.number,
inputFormatters: digitsOnlyFormatter,
),
),
],
),
Row(
children: [
Expanded(
child: _buildInput(
'Fuel Type',
fuelTypeController,required: true,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Date of Registration',
registrationDateController,required: true,
readOnly: true,
onTap: () => _pickDate(
registrationDateController,
context,
),
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Year of Manufacture',
yomController,required: true,
keyboardType: TextInputType.number,
inputFormatters: digitsOnlyFormatter,
),
),
],
),
Row(
children: [
Expanded(
child: _buildInput(
'Engine No',
engineNoController,required: true,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Chassis No',
chassisNoController,required: true,
),
),
const SizedBox(width: 8),
Expanded(
child: Expanded(
child: _buildInput(
'Make',
makeController,required: true,
),
),
),
],
),
Row(
children: [
Expanded(
child: _buildInput(
'Model',
modelController,required: true,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Cubic Capacity',
cubicCapacityController,required: true,
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: decimalFormatter,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Vehicle Type',
vehicleTypeController,required: true,
),
),
],
),
],
),
),
),
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: true,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInput(
'Commission Amount',
commissionAmountController,required: true,
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: decimalFormatter,
),
),
],
),
],
),
),
),
const SizedBox(
height: 20,
), // spacing above fixed button
],
),
),
),
),
),
),
)
],
),
),

View File

@ -700,26 +700,26 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
url: "https://pub.dev"
source: hosted
version: "10.0.9"
version: "11.0.2"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
url: "https://pub.dev"
source: hosted
version: "3.0.9"
version: "3.0.10"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
lints:
dependency: transitive
description:
@ -1297,10 +1297,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
url: "https://pub.dev"
source: hosted
version: "0.7.4"
version: "0.7.6"
toastification:
dependency: "direct main"
description:
@ -1417,10 +1417,10 @@ packages:
dependency: transitive
description:
name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.2.0"
vm_service:
dependency: transitive
description: