UI_Enq_Tabs UI_Staff_Web
This commit is contained in:
parent
f107692905
commit
720a27985a
File diff suppressed because one or more lines are too long
@ -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 {
|
||||
|
||||
@ -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';
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
52
lib/presentation/screens/Enquiry/enquiry/policy_popup.dart
Normal file
52
lib/presentation/screens/Enquiry/enquiry/policy_popup.dart
Normal 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)),
|
||||
);
|
||||
}
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@ -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);
|
||||
// }
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
);
|
||||
}
|
||||
@ -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,
|
||||
);
|
||||
}
|
||||
@ -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;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
761
lib/presentation/screens/staff/policy/policy.dart
Normal file
761
lib/presentation/screens/staff/policy/policy.dart
Normal 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,
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
700
lib/presentation/screens/staff/policy/policy_list.dart
Normal file
700
lib/presentation/screens/staff/policy/policy_list.dart
Normal 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,
|
||||
);
|
||||
}
|
||||
855
lib/presentation/screens/staff/quotations/quotation.dart
Normal file
855
lib/presentation/screens/staff/quotations/quotation.dart
Normal 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,
|
||||
);
|
||||
}
|
||||
@ -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),
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
36
pubspec.lock
36
pubspec.lock
@ -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"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user