UI_Enq_Tabs UI_Staff_Web

This commit is contained in:
venbaittech 2025-09-22 09:59:19 +05:30
parent f107692905
commit 720a27985a
19 changed files with 5629 additions and 758 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,12 +1,15 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:nhance_partner/core/routing/routes.dart';
import 'package:nhance_partner/presentation/screens/Enquiry/enquiryList.dart';
import 'package:nhance_partner/presentation/screens/UserManagement/Profile/profile_web.dart';
import 'package:nhance_partner/presentation/screens/claims/claimsList.dart';
import 'package:nhance_partner/presentation/screens/dashboard/dashboard.dart';
import '../../data/services/auth_service.dart';
import '../../presentation/providers/manager_provider.dart';
import '../../presentation/screens/Enquiry/enquiry/tabs.dart';
import '../../presentation/screens/Enquiry/policy_claims_endros/claims.dart';
import '../../presentation/screens/Enquiry/policy_claims_endros/endrosment.dart';
import '../../presentation/screens/UserManagement/Agent/agent.dart';
import '../../presentation/screens/UserManagement/Agent/agentList.dart';
import '../../presentation/screens/UserManagement/Profile/profile_mobile.dart';
@ -15,6 +18,9 @@ import '../../presentation/screens/UserManagement/Staff/staffList.dart';
import '../../presentation/screens/home/home_screen.dart';
import '../../presentation/screens/login/login_screen.dart';
import '../../presentation/screens/splash/splash_screen.dart';
import '../../presentation/screens/staff/policy/policy.dart';
import '../../presentation/screens/staff/policy/policy_list.dart';
import '../../presentation/screens/staff/quotations/quotation.dart';
final GoRouter appRouter = GoRouter(
initialLocation: AppRoutes.home,
@ -85,9 +91,59 @@ final GoRouter appRouter = GoRouter(
builder: (context, state) => const EnquiryList(),
),
// GoRoute(
// path: '/tabEnquiry/:id',
// builder: (context, state) {
// final id = state.pathParameters['id']!;
// // if "create", open empty form
// if (id == 'tab') {
// return TabEnquiryList(); // create mode
// } else {
// return TabEnquiryList(id: id); // update mode
// }
// },
// ),
GoRoute(
path: AppRoutes.tabEnquiry,
builder: (context, state) => const TabEnquiryList(),
builder: (context, state) {
return TabEnquiryList(); // no id in path
},
),
// GoRoute(
// path: AppRoutes.tabEnquiry,
// builder: (context, state) {
// return Consumer(
// builder: (context, ref, _) {
// final id = state.pathParameters['id']!;
// ref.read(enquiryIdProvider.notifier).state = (id == 'tab')
// ? null
// : id;
// return TabEnquiryList();
// },
// );
// },
// ),
GoRoute(
path: AppRoutes.claimlist,
builder: (context, state) => const claimList(),
),
GoRoute(
path: AppRoutes.endosement,
builder: (context, state) => const endosement(),
),
GoRoute(
path: AppRoutes.policylist,
builder: (context, state) => const policylist(),
),
GoRoute(
path: AppRoutes.quotation,
builder: (context, state) => const QuotationScreen(),
),
GoRoute(
path: AppRoutes.policy,
builder: (context, state) => const PolicyScreen(),
),
],
redirect: (context, state) async {

View File

@ -10,4 +10,10 @@ class AppRoutes {
static const staff = '/staff/:id';
static const String enquiryLst = '/enquiryLst';
static const String tabEnquiry = '/tabEnquiry';
static const String claimlist = '/claimList';
static const String endosement = '/endosement';
static const String policylist = '/policylist';
static const String quotation = '/QuotationScreen';
static const String policy = '/PolicyScreen';
}

View File

@ -402,6 +402,22 @@ class ApiService {
return response;
}
Future<Map<String, dynamic>> findEnqQuotePolicyView(id) async {
// print(_token);
if (_token == null) {
await _initializeToken();
}
final url = Uri.parse(
'${Env.apiUrl}enquiry/enquiryQuotePolicyView?enquiry_id=$id',
);
final headers = {
'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK',
};
final response = await _makeGetRequest(url, headers);
return response;
}
//------------------------------------ Quotation ------------------------------------------------
Future<Map<String, dynamic>> fetchQuotationList(int managerId) async {
@ -425,6 +441,114 @@ class ApiService {
return response;
}
Future<Map<String, dynamic>> findSingleQuotationData(id) async {
// print(_token);
if (_token == null) {
await _initializeToken();
}
final url = Uri.parse('${Env.apiUrl}/quotation/findQuotation?id=1=$id');
final headers = {
'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK',
};
final response = await _makeGetRequest(url, headers);
return response;
}
// ----------------------------------- POLICY -------------------------------------------------
Future<Map<String, dynamic>> fetchPolicyList(int id, role) async {
// print(_token);
if (_token == null) {
await _initializeToken();
}
final userId = '1';
final url;
if (role == 'manager') {
url = Uri.parse('${Env.apiUrl}enquiry/enquiryList?manager_id=$id');
} else {
url = Uri.parse('${Env.apiUrl}enquiry/enquiryList?staff_id=$id');
}
// else {
// url = Uri.parse('${Env.apiUrl}endorsement/endorsementList?agent_id=$id');
// }
// final url = Uri.parse(
// 'https://venbait.in/nhance/partner/dev/api/agent/agentList?manager_id=${managerId}',
// );
final headers = {
'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK',
};
final response = await _makeGetRequest(url, headers);
return response;
}
// ----------------------------------- CLAIMS -------------------------------------------------
Future<Map<String, dynamic>> fetchClaimList(int id, role) async {
// print(_token);
if (_token == null) {
await _initializeToken();
}
final userId = '1';
final url;
if (role == 'manager') {
url = Uri.parse('${Env.apiUrl}claim/ClaimList?manager_id=$id');
}
// else if (role == 'staff') {
// url = Uri.parse('${Env.apiUrl}enquiry/enquiryList?staff_id=$id');
// }
else {
url = Uri.parse('${Env.apiUrl}claim/ClaimList?agent_id=$id');
}
// final url = Uri.parse(
// 'https://venbait.in/nhance/partner/dev/api/agent/agentList?manager_id=${managerId}',
// );
final headers = {
'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK',
};
final response = await _makeGetRequest(url, headers);
return response;
}
// ----------------------------------- ENDORSEMENT -------------------------------------------------
Future<Map<String, dynamic>> fetchEndorsementList(int id, role) async {
// print(_token);
if (_token == null) {
await _initializeToken();
}
final userId = '1';
final url;
if (role == 'manager') {
url = Uri.parse(
'${Env.apiUrl}endorsement/endorsementList?manager_id=$id',
);
}
// else if (role == 'staff') {
// url = Uri.parse('${Env.apiUrl}enquiry/enquiryList?staff_id=$id');
// }
else {
url = Uri.parse('${Env.apiUrl}endorsement/endorsementList?agent_id=$id');
}
// final url = Uri.parse(
// 'https://venbait.in/nhance/partner/dev/api/agent/agentList?manager_id=${managerId}',
// );
final headers = {
'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK',
};
final response = await _makeGetRequest(url, headers);
return response;
}
// --------------------------------- MASTER DATA ----------------------------------------------
Future<Map<String, dynamic>> fetchMasterDropDown(String val) async {

View File

@ -2,3 +2,4 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
final managerIdProvider = StateProvider<int?>((ref) => null);
final userIdProvider = StateProvider<int?>((ref) => null);
final enquiryIdProvider = StateProvider<String?>((ref) => null);

View File

@ -6,6 +6,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:http/http.dart' as http;
import 'package:nhance_partner/presentation/layouts/responsive_layout.dart';
import 'package:toastification/toastification.dart';
import 'package:universal_html/html.dart' as html;
import '../../../../core/config/env.dart';
@ -13,6 +14,7 @@ import '../../../../core/routing/routes.dart';
import '../../../../core/services/api_service.dart';
import '../../../../data/services/auth_service.dart';
import '../../../../data/utils/Pagination.dart';
import '../../../../data/utils/toastNotification.dart';
import '../../../../data/utils/validators.dart';
import '../../../layouts/main_layout.dart';
import '../../../providers/manager_provider.dart';
@ -25,7 +27,9 @@ import '../../../themes/indicators/upload_doc_theme.dart'
hide ThemedUploadField;
class EnquiryTab extends ConsumerStatefulWidget {
const EnquiryTab({super.key});
String? id;
final Map<String, dynamic>? data;
EnquiryTab({super.key, this.data, this.id});
@override
ConsumerState<EnquiryTab> createState() => EnquiryTabState();
}
@ -84,15 +88,6 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
List<Map<String, dynamic>> filteredInsurersData = [];
Map<String, dynamic> dataDetails() {
// final data = {
// "name": controllers["name"]?.text,
// "email": controllers["email"]?.text,
// "mobile": controllers["mobile"]?.text,
// "address": controllers["address"]?.text,
// "agent_code": controllers["code"]?.text,
// "is_active": isActive,
// "manager_id": managerId,
// };
final data = {
"agent_id": 1,
"name": controllers["name"]?.text,
@ -121,6 +116,11 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
controllers[field] = TextEditingController();
}
if (widget.data != null) {
print("EnQ has Data");
} else {
print("EnQ has Data 1");
}
_initializeToken();
Future.microtask(() {
managerId = ref.watch(managerIdProvider);
@ -203,68 +203,64 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
}
void updateData() async {
// if (widget.id != null && widget.id != 'create') {
if (widget.data != null && widget.data != 'tab' && widget.id != null) {
// dynamic response = await apiService.findEnqQuotePolicyView(widget.id!);
// final enq = response['data'];
final data = widget.data;
print("updateDataEnq - $data");
dynamic response = await apiService.findSingleEnquiryData(1);
// dynamic response = await apiService.findSingleAgentData(widget.id!);
final data = response['data'];
print("updateData - ${response['data']}");
if (data == null) return;
if (data == null) return;
setState(() {
// selectedId = widget.id;
controllers['name']?.text = data['name'] ?? '';
controllers['email']?.text = data['email'] ?? '';
controllers['mobile']?.text = data['mobile'] ?? '';
controllers['regNo']?.text = data['reg_no'] ?? '';
controllers['remarks']?.text = data['remarks'] ?? '';
isActive = data["is_active"];
// selectedVehicleType = data['vehicle_type_id'] ?? '2';
selectedVehicleTypeId = 2;
selectedInsurer = data['insurer_id'] ?? '3';
setState(() {
selectedId = widget.id;
controllers['name']?.text = data['name'] ?? '';
controllers['email']?.text = data['email'] ?? '';
controllers['mobile']?.text = data['mobile'] ?? '';
controllers['regNo']?.text = data['reg_no'] ?? '';
controllers['remarks']?.text = data['remarks'] ?? '';
isActive = data["is_active"];
selectedVehicleType = data['vehicle_type_id'] ?? '';
selectedInsurer = data['insurer_id'] ?? '';
String? apiDocPath = data["rc_file_name"];
if (apiDocPath != null && apiDocPath.isNotEmpty) {
print('apiDocPath - $apiDocPath');
selectedRCFile = apiDocPath.split('/').last;
print('selectedRCFile - $selectedRCFile');
rcFileUrlFromApi = apiDocPath;
print('rcFileUrlFromApi - $rcFileUrlFromApi');
docUploadedRCFile = null;
} else {
selectedRCFile = null;
docUploadedRCFile = null;
rcFileUrlFromApi = null;
}
// RC FILE
String? rcPath = data["rc_file_name"];
if (rcPath != null && rcPath.isNotEmpty) {
selectedRCFile = rcPath.split('/').last; // UI filename
rcFileUrlFromApi = rcPath; // API download URL
docUploadedRCFile =
rcFileUrlFromApi as PlatformFile?; // user has not re-uploaded yet
} else {
selectedRCFile = null; // no UI file shown
rcFileUrlFromApi = null;
docUploadedRCFile = null;
}
String? apiDocPathRC = data["id_proof_file_name"];
if (apiDocPathRC != null && apiDocPathRC.isNotEmpty) {
print('apiDocPathRC - $apiDocPathRC');
selectedIdProof = apiDocPathRC.split('/').last;
print('selectedIdProof - $selectedIdProof');
prevPolicyFileUrlFromApi = apiDocPathRC;
print('prevPolicyFileUrlFromApi - $prevPolicyFileUrlFromApi');
docUploadedIDProof = null;
} else {
selectedIdProof = null;
docUploadedIDProof = null;
prevPolicyFileUrlFromApi = null;
}
// ID PROOF FILE
String? idProofPath = data["id_proof_file_name"];
if (idProofPath != null && idProofPath.isNotEmpty) {
selectedIdProof = idProofPath.split('/').last;
idProofFileUrlFromApi = idProofPath; // FIXED correct variable
docUploadedIDProof = idProofFileUrlFromApi as PlatformFile?;
} else {
selectedIdProof = null;
idProofFileUrlFromApi = null;
docUploadedIDProof = null;
}
String? apiDocPathPrevPolicy = data["previous_policy_file_name"];
if (apiDocPathPrevPolicy != null && apiDocPathPrevPolicy.isNotEmpty) {
print('apiDocPathPrevPolicy - $apiDocPathPrevPolicy');
selectedPrevPolicy = apiDocPathPrevPolicy.split('/').last;
print('selectedPrevPolicy - $selectedPrevPolicy');
idProofFileUrlFromApi = apiDocPathPrevPolicy;
print('idProofFileUrlFromApi - $idProofFileUrlFromApi');
docUploadedPrevPolicy = null;
} else {
selectedPrevPolicy = null;
docUploadedPrevPolicy = null;
idProofFileUrlFromApi = null;
}
});
// PREVIOUS POLICY FILE
String? prevPolicyPath = data["previous_policy_file_name"];
if (prevPolicyPath != null && prevPolicyPath.isNotEmpty) {
selectedPrevPolicy = prevPolicyPath.split('/').last;
prevPolicyFileUrlFromApi =
prevPolicyPath; // FIXED correct variable
docUploadedPrevPolicy = prevPolicyFileUrlFromApi as PlatformFile?;
} else {
selectedPrevPolicy = null;
prevPolicyFileUrlFromApi = null;
docUploadedPrevPolicy = null;
}
});
}
}
Future<void> handleSave() async {
@ -283,6 +279,59 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
}
Future<void> attachFiles(http.MultipartRequest request) async {
Future<void> addFileOrKeepName(
PlatformFile? file,
String? apiFileName,
String fieldName,
) async {
if (file != null) {
// User uploaded a new file send as multipart
if (file.bytes != null) {
request.files.add(
http.MultipartFile.fromBytes(
fieldName,
file.bytes!,
filename: file.name,
),
);
} else if (file.path != null) {
request.files.add(
await http.MultipartFile.fromPath(
fieldName,
file.path!,
filename: file.name,
),
);
}
print("📎 Attached new file → $fieldName");
} else if (apiFileName != null && apiFileName.isNotEmpty) {
// No new upload tell backend to keep old file
request.fields[fieldName] = apiFileName;
print("🔗 Kept old file → $fieldName = $apiFileName");
} else {
// Nothing at all
request.fields[fieldName] = "";
}
}
await addFileOrKeepName(
docUploadedRCFile,
rcFileUrlFromApi,
'rc_file_name',
);
await addFileOrKeepName(
docUploadedIDProof,
idProofFileUrlFromApi,
'id_proof_file_name',
);
await addFileOrKeepName(
docUploadedPrevPolicy,
prevPolicyFileUrlFromApi,
'previous_policy_file_name',
);
}
Future<void> attachFiles1(http.MultipartRequest request) async {
Future<void> addFile(PlatformFile? file, String fieldName) async {
if (file == null) return;
try {
@ -313,14 +362,16 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
}
Future<void> createUserData(Map<String, dynamic> userData) async {
// final bool isUpdating = widget.id != null && widget.id != 'create';
// final id = widget.id;
final bool isUpdating = false;
final bool isUpdating =
widget.data != null && widget.id != 'tab' && widget.id != 'null';
final id = widget.id;
print('UPDId- $id');
// final bool isUpdating = false;
final uri = Uri.parse(
// isUpdating
// ? '${Env.apiUrl}agent/updateAgent'
// : '${Env.apiUrl}agent/createAgent',
'${Env.apiUrl}enquiry/createEnquiry',
isUpdating
? '${Env.apiUrl}enquiry/updateEnquiry'
: '${Env.apiUrl}enquiry/createEnquiry',
);
if (_token == null) {
throw Exception('Token not found. Please log in.');
@ -334,7 +385,7 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
// If updating, spoof the method Laravel-style
if (isUpdating) {
// request.fields['id'] = id!;
request.fields['id'] = id!;
request.fields['updated_by'] = userId!.toString();
} else {
request.fields['created_by'] = userId!.toString();
@ -370,7 +421,7 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
if (response.statusCode == 200 || response.statusCode == 201) {
// dispose();
print("✅ Agent submitted successfully!");
ToastHelper.showSuccessToast(context, 'Saved Enquiry');
print("Response: ${response.body}");
context.go(AppRoutes.tabEnquiry);
} else {
@ -532,40 +583,41 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
}
}
Widget buildResponsiveUploadField({
required String label,
required String? hintText,
required void Function(String fileName, dynamic file) onFileSelected,
}) {
final isMobile = ResponsiveLayout.isMobile(context);
final uploadWidget = ThemedUploadField(
hintText: hintText ?? "Upload Document",
txtwidth: MediaQuery.of(context).size.width * 0.26,
onFileSelected: onFileSelected,
);
if (isMobile) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: _textStyle),
const SizedBox(height: 8),
uploadWidget,
const SizedBox(height: 16),
],
);
} else {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: Text(label, style: _textStyle)),
const SizedBox(width: 10),
uploadWidget,
],
);
}
}
// Widget buildResponsiveUploadField({
// required String label,
// required String? hintText,
// required void Function(String fileName, dynamic file) onFileSelected,
// })
// {
// final isMobile = ResponsiveLayout.isMobile(context);
//
// final uploadWidget = ThemedUploadField(
// hintText: hintText ?? "Upload Document",
// txtwidth: MediaQuery.of(context).size.width * 0.26,
// onFileSelected: onFileSelected,
// );
//
// if (isMobile) {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(label, style: _textStyle),
// const SizedBox(height: 8),
// uploadWidget,
// const SizedBox(height: 16),
// ],
// );
// } else {
// return Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Expanded(child: Text(label, style: _textStyle)),
// const SizedBox(width: 10),
// uploadWidget,
// ],
// );
// }
// }
Widget buildName(BuildContext context) {
return buildResponsiveField(
@ -621,8 +673,9 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
Widget buildVehicleType(BuildContext context) {
// Find the matching map from your list
Map<String, dynamic>? selectedVehicle = filteredVechicleData.firstWhere(
(item) => item['id'] == selectedVehicleTypeId,
(item) => item['id'].toString() == selectedVehicleType,
orElse: () => {},
);
@ -698,6 +751,10 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
}
Widget buildInsurer(BuildContext context) {
Map<String, dynamic>? selectedInsurerd = filteredInsurersData.firstWhere(
(item) => item['id'].toString() == selectedInsurer,
orElse: () => {},
);
return buildResponsiveField(
label: "Insurer",
field: Container(
@ -708,7 +765,7 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
// height: 40,
child: DropdownSearch<Map<String, dynamic>>(
key: dropDownKeyInsurer,
selectedItem: null,
selectedItem: selectedInsurerd.isNotEmpty ? selectedInsurerd : null,
items: (filter, infiniteScrollProps) {
return filteredInsurersData;
},
@ -769,42 +826,223 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
);
}
// Widget buildUploadRCDocument(BuildContext context) {
// return buildResponsiveUploadField(
// label: "Upload RC Document",
// hintText: selectedRCFile,
// onFileSelected: (fileName, file) {
// print("File picked: $fileName");
// setState(() {
// docUploadedRCFile = file;
// });
// },
// );
// }
Widget buildResponsiveUploadField({
required String label,
required String? hintText,
required void Function(String fileName, dynamic file) onFileSelected,
bool showDownload = false,
VoidCallback? onRemove,
VoidCallback? onDownload,
}) {
final isMobile = ResponsiveLayout.isMobile(context);
final uploadWidget = ThemedUploadField(
hintText: hintText ?? "Upload Document",
txtwidth: isMobile ? null : MediaQuery.of(context).size.width * 0.26,
onFileSelected: onFileSelected,
);
final downloadRow = showDownload
? Padding(
padding: const EdgeInsets.only(top: 5),
child: Row(
children: [
IconButton(
onPressed: onRemove,
icon: const Icon(
Icons.remove_circle_outline_rounded,
color: Colors.redAccent,
),
tooltip: 'Remove Upload',
),
GestureDetector(
onTap: onDownload,
child: Container(
padding: const EdgeInsets.all(5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: const Color(0xFF425B5B),
),
child: Row(
children: const [
Text(
"Download",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w200,
color: Colors.white,
),
),
SizedBox(width: 5),
Icon(Icons.download, size: 13, color: Colors.white),
],
),
),
),
],
),
)
: const SizedBox.shrink();
if (isMobile) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: _textStyle),
const SizedBox(height: 8),
uploadWidget,
downloadRow,
const SizedBox(height: 16),
],
);
} else {
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: Text(label, style: _textStyle)),
const SizedBox(width: 10),
uploadWidget,
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [SizedBox.shrink(), downloadRow],
),
],
);
}
}
Widget buildUploadRCDocument(BuildContext context) {
return buildResponsiveUploadField(
label: "Upload RC Document",
hintText: selectedRCFile,
onFileSelected: (fileName, file) {
print("File picked: $fileName");
setState(() {
docUploadedRCFile = file;
// selectedFileNames = fileName;
});
},
showDownload: docUploadedRCFile != null || rcFileUrlFromApi != null,
onRemove: () {
setState(() {
docUploadedRCFile = null;
rcFileUrlFromApi = null;
// selectedFileNames = null;
});
},
onDownload: () => apiService.downloadFile(
// apiUrl: 'api/agent/downloadAgentCertificateFile?agent_id=$selectedId',
apiUrl:
'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=rc',
apiId: null,
localFile: docUploadedRCFile,
fileName: 'RC',
),
);
}
// Widget buildUploadIDDocument(BuildContext context) {
// return buildResponsiveUploadField(
// label: "Upload ID Proof",
// hintText: selectedIdProof,
// onFileSelected: (fileName, file) {
// print("File picked: $fileName");
// setState(() {
// docUploadedIDProof = file;
// });
// },
// );
// }
Widget buildUploadIDDocument(BuildContext context) {
return buildResponsiveUploadField(
label: "Upload ID Proof",
hintText: selectedIdProof,
onFileSelected: (fileName, file) {
print("File picked: $fileName");
setState(() {
docUploadedIDProof = file;
// selectedFileNames = fileName;
});
},
showDownload: docUploadedIDProof != null || idProofFileUrlFromApi != null,
onRemove: () {
setState(() {
docUploadedIDProof = null;
idProofFileUrlFromApi = null;
// selectedFileNames = null;
});
},
onDownload: () => apiService.downloadFile(
// apiUrl: 'api/agent/downloadAgentCertificateFile?agent_id=$selectedId',
apiUrl:
'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=id_proof',
apiId: null,
localFile: docUploadedRCFile,
fileName: 'Id_Proof',
),
);
}
// Widget buildUploadPolicyDocument(BuildContext context) {
// return buildResponsiveUploadField(
// label: "Upload Previous Policy",
// hintText: selectedPrevPolicy,
// onFileSelected: (fileName, file) {
// print("File picked: $fileName");
// setState(() {
// docUploadedPrevPolicy = file;
// });
// },
// );
// }
Widget buildUploadPolicyDocument(BuildContext context) {
return buildResponsiveUploadField(
label: "Upload Previous Policy",
hintText: selectedPrevPolicy,
onFileSelected: (fileName, file) {
print("File picked: $fileName");
setState(() {
docUploadedPrevPolicy = file;
// selectedFileNames = fileName;
});
},
showDownload:
docUploadedPrevPolicy != null || prevPolicyFileUrlFromApi != null,
onRemove: () {
setState(() {
docUploadedPrevPolicy = null;
prevPolicyFileUrlFromApi = null;
// selectedFileNames = null;
});
},
onDownload: () => apiService.downloadFile(
// apiUrl: 'api/agent/downloadAgentCertificateFile?agent_id=$selectedId',
apiUrl:
'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=previous_policy',
apiId: null,
localFile: docUploadedPrevPolicy,
fileName: 'Previous_Policy',
),
);
}

View File

@ -0,0 +1,52 @@
import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
Future<void> showAddDialog({
required BuildContext context,
required String title,
required void Function(String value) onSubmit,
}) async {
final TextEditingController controller = TextEditingController();
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(title),
content: title == 'Claim'
? claims()
: endorsement(), // 👈 conditional content
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text("Cancel"),
),
ElevatedButton(
onPressed: () {
onSubmit(controller.text.trim());
Navigator.of(context).pop();
},
child: const Text("Save"),
),
],
);
},
);
}
Widget claims() {
return Container(
padding: const EdgeInsets.all(16),
color: Colors.redAccent,
child: const Text('Claims', style: TextStyle(color: Colors.white)),
);
}
Widget endorsement() {
return Container(
padding: const EdgeInsets.all(16),
color: Colors.yellow,
child: const Text('Endorsement', style: TextStyle(color: Colors.black)),
);
}

View File

@ -2,6 +2,8 @@ import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:nhance_partner/presentation/screens/Enquiry/enquiry/policy_popup.dart';
import '../../../../core/services/api_service.dart';
import '../../../../data/services/auth_service.dart';
@ -15,7 +17,9 @@ import '../../../themes/indicators/search_field_theme.dart';
import '../../../themes/indicators/text_field_theme.dart';
class PolicyTab extends ConsumerStatefulWidget {
const PolicyTab({super.key});
final List<Map<String, dynamic>>? data;
// const PolicyTab({super.key});
const PolicyTab({super.key, this.data});
@override
ConsumerState<PolicyTab> createState() => PolicyTabState();
}
@ -40,6 +44,15 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
'code',
'address',
'regNo',
'regNum',
'insurer',
'idv',
'insurerName',
'policyNo',
'paymentMode',
'premAmount',
'planType',
];
Map<String, TextEditingController> controllers = {};
@ -77,12 +90,15 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
});
try {
final response = await apiService.fetchQuotationList(managerId);
// final response = await apiService.fetchQuotationList(managerId);
if (response['status'] == 'success') {
print('quoationListData - ${response['data']}');
if (widget.data != null) {
final data = List<Map<String, dynamic>>.from(widget.data as Iterable);
print('policyListData - ${widget.data}');
setState(() {
getQuotationData = List<Map<String, dynamic>>.from(response['data']);
getQuotationData = data;
// getQuotationData = List<Map<String, dynamic>>.from(response['data']);
originalData = getQuotationData;
filteredData = List.from(originalData);
// print('originalData - $getClaimPolicies');
@ -120,6 +136,80 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
padding: EdgeInsets.all(26.0),
child: Column(
children: [
Container(
child: Row(
children: [
Text(
'Policy Details',
style: GoogleFonts.inter(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
Spacer(),
GestureDetector(
onTap: () {},
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: const Color(0xFF425B5B),
),
child: Row(
children: const [
Text(
"Download Policy",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w200,
color: Colors.white,
),
),
SizedBox(width: 15),
Icon(
Icons.file_download_outlined,
size: 16,
color: Colors.white,
),
],
),
),
),
SizedBox(width: 15),
GestureDetector(
onTap: () {},
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: const Color(0xFF425B5B),
),
child: Row(
children: const [
Text(
"Download Receipt",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w200,
color: Colors.white,
),
),
SizedBox(width: 15),
Icon(
Icons.file_download_outlined,
size: 16,
color: Colors.white,
),
],
),
),
),
],
),
),
const SizedBox(height: 20),
SingleChildScrollView(child: buildFormFields(context)),
const SizedBox(height: 20),
@ -159,9 +249,18 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('', style: _headerStyle),
Container(child: buildClaimTable()),
IconButton(
onPressed: () {},
onPressed: () {
showAddDialog(
context: context,
title: "Claim",
onSubmit: (value) {
print("New Claim: $value");
// update claim list here
},
);
},
icon: Icon(Icons.add),
),
],
@ -189,9 +288,18 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('', style: _headerStyle),
Container(child: buildEndrosmentTable()),
IconButton(
onPressed: () {},
onPressed: () {
showAddDialog(
context: context,
title: "Endorsement",
onSubmit: (value) {
print("New Claim: $value");
// update claim list here
},
);
},
icon: Icon(Icons.add),
),
],
@ -302,7 +410,7 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(child: Text(label, style: _textStyle)),
Text(label, style: _textStyle),
const SizedBox(height: 8),
field,
const SizedBox(height: 16),
@ -424,6 +532,14 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
);
}
Widget buildClaimTable() {
return Text('data');
}
Widget buildEndrosmentTable() {
return Text('data');
}
static const _headerStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,

View File

@ -1,10 +1,15 @@
import 'dart:convert';
import 'dart:io' as html;
import 'package:dropdown_search/dropdown_search.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http;
import '../../../../core/config/env.dart';
import '../../../../core/services/api_service.dart';
import '../../../../data/services/auth_service.dart';
import '../../../../data/utils/toastNotification.dart';
import '../../../../data/utils/validators.dart';
import '../../../layouts/responsive_layout.dart';
import '../../../providers/manager_provider.dart';
@ -15,7 +20,10 @@ import '../../../themes/indicators/upload_doc_theme.dart'
hide ThemedUploadField;
class QuotationTab extends ConsumerStatefulWidget {
const QuotationTab({super.key});
// final Map<String, dynamic>? data;
final List<Map<String, dynamic>>? data;
String? id;
QuotationTab({super.key, this.data, this.id});
@override
ConsumerState<QuotationTab> createState() => QuotationTabState();
}
@ -34,19 +42,25 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
List<String> tabHeader = [
'name',
'email',
'mobile',
'code',
'address',
'regNo',
'regNum',
'insurer',
'idv',
'premAmount',
'planType',
'addit_doc',
'remarks',
// 'mobile',
// 'code',
// 'address',
// 'regNo',
];
late String isActive = "1";
html.File? docUploadedFile;
// html.File? docUploadedFile;
// PlatformFile? passportFile;
PlatformFile? docUploadedFile;
String? selectedFileNames;
String? passportFileUrlFromApi;
String? docUploadedFileFromApi;
String? selectedId;
bool isLoading = false;
bool isquotation = false;
@ -64,8 +78,8 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
Map<String, dynamic> dataDetails() {
final data = {
"name": controllers["name"]?.text,
"email": controllers["email"]?.text,
"regNum": controllers["regNum"]?.text,
"insurer": controllers["insurer"]?.text,
"mobile": controllers["mobile"]?.text,
"address": controllers["address"]?.text,
"agent_code": controllers["code"]?.text,
@ -78,6 +92,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
List<Map<String, dynamic>> getQuotationData = [];
List<Map<String, dynamic>> originalData = [];
List<Map<String, dynamic>> filteredData = [];
// bool isLoading = false;
@override
@ -103,19 +118,46 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
print("APISERTOKEN - $_token");
}
Future<void> getQuotationList(int managerId) async {
void refresh() {
getQuotationList(managerId);
}
Future<void> getQuotationList(managerId) async {
print('getClaimList called MagId - $managerId');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchQuotationList(managerId);
// if (widget.data != null) {
// final data = List<Map<String, dynamic>>.from(widget.data as Iterable);
//
// print('quoationListData - ${widget.data}');
// setState(() {
// getQuotationData = data;
// // getQuotationData = List<Map<String, dynamic>>.from(response['data']);
// originalData = getQuotationData;
// filteredData = List.from(originalData);
// // print('originalData - $getClaimPolicies');
// });
// }
final response = await apiService.findSingleQuotationData(managerId);
if (response['status'] == 'success') {
print('quoationListData - ${response['data']}');
final rawData = response['data'];
print('quoationListData1 - ${response['data']}');
setState(() {
getQuotationData = List<Map<String, dynamic>>.from(response['data']);
if (rawData is List) {
// already a list
getQuotationData = List<Map<String, dynamic>>.from(rawData);
} else if (rawData is Map) {
// single object, wrap into a list
getQuotationData = [Map<String, dynamic>.from(rawData)];
} else {
getQuotationData = [];
}
// getQuotationData = List<Map<String, dynamic>>.from(response['data']);
originalData = getQuotationData;
filteredData = List.from(originalData);
// print('originalData - $getClaimPolicies');
@ -133,6 +175,97 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
}
}
void findAndUpdateById(updateId) {
try {
final match = getQuotationData.firstWhere(
(q) => q['id'] == updateId,
orElse: () => {},
);
if (match.isNotEmpty) {
print("Found quotation: $match");
updateData(match);
} else {
print("No quotation found with id $updateId");
}
} catch (e) {
print("Error finding quotation: $e");
}
}
void updateData(Map<String, dynamic> data) {
print('UPDID - $data}');
setState(() {
controllers['regNum']?.text = data['reg_no']?.toString() ?? '';
controllers['insurer']?.text = data['insurer_name']?.toString() ?? '';
controllers['idv']?.text =
data['insured_declared_value']?.toString() ?? '';
controllers['premAmount']?.text =
data['premium_amount']?.toString() ?? '';
controllers['planType']?.text =
data['insurance_plan_type_id']?.toString() ?? '';
controllers['addit_doc']?.text =
data['additional_uploaded_file_name']?.toString() ?? '';
controllers['remarks']?.text = data['reject_reason']?.toString() ?? '';
});
}
void handleActions(data) {
print('Action - $data');
createData(data);
}
Future<void> createData(val) async {
final String apiUrldata;
apiUrldata = '${Env.apiUrl}quotation/acceptOrRejectQuotation';
// final token = await getToken(); // Fetch token
if (_token == null) {
throw Exception('Token not found. Please log in.');
}
final Map<String, dynamic> data = {"id": selectedId, "status": val};
// data['id'] = selectedId; // Add plan_id for update
// data['status'] = val;
print("data------- $data}");
try {
final response = await http.post(
Uri.parse(apiUrldata),
headers: {
'Authorization': 'Bearer $_token',
'Content-Type': 'application/json',
'app-signature': 'nhance-partner-2025-signature-35468846JRhH551HK',
},
body: jsonEncode(data), // Convert map to JSON
);
if (response.statusCode == 200) {
print("Response: ${response.body}");
ToastHelper.showSuccessToast(context, 'Status Updated');
selectedId = null; // just update field
isquotation = false;
refresh();
// context.go(AppRoutes.staffLst);
} else {
final responseBody = jsonDecode(response.body);
dynamic msg = responseBody['data'];
ToastHelper.showErrorToast(context, 'Status Updation Failed');
print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}");
}
} catch (e) {
print(" Error submitting Staff: $e");
}
}
@override
Widget build(BuildContext context) {
return Container(
@ -181,7 +314,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
children: [
GestureDetector(
onTap: () {
// handleSave();
handleActions('Rejected');
},
child: Container(
padding: EdgeInsets.symmetric(
@ -202,7 +335,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
const SizedBox(width: 10),
GestureDetector(
onTap: () {
// handleSave();
handleActions('Accepted');
},
child: Container(
padding: EdgeInsets.symmetric(
@ -231,240 +364,6 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
);
}
Widget buildFormFields(BuildContext context) {
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildResponsiveRow(
context,
buildName(context),
buildInsusrer(context),
),
if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10),
_buildResponsiveRow(
context,
buildIdv(context),
buildPremiumAmnt(context),
),
if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10),
_buildResponsiveRow(
context,
buildPlanType(context),
buildDocuments(context),
),
if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10),
_buildResponsiveRow(
context,
buildAdditonalDocuments(context),
buildRemarks(context),
),
],
),
);
}
Widget _buildResponsiveRow(
BuildContext context,
Widget first,
Widget second,
) {
if (ResponsiveLayout.isMobile(context)) {
// Stack vertically
return Column(children: [first, const SizedBox(height: 2), second]);
} else {
// Place side by side
return Row(
children: [
Expanded(child: first),
const SizedBox(width: 25),
Expanded(child: second),
],
);
}
}
Widget buildName(BuildContext context) {
return buildResponsiveField(
label: "Registration Number",
field: ThemedFormField(
controller: controllers['name']!,
validator: (value) => Validators.requiredField(value, "name"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
);
}
Widget buildInsusrer(BuildContext context) {
return buildResponsiveField(
label: "Insusrer",
field: ThemedFormField(
controller: controllers['email']!,
validator: (value) => Validators.email(value, "email"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
);
}
Widget buildIdv(BuildContext context) {
return buildResponsiveField(
label: "IDV",
field: ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
);
}
Widget buildPremiumAmnt(BuildContext context) {
return buildResponsiveField(
label: "Premium Amount",
field: ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
);
}
Widget buildPlanType(BuildContext context) {
return buildResponsiveField(
label: "Plan Type",
field: ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
);
}
Widget buildDocuments(BuildContext context) {
return buildResponsiveUploadField(
label: "Upload RC Certificate",
hintText: selectedFileNames,
onFileSelected: (fileName, file) {
print("File picked: $fileName");
setState(() {
docUploadedFile = file;
});
},
);
}
Widget buildAdditonalDocuments(BuildContext context) {
return buildResponsiveField(
label: "Additional Documents",
field: ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
);
}
Widget buildRemarks(BuildContext context) {
return buildResponsiveField(
label: "Remarks",
field: ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
);
}
Widget buildResponsiveField({required String label, required Widget field}) {
final isMobile = ResponsiveLayout.isMobile(context);
if (isMobile) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: _textStyle),
const SizedBox(height: 8),
field,
const SizedBox(height: 16),
],
);
} else {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: Text(label, style: _textStyle)),
const SizedBox(width: 10),
field,
],
);
}
}
Widget buildResponsiveUploadField({
required String label,
required String? hintText,
required void Function(String fileName, dynamic file) onFileSelected,
}) {
final isMobile = ResponsiveLayout.isMobile(context);
final uploadWidget = ThemedUploadField(
hintText: hintText ?? "Upload Document",
txtwidth: isMobile ? null : MediaQuery.of(context).size.width * 0.26,
onFileSelected: onFileSelected,
);
if (isMobile) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: _textStyle),
const SizedBox(height: 8),
uploadWidget,
const SizedBox(height: 16),
],
);
} else {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: Text(label, style: _textStyle)),
const SizedBox(width: 10),
uploadWidget,
],
);
}
}
Widget buildId(BuildContext context) {
return buildResponsiveField(
label: "Registration Number *",
field: ThemedFormField(
controller: controllers['regNo']!,
validator: (value) => Validators.requiredField(value, "regNo"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
);
}
Widget _buildDataTable(BuildContext context) {
if (filteredData.isEmpty) {
return const SizedBox(
@ -507,6 +406,346 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
);
}
Widget buildFormFields(BuildContext context) {
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildResponsiveRow(
context,
buildName(context),
buildInsusrer(context),
),
if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10),
_buildResponsiveRow(
context,
buildIdv(context),
buildPremiumAmnt(context),
),
if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10),
_buildResponsiveRow(
context,
buildPlanType(context),
buildDocuments(context),
),
// if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10),
// _buildResponsiveRow(
// context,
// buildAdditonalDocuments(context),
// buildRemarks(context),
// ),
],
),
);
}
Widget _buildResponsiveRow(
BuildContext context,
Widget first,
Widget second,
) {
if (ResponsiveLayout.isMobile(context)) {
// Stack vertically
return Column(children: [first, const SizedBox(height: 2), second]);
} else {
// Place side by side
return Row(
children: [
Expanded(child: first),
const SizedBox(width: 25),
Expanded(child: second),
],
);
}
}
Widget buildName(BuildContext context) {
return buildResponsiveField(
label: "Registration Number",
field: ThemedFormField(
controller: controllers['regNum']!,
readOnly: true,
// validator: (value) => Validators.requiredField(value, "regNum"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
);
}
Widget buildInsusrer(BuildContext context) {
return buildResponsiveField(
label: "Insusrer",
field: ThemedFormField(
controller: controllers['insurer']!,
readOnly: true,
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
);
}
Widget buildIdv(BuildContext context) {
return buildResponsiveField(
label: "IDV",
field: ThemedFormField(
controller: controllers['idv']!,
readOnly: true,
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
);
}
Widget buildPremiumAmnt(BuildContext context) {
return buildResponsiveField(
label: "Premium Amount",
field: ThemedFormField(
controller: controllers['premAmount']!,
readOnly: true,
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
);
}
Widget buildPlanType(BuildContext context) {
return buildResponsiveField(
label: "Plan Type",
field: ThemedFormField(
controller: controllers['planType']!,
readOnly: true,
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
);
}
Widget buildDocuments(BuildContext context) {
return buildResponsiveUploadField(
label: "Passport File",
hintText: selectedFileNames,
onFileSelected: (fileName, file) {
setState(() {
docUploadedFile = file;
selectedFileNames = fileName;
});
},
showDownload: docUploadedFile != null || docUploadedFileFromApi != null,
onRemove: () {
setState(() {
docUploadedFile = null;
docUploadedFileFromApi = null;
selectedFileNames = null;
});
},
onDownload: () => apiService.downloadFile(
apiUrl: 'api/agent/downloadAgentCertificateFile?agent_id=$selectedId',
apiId: null,
localFile: docUploadedFile,
fileName: selectedFileNames,
),
);
}
// Widget buildAdditonalDocuments(BuildContext context) {
// return buildResponsiveField(
// label: "Additional Documents",
// field: ThemedFormField(
// controller: controllers['addit_doc']!,
// // validator: (value) => Validators.phone(value, "phNumber"),
// txtwidth: ResponsiveLayout.isMobile(context)
// ? null
// : MediaQuery.of(context).size.width * 0.26,
// ),
// );
// }
//
// Widget buildRemarks(BuildContext context) {
// return buildResponsiveField(
// label: "Remarks",
// field: ThemedFormField(
// controller: controllers['remarks']!,
// // validator: (value) => Validators.phone(value, "phNumber"),
// txtwidth: ResponsiveLayout.isMobile(context)
// ? null
// : MediaQuery.of(context).size.width * 0.26,
// ),
// );
// }
Widget buildResponsiveField({required String label, required Widget field}) {
final isMobile = ResponsiveLayout.isMobile(context);
if (isMobile) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: _textStyle),
const SizedBox(height: 8),
field,
const SizedBox(height: 16),
],
);
} else {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: Text(label, style: _textStyle)),
const SizedBox(width: 10),
field,
],
);
}
}
// Widget buildResponsiveUploadField({
// required String label,
// required String? hintText,
// required void Function(String fileName, dynamic file) onFileSelected,
// })
// {
// final isMobile = ResponsiveLayout.isMobile(context);
//
// final uploadWidget = ThemedUploadField(
// hintText: hintText ?? "Upload Document",
// txtwidth: isMobile ? null : MediaQuery.of(context).size.width * 0.26,
// onFileSelected: onFileSelected,
// );
//
// if (isMobile) {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(label, style: _textStyle),
// const SizedBox(height: 8),
// uploadWidget,
// const SizedBox(height: 16),
// ],
// );
// } else {
// return Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Expanded(child: Text(label, style: _textStyle)),
// const SizedBox(width: 10),
// uploadWidget,
// ],
// );
// }
// }
Widget buildResponsiveUploadField({
required String label,
required String? hintText,
required void Function(String fileName, dynamic file) onFileSelected,
bool showDownload = false,
VoidCallback? onRemove,
VoidCallback? onDownload,
}) {
final isMobile = ResponsiveLayout.isMobile(context);
final uploadWidget = ThemedUploadField(
hintText: hintText ?? "Upload Document",
txtwidth: isMobile ? null : MediaQuery.of(context).size.width * 0.26,
onFileSelected: onFileSelected,
);
final downloadRow = showDownload
? Padding(
padding: const EdgeInsets.only(top: 5),
child: Row(
children: [
IconButton(
onPressed: onRemove,
icon: const Icon(
Icons.remove_circle_outline_rounded,
color: Colors.redAccent,
),
tooltip: 'Remove Upload',
),
GestureDetector(
onTap: onDownload,
child: Container(
padding: const EdgeInsets.all(5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: const Color(0xFF425B5B),
),
child: Row(
children: const [
Text(
"Download",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w200,
color: Colors.white,
),
),
SizedBox(width: 5),
Icon(Icons.download, size: 13, color: Colors.white),
],
),
),
),
],
),
)
: const SizedBox.shrink();
if (isMobile) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: _textStyle),
const SizedBox(height: 8),
uploadWidget,
downloadRow,
const SizedBox(height: 16),
],
);
} else {
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: Text(label, style: _textStyle)),
const SizedBox(width: 10),
uploadWidget,
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [SizedBox.shrink(), downloadRow],
),
],
);
}
}
Widget buildId(BuildContext context) {
return buildResponsiveField(
label: "Registration Number *",
field: ThemedFormField(
controller: controllers['regNo']!,
validator: (value) => Validators.requiredField(value, "regNo"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
);
}
Widget _buildHeader() {
return Container(
decoration: BoxDecoration(
@ -560,23 +799,20 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
isquotation = false; // unselect
}
});
findAndUpdateById(selectedId);
print("Selected row id: $selectedId");
},
),
),
Expanded(flex: 1, child: Text(item['id'] ?? '-', style: _dataBold)),
Expanded(
flex: 1,
child: Text(item['email'] ?? '-', style: _dataBold),
child: Text(item['reg_no'] ?? '-', style: _dataBold),
),
Expanded(
flex: 1,
child: Text(item['mobile'] ?? '-', style: _dataBold),
),
Expanded(
flex: 1,
child: Text(item['insurance_plan_type'] ?? '-', style: _dataBold),
child: Text(item['insurer_name'] ?? '-', style: _dataBold),
),
Expanded(
flex: 1,
@ -585,6 +821,17 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
style: _dataBold,
),
),
Expanded(
flex: 1,
child: Text(
item['insurance_plan_type_id'] ?? '-',
style: _dataBold,
),
),
Expanded(
flex: 1,
child: Text(item['premium_amount'] ?? '-', style: _dataBold),
),
Expanded(
flex: 1,
child: Text(
@ -628,6 +875,8 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
isquotation = false; // unselect
}
});
findAndUpdateById(selectedId);
print("Selected row id: $selectedId");
},
),
@ -648,9 +897,22 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text("New India", style: _cardBodyStyle),
const Text("TN64V3456", style: _cardheaderStyle),
const Text("Status: Rejected", style: _cardBodyStyle),
Text(
item['insurer_name'] ?? '-',
style: _cardBodyStyle,
),
Text(
// "TN64V3456",
item['reg_no'] ?? '-',
style: _cardheaderStyle,
),
Text(
'Status : ${item['status']}' ?? '-',
style: _cardBodyStyle,
),
],
),
),
@ -660,9 +922,18 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text("Comprehensive", style: _cardBodyStyle),
const Text("IDV:₹145000", style: _cardBodyStyle),
const Text("₹1000", style: _cardheaderStyle),
Text(
item['insurance_plan_type_id'] ?? '-',
style: _cardBodyStyle,
),
Text(
item['insured_declared_value'] ?? '-',
style: _cardBodyStyle,
),
Text(
'Premium Amount - ${item['premium_amount']}' ?? '-',
style: _cardheaderStyle,
),
],
),
),

View File

@ -4,124 +4,633 @@ import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import '../../../../core/routing/routes.dart';
import '../../../../core/services/api_service.dart';
import '../../../providers/manager_provider.dart';
import 'enquiry_tab.dart';
import 'quotation_tab.dart';
import 'policy_tab.dart';
import '../../../layouts/main_layout.dart';
class TabEnquiryList extends ConsumerStatefulWidget {
const TabEnquiryList({super.key});
String? id;
TabEnquiryList({super.key, this.id});
@override
ConsumerState<TabEnquiryList> createState() => TabEnquiryListState();
}
class TabEnquiryListState extends ConsumerState<TabEnquiryList> {
int selectedIndex = 0; // 0 = Enquiry, 1 = Quotation, 2 = Policy
int selectedIndex = 0;
List<TabItem> tabs = [];
Map<String, dynamic>? enquiryData;
bool isLoading = true;
late ApiService apiService;
final List<String> tabs = ["Enquiry", "Quotation", "Policy"];
final List<Widget> tabWidgets = [EnquiryTab(), QuotationTab(), PolicyTab()];
@override
void initState() {
super.initState();
apiService = ApiService();
Future.microtask(() {
final id = ref.read(enquiryIdProvider);
print("IntialID - $id");
if (id != null) {
_loadData(id);
} else {
setState(() => isLoading = false);
tabs = [
TabItem("Enquiry", EnquiryTab()),
TabItem("Quotation", QuotationTab()),
TabItem("Policy", PolicyTab()),
];
}
});
// fetch immediately
}
Future<void> _loadData(id) async {
print('Load Data');
setState(() => isLoading = true);
final response = await apiService.findEnqQuotePolicyView(id);
setState(() {
enquiryData = response["data"];
print('Load Data - $enquiryData');
isLoading = false;
tabs = [
TabItem(
"Enquiry",
EnquiryTab(data: enquiryData?["enquiry"], id: id ?? ""),
),
TabItem(
"Quotation",
QuotationTab(
data: (enquiryData?["quotations"] as List<dynamic>?)!
.map((e) => Map<String, dynamic>.from(e as Map))
.toList(),
id: id ?? "",
),
),
TabItem(
"Policy",
PolicyTab(
data: (enquiryData?["policies"] as List<dynamic>?)!
.map((e) => Map<String, dynamic>.from(e as Map))
.toList(),
),
),
// TabItem("Quotation", QuotationTab(data: enquiryData?["quotations"])),
// TabItem("Policy", PolicyTab()),
];
});
}
@override
Widget build(BuildContext context) {
final bool isMobile = MediaQuery.of(context).size.width < 600;
final id = ref.watch(enquiryIdProvider);
print("TABUPDID- $id");
// When provider changes, re-fetch
ref.listen<String?>(enquiryIdProvider, (prev, next) {
if (prev != next) {
_loadData(id);
}
});
print('ENQID: $id');
return MainLayout(
title: "Enquiry",
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
// Header
Padding(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
child: GestureDetector(
onTap: () {
context.go(AppRoutes.dashboard);
},
child: Row(
children: [
const Icon(
Icons.arrow_left_sharp,
size: 35,
color: Color(0xFF425B5B),
),
const SizedBox(width: 8),
Text(
"Enquiry",
style: GoogleFonts.inter(
fontSize: 18,
fontWeight: FontWeight.w700,
color: Colors.black87,
),
),
],
),
),
),
const SizedBox(height: 10),
// Tab Buttons
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
children: List.generate(tabs.length, (index) {
final bool isSelected = selectedIndex == index;
return Padding(
padding: const EdgeInsets.only(right: 12),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 2,
backgroundColor: isSelected
? const Color(0xFF425B5B) // selected dark green
: const Color(0xFFEDFFFC), // light teal
foregroundColor: isSelected
? Colors.white
: Colors.black87,
side: BorderSide(
color: isSelected
? const Color(0xFF425B5B)
: const Color(0xFFEDFFFC),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
onPressed: () {
setState(() {
selectedIndex = index;
});
},
child: Text(
tabs[index],
style: GoogleFonts.inter(
fontWeight: isSelected
? FontWeight.w600
: FontWeight.w500,
fontSize: 15,
),
),
),
);
}),
),
),
const SizedBox(height: 16),
// Tab content
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: tabWidgets[selectedIndex],
),
),
],
),
child: isLoading
? const Center(child: CircularProgressIndicator())
: isMobile
? _buildMobileTabs()
: _buildDesktopTabs(),
),
);
}
Widget _buildMobileTabs() {
return ListView.builder(
itemCount: tabs.length,
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.only(bottom: 12),
color: const Color(0xFF425B5B),
child: ExpansionTile(
collapsedIconColor: Colors.white,
iconColor: Colors.white,
title: Text(
tabs[index].title,
style: GoogleFonts.inter(
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
children: [
Container(
padding: const EdgeInsets.all(12),
child: tabs[index].widget,
),
],
),
);
},
);
}
Widget _buildDesktopTabs() {
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
child: GestureDetector(
onTap: () {
context.go(AppRoutes.dashboard);
},
child: Row(
children: [
const Icon(
Icons.arrow_left_sharp,
size: 35,
color: Color(0xFF425B5B),
),
const SizedBox(width: 8),
Text(
"Enquiry",
style: GoogleFonts.inter(
fontSize: 18,
fontWeight: FontWeight.w700,
color: Colors.black87,
),
),
],
),
),
),
Row(
children: List.generate(tabs.length, (index) {
final isSelected = selectedIndex == index;
return Padding(
padding: const EdgeInsets.only(left: 10.0),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 2,
backgroundColor: isSelected
? const Color(0xFF425B5B)
: const Color(0xFFEDFFFC),
foregroundColor: isSelected ? Colors.white : Colors.black87,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
onPressed: () {
setState(() => selectedIndex = index);
},
child: Text(tabs[index].title),
),
);
}),
),
SizedBox(height: 10),
Expanded(child: tabs[selectedIndex].widget),
],
);
}
}
class TabItem {
final String title;
final Widget widget;
TabItem(this.title, this.widget);
}
// class TabEnquiryListState extends ConsumerState<TabEnquiryList> {
// int selectedIndex = 0; // 0 = Enquiry, 1 = Quotation, 2 = Policy
//
// // final List<String> tabs = ["Enquiry", "Quotation", "Policy"];
// // final List<Widget> tabWidgets = [EnquiryTab(), QuotationTab(), PolicyTab()];
// // late List<Widget> tabWidgets;
//
// late List<Map<String, dynamic>> tabs;
//
// Map<String, dynamic>? enquiryData;
// bool isLoading = true;
// late ApiService apiService;
//
// @override
// void initState() {
// super.initState();
// apiService = ApiService();
// _loadData();
// }
//
// Future<void> _loadData() async {
// final id = ref.read(enquiryIdProvider);
// if (id != null && id.isNotEmpty) {
// setState(() => isLoading = true);
// final response = await apiService.findEnqQuotePolicyView(id);
// setState(() {
// enquiryData = response["data"];
// isLoading = false;
// tabs = [
// TabItem("Enquiry", EnquiryTab(data: enquiryData?["enquiry"])),
// TabItem("Quotation", QuotationTab(id: id)),
// TabItem("Policy", PolicyTab()),
// ];
// });
// } else {
// setState(() {
// isLoading = false;
// tabs = [
// TabItem("Enquiry", EnquiryTab()),
// TabItem("Quotation", QuotationTab(id: "")),
// TabItem("Policy", PolicyTab()),
// ];
// });
// }
// }
//
// // Future<void> _fetchData() async {
// // final id = ref.read(enquiryIdProvider);
// // if (id != null && id.isNotEmpty) {
// // setState(() {
// // isLoading = true;
// // });
// //
// // final response = await apiService.findEnqQuotePolicyView(id);
// //
// // setState(() {
// // enquiryData = response["data"];
// // tabs = [
// // TabItem("Enquiry", EnquiryTab(data: enquiryData?["enquiry"])),
// // TabItem("Quotation", QuotationTab(id: id)),
// // TabItem("Policy", PolicyTab()),
// // ];
// // isLoading = false;
// // });
// // } else {
// // setState(() {
// // tabs = [
// // TabItem("Enquiry", EnquiryTab()),
// // TabItem("Quotation", QuotationTab(id: "")),
// // TabItem("Policy", PolicyTab()),
// // ];
// // isLoading = false;
// // });
// // }
// // }
//
// // Future<void> _fetchData() async {
// // final id = ref.read(enquiryIdProvider);
// // if (id != null && id.isNotEmpty) {
// // final response = await apiService.findEnqQuotePolicyView(id);
// // setState(() {
// // enquiryData = response["data"];
// // isLoading = false;
// // });
// // }
// // }
//
// // @override
// // Widget build(BuildContext context) {
// // final bool isMobile = MediaQuery.of(context).size.width < 600;
// // final id = ref.watch(enquiryIdProvider); // listen to provider
// //
// // print('ENQID: $id');
// // // final tabs = [
// // // TabItem("Enquiry", EnquiryTab(id: id ?? "")),
// // // TabItem("Quotation", QuotationTab(id: id ?? "")),
// // // TabItem("Policy", PolicyTab()),
// // // ];
// // final tabs;
// // if (id != null) {
// // print('HASENQID: $id');
// // setState(() {
// // isLoading = true;
// // });
// //
// // _fetchData();
// //
// // setState(() {
// // isLoading = false;
// // });
// //
// // tabs = [
// // TabItem("Enquiry", EnquiryTab(data: enquiryData?["enquiry"])),
// //
// // // TabItem("Quotation", QuotationTab(data: enquiryData?["quotations"])),
// // // TabItem("Policy", PolicyTab(data: enquiryData?["policies"])),
// // TabItem("Quotation", QuotationTab(id: id ?? "")),
// // TabItem("Policy", PolicyTab()),
// // ];
// // } else {
// // setState(() {
// // isLoading = false;
// // });
// //
// // print('HASENQIDNot');
// // tabs = [
// // TabItem("Enquiry", EnquiryTab()),
// //
// // // TabItem("Quotation", QuotationTab(data: enquiryData?["quotations"])),
// // // TabItem("Policy", PolicyTab(data: enquiryData?["policies"])),
// // TabItem("Quotation", QuotationTab(id: id ?? "")),
// // TabItem("Policy", PolicyTab()),
// // ];
// // }
// //
// // return MainLayout(
// // title: "Enquiry",
// // body: SafeArea(
// // child: isLoading
// // ? const Center(
// // child: CircularProgressIndicator(), // 👈 loader inside SafeArea
// // )
// // : isMobile
// // ? ListView.builder(
// // itemCount: tabs.length,
// // padding: const EdgeInsets.all(16),
// // itemBuilder: (context, index) {
// // return Card(
// // shape: RoundedRectangleBorder(
// // borderRadius: BorderRadius.circular(8),
// // ),
// // margin: const EdgeInsets.only(bottom: 12),
// // color: const Color(0xFF425B5B), // Header background
// // child: Theme(
// // data: Theme.of(context).copyWith(
// // dividerColor:
// // Colors.transparent, // remove default divider
// // ),
// // child: ExpansionTile(
// // collapsedIconColor: Colors.white,
// // iconColor: Colors.white,
// // title: Text(
// // // tabs[index]["title"],
// // tabs[index].title,
// // style: GoogleFonts.inter(
// // color: Colors.white,
// // fontWeight: FontWeight.w600,
// // ),
// // ),
// // children: [
// // Container(
// // width: double.infinity,
// // decoration: BoxDecoration(
// // color: const Color(0xFFEAF6F4),
// // borderRadius: BorderRadius.circular(8),
// // border: Border.all(
// // color: const Color(0xFFB0CFCB),
// // width: 1,
// // ),
// // ),
// // padding: const EdgeInsets.all(12),
// // child: SizedBox(
// // height: MediaQuery.of(context).size.height,
// // child: tabs[selectedIndex].widget,
// // // child: tabs[index]["widget"] as Widget,
// // ), // directly, no SizedBox height
// // ),
// // // Container(
// // // width: double.infinity,
// // //
// // // decoration: BoxDecoration(
// // // color: const Color(0xFFEAF6F4), // light teal bg like screenshot
// // // borderRadius: BorderRadius.circular(8),
// // // border: Border.all(
// // // color: const Color(0xFFB0CFCB), // soft border color
// // // width: 1,
// // // ),
// // // ),
// // // padding: const EdgeInsets.all(12),
// // // child: SizedBox(
// // // height: MediaQuery.of(context).size.height,
// // // // mainAxisSize: MainAxisSize.min, // 👈 prevents collapse
// // // // children: [
// // // child: tabs[index]["widget"] as Widget, // actual tab widget
// // // // ],
// // // ),
// // // ),
// // ],
// // ),
// // ),
// // );
// // },
// // )
// // : Column(
// // crossAxisAlignment: CrossAxisAlignment.start,
// // children: [
// // // Back Button + Title
// // Padding(
// // padding: const EdgeInsets.symmetric(
// // horizontal: 6,
// // vertical: 2,
// // ),
// // child: GestureDetector(
// // onTap: () {
// // context.go(AppRoutes.dashboard);
// // },
// // child: Row(
// // children: [
// // const Icon(
// // Icons.arrow_left_sharp,
// // size: 35,
// // color: Color(0xFF425B5B),
// // ),
// // const SizedBox(width: 8),
// // Text(
// // "Enquiry",
// // style: GoogleFonts.inter(
// // fontSize: 18,
// // fontWeight: FontWeight.w700,
// // color: Colors.black87,
// // ),
// // ),
// // ],
// // ),
// // ),
// // ),
// //
// // const SizedBox(height: 10),
// //
// // // Tabs
// // Padding(
// // padding: const EdgeInsets.symmetric(horizontal: 16),
// // child: Row(
// // children: List.generate(tabs.length, (index) {
// // final bool isSelected = selectedIndex == index;
// // return Padding(
// // padding: const EdgeInsets.only(right: 12),
// // child: ElevatedButton(
// // style: ElevatedButton.styleFrom(
// // elevation: 2,
// // backgroundColor: isSelected
// // ? const Color(0xFF425B5B)
// // : const Color(0xFFEDFFFC),
// // foregroundColor: isSelected
// // ? Colors.white
// // : Colors.black87,
// // shape: RoundedRectangleBorder(
// // borderRadius: BorderRadius.circular(6),
// // ),
// // padding: const EdgeInsets.symmetric(
// // horizontal: 24,
// // vertical: 12,
// // ),
// // ),
// // onPressed: () {
// // setState(() {
// // selectedIndex = index;
// // });
// // },
// // child: Text(
// // // tabs[index]["title"],
// // tabs[index].title,
// // style: GoogleFonts.inter(
// // fontWeight: isSelected
// // ? FontWeight.w600
// // : FontWeight.w500,
// // fontSize: 15,
// // ),
// // ),
// // ),
// // );
// // }),
// // ),
// // ),
// //
// // const SizedBox(height: 16),
// //
// // // Tab Content
// // Expanded(
// // child: Padding(
// // padding: const EdgeInsets.symmetric(horizontal: 16),
// // child: tabs[selectedIndex].widget,
// // // child: tabs[selectedIndex]["widget"],
// // ),
// // ),
// // ],
// // ),
// // ),
// // );
// // }
//
// // Widget build(BuildContext context) {
// // return MainLayout(
// // title: "Enquiry",
// // body: SafeArea(
// // child: Column(
// // crossAxisAlignment: CrossAxisAlignment.start,
// // mainAxisAlignment: MainAxisAlignment.start,
// // children: [
// // // Header
// // Padding(
// // padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
// // child: GestureDetector(
// // onTap: () {
// // context.go(AppRoutes.dashboard);
// // },
// // child: Row(
// // children: [
// // const Icon(
// // Icons.arrow_left_sharp,
// // size: 35,
// // color: Color(0xFF425B5B),
// // ),
// // const SizedBox(width: 8),
// // Text(
// // "Enquiry",
// // style: GoogleFonts.inter(
// // fontSize: 18,
// // fontWeight: FontWeight.w700,
// // color: Colors.black87,
// // ),
// // ),
// // ],
// // ),
// // ),
// // ),
// //
// // const SizedBox(height: 10),
// //
// // // Tab Buttons
// // Padding(
// // padding: const EdgeInsets.symmetric(horizontal: 16),
// // child: Row(
// // children: List.generate(tabs.length, (index) {
// // final bool isSelected = selectedIndex == index;
// // return Padding(
// // padding: const EdgeInsets.only(right: 12),
// // child: ElevatedButton(
// // style: ElevatedButton.styleFrom(
// // elevation: 2,
// // backgroundColor: isSelected
// // ? const Color(0xFF425B5B) // selected dark green
// // : const Color(0xFFEDFFFC), // light teal
// // foregroundColor: isSelected
// // ? Colors.white
// // : Colors.black87,
// // side: BorderSide(
// // color: isSelected
// // ? const Color(0xFF425B5B)
// // : const Color(0xFFEDFFFC),
// // ),
// // shape: RoundedRectangleBorder(
// // borderRadius: BorderRadius.circular(6),
// // ),
// // padding: const EdgeInsets.symmetric(
// // horizontal: 24,
// // vertical: 12,
// // ),
// // ),
// // onPressed: () {
// // setState(() {
// // selectedIndex = index;
// // });
// // },
// // child: Text(
// // tabs[index],
// // style: GoogleFonts.inter(
// // fontWeight: isSelected
// // ? FontWeight.w600
// // : FontWeight.w500,
// // fontSize: 15,
// // ),
// // ),
// // ),
// // );
// // }),
// // ),
// // ),
// //
// // const SizedBox(height: 16),
// //
// // // Tab content
// // Expanded(
// // child: Padding(
// // padding: const EdgeInsets.symmetric(horizontal: 16),
// // child: tabWidgets[selectedIndex],
// // ),
// // ),
// // ],
// // ),
// // ),
// // );
// // }
// }
// class TabItem {
// final String title;
// final Widget widget;
// TabItem(this.title, this.widget);
// }

View File

@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:http/http.dart';
import 'package:intl/intl.dart';
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
import '../../../../core/routing/routes.dart';
@ -139,8 +140,13 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
onTap: () {
Navigator.pop(context);
print('EDITStaff - ${data['id']}');
dynamic id = data['id'];
// context.go('/staff/$id');
// dynamic id = data['id'];
// context.go('/tabEnquiry/$id');
// update provider
final id = data['id'].toString();
ref.read(enquiryIdProvider.notifier).state = id;
context.go(AppRoutes.tabEnquiry);
},
child: Row(
mainAxisSize: MainAxisSize.min,
@ -262,10 +268,10 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
GestureDetector(
onTap: () {
// context.go(AppRoutes.agent / create);
context.go('/staff/create');
context.go('/tabEnquiry/tab');
},
child: Text(
'Create New Staff',
'Create New Enquiry',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,

View File

@ -0,0 +1,699 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
import '../../../../core/routing/routes.dart';
import '../../../../core/services/api_service.dart';
import '../../../../data/utils/Pagination.dart';
import '../../../layouts/main_layout.dart';
import '../../../layouts/responsive_layout.dart';
import '../../../providers/manager_provider.dart';
import '../../../themes/indicators/export_btn.dart';
import '../../../themes/indicators/search_field_theme.dart';
import '../../../widgets/custom_action_popup.dart';
class claimList extends ConsumerStatefulWidget {
const claimList({super.key});
@override
ConsumerState<claimList> createState() => claimListState();
}
class claimListState extends ConsumerState<claimList> {
int currentPage = 1;
int itemsPerPage = 10;
late ApiService apiService;
// List<Map<String, dynamic>> dataVal = [];
List<Map<String, dynamic>> getStaffData = [];
List<Map<String, dynamic>> originalData = [];
List<Map<String, dynamic>> filteredData = [];
bool isLoading = false;
@override
void initState() {
super.initState();
apiService = ApiService();
Future.microtask(() {
final id = ref.read(managerIdProvider);
final roleId = ref.read(userRoleProvider);
print("ENQroleId - $roleId");
if (id != null) {
getStaffList(id, roleId);
}
});
}
Future<void> getStaffList(int managerId, role) async {
print('getClaimList called MagId - $managerId - $role');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchClaimList(managerId, role);
if (response['status'] == 'success') {
final data = response['data'];
print('clImlist - ${response['data']}');
setState(() {
if (data is List) {
// Already a list of maps
getStaffData = List<Map<String, dynamic>>.from(data);
} else if (data is Map) {
// Single object, wrap in a list
getStaffData = [Map<String, dynamic>.from(data)];
} else {
getStaffData = [];
}
// getStaffData = List<Map<String, dynamic>>.from(response['data']);
originalData = getStaffData;
filteredData = List.from(originalData);
// print('originalData - $getClaimPolicies');
});
} else {
getStaffData = [];
originalData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
List<dynamic> get _paginatedData {
// Sort descending by id first
final sortedData = [...filteredData]
..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
final startIndex = (currentPage - 1) * itemsPerPage;
final endIndex = (currentPage * itemsPerPage).clamp(0, sortedData.length);
return sortedData.sublist(startIndex, endIndex);
}
void filterData(String query) {
print("FilterDAta - $query");
setState(() {
filteredData = getStaffData.where((item) {
// final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive";
return (item['reg_no'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['insurer_name'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['policy_no'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['policy_end_date'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['claim_type'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['claim_number'] ?? '').toLowerCase().contains(
query.toLowerCase(),
);
}).toList();
});
}
final TextEditingController _searchStaffController = TextEditingController();
String _formatDate(String rawDate) {
try {
final dateTime = DateTime.parse(rawDate);
return DateFormat('dd/MM/yyyy HH:mm').format(dateTime); // 24-hour format
} catch (e) {
return rawDate; // fallback if parsing fails
}
}
List<Widget> _buildPopupMenuActions(BuildContext context, dynamic data) {
return [
GestureDetector(
onTap: () {
Navigator.pop(context);
print('EDITStaff - ${data['id']}');
dynamic id = data['id'];
// context.go('/staff/$id');
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.edit_sharp, color: Color(0xFF319718), size: 18),
SizedBox(width: 10),
Text('Edit'),
],
),
),
];
}
@override
Widget build(BuildContext context) {
return MainLayout(
title: "claims",
body: Container(
// color: Colors.yellow.shade50,
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 30,
width: MediaQuery.of(context).size.width,
child: GestureDetector(
onTap: () {
context.go(AppRoutes.dashboard);
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Icon(
Icons.arrow_left_sharp,
size: 35,
color: Color(0xFF425B5B),
),
Text(
"Claims",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
SizedBox(height: 10),
Expanded(
child: Container(
// color: Colors.green,
// color: Colors.green.shade50,
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.all(8.0),
child: Column(
children: [
Container(
// height: 40,
// color: Colors.pink,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
ThemedSearchField(
hintText: 'Search',
backgroundColor: Color(0xFFF6F8F8),
onChanged: filterData,
controller: _searchStaffController,
txtwidth: ResponsiveLayout.isMobile(context)
? MediaQuery.of(context).size.width * 0.6
: MediaQuery.of(context).size.width * 0.2,
),
Spacer(),
ExportBtn(
sheetName: "Claims",
fileName: "claim_list",
data: filteredData,
txt: !ResponsiveLayout.isMobile(context)
? true
: false,
headers: [
"reg_no",
"insurer_name",
"policy_no",
"policy_end_date",
"claim_number",
"claim_type",
],
),
// SizedBox(width: 10),
// GestureDetector(
// onTap: () {
// // print('Export');
// },
// child: Container(
// padding: EdgeInsets.all(8.0),
// decoration: BoxDecoration(
// color: Color(0xFF425B5B),
// borderRadius: BorderRadius.circular(8.0),
// ),
// child: Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// Icon(Icons.add, color: Colors.white),
//
// if (!ResponsiveLayout.isMobile(context)) ...[
// SizedBox(width: 10),
//
// GestureDetector(
// onTap: () {
// // context.go(AppRoutes.agent / create);
// context.go('/staff/create');
// },
// child: Text(
// 'Create New Staff',
// style: TextStyle(
// color: Colors.white,
// fontWeight: FontWeight.w600,
// fontSize: 14,
// ),
// ),
// ),
// ],
// ],
// ),
// ),
// ),
],
),
),
SizedBox(height: 10),
if (!ResponsiveLayout.isMobile(context))
Container(
decoration: BoxDecoration(
color: const Color(0xFFEDF6F5),
borderRadius: BorderRadius.circular(6),
),
padding: const EdgeInsets.symmetric(
vertical: 12,
horizontal: 16,
),
child: const Row(
children: [
Expanded(
flex: 2,
child: Text('S.No.', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Reg.No.', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Company', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Policy No.', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text(
'Policy Expiry Date',
style: _headerStyle,
),
),
Expanded(
flex: 2,
child: Text('Claim Type', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Claim No.', style: _headerStyle),
),
Expanded(
flex: 1,
child: Text('Action', style: _headerStyle),
),
],
),
),
Expanded(child: _buildDataTable(context)),
],
),
),
),
Container(
// height: 20,
width: MediaQuery.of(context).size.width,
// color: Colors.green.shade50,
child: PaginationControls(
currentPage: currentPage,
itemsPerPage: itemsPerPage,
// totalItems: dataVal.length,
totalItems: filteredData.length,
// activeColor: layoutColor, // your theme color
onPageChanged: (page) {
setState(() {
currentPage = page;
});
},
onItemsPerPageChanged: (items) {
setState(() {
itemsPerPage = items;
currentPage = 1;
});
},
),
),
],
),
),
);
}
Widget _buildDataTable(BuildContext context) {
if (filteredData.isEmpty) {
return const SizedBox(
height: 50,
child: Center(child: Text('No available data')),
);
}
final sortedData = [..._paginatedData];
return ListView.builder(
itemCount: ResponsiveLayout.isMobile(context)
? sortedData
.length // only cards for mobile
: sortedData.length + 1, // +1 for header in desktop
itemBuilder: (context, index) {
if (!ResponsiveLayout.isMobile(context) && index == 0) {
return _buildHeader();
}
final startIndex = (currentPage - 1) * itemsPerPage;
final item =
sortedData[index - (ResponsiveLayout.isMobile(context) ? 0 : 1)];
final sno = startIndex + index;
return !ResponsiveLayout.isMobile(context)
? _buildDataRow(item, sno)
: _buildDataCard(item, sno);
},
);
}
Widget _buildHeader() {
return SizedBox.shrink();
}
Widget _buildDataRow(Map<String, dynamic> item, sno) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 16),
// margin: const EdgeInsets.only(top: 10),
decoration: BoxDecoration(
color: Colors.white,
// color: Color(0xFFE0F7F9),
border: const Border(
bottom: BorderSide(color: Color(0xFFEAEAEA), width: 1),
),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Expanded(flex: 2, child: Text('$sno' ?? '-', style: _dataBold)),
Expanded(
flex: 2,
child: Text(
item['reg_no'] != null
? _formatDate(item['reg_no'])
: '-', // fallback
style: _dataBold,
),
),
Expanded(
flex: 2,
child: Text(
item['insurer_name'] != null
? _formatDate(item['insurer_name'])
: '-', // fallback
style: _dataBold,
),
),
Expanded(
flex: 2,
child: Text(
_formatDate(item['policy_no']) ?? '-',
style: _dataBold,
),
),
Expanded(
flex: 2,
child: Text(
_formatDate(item['policy_end_date']) ?? '-',
style: _dataBold,
),
),
Expanded(
flex: 2,
child: Text(
item['claim_type'] != null
? _formatDate(item['claim_number'])
: '-', // fallback
style: _dataBold,
),
),
Expanded(
flex: 2,
child: Text(
item['claim_number'] != null
? _formatDate(item['claim_number'])
: '-', // fallback
style: _dataBold,
),
),
Expanded(
flex: 1,
child: Row(
children: [
PopupMenuButton<int>(
color: Colors.white,
padding: EdgeInsets.zero,
offset: Offset(0, 30),
icon: Icon(
Icons.more_vert,
color: Color(0xFF475569),
size: 14,
),
itemBuilder: (context) => [
CustomPopupMenuEntry(
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 8,
vertical: 8,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: _buildPopupMenuActions(context, item),
),
),
),
],
),
],
),
),
// Expanded(s
// flex: 1,
// child: Row(
// children: [
// PopupMenuButton<int>(
// color: Colors.white,
// padding: EdgeInsets.zero,
// offset: Offset(0, 30),
// icon: Icon(
// Icons.more_vert,
// color: Color(0xFF475569),
// size: 14,
// ),
// itemBuilder: (context) => [
// CustomPopupMenuEntry(
// child: Container(
// padding: EdgeInsets.symmetric(
// horizontal: 8,
// vertical: 8,
// ),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// mainAxisAlignment: MainAxisAlignment.center,
// children: _buildPopupMenuActions(context, item),
// ),
// ),
// ),
// ],
// ),
// ],
// ),
// ),
],
),
);
}
Widget _buildDataCard(Map<String, dynamic> item, int sno) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 8),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: const Color(0xFFF6FEFD),
borderRadius: BorderRadius.circular(8.0),
border: Border.all(color: const Color(0xffD9EBE8)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
//reg no
Text(
item['reg_no'] != null ? _formatDate(item['reg_no']) : '-',
style: _headerStyle,
),
PopupMenuButton<int>(
color: Colors.white,
padding: EdgeInsets.zero,
offset: Offset(0, 30),
icon: Icon(Icons.more_vert, color: Color(0xFF475569), size: 14),
itemBuilder: (context) => [
CustomPopupMenuEntry(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: _buildPopupMenuActions(context, item),
),
),
),
],
),
],
),
const Divider(color: Color(0xffD9EBE8), thickness: 0.8),
// Company + Vehicle Reg No
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
//company
const Text("Company", style: _cardheaderStyle),
Text(
item['reg_no'] != null
? _formatDate(item['reg_no'])
: '-',
style: _cardBodyStyle,
maxLines: 3,
softWrap: true,
),
],
),
),
SizedBox(width: 5),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
//status
const Text("Claim Type", style: _cardheaderStyle),
Text(
item['claim_type'] ?? '-',
style: _cardBodyStyle,
maxLines: 2,
softWrap: true,
),
],
),
),
],
),
const SizedBox(height: 15),
// Created On + Remarks
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//date and time
const Text("policy Number", style: _cardheaderStyle),
Text(
_formatDate(item['policy_no']) ?? '-',
style: _cardBodyStyle,
),
],
),
),
SizedBox(width: 5),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//remarks
const Text("Claim Number", style: _cardheaderStyle),
Text(
item['claim_number'] ?? '-',
style: _cardBodyStyle,
maxLines: 3,
softWrap: true,
),
],
),
),
],
),
],
),
);
}
static final _dataBold = TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Color(0xFF000000),
);
static final _dataSub = TextStyle(
fontSize: 10,
fontWeight: FontWeight.w300,
color: Color(0xFF585757),
);
static const _headerStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
);
static const _cardheaderStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600,
fontSize: 12,
);
static const _cardBodyStyle = TextStyle(
color: Color(0xFF545454),
fontWeight: FontWeight.w400,
fontSize: 12,
);
}

View File

@ -0,0 +1,651 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
import '../../../../core/routing/routes.dart';
import '../../../../core/services/api_service.dart';
import '../../../../data/utils/Pagination.dart';
import '../../../layouts/main_layout.dart';
import '../../../layouts/responsive_layout.dart';
import '../../../providers/manager_provider.dart';
import '../../../themes/indicators/export_btn.dart';
import '../../../themes/indicators/search_field_theme.dart';
import '../../../widgets/custom_action_popup.dart';
class endosement extends ConsumerStatefulWidget {
const endosement({super.key});
@override
ConsumerState<endosement> createState() => endosementState();
}
class endosementState extends ConsumerState<endosement> {
int currentPage = 1;
int itemsPerPage = 10;
late ApiService apiService;
// List<Map<String, dynamic>> dataVal = [];
List<Map<String, dynamic>> getStaffData = [];
List<Map<String, dynamic>> originalData = [];
List<Map<String, dynamic>> filteredData = [];
bool isLoading = false;
@override
void initState() {
super.initState();
apiService = ApiService();
Future.microtask(() {
final id = ref.read(managerIdProvider);
final roleId = ref.read(userRoleProvider);
print("ENQroleId - $roleId");
if (id != null) {
getStaffList(id, roleId);
}
});
}
Future<void> getStaffList(int managerId, role) async {
print('getClaimList called MagId - $managerId - $role');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchEndorsementList(managerId, role);
if (response['status'] == 'success') {
final data = response['data'];
print('getStaffListData - ${response['data']}');
setState(() {
if (data is List) {
// Already a list of maps
getStaffData = List<Map<String, dynamic>>.from(data);
} else if (data is Map) {
// Single object, wrap in a list
getStaffData = [Map<String, dynamic>.from(data)];
} else {
getStaffData = [];
}
// getStaffData = List<Map<String, dynamic>>.from(response['data']);
originalData = getStaffData;
filteredData = List.from(originalData);
// print('originalData - $getClaimPolicies');
});
} else {
getStaffData = [];
originalData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
List<dynamic> get _paginatedData {
// Sort descending by id first
final sortedData = [...filteredData]
..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
final startIndex = (currentPage - 1) * itemsPerPage;
final endIndex = (currentPage * itemsPerPage).clamp(0, sortedData.length);
return sortedData.sublist(startIndex, endIndex);
}
void filterData(String query) {
print("FilterDAta - $query");
setState(() {
filteredData = getStaffData.where((item) {
// final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive";
return (item['reg_no'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['insurer_name'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['policy_number'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['endorsement_type'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['endorsement_no'] ?? '').toLowerCase().contains(
query.toLowerCase(),
);
}).toList();
});
}
final TextEditingController _searchStaffController = TextEditingController();
String _formatDate(String rawDate) {
try {
final dateTime = DateTime.parse(rawDate);
return DateFormat('dd/MM/yyyy HH:mm').format(dateTime); // 24-hour format
} catch (e) {
return rawDate; // fallback if parsing fails
}
}
List<Widget> _buildPopupMenuActions(BuildContext context, dynamic data) {
return [
GestureDetector(
onTap: () {
Navigator.pop(context);
print('EDITStaff - ${data['id']}');
dynamic id = data['id'];
// context.go('/staff/$id');
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.edit_sharp, color: Color(0xFF319718), size: 18),
SizedBox(width: 10),
Text('Edit'),
],
),
),
];
}
@override
Widget build(BuildContext context) {
return MainLayout(
title: "Endosement",
body: Container(
// color: Colors.yellow.shade50,
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 30,
width: MediaQuery.of(context).size.width,
child: GestureDetector(
onTap: () {
context.go(AppRoutes.dashboard);
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Icon(
Icons.arrow_left_sharp,
size: 35,
color: Color(0xFF425B5B),
),
Text(
"Endosement",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
SizedBox(height: 10),
Expanded(
child: Container(
// color: Colors.green,
// color: Colors.green.shade50,
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.all(8.0),
child: Column(
children: [
Container(
// height: 40,
// color: Colors.pink,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
ThemedSearchField(
hintText: 'Search',
backgroundColor: Color(0xFFF6F8F8),
onChanged: filterData,
controller: _searchStaffController,
txtwidth: ResponsiveLayout.isMobile(context)
? MediaQuery.of(context).size.width * 0.6
: MediaQuery.of(context).size.width * 0.2,
),
Spacer(),
ExportBtn(
sheetName: "Endorsement",
fileName: "endorsement_list",
data: filteredData,
txt: !ResponsiveLayout.isMobile(context)
? true
: false,
headers: [
"reg_no",
"insurer_name",
"policy_number",
"endorsement_type",
"endorsement_no",
],
),
// SizedBox(width: 10),
// GestureDetector(
// onTap: () {
// // print('Export');
// },
// child: Container(
// padding: EdgeInsets.all(8.0),
// decoration: BoxDecoration(
// color: Color(0xFF425B5B),
// borderRadius: BorderRadius.circular(8.0),
// ),
// child: Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// Icon(Icons.add, color: Colors.white),
//
// if (!ResponsiveLayout.isMobile(context)) ...[
// SizedBox(width: 10),
//
// GestureDetector(
// onTap: () {
// // context.go(AppRoutes.agent / create);
// context.go('/staff/create');
// },
// child: Text(
// 'Create New Staff',
// style: TextStyle(
// color: Colors.white,
// fontWeight: FontWeight.w600,
// fontSize: 14,
// ),
// ),
// ),
// ],
// ],
// ),
// ),
// ),
],
),
),
SizedBox(height: 10),
if (!ResponsiveLayout.isMobile(context))
Container(
decoration: BoxDecoration(
color: Color(0xFFEDF6F5),
borderRadius: BorderRadius.circular(6),
),
padding: const EdgeInsets.symmetric(
vertical: 12,
horizontal: 16,
),
child: const Row(
children: [
Expanded(
flex: 2,
child: Text('S.No.', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Reg.No.', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Company', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Policy No.', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text(
'Endorsement Type',
style: _headerStyle,
),
),
Expanded(
flex: 2,
child: Text(
'Endorsement No',
style: _headerStyle,
),
),
Expanded(
flex: 1,
child: Text('Action', style: _headerStyle),
),
],
),
),
Expanded(child: _buildDataTable(context)),
],
),
),
),
Container(
// height: 20,
width: MediaQuery.of(context).size.width,
// color: Colors.green.shade50,
child: PaginationControls(
currentPage: currentPage,
itemsPerPage: itemsPerPage,
// totalItems: dataVal.length,
totalItems: filteredData.length,
// activeColor: layoutColor, // your theme color
onPageChanged: (page) {
setState(() {
currentPage = page;
});
},
onItemsPerPageChanged: (items) {
setState(() {
itemsPerPage = items;
currentPage = 1;
});
},
),
),
],
),
),
);
}
Widget _buildDataTable(BuildContext context) {
if (filteredData.isEmpty) {
return const SizedBox(
height: 50,
child: Center(child: Text('No available data')),
);
}
final sortedData = [..._paginatedData];
return ListView.builder(
itemCount: ResponsiveLayout.isMobile(context)
? sortedData
.length // only cards for mobile
: sortedData.length + 1, // +1 for header in desktop
itemBuilder: (context, index) {
if (!ResponsiveLayout.isMobile(context) && index == 0) {
return _buildHeader();
}
final startIndex = (currentPage - 1) * itemsPerPage;
final item =
sortedData[index - (ResponsiveLayout.isMobile(context) ? 0 : 1)];
final sno = startIndex + index;
return !ResponsiveLayout.isMobile(context)
? _buildDataRow(item, sno)
: _buildDataCard(item, sno);
},
);
}
Widget _buildHeader() {
return SizedBox.shrink();
}
Widget _buildDataRow(Map<String, dynamic> item, sno) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 16),
// margin: const EdgeInsets.only(top: 10),
decoration: BoxDecoration(
color: Colors.white,
// color: Color(0xFFE0F7F9),
border: const Border(
bottom: BorderSide(color: Color(0xFFEAEAEA), width: 1),
),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Expanded(flex: 2, child: Text('$sno' ?? '-', style: _dataBold)),
Expanded(
flex: 2,
child: Text(
item['reg_no'] != null
? _formatDate(item['reg_no'])
: '-', // fallback
style: _dataBold,
),
),
Expanded(
flex: 2,
child: Text(
item['insurer_name'] != null
? _formatDate(item['insurer_name'])
: '-', // fallback
style: _dataBold,
),
),
Expanded(
flex: 2,
child: Text(
_formatDate(item['policy_number']) ?? '-',
style: _dataBold,
),
),
Expanded(
flex: 2,
child: Text(
_formatDate(item['endorsement_no']) ?? '-',
style: _dataBold,
),
),
Expanded(
flex: 2,
child: Text(
_formatDate(item['endorsement_type']) ?? '-',
style: _dataBold,
),
),
Expanded(
flex: 1,
child: Row(
children: [
PopupMenuButton<int>(
color: Colors.white,
padding: EdgeInsets.zero,
offset: Offset(0, 30),
icon: Icon(
Icons.more_vert,
color: Color(0xFF475569),
size: 14,
),
itemBuilder: (context) => [
CustomPopupMenuEntry(
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 8,
vertical: 8,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: _buildPopupMenuActions(context, item),
),
),
),
],
),
],
),
),
],
),
);
}
Widget _buildDataCard(Map<String, dynamic> item, int sno) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 8),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: const Color(0xFFF6FEFD),
borderRadius: BorderRadius.circular(8.0),
border: Border.all(color: const Color(0xffD9EBE8)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
//reg no
Text(
item['reg_no'] != null ? _formatDate(item['reg_no']) : '-',
style: _headerStyle,
),
PopupMenuButton<int>(
color: Colors.white,
padding: EdgeInsets.zero,
offset: Offset(0, 30),
icon: Icon(Icons.more_vert, color: Color(0xFF475569), size: 14),
itemBuilder: (context) => [
CustomPopupMenuEntry(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: _buildPopupMenuActions(context, item),
),
),
),
],
),
],
),
const Divider(color: Color(0xffD9EBE8), thickness: 0.8),
// Company + Vehicle Reg No
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
//company
const Text("Company", style: _cardheaderStyle),
Text(
item['insurer_name'] != null
? _formatDate(item['insurer_name'])
: '-',
style: _cardBodyStyle,
maxLines: 3,
softWrap: true,
),
],
),
),
SizedBox(width: 5),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
//status
const Text("Endorsement Type", style: _cardheaderStyle),
Text(
item['endorsement_type'] ?? '-',
style: _cardBodyStyle,
maxLines: 2,
softWrap: true,
),
],
),
),
],
),
const SizedBox(height: 15),
// Created On + Remarks
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//date and time
const Text("policy Number", style: _cardheaderStyle),
Text(
_formatDate(item['policy_number']) ?? '-',
style: _cardBodyStyle,
),
],
),
),
SizedBox(width: 5),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//remarks
const Text("Endorsement Number", style: _cardheaderStyle),
Text(
item['endorsement_no'] ?? '-',
style: _cardBodyStyle,
maxLines: 3,
softWrap: true,
),
],
),
),
],
),
],
),
);
}
static final _dataBold = TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Color(0xFF000000),
);
static final _dataSub = TextStyle(
fontSize: 10,
fontWeight: FontWeight.w300,
color: Color(0xFF585757),
);
static const _headerStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
);
static const _cardheaderStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600,
fontSize: 12,
);
static const _cardBodyStyle = TextStyle(
color: Color(0xFF545454),
fontWeight: FontWeight.w400,
fontSize: 12,
);
}

View File

@ -1,235 +0,0 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../../../data/utils/Pagination.dart';
import '../../layouts/main_layout.dart';
import '../../widgets/custom_action_popup.dart';
// import '../../widgets/custom_dataTable.dart';
class ClaimsList extends StatefulWidget {
const ClaimsList({super.key});
@override
State<ClaimsList> createState() => _ClaimsListState();
}
class _ClaimsListState extends State<ClaimsList> {
int currentPage = 0;
int itemsPerPage = 10;
List<Map<String, dynamic>> dataVal = [
{
"planId": "PLAN-1001",
"tripTitle": "Trip to Bangalore",
"tripType": "Business",
"employeeCode": "EMP200",
"userName": "Alice",
"travellerName": "Traveller 1",
"createdOn": "2025-08-01T10:00:00Z",
"statusValue": "Pending Approval",
"forexId": "FX-501",
},
{
"planId": "PLAN-1002",
"tripTitle": "Trip to Goa",
"tripType": "Leisure",
"employeeCode": "EMP201",
"userName": "",
"travellerName": "Traveller 2",
"createdOn": "2025-08-05T14:30:00Z",
"statusValue": "Approved",
"forexId": null,
},
// ...more dummy data
];
List<Map<String, dynamic>> get paginatedData =>
dataVal.skip(currentPage * itemsPerPage).take(itemsPerPage).toList();
List<Widget> _buildPopupMenuActions(BuildContext context, dynamic data) {
return [
IconButton(
icon: const Icon(
Icons.remove_red_eye,
color: Color(0xFF475569),
size: 18,
),
tooltip: 'View The Trip Details',
onPressed: () {
Navigator.pop(context);
// ApiService.viewPlan(context, plan.planId, isViewMode: true);
},
),
IconButton(
icon: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
),
tooltip: 'Edit The Trip Details',
onPressed: () {
Navigator.pop(context);
// ApiService.viewPlan(context, data.planId, isViewMode: false);
},
),
IconButton(
icon: const Icon(Icons.cancel_rounded, size: 18),
tooltip: 'Cancellation The Trip Details',
onPressed: () {
Navigator.pop(context);
// deletePlan(data.planId);
},
),
IconButton(
icon: const Icon(Icons.download, color: Color(0xFF475569), size: 18),
tooltip: 'Download The PDF',
onPressed: () {
Navigator.pop(context);
// apiService.getPdfDownload(data.planId);
},
),
IconButton(
icon: const Icon(
Icons.monetization_on_outlined,
color: Color(0xFF475569),
size: 18,
),
tooltip: 'Download Forex PDF',
onPressed: () {
Navigator.pop(context);
// apiService.getForexPdfDownload(data.forexId);
},
),
];
}
@override
Widget build(BuildContext context) {
return MainLayout(
title: "Claims",
body: Container(
// color: Colors.yellow.shade50,
margin: const EdgeInsets.all(8.0),
child: Column(
children: [
Container(
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.all(8.0),
// color: Colors.grey.shade200,
// color: Colors.red.shade50,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
columns: const [
DataColumn(label: Text("S.NO")),
DataColumn(label: Text("Trip ID")),
DataColumn(label: Text("Trip Name")),
DataColumn(label: Text("Trip Type")),
DataColumn(label: Text("Emp Code")),
DataColumn(label: Text("Traveller")),
DataColumn(label: Text("Created On")),
DataColumn(label: Text("Actions")),
],
rows: paginatedData.asMap().entries.map((entry) {
int index = entry.key;
var data = entry.value;
String createdOn = "";
final rawDateStr = data["createdOn"];
if (rawDateStr != null &&
rawDateStr.toString().isNotEmpty) {
try {
final parsed = DateTime.parse(rawDateStr);
createdOn = DateFormat("d MMM yyyy").format(parsed);
} catch (_) {
createdOn = rawDateStr.toString().split(" ").first;
}
}
return DataRow(
cells: [
DataCell(
Text("${(currentPage * itemsPerPage) + index + 1}"),
),
DataCell(Text(data["planId"] ?? "-")),
DataCell(Text(data["tripTitle"] ?? "-")),
DataCell(Text(data["tripType"] ?? "-")),
DataCell(Text(data["employeeCode"] ?? "-")),
DataCell(
Text(
(data["userName"] != null &&
data["userName"].toString().isNotEmpty)
? data["userName"]
: data["travellerName"] ?? "-",
),
),
DataCell(Text(createdOn)),
DataCell(
Row(
children: [
PopupMenuButton<int>(
color: Colors.white,
padding: EdgeInsets.zero,
offset: Offset(0, 30),
icon: Icon(
Icons.more_vert,
color: Color(0xFF475569),
size: 14,
),
itemBuilder: (context) => [
CustomPopupMenuEntry(
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 8,
vertical: 8,
),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.center,
children: _buildPopupMenuActions(
context,
data,
),
),
),
),
],
),
],
),
),
],
);
}).toList(),
),
),
),
PaginationControls(
currentPage: currentPage,
itemsPerPage: itemsPerPage,
totalItems: dataVal.length,
// activeColor: layoutColor, // your theme color
onPageChanged: (page) {
setState(() {
currentPage = page;
});
},
onItemsPerPageChanged: (items) {
setState(() {
itemsPerPage = items;
currentPage = 0;
});
},
),
],
),
),
);
}
}

View File

@ -0,0 +1,761 @@
import 'dart:io' as html;
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/cupertino.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 '../../../../core/routing/routes.dart';
import '../../../../core/services/api_service.dart';
import '../../../../data/services/auth_service.dart';
import '../../../../data/utils/Pagination.dart';
import '../../../../data/utils/validators.dart';
import '../../../layouts/main_layout.dart';
import '../../../layouts/responsive_layout.dart';
import '../../../providers/manager_provider.dart';
import '../../../themes/indicators/customizd_file_upload.dart';
import '../../../themes/indicators/text_field_theme.dart';
class PolicyScreen extends ConsumerStatefulWidget {
const PolicyScreen({super.key});
@override
ConsumerState<PolicyScreen> createState() => PolicyScreenState();
}
class PolicyScreenState extends ConsumerState<PolicyScreen> {
int currentPage = 0;
int itemsPerPage = 10;
List<Map<String, dynamic>> dataVal = [];
final TextEditingController _searchController = TextEditingController();
late ApiService apiService;
final _formKey = GlobalKey<FormState>();
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKey =
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
List<String> tabHeader = [
'name',
'email',
'mobile',
'code',
'address',
'regNo',
];
late String isActive = "1";
html.File? docUploadedFile;
// PlatformFile? passportFile;
String? selectedFileNames;
String? passportFileUrlFromApi;
String? selectedId;
bool isLoading = false;
bool isquotation = false;
Map<String, TextEditingController> controllers = {};
String? _token;
dynamic userId;
dynamic managerId;
List<Map<String, dynamic>> getVehicleTypeData = [];
List<Map<String, dynamic>> filteredVechicleData = [];
List<Map<String, dynamic>> getInsurersData = [];
List<Map<String, dynamic>> filteredInsurersData = [];
Map<String, dynamic> dataDetails() {
final data = {
"name": controllers["name"]?.text,
"email": controllers["email"]?.text,
"mobile": controllers["mobile"]?.text,
"address": controllers["address"]?.text,
"agent_code": controllers["code"]?.text,
"is_active": isActive,
"manager_id": managerId,
};
return data;
}
List<Map<String, dynamic>> getQuotationData = [];
List<Map<String, dynamic>> originalData = [];
List<Map<String, dynamic>> filteredData = [];
// bool isLoading = false;
@override
void initState() {
super.initState();
apiService = ApiService();
for (String field in tabHeader) {
controllers[field] = TextEditingController();
}
// updateData();
_initializeToken();
Future.microtask(() {
managerId = ref.watch(managerIdProvider);
userId = ref.watch(userIdProvider);
getQuotationList(managerId);
});
}
Future<void> _initializeToken() async {
_token = await AuthService.getToken();
print("APISERTOKEN - $_token");
}
Future<void> getQuotationList(int managerId) async {
print('getClaimList called MagId - $managerId');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchQuotationList(managerId);
if (response['status'] == 'success') {
print('quoationListData - ${response['data']}');
setState(() {
getQuotationData = List<Map<String, dynamic>>.from(response['data']);
originalData = getQuotationData;
filteredData = List.from(originalData);
// print('originalData - $getClaimPolicies');
});
} else {
getQuotationData = [];
originalData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
@override
Widget build(BuildContext context) {
return
MainLayout(
title: 'policy',
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
Container(
height: 30,
width: MediaQuery.of(context).size.width,
child: GestureDetector(
onTap: () {
context.go(AppRoutes.dashboard);
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Icon(
Icons.arrow_left_sharp,
size: 35,
color: Color(0xFF425B5B),
),
Text(
"Policy",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
SizedBox(height: 10),
//1ST SECTION
Container(
decoration: BoxDecoration(
color: const Color(0xFFEDF6F5),
borderRadius: BorderRadius.circular(10),
),
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Enquiry Details",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w700,
),
),
SizedBox(height: 10),
LayoutBuilder(
builder: (context, constraints) {
final isMobile = constraints.maxWidth < 600; // breakpoint
if (isMobile) {
// 📱 MOBILE Column layout
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
registernumber(context),
const SizedBox(height: 16),
insurer(context),
const SizedBox(height: 16),
buildIdv(context),
const SizedBox(height: 16),
buildPremiumAmnt(context),
const SizedBox(height: 16),
buildPlanType(context),
const SizedBox(height: 16),
Wrap(
spacing: 12,
runSpacing: 8,
children: [
_downloadButton("Download RC"),
_downloadButton("Download ID Proof"),
_downloadButton("Download Previous Policy"),
_downloadButton("Quotation Document"),
],
),
],
);
} else {
// 💻 WEB Row layout
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(flex: 2, child: registernumber(context)),
const SizedBox(width: 20),
Expanded(flex: 2, child: insurer(context)),
const SizedBox(width: 20),
Expanded(flex: 2, child: buildIdv(context)),
const SizedBox(width: 20),
Expanded(flex: 2, child: buildPremiumAmnt(context)),
const SizedBox(width: 20),
Expanded(flex: 2, child: buildPlanType(context)),
const SizedBox(width: 20),
],
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
_downloadButton("Download RC"),
const SizedBox(width: 20),
_downloadButton("Download ID Proof"),
const SizedBox(width: 20),
_downloadButton("Download Previous Policy"),
const SizedBox(width: 20),
_downloadButton("Quotation Document"),
],
),
],
);
}
},
),
],
),
),
const SizedBox(height: 20),
//2ND SECTION
Container(
// color: Colors.green,
decoration: BoxDecoration(
color: Color(0xffEDF6F5),
borderRadius: BorderRadius.circular(10.0),
),
width: MediaQuery.of(context).size.width,
// height: MediaQuery.of(context).size.height * 0.8,
padding: EdgeInsets.all(26.0),
child: Column(
children: [
SingleChildScrollView(child: buildFormFields(context)),
const SizedBox(height: 20),
//confirm button
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: () {
// handleSave();
},
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 45.0,
vertical: 8,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
color: Color(0xFF425B5B),
),
child: Text(
'Sumbit',
style: TextStyle(color: Colors.white),
),
),
),
],
),
],
),
),
const SizedBox(height: 20),
],
),
),
),
);
}
Widget _readonlyField(String label, String value) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: GoogleFonts.inter(fontSize: 13, fontWeight: FontWeight.w600)),
const SizedBox(height: 6),
Container(
padding: const EdgeInsets.symmetric(horizontal: 60, vertical: 14),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(6),
border: Border.all(color: Colors.grey.shade300),
),
child: Text(value, style: GoogleFonts.inter(fontSize: 14)),
),
],
);
}
Widget _downloadButton(String label) {
return ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF425B5B),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)),
),
onPressed: () {
// TODO: file download logic
},
icon: const Icon(Icons.download, size: 18),
label: Text(label, style: GoogleFonts.inter(fontSize: 13)),
);
}
Widget buildFormFields(BuildContext context) {
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildResponsiveRow(
context,
Insuredname(context),
premiumamount(context),
policynumber(context),
),
if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10),
_buildResponsiveRow(
context,
Paymentmode(context),
policyissuedate(context),
policystartdate(context),
),
if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10),
_buildResponsiveRow(
context,
policyenddate(context),
buildDocuments(context),
buildDocuments(context),
),
// if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10),
// _buildResponsiveRow(
// context,
// buildAdditonalDocuments(context),
// buildRemarks(context),
// ),
],
),
);
}
Widget _buildResponsiveRow(
BuildContext context,
Widget first,
Widget second,
Widget third,
)
{
if (ResponsiveLayout.isMobile(context)) {
// Stack vertically
return Column(children: [first, const SizedBox(height: 2), second]);
} else {
// Place side by side
return Row(
children: [
Expanded(child: first),
const SizedBox(width: 25),
Expanded(child: second),
const SizedBox(width: 25),
Expanded(child: third),
],
);
}
}
// Widget buildName(BuildContext context) {
// return buildResponsiveField(
// label: "Registration Number",
// field: ThemedFormField(
// controller: controllers['name']!,
// validator: (value) => Validators.requiredField(value, "name"),
// txtwidth: ResponsiveLayout.isMobile(context)
// ? null
// : MediaQuery.of(context).size.width * 0.26,
// ),
// );
// }
//
// Widget buildInsusrer(BuildContext context) {
// return buildResponsiveField(
// label: "Insusrer",
// field: ThemedFormField(
// controller: controllers['email']!,
// validator: (value) => Validators.email(value, "email"),
// txtwidth: ResponsiveLayout.isMobile(context)
// ? null
// : MediaQuery.of(context).size.width * 0.26,
// ),
// );
// }
Widget registernumber(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Register Number',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
readOnly:true,
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget insurer(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Insurer',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
readOnly:true,
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget buildIdv(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('IDV',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
readOnly:true,
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget buildPremiumAmnt(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Premium Amount',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
readOnly:true,
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget buildPlanType(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Plan Type',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
readOnly:true,
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget Insuredname(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Insured Name',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget premiumamount(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Premium Amount',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget policynumber(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Policy Number',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget Paymentmode(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Payment Mode',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget policyissuedate(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Policy Issue Date',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget policystartdate(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Policy Start Date',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget policyenddate(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Policy End Date',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget buildDocuments(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Quotation Documents ',
style: _textStyle,
),
const SizedBox(height: 10),
buildResponsiveUploadField(
hintText: selectedFileNames,
onFileSelected: (fileName, file) {
print("File picked: $fileName");
setState(() {
docUploadedFile = file;
});
},
),
],
);
}
Widget buildResponsiveUploadField({
String? label, // 🔹 make optional
required String? hintText,
required void Function(String fileName, dynamic file) onFileSelected,
}) {
final isMobile = ResponsiveLayout.isMobile(context);
final uploadWidget = ThemedUploadField(
hintText: hintText ?? "Upload Documents",
txtwidth: isMobile ? null : MediaQuery.of(context).size.width * 0.26,
onFileSelected: onFileSelected,
);
if (isMobile) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (label != null && label.isNotEmpty) ...[ // only render if label is given
Text(label, style: _textStyle),
const SizedBox(height: 8),
],
uploadWidget,
const SizedBox(height: 16),
],
);
} else {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (label != null && label.isNotEmpty) ...[
Expanded(child: Text(label, style: _textStyle)),
const SizedBox(width: 10),
],
uploadWidget,
],
);
}
}
Widget buildResponsiveField({required String label, required Widget field}) {
final isMobile = ResponsiveLayout.isMobile(context);
if (isMobile) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: _textStyle),
const SizedBox(height: 8),
field,
const SizedBox(height: 16),
],
);
} else {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: Text(label, style: _textStyle)),
const SizedBox(width: 10),
field,
],
);
}
}
static const _textStyle = TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
);
}

View File

@ -0,0 +1,700 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
import '../../../../core/routing/routes.dart';
import '../../../../core/services/api_service.dart';
import '../../../../data/utils/Pagination.dart';
import '../../../layouts/main_layout.dart';
import '../../../layouts/responsive_layout.dart';
import '../../../providers/manager_provider.dart';
import '../../../themes/indicators/export_btn.dart';
import '../../../themes/indicators/search_field_theme.dart';
import '../../../widgets/custom_action_popup.dart';
class policylist extends ConsumerStatefulWidget {
const policylist({super.key});
@override
ConsumerState<policylist> createState() => policylistState();
}
class policylistState extends ConsumerState<policylist> {
int currentPage = 1;
int itemsPerPage = 10;
late ApiService apiService;
// List<Map<String, dynamic>> dataVal = [];
List<Map<String, dynamic>> getStaffData = [];
List<Map<String, dynamic>> originalData = [];
List<Map<String, dynamic>> filteredData = [];
bool isLoading = false;
@override
void initState() {
super.initState();
apiService = ApiService();
Future.microtask(() {
final id = ref.read(managerIdProvider);
final roleId = ref.read(userRoleProvider);
print("ENQroleId - $roleId");
if (id != null) {
getStaffList(id, roleId);
}
});
}
Future<void> getStaffList(int managerId, role) async {
print('getClaimList called MagId - $managerId - $role');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchPolicyList(managerId, role);
if (response['status'] == 'success') {
final data = response['data'];
print('getStaffListData - ${response['data']}');
setState(() {
if (data is List) {
// Already a list of maps
getStaffData = List<Map<String, dynamic>>.from(data);
} else if (data is Map) {
// Single object, wrap in a list
getStaffData = [Map<String, dynamic>.from(data)];
} else {
getStaffData = [];
}
// getStaffData = List<Map<String, dynamic>>.from(response['data']);
originalData = getStaffData;
filteredData = List.from(originalData);
// print('originalData - $getClaimPolicies');
});
} else {
getStaffData = [];
originalData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
List<dynamic> get _paginatedData {
// Sort descending by id first
final sortedData = [...filteredData]
..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
final startIndex = (currentPage - 1) * itemsPerPage;
final endIndex = (currentPage * itemsPerPage).clamp(0, sortedData.length);
return sortedData.sublist(startIndex, endIndex);
}
void filterData(String query) {
print("FilterDAta - $query");
setState(() {
filteredData = getStaffData.where((item) {
// final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive";
return (item['agent_name'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['reg_no'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['insurer_name'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['assigned_to_name'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['insured_name'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['premium_amount'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['payment_mode'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['updated_on'] ?? '').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['policy_number'] ?? '').toLowerCase().contains(query.toLowerCase());
}).toList();
});
}
final TextEditingController _searchStaffController = TextEditingController();
String _formatDate(String rawDate) {
try {
final dateTime = DateTime.parse(rawDate);
return DateFormat('dd/MM/yyyy HH:mm').format(dateTime); // 24-hour format
} catch (e) {
return rawDate; // fallback if parsing fails
}
}
List<Widget> _buildPopupMenuActions(BuildContext context, dynamic data) {
return [
GestureDetector(
onTap: () {
Navigator.pop(context);
print('EDITStaff - ${data['id']}');
dynamic id = data['id'];
// context.go('/staff/$id');
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.edit_sharp, color: Color(0xFF319718), size: 18),
SizedBox(width: 10),
Text('Edit'),
],
),
),
];
}
@override
Widget build(BuildContext context) {
return MainLayout(
title: "Policy",
body: Container(
// color: Colors.yellow.shade50,
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 30,
width: MediaQuery.of(context).size.width,
child: GestureDetector(
onTap: () {
context.go(AppRoutes.dashboard);
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Icon(
Icons.arrow_left_sharp,
size: 35,
color: Color(0xFF425B5B),
),
Text(
"Policy",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
SizedBox(height: 10),
Expanded(
child: Container(
// color: Colors.green,
// color: Colors.green.shade50,
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.all(8.0),
child: Column(
children: [
Container(
// height: 40,
// color: Colors.pink,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
ThemedSearchField(
hintText: 'Search',
backgroundColor: Color(0xFFF6F8F8),
onChanged: filterData,
controller: _searchStaffController,
txtwidth: ResponsiveLayout.isMobile(context)
? MediaQuery.of(context).size.width * 0.6
: MediaQuery.of(context).size.width * 0.2,
),
Spacer(),
ExportBtn(
sheetName: "Policy",
fileName: "Policy_list",
data: filteredData,
txt: !ResponsiveLayout.isMobile(context)
? true
: false,
headers: [
"reg_no",
"agent_name",
"assigned_to_name",
"insurer_name",
"insured_name",
"premium_amount",
"payment_mode",
"updated_on",
"status",
],
),
// SizedBox(width: 10),
// GestureDetector(
// onTap: () {
// // print('Export');
// },
// child: Container(
// padding: EdgeInsets.all(8.0),
// decoration: BoxDecoration(
// color: Color(0xFF425B5B),
// borderRadius: BorderRadius.circular(8.0),
// ),
// child: Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// Icon(Icons.add, color: Colors.white),
//
// if (!ResponsiveLayout.isMobile(context)) ...[
// SizedBox(width: 10),
//
// GestureDetector(
// onTap: () {
// // context.go(AppRoutes.agent / create);
// context.go('/staff/create');
// },
// child: Text(
// 'Create New Staff',
// style: TextStyle(
// color: Colors.white,
// fontWeight: FontWeight.w600,
// fontSize: 14,
// ),
// ),
// ),
// ],
// ],
// ),
// ),
// ),
],
),
),
SizedBox(height: 10),
if (!ResponsiveLayout.isMobile(context))
Container(
decoration: BoxDecoration(
color: Color(0xFFEDF6F5),
borderRadius: BorderRadius.circular(6),
),
padding: const EdgeInsets.symmetric(
vertical: 12,
horizontal: 16,
),
child: const Row(
children: [
Expanded(
flex: 2,
child: Text('Reg.No', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text(
'Agents',
style: _headerStyle,
),
),
Expanded(
flex: 2,
child: Text('Assigned To', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Insurer', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Insured Name', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Premium', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Payment Mode', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Policy Number', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Date', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Status', style: _headerStyle),
),
Expanded(
flex: 1,
child: Text('Action', style: _headerStyle),
),
],
),
),
Expanded(child: _buildDataTable(context)),
],
),
),
),
Container(
// height: 20,
width: MediaQuery.of(context).size.width,
// color: Colors.green.shade50,
child: PaginationControls(
currentPage: currentPage,
itemsPerPage: itemsPerPage,
// totalItems: dataVal.length,
totalItems: filteredData.length,
// activeColor: layoutColor, // your theme color
onPageChanged: (page) {
setState(() {
currentPage = page;
});
},
onItemsPerPageChanged: (items) {
setState(() {
itemsPerPage = items;
currentPage = 1;
});
},
),
),
],
),
),
);
}
Widget _buildDataTable(BuildContext context) {
if (filteredData.isEmpty) {
return const SizedBox(
height: 50,
child: Center(child: Text('No available data')),
);
}
final sortedData = [..._paginatedData];
return ListView.builder(
itemCount: ResponsiveLayout.isMobile(context)
? sortedData
.length // only cards for mobile
: sortedData.length + 1, // +1 for header in desktop
itemBuilder: (context, index) {
if (!ResponsiveLayout.isMobile(context) && index == 0) {
return _buildHeader();
}
final startIndex = (currentPage - 1) * itemsPerPage;
final item =
sortedData[index - (ResponsiveLayout.isMobile(context) ? 0 : 1)];
final sno = startIndex + index;
return !ResponsiveLayout.isMobile(context)
? _buildDataRow(item, sno)
: _buildDataCard(item, sno);
},
);
}
Widget _buildHeader() {
return SizedBox.shrink();
}
Widget _buildDataRow(Map<String, dynamic> item, sno) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
// margin: const EdgeInsets.only(top: 10),
decoration: BoxDecoration(
color: Colors.white,
// color: Color(0xFFE0F7F9),
border: const Border(
bottom: BorderSide(color: Color(0xFFEAEAEA), width: 1),
),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Expanded(flex: 2, child: Text('reg_no' ?? '-', style: _dataBold)),
Expanded(
flex: 2,
child: Text(
_formatDate(item['agent_name']) ?? '-',
style: _dataBold,
),
),
Expanded(
flex: 2,
child: Text(item['assigned_to_name'] ?? '-', style: _dataBold),
),
Expanded(
flex: 2,
child: Text(
item['insurer_name'] ?? '-',
style: _dataBold,
softWrap: true,
maxLines: 3,
),
),
Expanded(
flex: 2,
child: Text(
item['insured_name'] ?? '-',
style: _dataBold,
softWrap: true,
maxLines: 3,
),
),
Expanded(
flex: 2,
child: Text(
item['premium_amount'] ?? '-',
style: _dataBold,
softWrap: true,
maxLines: 3,
),
),
Expanded(
flex: 2,
child: Text(
item['payment_mode'] ?? '-',
style: _dataBold,
softWrap: true,
maxLines: 3,
),
),
Expanded(
flex: 2,
child: Text(
item['policy_number'] ?? '-',
style: _dataBold,
softWrap: true,
maxLines: 3,
),
),
Expanded(
flex: 2,
child: Text(
item['updated_on'] ?? '-',
style: _dataBold,
softWrap: true,
maxLines: 3,
),
),
Expanded(
flex: 2,
child: Text(item['status'] ?? '-', style: _dataBold),
),
Expanded(
flex: 1,
child: Row(
children: [
PopupMenuButton<int>(
color: Colors.white,
padding: EdgeInsets.zero,
offset: Offset(0, 30),
icon: Icon(
Icons.more_vert,
color: Color(0xFF475569),
size: 14,
),
itemBuilder: (context) => [
CustomPopupMenuEntry(
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 8,
vertical: 8,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: _buildPopupMenuActions(context, item),
),
),
),
],
),
],
),
),
],
),
);
}
Widget _buildDataCard(Map<String, dynamic> item, int sno) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 8),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: const Color(0xFFF6FEFD),
borderRadius: BorderRadius.circular(8.0),
border: Border.all(color: const Color(0xffD9EBE8)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(item['reg_no'] ?? '-', style: _headerStyle),
PopupMenuButton<int>(
color: Colors.white,
padding: EdgeInsets.zero,
offset: Offset(0, 30),
icon: Icon(Icons.more_vert, color: Color(0xFF475569), size: 14),
itemBuilder: (context) => [
CustomPopupMenuEntry(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: _buildPopupMenuActions(context, item),
),
),
),
],
),
],
),
const Divider(color: Color(0xffD9EBE8), thickness: 0.8),
// Company + Vehicle Reg No
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text("Company", style: _cardheaderStyle),
Text(
item['insurer_name'] ?? '-',
style: _cardBodyStyle,
maxLines: 3,
softWrap: true,
),
],
),
),
SizedBox(width: 5),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text("Status", style: _cardheaderStyle),
Text(
item['status'] ?? '-',
style: _cardBodyStyle,
maxLines: 2,
softWrap: true,
),
],
),
),
],
),
const SizedBox(height: 15),
// Created On + Remarks
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text("Received Date & Time", style: _cardheaderStyle),
Text(
_formatDate(item['created_on']) ?? '-',
style: _cardBodyStyle,
),
],
),
),
SizedBox(width: 5),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text("Remarks", style: _cardheaderStyle),
Text(
item['remarks'] ?? '-',
style: _cardBodyStyle,
maxLines: 3,
softWrap: true,
),
],
),
),
],
),
],
),
);
}
static final _dataBold = TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Color(0xFF000000),
);
static final _dataSub = TextStyle(
fontSize: 10,
fontWeight: FontWeight.w300,
color: Color(0xFF585757),
);
static const _headerStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
);
static const _cardheaderStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600,
fontSize: 12,
);
static const _cardBodyStyle = TextStyle(
color: Color(0xFF545454),
fontWeight: FontWeight.w400,
fontSize: 12,
);
}

View File

@ -0,0 +1,855 @@
import 'dart:io' as html;
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/cupertino.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 '../../../../core/routing/routes.dart';
import '../../../../core/services/api_service.dart';
import '../../../../data/services/auth_service.dart';
import '../../../../data/utils/Pagination.dart';
import '../../../../data/utils/validators.dart';
import '../../../layouts/main_layout.dart';
import '../../../layouts/responsive_layout.dart';
import '../../../providers/manager_provider.dart';
import '../../../themes/indicators/customizd_file_upload.dart';
import '../../../themes/indicators/text_field_theme.dart';
class QuotationScreen extends ConsumerStatefulWidget {
const QuotationScreen({super.key});
@override
ConsumerState<QuotationScreen> createState() => QuotationScreenState();
}
class QuotationScreenState extends ConsumerState<QuotationScreen> {
int currentPage = 0;
int itemsPerPage = 10;
List<Map<String, dynamic>> dataVal = [];
final TextEditingController _searchController = TextEditingController();
late ApiService apiService;
final _formKey = GlobalKey<FormState>();
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKey =
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
List<String> tabHeader = [
'name',
'email',
'mobile',
'code',
'address',
'regNo',
];
late String isActive = "1";
html.File? docUploadedFile;
// PlatformFile? passportFile;
String? selectedFileNames;
String? passportFileUrlFromApi;
String? selectedId;
bool isLoading = false;
bool isquotation = false;
Map<String, TextEditingController> controllers = {};
String? _token;
dynamic userId;
dynamic managerId;
List<Map<String, dynamic>> getVehicleTypeData = [];
List<Map<String, dynamic>> filteredVechicleData = [];
List<Map<String, dynamic>> getInsurersData = [];
List<Map<String, dynamic>> filteredInsurersData = [];
Map<String, dynamic> dataDetails() {
final data = {
"name": controllers["name"]?.text,
"email": controllers["email"]?.text,
"mobile": controllers["mobile"]?.text,
"address": controllers["address"]?.text,
"agent_code": controllers["code"]?.text,
"is_active": isActive,
"manager_id": managerId,
};
return data;
}
List<Map<String, dynamic>> getQuotationData = [];
List<Map<String, dynamic>> originalData = [];
List<Map<String, dynamic>> filteredData = [];
// bool isLoading = false;
@override
void initState() {
super.initState();
apiService = ApiService();
for (String field in tabHeader) {
controllers[field] = TextEditingController();
}
// updateData();
_initializeToken();
Future.microtask(() {
managerId = ref.watch(managerIdProvider);
userId = ref.watch(userIdProvider);
getQuotationList(managerId);
});
}
Future<void> _initializeToken() async {
_token = await AuthService.getToken();
print("APISERTOKEN - $_token");
}
Future<void> getQuotationList(int managerId) async {
print('getClaimList called MagId - $managerId');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchQuotationList(managerId);
if (response['status'] == 'success') {
print('quoationListData - ${response['data']}');
setState(() {
getQuotationData = List<Map<String, dynamic>>.from(response['data']);
originalData = getQuotationData;
filteredData = List.from(originalData);
// print('originalData - $getClaimPolicies');
});
} else {
getQuotationData = [];
originalData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
@override
Widget build(BuildContext context) {
return
MainLayout(
title: 'quotation',
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
Container(
height: 30,
width: MediaQuery.of(context).size.width,
child: GestureDetector(
onTap: () {
context.go(AppRoutes.dashboard);
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Icon(
Icons.arrow_left_sharp,
size: 35,
color: Color(0xFF425B5B),
),
Text(
"Quotation",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
SizedBox(height: 10),
//1ST SECTION
Container(
decoration: BoxDecoration(
color: const Color(0xFFEDF6F5),
borderRadius: BorderRadius.circular(10),
),
padding: const EdgeInsets.all(20),
child: LayoutBuilder(
builder: (context, constraints) {
final isMobile = constraints.maxWidth < 600; // breakpoint
if (isMobile) {
// 📱 MOBILE Column layout
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
registernumber(context),
const SizedBox(height: 16),
insurer(context),
const SizedBox(height: 16),
Wrap(
spacing: 12,
runSpacing: 8,
children: [
_downloadButton("Download RC"),
_downloadButton("Download ID Proof"),
_downloadButton("Download Previous Policy"),
],
),
],
);
} else {
// 💻 WEB Row layout
return Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(flex: 2, child: registernumber(context)),
const SizedBox(width: 20),
Expanded(flex: 2, child: insurer(context)),
const SizedBox(width: 20),
_downloadButton("Download RC"),
const SizedBox(width: 20),
_downloadButton("Download ID Proof"),
const SizedBox(width: 20),
_downloadButton("Download Previous Policy"),
],
);
}
},
),
),
const SizedBox(height: 20),
//2ND SECTION
Container(
// color: Colors.green,
decoration: BoxDecoration(
color: Color(0xffEDF6F5),
borderRadius: BorderRadius.circular(10.0),
),
width: MediaQuery.of(context).size.width,
// height: MediaQuery.of(context).size.height * 0.8,
padding: EdgeInsets.all(26.0),
child: Column(
children: [
SingleChildScrollView(child: buildFormFields(context)),
const SizedBox(height: 20),
//confirm button
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
// GestureDetector(
// onTap: () {
// // handleSave();
// },
// child: Container(
// padding: EdgeInsets.symmetric(
// horizontal: 45.0,
// vertical: 8,
// ),
//
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(8.0),
// color: Color(0xFF425B5B),
// ),
// child: Text(
// 'Reject',
// style: TextStyle(color: Colors.white),
// ),
// ),
// ),
//confirm button
GestureDetector(
onTap: () {
// handleSave();
},
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 45.0,
vertical: 8,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
color: Color(0xFF425B5B),
),
child: Text(
'Confirm',
style: TextStyle(color: Colors.white),
),
),
),
],
),
],
),
),
const SizedBox(height: 20),
//3RD SECTION (TABLE)
Container(
// color: Colors.green,
decoration: BoxDecoration(
color: Color(0xFFEDF6F5),
borderRadius: BorderRadius.circular(10.0),
),
width: MediaQuery.of(context).size.width,
// height: MediaQuery.of(context).size.height * 0.8,
padding: EdgeInsets.all(16.0),
child: Column(
children: [
// Text('datta')
_buildDataTable(context),
],
),
),
],
),
),
),
);
}
Widget _readonlyField(String label, String value) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: GoogleFonts.inter(fontSize: 13, fontWeight: FontWeight.w600)),
const SizedBox(height: 6),
Container(
padding: const EdgeInsets.symmetric(horizontal: 60, vertical: 14),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(6),
border: Border.all(color: Colors.grey.shade300),
),
child: Text(value, style: GoogleFonts.inter(fontSize: 14)),
),
],
);
}
Widget _downloadButton(String label) {
return ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF425B5B),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)),
),
onPressed: () {
// TODO: file download logic
},
icon: const Icon(Icons.download, size: 18),
label: Text(label, style: GoogleFonts.inter(fontSize: 13)),
);
}
Widget buildFormFields(BuildContext context) {
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// _buildResponsiveRow(
// context,
// buildName(context),
// buildInsusrer(context),
// ),
if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10),
_buildResponsiveRow(
context,
buildIdv(context),
buildPremiumAmnt(context),
),
if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10),
_buildResponsiveRow(
context,
buildPlanType(context),
buildDocuments(context),
),
// if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10),
// _buildResponsiveRow(
// context,
// buildAdditonalDocuments(context),
// buildRemarks(context),
// ),
],
),
);
}
Widget _buildResponsiveRow(
BuildContext context,
Widget first,
Widget second,
)
{
if (ResponsiveLayout.isMobile(context)) {
// Stack vertically
return Column(children: [first, const SizedBox(height: 2), second]);
} else {
// Place side by side
return Row(
children: [
Expanded(child: first),
const SizedBox(width: 25),
Expanded(child: second),
],
);
}
}
Widget registernumber(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Register Number',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
readOnly:true,
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget insurer(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Insurer',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
readOnly:true,
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget buildIdv(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('IDV',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
readOnly:true,
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget buildPremiumAmnt(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Premium Amount',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget buildPlanType(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Plan Type',style:_textStyle ,),
SizedBox(height: 10,),
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
]
);
}
Widget buildDocuments(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Quotation Documents ',
style: _textStyle,
),
const SizedBox(height: 10),
buildResponsiveUploadField(
hintText: selectedFileNames,
onFileSelected: (fileName, file) {
print("File picked: $fileName");
setState(() {
docUploadedFile = file;
});
},
),
],
);
}
Widget buildResponsiveUploadField({
String? label, // 🔹 make optional
required String? hintText,
required void Function(String fileName, dynamic file) onFileSelected,
}) {
final isMobile = ResponsiveLayout.isMobile(context);
final uploadWidget = ThemedUploadField(
hintText: hintText ?? "Upload Documents",
txtwidth: isMobile ? null : MediaQuery.of(context).size.width * 0.26,
onFileSelected: onFileSelected,
);
if (isMobile) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (label != null && label.isNotEmpty) ...[ // only render if label is given
Text(label, style: _textStyle),
const SizedBox(height: 8),
],
uploadWidget,
const SizedBox(height: 16),
],
);
} else {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (label != null && label.isNotEmpty) ...[
Expanded(child: Text(label, style: _textStyle)),
const SizedBox(width: 10),
],
uploadWidget,
],
);
}
}
Widget buildResponsiveField({required String label, required Widget field}) {
final isMobile = ResponsiveLayout.isMobile(context);
if (isMobile) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: _textStyle),
const SizedBox(height: 8),
field,
const SizedBox(height: 16),
],
);
} else {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: Text(label, style: _textStyle)),
const SizedBox(width: 10),
field,
],
);
}
}
Widget buildId(BuildContext context) {
return buildResponsiveField(
label: "Registration Number *",
field: ThemedFormField(
controller: controllers['regNo']!,
validator: (value) => Validators.requiredField(value, "regNo"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
);
}
Widget _buildDataTable(BuildContext context) {
if (filteredData.isEmpty) {
return const SizedBox(
height: 50,
child: Center(child: Text('No available data')),
);
}
final sortedData = [...filteredData]
..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
return SingleChildScrollView(
child: Column(
children: [
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: ResponsiveLayout.isMobile(context)
? sortedData
.length // only cards for mobile
: sortedData.length + 1, // +1 for header in desktop
itemBuilder: (context, index) {
if (!ResponsiveLayout.isMobile(context) && index == 0) {
return _buildHeader();
}
final startIndex = (currentPage - 1) * itemsPerPage;
final item =
sortedData[index -
(ResponsiveLayout.isMobile(context) ? 0 : 1)];
final sno = startIndex + index;
return !ResponsiveLayout.isMobile(context)
? _buildDataRow(item, sno)
: _buildDataCard(item, sno);
},
),
],
),
);
}
Widget _buildHeader() {
return Container(
decoration: BoxDecoration(
color: Color(0xFFEDF6F5),
borderRadius: BorderRadius.circular(6),
),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
child: const Row(
children: [
// Expanded(flex: 3, child: Text(' ', style: _headerStyle)),
Expanded(
flex: 3,
child: Text('Registration Number', style: _headerStyle),
),
Expanded(flex: 3, child: Text('Insurer', style: _headerStyle)),
Expanded(flex: 3, child: Text('IDV', style: _headerStyle)),
Expanded(flex: 3, child: Text('Plan Type', style: _headerStyle)),
Expanded(flex: 3, child: Text('Premium Amount', style: _headerStyle)),
// Expanded(flex: 1, child: Text('Status', style: _headerStyle)),
],
),
);
}
Widget _buildDataRow(Map<String, dynamic> item, sno) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 16),
// margin: const EdgeInsets.only(top: 10),
decoration: BoxDecoration(
color: Colors.white,
// color: Color(0xFFE0F7F9),
border: const Border(
bottom: BorderSide(color: Color(0xFFEAEAEA), width: 1),
),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
// Single-select checkbox
// Expanded(
// flex: 1,
// child: Checkbox(
// value: selectedId == item['id'], // only selected row is checked
// onChanged: (val) {
// setState(() {
// if (val == true) {
// selectedId = item['id']; // select this row
// isquotation = true;
// } else {
// selectedId = null;
// isquotation = false; // unselect
// }
// });
// print("Selected row id: $selectedId");
// },
// ),
// ),
Expanded(flex: 2, child: Text(item['id'] ?? '-', style: _dataBold)),
Expanded(
flex: 2,
child: Text(item['email'] ?? '-', style: _dataBold),
),
Expanded(
flex: 2,
child: Text(item['mobile'] ?? '-', style: _dataBold),
),
Expanded(
flex: 2,
child: Text(item['premium_amount'] ?? '-', style: _dataBold),
),
Expanded(
flex: 2,
child: Text(
item['premium_amount'] ?? '-',
style: _dataBold,
),
),
// Expanded(
// flex: 1,
// child: Text(
// item['status'] ?? '-',
// style: TextStyle(
// fontSize: 14,
//
// fontWeight: FontWeight.w400,
// color: item['status'] == 'Accepted' ? Colors.green : Colors.red,
// ),
// ),
// ),
],
),
);
}
Widget _buildDataCard(Map<String, dynamic> item, int sno) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 8),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: const Color(0xFFF6FEFD),
borderRadius: BorderRadius.circular(8.0),
border: Border.all(color: const Color(0xffD9EBE8)),
),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Company + Vehicle Reg No
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text("New India", style: _cardBodyStyle),
const Text("TN64V3456", style: _cardheaderStyle),
const Text("Status: Rejected", style: _cardBodyStyle),
],
),
),
SizedBox(width: 5),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text("Comprehensive", style: _cardBodyStyle),
const Text("IDV:₹145000", style: _cardBodyStyle),
const Text("₹1000", style: _cardheaderStyle),
],
),
),
],
),
],
),
),
],
),
);
}
static final _dataBold = TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Color(0xFF000000),
);
static final _dataSub = TextStyle(
fontSize: 10,
fontWeight: FontWeight.w300,
color: Color(0xFF585757),
);
static const _headerStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
);
static const _textStyle = TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
);
static const _cardheaderStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600,
fontSize: 12,
);
static const _cardBodyStyle = TextStyle(
color: Color(0xFF545454),
fontWeight: FontWeight.w400,
fontSize: 12,
);
}

View File

@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../core/routing/routes.dart';
import 'package:go_router/go_router.dart';
import '../providers/manager_provider.dart';
import '../providers/userRoleProvider.dart';
import 'drawerContentWrapper.dart';
@ -70,6 +71,19 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
],
if (key == 'Reports') ...[
GestureDetector(
onTap: () {
context.go(AppRoutes.claimlist);
},
child: const Text(
"Claims",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
),
),
),
const SizedBox(height: 5),
GestureDetector(
onTap: () {
context.go(AppRoutes.enquiryLst);
@ -85,10 +99,10 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
const SizedBox(height: 5),
GestureDetector(
onTap: () {
print("Bf clicked");
context.go(AppRoutes.endosement);
},
child: const Text(
"Claims",
"Endorsement",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
@ -98,10 +112,39 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
const SizedBox(height: 5),
GestureDetector(
onTap: () {
print("Bf clicked");
context.go(AppRoutes.policylist);
},
child: const Text(
"Endorsement",
"Policy",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
),
),
),
const SizedBox(height: 5),
GestureDetector(
onTap: () {
context.go(AppRoutes.quotation);
},
child: const Text(
"Quotation",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
),
),
),
const SizedBox(height: 5),
GestureDetector(
onTap: () {
context.go(AppRoutes.policy);
},
child: const Text(
"Policy Form",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
@ -172,13 +215,31 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
},
),
DrawerLabel("Reports"),
// DrawerContentWrapper(
// child: IconButton(
// onPressed: () {
// // context.go('/tabEnquiry/tab');
// ref.read(enquiryIdProvider.notifier).state = 'tab';
// context.go(AppRoutes.tabEnquiry);
// },
// icon: Icon(Icons.list_alt_rounded, size: 30, color: Colors.black),
// ),
// ),
DrawerContentWrapper(
child: IconButton(
onPressed: () {
context.go(AppRoutes.tabEnquiry);
child: Consumer(
builder: (context, ref, _) {
return IconButton(
onPressed: () {
ref.read(enquiryIdProvider.notifier).state = null;
context.go(AppRoutes.tabEnquiry);
},
icon: const Icon(
Icons.list_alt_rounded,
size: 30,
color: Colors.black,
),
);
},
icon: Icon(Icons.list_alt_rounded, size: 30, color: Colors.black),
),
),

View File

@ -692,26 +692,26 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
url: "https://pub.dev"
source: hosted
version: "11.0.2"
version: "10.0.9"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
url: "https://pub.dev"
source: hosted
version: "3.0.10"
version: "3.0.9"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
version: "3.0.1"
lints:
dependency: transitive
description:
@ -732,10 +732,10 @@ packages:
dependency: transitive
description:
name: local_auth_android
sha256: "1ee0e63fb8b5c6fa286796b5fb1570d256857c2f4a262127e728b36b80a570cf"
sha256: "48924f4a8b3cc45994ad5993e2e232d3b00788a305c1bf1c7db32cef281ce9a3"
url: "https://pub.dev"
source: hosted
version: "1.0.53"
version: "1.0.52"
local_auth_darwin:
dependency: transitive
description:
@ -1217,10 +1217,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
url: "https://pub.dev"
source: hosted
version: "0.7.6"
version: "0.7.4"
toastification:
dependency: "direct main"
description:
@ -1273,10 +1273,10 @@ packages:
dependency: transitive
description:
name: url_launcher_android
sha256: "07cffecb7d68cbc6437cd803d5f11a86fe06736735c3dfe46ff73bcb0f958eed"
sha256: "81777b08c498a292d93ff2feead633174c386291e35612f8da438d6e92c4447e"
url: "https://pub.dev"
source: hosted
version: "6.3.21"
version: "6.3.20"
url_launcher_ios:
dependency: transitive
description:
@ -1337,18 +1337,18 @@ packages:
dependency: transitive
description:
name: vector_math
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
version: "2.1.4"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
url: "https://pub.dev"
source: hosted
version: "15.0.2"
version: "15.0.0"
watcher:
dependency: transitive
description:
@ -1414,5 +1414,5 @@ packages:
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.9.0 <4.0.0"
flutter: ">=3.35.0"
dart: ">=3.8.1 <4.0.0"
flutter: ">=3.32.0"