This commit is contained in:
venbaittech 2025-12-24 12:48:16 +05:30
parent 18bd0b3161
commit 10e5751367
13 changed files with 368 additions and 226 deletions

File diff suppressed because one or more lines are too long

View File

@ -43,23 +43,6 @@ class ApiService {
return _handleResponse(response); return _handleResponse(response);
} }
// Future<Map<String, dynamic>> _makePostRequest(
// Uri url, Map<String, String> body, Map<String, String> headers) async {
// final response = await http.post(url, headers: headers, body: body);
// return _handleResponse(response);
// }
//
// Future<Map<String, dynamic>> _handleResponse(http.Response response) async {
// if (response.statusCode == 200) {
// return jsonDecode(response.body);
// } else if (response.statusCode == 401) {
// await clearLocalStorageAndRedirect();
// return {};
// } else {
// throw Exception('Failed to load data');
// }
// }
Future<http.Response> _makeGethttpRequest( Future<http.Response> _makeGethttpRequest(
Uri url, Uri url,
Map<String, String> headers, Map<String, String> headers,
@ -176,21 +159,39 @@ class ApiService {
} }
// 3. UNAUTHORIZED / FORBIDDEN (The 401/403 Fix) // 3. UNAUTHORIZED / FORBIDDEN (The 401/403 Fix)
if ((response.statusCode == 401 && body['status'] == 401) || // if ((response.statusCode == 401 && body['status'] == 401) ||
(response.statusCode == 403 && body['status'] == 403)) { // (response.statusCode == 403 && body['status'] == 403)) {
// Perform cleanup // // Perform cleanup
await AuthService.clearToken(); // await AuthService.clearToken();
//
// // Redirect using global appRouter (avoids context errors)
// context.go(AppRoutes.login);
//
// // Return a structured error so the UI knows why it failed
// return {'status': 401, 'message': 'Session expired or invalid'};
// }
//
// if (response.statusCode == 401 || response.statusCode == 403) {
// await clearLocalStorageAndRedirect();
// return {};
// }
// Redirect using global appRouter (avoids context errors) final message = (body['message'] ?? body['error'] ?? '')
context.go(AppRoutes.login); .toString()
.toLowerCase();
// Return a structured error so the UI knows why it failed // 2 TOKEN / AUTH FAILURE (message OR status based)
return {'status': 401, 'message': 'Session expired or invalid'}; final isAuthError =
} response.statusCode == 401 ||
response.statusCode == 403 ||
message.contains('token required') ||
message.contains('invalid or expired token');
if (response.statusCode == 401 || response.statusCode == 403) { if (isAuthError) {
await clearLocalStorageAndRedirect(); await clearLocalStorageAndRedirect(); // handles navigation internally
return {};
// Stop further execution
throw Exception('Authentication error');
} }
// 4. ALL OTHER ERRORS // 4. ALL OTHER ERRORS

View File

@ -785,6 +785,7 @@ class _AddDialogState extends State<AddDialog> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
buildUploadDocumentClaims(context), buildUploadDocumentClaims(context),
SizedBox(width: 15), SizedBox(width: 15),
@ -813,6 +814,7 @@ class _AddDialogState extends State<AddDialog> {
SizedBox(height: 10), SizedBox(height: 10),
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
buildUploadDocumentClaims(context), buildUploadDocumentClaims(context),
@ -850,11 +852,11 @@ class _AddDialogState extends State<AddDialog> {
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, // txtheight: 45,
validator: (value) => Validators.requiredField(value, "claimsDesc"), validator: (value) => Validators.requiredField(value, "claimsDesc"),
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
@ -960,7 +962,7 @@ class _AddDialogState extends State<AddDialog> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text("Upload Document", style: _textStyle), Text("Upload Document", style: _textStyle),
SizedBox(width: 10), SizedBox(height: 10),
ThemedUploadField( ThemedUploadField(
backgroundColor: Color(0xFFEDF6F5), backgroundColor: Color(0xFFEDF6F5),
hintText: selectedClaimFileNames ?? "Upload Document", hintText: selectedClaimFileNames ?? "Upload Document",
@ -1143,8 +1145,8 @@ class _AddDialogState extends State<AddDialog> {
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
: MediaQuery.of(context).size.width * 0.26, : MediaQuery.of(context).size.width * 0.26,
keyboardType: TextInputType.multiline, // keyboardType: TextInputType.multiline,
txtheight: 45, // txtheight: 45,
), ),
], ],
); );

View File

@ -719,6 +719,7 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Expanded(child: Text('Product-Wise', style: _chartHeader)), Expanded(child: Text('Product-Wise', style: _chartHeader)),
Text( Text(

View File

@ -301,7 +301,7 @@ class _DashboardState extends ConsumerState<PartnerDashboard> {
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
child: Column( child: Column(
children: [ children: [
if (role == 'manager' || role == 'hanlder') if (role == 'manager' || role == 'handler')
SizedBox( SizedBox(
height: MediaQuery.of(context).size.height * 0.78, height: MediaQuery.of(context).size.height * 0.78,
// replace Expanded // replace Expanded

View File

@ -353,6 +353,7 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
return Card( return Card(
margin: const EdgeInsets.only(right: 10), margin: const EdgeInsets.only(right: 10),
color: Colors.white, color: Colors.white,
shadowColor: Colors.black, shadowColor: Colors.black,
elevation: 1, // card shadow elevation: 1, // card shadow
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
@ -394,7 +395,9 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
], ],
), ),
SizedBox(height: 10), SizedBox(height: 10),
Expanded( Container(
// color: Colors.amber.shade100,
child: Expanded(
child: CustomStackedBarChart( child: CustomStackedBarChart(
labels: staffLabels, labels: staffLabels,
labelsId: staffLabelsId, labelsId: staffLabelsId,
@ -407,6 +410,7 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
staffVehicleTypeNames, // 👈 NEW: Pass vehicle names staffVehicleTypeNames, // 👈 NEW: Pass vehicle names
), ),
), ),
),
Row(children: [Expanded(child: legendWidget())]), Row(children: [Expanded(child: legendWidget())]),
], ],
), ),

View File

@ -292,7 +292,7 @@ class _DateFilterRowState extends ConsumerState<DateFilterRowPayout> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('Start Date', style: _textStyle), Text('Start Date *', style: _textStyle),
SizedBox(height: 5), SizedBox(height: 5),
SizedBox( SizedBox(
height: 35, height: 35,
@ -323,7 +323,7 @@ class _DateFilterRowState extends ConsumerState<DateFilterRowPayout> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('End Date', style: _textStyle), Text('End Date *', style: _textStyle),
SizedBox(height: 5), SizedBox(height: 5),
SizedBox( SizedBox(
height: 35, height: 35,
@ -371,7 +371,7 @@ class _DateFilterRowState extends ConsumerState<DateFilterRowPayout> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('Broker', style: _textStyle), Text('Broker *', style: _textStyle),
SizedBox(height: 5), SizedBox(height: 5),
SizedBox( SizedBox(
height: 35, height: 35,
@ -523,7 +523,7 @@ class _DateFilterRowState extends ConsumerState<DateFilterRowPayout> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text("Referer", style: _textStyle), Text("Referer *", style: _textStyle),
SizedBox(height: 5), SizedBox(height: 5),
SizedBox( SizedBox(
height: 35, height: 35,
@ -554,9 +554,14 @@ class _DateFilterRowState extends ConsumerState<DateFilterRowPayout> {
// }, // },
validator: (val) { validator: (val) {
if (val == null || val.isEmpty) { if (val == null || val.isEmpty) {
return "Required"; return ""; // 👈 triggers error border, no text
} }
return null; return null;
// if (val == null || val.isEmpty) {
// return "Required";
// }
// return null;
}, },
decoratorProps: DropDownDecoratorProps( decoratorProps: DropDownDecoratorProps(
@ -569,6 +574,7 @@ class _DateFilterRowState extends ConsumerState<DateFilterRowPayout> {
color: Colors.black, color: Colors.black,
), ),
filled: true, filled: true,
errorStyle: const TextStyle(height: 0, fontSize: 0),
fillColor: fillColor:
Colors.white, // 👈 makes the dropdown input white Colors.white, // 👈 makes the dropdown input white
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(

View File

@ -783,8 +783,8 @@ class _PayOutScreenState extends ConsumerState<PayOutScreen> {
), ),
), ),
), ),
SizedBox(height: 5),
// SizedBox(height: 5),
if (!isEdit) ...[ if (!isEdit) ...[
Container( Container(
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),
@ -828,6 +828,8 @@ class _PayOutScreenState extends ConsumerState<PayOutScreen> {
}, },
), ),
), ),
SizedBox(height: 10),
], ],
// Policy Selection // Policy Selection
Card( Card(

View File

@ -295,10 +295,13 @@ class policylistState extends ConsumerState<policylist> {
} }
Future<void> fetchPolicyExcelReport() async { Future<void> fetchPolicyExcelReport() async {
final String fromDate = controllers['startDate']!.text; // "11-01-2025" final String fromDate = controllers['startDate']!.text; // "11-01-2025"
final String toDate = controllers['endDate']!.text; // "20-01-2025" final String toDate = controllers['endDate']!.text; // "20-01-2025"
final response = await apiService.generatePolicyExcel(managerId,fromDate,toDate); final response = await apiService.generatePolicyExcel(
managerId,
fromDate,
toDate,
);
// Map your controllers and IDs to the API parameters // Map your controllers and IDs to the API parameters
// final String fromDate = controllers['startDate']!.text; // "11-01-2025" // final String fromDate = controllers['startDate']!.text; // "11-01-2025"
// final String toDate = controllers['endDate']!.text; // "20-01-2025" // final String toDate = controllers['endDate']!.text; // "20-01-2025"
@ -321,7 +324,6 @@ class policylistState extends ConsumerState<policylist> {
// } // }
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MainLayout( return MainLayout(
@ -824,7 +826,7 @@ class policylistState extends ConsumerState<policylist> {
SizedBox(width: 10), SizedBox(width: 10),
InkWell( InkWell(
onTap: () { onTap: () {
showAuditHistoryModal(context,item['id']); showAuditHistoryModal(context, item['id']);
}, },
child: Container( child: Container(
padding: EdgeInsets.all(5.4), padding: EdgeInsets.all(5.4),
@ -859,6 +861,10 @@ class policylistState extends ConsumerState<policylist> {
onTap: () { onTap: () {
context.push(AppRoutes.policyValidation, extra: item); context.push(AppRoutes.policyValidation, extra: item);
}, },
child: Tooltip(
message: item['is_data_accuracy_checked'] == '1'
? 'Verified'
: 'To Verify',
child: Container( child: Container(
width: 80, // FIXED WIDTH Equal in both states width: 80, // FIXED WIDTH Equal in both states
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@ -873,8 +879,8 @@ class policylistState extends ConsumerState<policylist> {
), ),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment
MainAxisAlignment.spaceEvenly, // Center content .spaceEvenly, // Center content
children: [ children: [
Icon( Icon(
item['is_data_accuracy_checked'] == '1' item['is_data_accuracy_checked'] == '1'
@ -883,22 +889,23 @@ class policylistState extends ConsumerState<policylist> {
size: 12, size: 12,
color: Colors.white, color: Colors.white,
), ),
const SizedBox(width: 1), // const SizedBox(width: 1),
Text( // Text(
item['is_data_accuracy_checked'] == '1' // item['is_data_accuracy_checked'] == '1'
? 'Verified' // ? 'Verified'
: 'To Verify', // : 'To Verify',
style: GoogleFonts.poppins( // style: GoogleFonts.poppins(
color: Colors.white, // color: Colors.white,
fontSize: 10, // fontSize: 10,
fontWeight: FontWeight.w500, // fontWeight: FontWeight.w500,
), // ),
), // ),
], ],
), ),
), ),
), ),
), ),
),
], ],
], ],
), ),
@ -1134,7 +1141,10 @@ void showAuditHistoryModal(BuildContext context, dynamic policyId) {
class AuditHistoryModal extends ConsumerStatefulWidget { class AuditHistoryModal extends ConsumerStatefulWidget {
final dynamic policyId; // Add this final dynamic policyId; // Add this
const AuditHistoryModal({super.key, required this.policyId}); // Update constructor const AuditHistoryModal({
super.key,
required this.policyId,
}); // Update constructor
@override @override
ConsumerState<AuditHistoryModal> createState() => AuditHistoryModalState(); ConsumerState<AuditHistoryModal> createState() => AuditHistoryModalState();
@ -1158,11 +1168,15 @@ class AuditHistoryModalState extends ConsumerState<AuditHistoryModal> {
setState(() => isLoading = true); setState(() => isLoading = true);
try { try {
// Use widget.policyId here! // Use widget.policyId here!
final response = await apiService.fetchAuditHistory(widget.policyId.toString()); final response = await apiService.fetchAuditHistory(
widget.policyId.toString(),
);
if (response != null && response['status'] == "success") { if (response != null && response['status'] == "success") {
setState(() { setState(() {
getAuditHistoryData = List<Map<String, dynamic>>.from(response['data']); getAuditHistoryData = List<Map<String, dynamic>>.from(
response['data'],
);
}); });
} }
} catch (e) { } catch (e) {
@ -1225,44 +1239,80 @@ class AuditHistoryModalState extends ConsumerState<AuditHistoryModal> {
child: SizedBox( child: SizedBox(
width: double.infinity, width: double.infinity,
child: Theme( child: Theme(
data: Theme.of(context).copyWith( data: Theme.of(
dividerColor: Colors.grey.shade200, context,
), ).copyWith(dividerColor: Colors.grey.shade200),
child: DataTable( child: DataTable(
headingRowColor: WidgetStateProperty.all(Color(0xFFF8FAFC)), headingRowColor: WidgetStateProperty.all(
Color(0xFFF8FAFC),
),
columnSpacing: 20, columnSpacing: 20,
columns: [ columns: [
DataColumn(label: Text("Column Name", style: _headerStyle())), DataColumn(
DataColumn(label: Text("Message", style: _headerStyle())), label: Text(
DataColumn(label: Text("Changed On", style: _headerStyle())), "Column Name",
DataColumn(label: Text("Changed By", style: _headerStyle())), 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 // Inside your build method's DataTable
rows: getAuditHistoryData.map((data) { rows: getAuditHistoryData.map((data) {
return DataRow(cells: [ return DataRow(
DataCell(Text(data['column_name'] ?? "-", style: _cellStyle())), cells: [
DataCell(
Text(
data['column_name'] ?? "-",
style: _cellStyle(),
),
),
DataCell( DataCell(
SizedBox( SizedBox(
width: 300, // Give message more width width: 300, // Give message more width
child: Text( child: Text(
data['message'] ?? "-", data['message'] ?? "-",
style: _cellStyle(), style: _cellStyle(),
softWrap: true, // Ensure text wraps to next line softWrap:
true, // Ensure text wraps to next line
), ),
)
), ),
DataCell(Text( ),
formatIndianDate(data['changed_on'] ?? ""), DataCell(
Text(
formatIndianDate(
data['changed_on'] ?? "",
),
style: _cellStyle(), style: _cellStyle(),
)), ),
DataCell(Text(data['changed_by'] ?? "-", style: _cellStyle())), ),
]); DataCell(
Text(
data['changed_by'] ?? "-",
style: _cellStyle(),
),
),
],
);
}).toList(), }).toList(),
), ),
), ),
), ),
), ),
) ),
], ],
), ),
), ),
@ -1270,14 +1320,17 @@ class AuditHistoryModalState extends ConsumerState<AuditHistoryModal> {
} }
} }
// Helper styles to keep code clean // Helper styles to keep code clean
TextStyle _headerStyle() => GoogleFonts.poppins( TextStyle _headerStyle() => GoogleFonts.poppins(
fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF475569)); fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF475569),
);
TextStyle _cellStyle() => GoogleFonts.poppins( TextStyle _cellStyle() =>
fontSize: 11, color: Color(0xFF1E293B)); GoogleFonts.poppins(fontSize: 11, color: Color(0xFF1E293B));
String formatIndianDate(String dateStr) { String formatIndianDate(String dateStr) {
try { try {
DateTime dateTime = DateTime.parse(dateStr); DateTime dateTime = DateTime.parse(dateStr);
// Format: Day-Month-Year Hour:Minute AM/PM // Format: Day-Month-Year Hour:Minute AM/PM
@ -1285,4 +1338,4 @@ class AuditHistoryModalState extends ConsumerState<AuditHistoryModal> {
} catch (e) { } catch (e) {
return dateStr; // Fallback to original string if parsing fails return dateStr; // Fallback to original string if parsing fails
} }
} }

View File

@ -36,6 +36,8 @@ class _policyValidationState extends ConsumerState<policyValidation> {
// --- Api / state // --- Api / state
late ApiService apiService; late ApiService apiService;
bool isLoading = false; bool isLoading = false;
bool isLoadingVehicleType = false;
bool isLoadingFuelType = false;
dynamic managerId; dynamic managerId;
dynamic userId; dynamic userId;
@ -266,7 +268,6 @@ class _policyValidationState extends ConsumerState<policyValidation> {
}); });
} }
@override @override
void dispose() { void dispose() {
for (final controller in controllers.values) { for (final controller in controllers.values) {
@ -289,7 +290,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
Future<void> getVehicleType() async { Future<void> getVehicleType() async {
print('getvehicleType called'); print('getvehicleType called');
setState(() => isLoading = true); setState(() => isLoadingVehicleType = true);
try { try {
final response = await apiService.fetchPolicyMasterDropDown( final response = await apiService.fetchPolicyMasterDropDown(
@ -311,13 +312,13 @@ class _policyValidationState extends ConsumerState<policyValidation> {
} catch (e) { } catch (e) {
print('Exception occurred: $e'); print('Exception occurred: $e');
} finally { } finally {
setState(() => isLoading = false); setState(() => isLoadingVehicleType = false);
} }
} }
Future<void> getFuelType() async { Future<void> getFuelType() async {
print('getfuelType called'); print('getfuelType called');
setState(() => isLoading = true); setState(() => isLoadingFuelType = true);
try { try {
final response = await apiService.fetchPolicyMasterDropDown('fuelType'); final response = await apiService.fetchPolicyMasterDropDown('fuelType');
@ -337,7 +338,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
} catch (e) { } catch (e) {
print('Exception occurred: $e'); print('Exception occurred: $e');
} finally { } finally {
setState(() => isLoading = false); setState(() => isLoadingFuelType = false);
} }
} }
@ -591,16 +592,16 @@ class _policyValidationState extends ConsumerState<policyValidation> {
// print('_fetchCommision2'); // print('_fetchCommision2');
// 👉 CRITICAL FIX: Set loading to true BEFORE the API call starts // 👉 CRITICAL FIX: Set loading to true BEFORE the API call starts
setState(() { isLoading = true; }); setState(() {
isLoading = true;
});
try { try {
final payload = buildCommissionPayload(); final payload = buildCommissionPayload();
debugPrint('Payload in fetchCommission: $payload'); debugPrint('Payload in fetchCommission: $payload');
final result = await apiService.calculateCommissionRequest(payload); final result = await apiService.calculateCommissionRequest(payload);
debugPrint('Result in fetchCommission: $result'); debugPrint('Result in fetchCommission: $result');
if (result != null && result['status'] == 'success') { if (result != null && result['status'] == 'success') {
if (!mounted) return; if (!mounted) return;
// setState(() => isLoading = false); // setState(() => isLoading = false);
@ -613,12 +614,16 @@ class _policyValidationState extends ConsumerState<policyValidation> {
isLoading = false; // Stop loading isLoading = false; // Stop loading
if (commissionAmount != null) { if (commissionAmount != null) {
// Update controller so the Confirm button becomes active // Update controller so the Confirm button becomes active
controllers["commission_amount"]?.text = controllers["commission_amount"]?.text = double.parse(
double.parse(commissionAmount.toString()).toStringAsFixed(2); commissionAmount.toString(),
).toStringAsFixed(2);
} }
}); });
ToastHelper.showSuccessToast(context, "Commission calculated successfully"); ToastHelper.showSuccessToast(
context,
"Commission calculated successfully",
);
// WidgetsBinding.instance.addPostFrameCallback((_) { // WidgetsBinding.instance.addPostFrameCallback((_) {
// // Now safe to do navigation + provider updates // // Now safe to do navigation + provider updates
@ -728,7 +733,10 @@ class _policyValidationState extends ConsumerState<policyValidation> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.spaceBetween, // mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("Vehicle Type", style: TextStyle(fontWeight: FontWeight.w500)), Text(
"Vehicle Type",
style: GoogleFonts.poppins(fontWeight: FontWeight.w500, fontSize: 11),
),
const SizedBox(height: 6), const SizedBox(height: 6),
DropdownSearch<String>( DropdownSearch<String>(
key: dropDownKey, key: dropDownKey,
@ -745,7 +753,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
validator: (val) { validator: (val) {
if (val == null || val.isEmpty) { if (val == null || val.isEmpty) {
return "Required"; return ""; // 👈 triggers error border, no text
} }
return null; return null;
}, },
@ -831,7 +839,10 @@ class _policyValidationState extends ConsumerState<policyValidation> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text("Fuel Type ", style: TextStyle(fontWeight: FontWeight.w500)), Text(
"Fuel Type ",
style: GoogleFonts.poppins(fontWeight: FontWeight.w500, fontSize: 11),
),
const SizedBox(width: 6), const SizedBox(width: 6),
DropdownSearch<String>( DropdownSearch<String>(
key: dropDownKeyFuel, key: dropDownKeyFuel,
@ -848,7 +859,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
validator: (val) { validator: (val) {
if (val == null || val.isEmpty) { if (val == null || val.isEmpty) {
return "Required"; return ""; // 👈 triggers error border, no text
} }
return null; return null;
}, },
@ -944,12 +955,12 @@ class _policyValidationState extends ConsumerState<policyValidation> {
color: Color(0xFF2E7D6E), color: Color(0xFF2E7D6E),
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: Icon(icon, size: 16, color: Colors.white), child: Icon(icon, size: 12, color: Colors.white),
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
Text( Text(
title, title,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600), style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w600),
), ),
], ],
), ),
@ -968,7 +979,10 @@ class _policyValidationState extends ConsumerState<policyValidation> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text(label, style: const TextStyle(fontWeight: FontWeight.w500)), Text(
label,
style: GoogleFonts.poppins(fontWeight: FontWeight.w500, fontSize: 11),
),
const SizedBox(height: 6), const SizedBox(height: 6),
TextFormField( TextFormField(
controller: controller, controller: controller,
@ -976,9 +990,9 @@ class _policyValidationState extends ConsumerState<policyValidation> {
readOnly: readOnly, readOnly: readOnly,
onTap: onTap, onTap: onTap,
inputFormatters: inputFormatters, // 👈 USE HERE inputFormatters: inputFormatters, // 👈 USE HERE
validator: (value) { validator: (val) {
if (required && (value == null || value.trim().isEmpty)) { if (val == null || val.isEmpty) {
return "$label is required"; return ""; // 👈 triggers error border, no text
} }
return null; return null;
}, },
@ -1026,10 +1040,16 @@ class _policyValidationState extends ConsumerState<policyValidation> {
// (controllers['commission_amount']?.text.isEmpty ?? true) // (controllers['commission_amount']?.text.isEmpty ?? true)
// ? null // ? null
// : _save, // : _save,
onPressed: ( onPressed:
widget.item?['is_data_accuracy_checked']?.toString() == '0' && (widget.item?['is_data_accuracy_checked']?.toString() ==
((double.tryParse(controllers["commission_amount"]?.text ?? '0') ?? 0).floor() >= 1) '0' &&
) ((double.tryParse(
controllers["commission_amount"]?.text ??
'0',
) ??
0)
.floor() >=
1))
? _save ? _save
: null, : null,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
@ -1162,7 +1182,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
const Text( const Text(
'Original Policy Document', 'Original Policy Document',
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 14,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
), ),
@ -1268,7 +1288,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
children: [ children: [
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'Policy Number', 'Policy Number *',
controllers['policyNumber']!, controllers['policyNumber']!,
required: true, required: true,
), ),
@ -1276,7 +1296,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'Insured Name', 'Insured Name *',
controllers['insuredName']!, controllers['insuredName']!,
required: true, required: true,
), ),
@ -1287,7 +1307,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
children: [ children: [
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'Issued Date', 'Issued Date *',
controllers['issuedDate']!, controllers['issuedDate']!,
readOnly: true, readOnly: true,
required: true, required: true,
@ -1300,7 +1320,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'Start Date', 'Start Date *',
controllers['startDate']!, controllers['startDate']!,
readOnly: true, readOnly: true,
@ -1314,7 +1334,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'End Date', 'End Date *',
controllers['endDate']!, controllers['endDate']!,
readOnly: true, readOnly: true,
required: true, required: true,
@ -1330,7 +1350,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
children: [ children: [
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'Premium Amount', 'Premium Amount *',
controllers['premiumAmount']!, controllers['premiumAmount']!,
required: true, required: true,
@ -1345,7 +1365,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'Remarks', 'Remarks *',
required: false, required: false,
controllers['remarks']!, controllers['remarks']!,
), ),
@ -1357,7 +1377,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
), ),
), ),
const SizedBox(height: 12), const SizedBox(height: 7),
// Tax Details // Tax Details
Card( Card(
@ -1373,7 +1393,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
CrossAxisAlignment.stretch, CrossAxisAlignment.stretch,
children: [ children: [
_sectionHeader( _sectionHeader(
'Tax / Cover Details', 'Tax / Cover Details *',
icon: Icons.attach_money, icon: Icons.attach_money,
), ),
SizedBox(height: 10), SizedBox(height: 10),
@ -1381,7 +1401,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
children: [ children: [
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'TP', 'TP *',
controllers['tp']!, controllers['tp']!,
required: true, required: true,
keyboardType: keyboardType:
@ -1395,7 +1415,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'OD', 'OD *',
controllers['od']!, controllers['od']!,
required: true, required: true,
keyboardType: keyboardType:
@ -1409,7 +1429,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'PA', 'PA *',
controllers['pa']!, controllers['pa']!,
required: true, required: true,
keyboardType: keyboardType:
@ -1426,7 +1446,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
children: [ children: [
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'CGST', 'CGST *',
controllers['cgst']!, controllers['cgst']!,
required: true, required: true,
keyboardType: keyboardType:
@ -1440,7 +1460,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'SGST', 'SGST *',
controllers['sgst']!, controllers['sgst']!,
required: true, required: true,
keyboardType: keyboardType:
@ -1454,7 +1474,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'IGST', 'IGST *',
controllers['igst']!, controllers['igst']!,
required: true, required: true,
keyboardType: keyboardType:
@ -1472,7 +1492,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
), ),
), ),
const SizedBox(height: 12), const SizedBox(height: 7),
// Vehicle Details // Vehicle Details
Card( Card(
@ -1497,7 +1517,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
children: [ children: [
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'RTO State Name', 'RTO State Name *',
controllers['rtoStateCode']!, controllers['rtoStateCode']!,
required: true, required: true,
), ),
@ -1505,7 +1525,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'RTO City Code', 'RTO City Code *',
controllers['rtoCityCode']!, controllers['rtoCityCode']!,
required: true, required: true,
keyboardType: keyboardType:
@ -1517,7 +1537,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'Weight', 'Weight *',
controllers['weight']!, controllers['weight']!,
required: true, required: true,
keyboardType: keyboardType:
@ -1541,7 +1561,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'Date of Registration', 'Date of Registration *',
controllers['dateOfRegistration']!, controllers['dateOfRegistration']!,
required: true, required: true,
readOnly: true, readOnly: true,
@ -1554,7 +1574,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'Year of Manufacture', 'Year of Manufacture *',
controllers['yearOfManufacture']!, controllers['yearOfManufacture']!,
required: true, required: true,
keyboardType: keyboardType:
@ -1569,7 +1589,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
children: [ children: [
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'Engine No', 'Engine No *',
controllers['engineNo']!, controllers['engineNo']!,
required: true, required: true,
), ),
@ -1577,7 +1597,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'Chassis No', 'Chassis No *',
controllers['chassisNo']!, controllers['chassisNo']!,
required: true, required: true,
), ),
@ -1586,7 +1606,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
Expanded( Expanded(
child: Expanded( child: Expanded(
child: _buildInput( child: _buildInput(
'Make', 'Make *',
controllers['make']!, controllers['make']!,
required: true, required: true,
), ),
@ -1598,7 +1618,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
children: [ children: [
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'Model', 'Model *',
controllers['model']!, controllers['model']!,
required: true, required: true,
), ),
@ -1606,7 +1626,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'Cubic Capacity', 'Cubic Capacity *',
controllers['cubicCapacity']!, controllers['cubicCapacity']!,
required: true, required: true,
keyboardType: keyboardType:
@ -1634,8 +1654,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
), ),
), ),
), ),
const SizedBox(height: 7),
const SizedBox(height: 12),
// Broker Details // Broker Details
Card( Card(
@ -1659,7 +1678,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
children: [ children: [
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'Broker Name', 'Broker Name *',
controllers['broker_name']!, controllers['broker_name']!,
required: true, required: true,
), ),
@ -1667,7 +1686,7 @@ class _policyValidationState extends ConsumerState<policyValidation> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: _buildInput( child: _buildInput(
'Commission Amount', 'Commission Amount *',
controllers['commission_amount']!, controllers['commission_amount']!,
// required: true, // required: true,
keyboardType: keyboardType:
@ -1681,24 +1700,36 @@ class _policyValidationState extends ConsumerState<policyValidation> {
], ],
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, // Pushes children to the right mainAxisAlignment: MainAxisAlignment
.end, // Pushes children to the right
children: [ children: [
TextButton( TextButton(
onPressed: (widget.item?['is_data_accuracy_checked'] == '1' || isLoading) onPressed:
(widget.item?['is_data_accuracy_checked'] ==
'1' ||
isLoading)
? null // Disable if already checked or currently loading ? null // Disable if already checked or currently loading
: _fetchCommision, : _fetchCommision,
child: Text(isLoading ? "Calculating..." : "Calculate", child: Text(
isLoading
? "Calculating..."
: "Calculate",
style: TextStyle( style: TextStyle(
color: (widget.item?['is_data_accuracy_checked'] == '1' || isLoading) color:
(widget.item?['is_data_accuracy_checked'] ==
'1' ||
isLoading)
? Colors.grey ? Colors.grey
: const Color(0xFF2E7D6E), : const Color(
fontWeight: FontWeight.bold, 0xFF2E7D6E,
) ),
fontWeight:
FontWeight.bold,
),
), ),
), ),
], ],
) ),
], ],
), ),
), ),

View File

@ -94,6 +94,24 @@ class _CustomBarChartState extends ConsumerState<CustomBarChart> {
} }
String compactNumber(num value) { String compactNumber(num value) {
if (value >= 10000000) {
return '${(value / 10000000).toStringAsFixed(1).replaceAll('.0', '')}Cr';
} else if (value >= 1000000) {
return '${(value / 1000000).toStringAsFixed(1).replaceAll('.0', '')}M';
} else if (value >= 1000) {
return '${(value / 1000).toStringAsFixed(1).replaceAll('.0', '')}K';
} else if (value >= 1) {
// 👇 remove .0 ONLY when it's an integer
return value % 1 == 0
? value.toInt().toString()
: value.toStringAsFixed(1);
} else {
// 👇 keep decimals for small values
return value == 0 ? '0' : value.toStringAsFixed(1);
}
}
String compactNumberToolTip(num value) {
if (value >= 10000000) { if (value >= 10000000) {
return '${(value / 10000000).toStringAsFixed(1).replaceAll('.0', '')}Cr'; return '${(value / 10000000).toStringAsFixed(1).replaceAll('.0', '')}Cr';
} else if (value >= 1000000) { } else if (value >= 1000000) {
@ -187,7 +205,7 @@ class _CustomBarChartState extends ConsumerState<CustomBarChart> {
// rod.toY.round(), // rod.toY.round(),
// ); // );
final formattedValue = compactNumber(rod.toY); final formattedValue = compactNumberToolTip(rod.toY);
return BarTooltipItem(formattedValue, textStyle); return BarTooltipItem(formattedValue, textStyle);
// return BarTooltipItem('${rod.toY.round()}', textStyle); // return BarTooltipItem('${rod.toY.round()}', textStyle);
}, },

View File

@ -85,6 +85,7 @@ class _CustomBarChartState extends ConsumerState<CustomBarChartHorizontal> {
// BarChartRodData(toY: 2, color: Colors.orange.shade300, width: 6), // BarChartRodData(toY: 2, color: Colors.orange.shade300, width: 6),
BarChartRodData( BarChartRodData(
toY: value2, toY: value2,
// toY: value2,
color: const Color(0xFFA5E4E1), color: const Color(0xFFA5E4E1),
// color: Colors.orange.shade300, // color: Colors.orange.shade300,
width: 10, width: 10,

View File

@ -60,12 +60,34 @@ class _CustomStackedBarChartState extends ConsumerState<CustomStackedBarChart> {
}); });
} }
String compactNumber(num value) {
if (value >= 10000000) {
return '${(value / 10000000).toStringAsFixed(1).replaceAll('.0', '')}Cr';
} else if (value >= 1000000) {
return '${(value / 1000000).toStringAsFixed(1).replaceAll('.0', '')}M';
} else if (value >= 1000) {
return '${(value / 1000).toStringAsFixed(1).replaceAll('.0', '')}K';
} else if (value >= 1) {
// 👇 remove .0 ONLY when it's an integer
return value % 1 == 0
? value.toInt().toString()
: value.toStringAsFixed(1);
} else {
// 👇 keep decimals for small values
return value == 0 ? '0' : value.toStringAsFixed(1);
}
}
// else {
// return value.toInt().toString();
// }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final maxY = widget.maxY <= 0 ? 100.0 : widget.maxY; final maxY = widget.maxY <= 0 ? 100.0 : widget.maxY;
return AspectRatio( return AspectRatio(
aspectRatio: 1.6, aspectRatio: 4,
child: BarChart( child: BarChart(
BarChartData( BarChartData(
alignment: BarChartAlignment.spaceAround, alignment: BarChartAlignment.spaceAround,
@ -110,7 +132,7 @@ class _CustomStackedBarChartState extends ConsumerState<CustomStackedBarChart> {
bottomTitles: AxisTitles( bottomTitles: AxisTitles(
sideTitles: SideTitles( sideTitles: SideTitles(
showTitles: true, showTitles: true,
reservedSize: 56, reservedSize: 130,
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) {
@ -124,7 +146,7 @@ class _CustomStackedBarChartState extends ConsumerState<CustomStackedBarChart> {
fontSize: 10, fontSize: 10,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
textAlign: TextAlign.center, textAlign: TextAlign.end,
), ),
); );
}, },
@ -140,7 +162,8 @@ class _CustomStackedBarChartState extends ConsumerState<CustomStackedBarChart> {
child: Padding( child: Padding(
padding: const EdgeInsets.only(right: 3.0), padding: const EdgeInsets.only(right: 3.0),
child: Text( child: Text(
value.toInt().toString(), compactNumber(value),
// value.toInt().toString(),
textAlign: TextAlign.end, textAlign: TextAlign.end,
style: GoogleFonts.inter(fontSize: 10), style: GoogleFonts.inter(fontSize: 10),
), ),