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/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:nhance_partner/core/routing/routes.dart';
|
import 'package:nhance_partner/core/routing/routes.dart';
|
||||||
import 'package:nhance_partner/presentation/screens/Enquiry/enquiryList.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/UserManagement/Profile/profile_web.dart';
|
||||||
import 'package:nhance_partner/presentation/screens/claims/claimsList.dart';
|
|
||||||
import 'package:nhance_partner/presentation/screens/dashboard/dashboard.dart';
|
import 'package:nhance_partner/presentation/screens/dashboard/dashboard.dart';
|
||||||
import '../../data/services/auth_service.dart';
|
import '../../data/services/auth_service.dart';
|
||||||
|
import '../../presentation/providers/manager_provider.dart';
|
||||||
import '../../presentation/screens/Enquiry/enquiry/tabs.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/agent.dart';
|
||||||
import '../../presentation/screens/UserManagement/Agent/agentList.dart';
|
import '../../presentation/screens/UserManagement/Agent/agentList.dart';
|
||||||
import '../../presentation/screens/UserManagement/Profile/profile_mobile.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/home/home_screen.dart';
|
||||||
import '../../presentation/screens/login/login_screen.dart';
|
import '../../presentation/screens/login/login_screen.dart';
|
||||||
import '../../presentation/screens/splash/splash_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(
|
final GoRouter appRouter = GoRouter(
|
||||||
initialLocation: AppRoutes.home,
|
initialLocation: AppRoutes.home,
|
||||||
@ -85,9 +91,59 @@ final GoRouter appRouter = GoRouter(
|
|||||||
builder: (context, state) => const EnquiryList(),
|
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(
|
GoRoute(
|
||||||
path: AppRoutes.tabEnquiry,
|
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 {
|
redirect: (context, state) async {
|
||||||
|
|||||||
@ -10,4 +10,10 @@ class AppRoutes {
|
|||||||
static const staff = '/staff/:id';
|
static const staff = '/staff/:id';
|
||||||
static const String enquiryLst = '/enquiryLst';
|
static const String enquiryLst = '/enquiryLst';
|
||||||
static const String tabEnquiry = '/tabEnquiry';
|
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;
|
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 ------------------------------------------------
|
//------------------------------------ Quotation ------------------------------------------------
|
||||||
|
|
||||||
Future<Map<String, dynamic>> fetchQuotationList(int managerId) async {
|
Future<Map<String, dynamic>> fetchQuotationList(int managerId) async {
|
||||||
@ -425,6 +441,114 @@ class ApiService {
|
|||||||
return response;
|
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 ----------------------------------------------
|
// --------------------------------- MASTER DATA ----------------------------------------------
|
||||||
|
|
||||||
Future<Map<String, dynamic>> fetchMasterDropDown(String val) async {
|
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 managerIdProvider = StateProvider<int?>((ref) => null);
|
||||||
final userIdProvider = 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:go_router/go_router.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:nhance_partner/presentation/layouts/responsive_layout.dart';
|
import 'package:nhance_partner/presentation/layouts/responsive_layout.dart';
|
||||||
|
import 'package:toastification/toastification.dart';
|
||||||
import 'package:universal_html/html.dart' as html;
|
import 'package:universal_html/html.dart' as html;
|
||||||
|
|
||||||
import '../../../../core/config/env.dart';
|
import '../../../../core/config/env.dart';
|
||||||
@ -13,6 +14,7 @@ import '../../../../core/routing/routes.dart';
|
|||||||
import '../../../../core/services/api_service.dart';
|
import '../../../../core/services/api_service.dart';
|
||||||
import '../../../../data/services/auth_service.dart';
|
import '../../../../data/services/auth_service.dart';
|
||||||
import '../../../../data/utils/Pagination.dart';
|
import '../../../../data/utils/Pagination.dart';
|
||||||
|
import '../../../../data/utils/toastNotification.dart';
|
||||||
import '../../../../data/utils/validators.dart';
|
import '../../../../data/utils/validators.dart';
|
||||||
import '../../../layouts/main_layout.dart';
|
import '../../../layouts/main_layout.dart';
|
||||||
import '../../../providers/manager_provider.dart';
|
import '../../../providers/manager_provider.dart';
|
||||||
@ -25,7 +27,9 @@ import '../../../themes/indicators/upload_doc_theme.dart'
|
|||||||
hide ThemedUploadField;
|
hide ThemedUploadField;
|
||||||
|
|
||||||
class EnquiryTab extends ConsumerStatefulWidget {
|
class EnquiryTab extends ConsumerStatefulWidget {
|
||||||
const EnquiryTab({super.key});
|
String? id;
|
||||||
|
final Map<String, dynamic>? data;
|
||||||
|
EnquiryTab({super.key, this.data, this.id});
|
||||||
@override
|
@override
|
||||||
ConsumerState<EnquiryTab> createState() => EnquiryTabState();
|
ConsumerState<EnquiryTab> createState() => EnquiryTabState();
|
||||||
}
|
}
|
||||||
@ -84,15 +88,6 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
|
|||||||
List<Map<String, dynamic>> filteredInsurersData = [];
|
List<Map<String, dynamic>> filteredInsurersData = [];
|
||||||
|
|
||||||
Map<String, dynamic> dataDetails() {
|
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 = {
|
final data = {
|
||||||
"agent_id": 1,
|
"agent_id": 1,
|
||||||
"name": controllers["name"]?.text,
|
"name": controllers["name"]?.text,
|
||||||
@ -121,6 +116,11 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
|
|||||||
controllers[field] = TextEditingController();
|
controllers[field] = TextEditingController();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (widget.data != null) {
|
||||||
|
print("EnQ has Data");
|
||||||
|
} else {
|
||||||
|
print("EnQ has Data 1");
|
||||||
|
}
|
||||||
_initializeToken();
|
_initializeToken();
|
||||||
Future.microtask(() {
|
Future.microtask(() {
|
||||||
managerId = ref.watch(managerIdProvider);
|
managerId = ref.watch(managerIdProvider);
|
||||||
@ -203,69 +203,65 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updateData() async {
|
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!);
|
||||||
dynamic response = await apiService.findSingleEnquiryData(1);
|
// final enq = response['data'];
|
||||||
// dynamic response = await apiService.findSingleAgentData(widget.id!);
|
final data = widget.data;
|
||||||
final data = response['data'];
|
print("updateDataEnq - $data");
|
||||||
print("updateData - ${response['data']}");
|
|
||||||
|
|
||||||
if (data == null) return;
|
if (data == null) return;
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
// selectedId = widget.id;
|
selectedId = widget.id;
|
||||||
controllers['name']?.text = data['name'] ?? '';
|
controllers['name']?.text = data['name'] ?? '';
|
||||||
controllers['email']?.text = data['email'] ?? '';
|
controllers['email']?.text = data['email'] ?? '';
|
||||||
controllers['mobile']?.text = data['mobile'] ?? '';
|
controllers['mobile']?.text = data['mobile'] ?? '';
|
||||||
controllers['regNo']?.text = data['reg_no'] ?? '';
|
controllers['regNo']?.text = data['reg_no'] ?? '';
|
||||||
controllers['remarks']?.text = data['remarks'] ?? '';
|
controllers['remarks']?.text = data['remarks'] ?? '';
|
||||||
isActive = data["is_active"];
|
isActive = data["is_active"];
|
||||||
// selectedVehicleType = data['vehicle_type_id'] ?? '2';
|
selectedVehicleType = data['vehicle_type_id'] ?? '';
|
||||||
selectedVehicleTypeId = 2;
|
selectedInsurer = data['insurer_id'] ?? '';
|
||||||
selectedInsurer = data['insurer_id'] ?? '3';
|
|
||||||
|
|
||||||
String? apiDocPath = data["rc_file_name"];
|
// RC FILE
|
||||||
if (apiDocPath != null && apiDocPath.isNotEmpty) {
|
String? rcPath = data["rc_file_name"];
|
||||||
print('apiDocPath - $apiDocPath');
|
if (rcPath != null && rcPath.isNotEmpty) {
|
||||||
selectedRCFile = apiDocPath.split('/').last;
|
selectedRCFile = rcPath.split('/').last; // UI filename
|
||||||
print('selectedRCFile - $selectedRCFile');
|
rcFileUrlFromApi = rcPath; // API download URL
|
||||||
rcFileUrlFromApi = apiDocPath;
|
docUploadedRCFile =
|
||||||
print('rcFileUrlFromApi - $rcFileUrlFromApi');
|
rcFileUrlFromApi as PlatformFile?; // user has not re-uploaded yet
|
||||||
docUploadedRCFile = null;
|
|
||||||
} else {
|
} else {
|
||||||
selectedRCFile = null;
|
selectedRCFile = null; // no UI file shown
|
||||||
docUploadedRCFile = null;
|
|
||||||
rcFileUrlFromApi = null;
|
rcFileUrlFromApi = null;
|
||||||
|
docUploadedRCFile = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String? apiDocPathRC = data["id_proof_file_name"];
|
// ID PROOF FILE
|
||||||
if (apiDocPathRC != null && apiDocPathRC.isNotEmpty) {
|
String? idProofPath = data["id_proof_file_name"];
|
||||||
print('apiDocPathRC - $apiDocPathRC');
|
if (idProofPath != null && idProofPath.isNotEmpty) {
|
||||||
selectedIdProof = apiDocPathRC.split('/').last;
|
selectedIdProof = idProofPath.split('/').last;
|
||||||
print('selectedIdProof - $selectedIdProof');
|
idProofFileUrlFromApi = idProofPath; // ✅ FIXED → correct variable
|
||||||
prevPolicyFileUrlFromApi = apiDocPathRC;
|
docUploadedIDProof = idProofFileUrlFromApi as PlatformFile?;
|
||||||
print('prevPolicyFileUrlFromApi - $prevPolicyFileUrlFromApi');
|
|
||||||
docUploadedIDProof = null;
|
|
||||||
} else {
|
} else {
|
||||||
selectedIdProof = null;
|
selectedIdProof = null;
|
||||||
|
idProofFileUrlFromApi = null;
|
||||||
docUploadedIDProof = null;
|
docUploadedIDProof = null;
|
||||||
prevPolicyFileUrlFromApi = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String? apiDocPathPrevPolicy = data["previous_policy_file_name"];
|
// PREVIOUS POLICY FILE
|
||||||
if (apiDocPathPrevPolicy != null && apiDocPathPrevPolicy.isNotEmpty) {
|
String? prevPolicyPath = data["previous_policy_file_name"];
|
||||||
print('apiDocPathPrevPolicy - $apiDocPathPrevPolicy');
|
if (prevPolicyPath != null && prevPolicyPath.isNotEmpty) {
|
||||||
selectedPrevPolicy = apiDocPathPrevPolicy.split('/').last;
|
selectedPrevPolicy = prevPolicyPath.split('/').last;
|
||||||
print('selectedPrevPolicy - $selectedPrevPolicy');
|
prevPolicyFileUrlFromApi =
|
||||||
idProofFileUrlFromApi = apiDocPathPrevPolicy;
|
prevPolicyPath; // ✅ FIXED → correct variable
|
||||||
print('idProofFileUrlFromApi - $idProofFileUrlFromApi');
|
docUploadedPrevPolicy = prevPolicyFileUrlFromApi as PlatformFile?;
|
||||||
docUploadedPrevPolicy = null;
|
|
||||||
} else {
|
} else {
|
||||||
selectedPrevPolicy = null;
|
selectedPrevPolicy = null;
|
||||||
|
prevPolicyFileUrlFromApi = null;
|
||||||
docUploadedPrevPolicy = null;
|
docUploadedPrevPolicy = null;
|
||||||
idProofFileUrlFromApi = null;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> handleSave() async {
|
Future<void> handleSave() async {
|
||||||
if (!_formKey.currentState!.validate()) return;
|
if (!_formKey.currentState!.validate()) return;
|
||||||
@ -283,6 +279,59 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> attachFiles(http.MultipartRequest request) async {
|
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 {
|
Future<void> addFile(PlatformFile? file, String fieldName) async {
|
||||||
if (file == null) return;
|
if (file == null) return;
|
||||||
try {
|
try {
|
||||||
@ -313,14 +362,16 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> createUserData(Map<String, dynamic> userData) async {
|
Future<void> createUserData(Map<String, dynamic> userData) async {
|
||||||
// final bool isUpdating = widget.id != null && widget.id != 'create';
|
final bool isUpdating =
|
||||||
// final id = widget.id;
|
widget.data != null && widget.id != 'tab' && widget.id != 'null';
|
||||||
final bool isUpdating = false;
|
final id = widget.id;
|
||||||
|
print('UPDId- $id');
|
||||||
|
|
||||||
|
// final bool isUpdating = false;
|
||||||
final uri = Uri.parse(
|
final uri = Uri.parse(
|
||||||
// isUpdating
|
isUpdating
|
||||||
// ? '${Env.apiUrl}agent/updateAgent'
|
? '${Env.apiUrl}enquiry/updateEnquiry'
|
||||||
// : '${Env.apiUrl}agent/createAgent',
|
: '${Env.apiUrl}enquiry/createEnquiry',
|
||||||
'${Env.apiUrl}enquiry/createEnquiry',
|
|
||||||
);
|
);
|
||||||
if (_token == null) {
|
if (_token == null) {
|
||||||
throw Exception('Token not found. Please log in.');
|
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 updating, spoof the method Laravel-style
|
||||||
if (isUpdating) {
|
if (isUpdating) {
|
||||||
// request.fields['id'] = id!;
|
request.fields['id'] = id!;
|
||||||
request.fields['updated_by'] = userId!.toString();
|
request.fields['updated_by'] = userId!.toString();
|
||||||
} else {
|
} else {
|
||||||
request.fields['created_by'] = userId!.toString();
|
request.fields['created_by'] = userId!.toString();
|
||||||
@ -370,7 +421,7 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
|
|||||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||||
// dispose();
|
// dispose();
|
||||||
print("✅ Agent submitted successfully!");
|
print("✅ Agent submitted successfully!");
|
||||||
|
ToastHelper.showSuccessToast(context, 'Saved Enquiry');
|
||||||
print("Response: ${response.body}");
|
print("Response: ${response.body}");
|
||||||
context.go(AppRoutes.tabEnquiry);
|
context.go(AppRoutes.tabEnquiry);
|
||||||
} else {
|
} else {
|
||||||
@ -532,40 +583,41 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildResponsiveUploadField({
|
// Widget buildResponsiveUploadField({
|
||||||
required String label,
|
// required String label,
|
||||||
required String? hintText,
|
// required String? hintText,
|
||||||
required void Function(String fileName, dynamic file) onFileSelected,
|
// required void Function(String fileName, dynamic file) onFileSelected,
|
||||||
}) {
|
// })
|
||||||
final isMobile = ResponsiveLayout.isMobile(context);
|
// {
|
||||||
|
// final isMobile = ResponsiveLayout.isMobile(context);
|
||||||
final uploadWidget = ThemedUploadField(
|
//
|
||||||
hintText: hintText ?? "Upload Document",
|
// final uploadWidget = ThemedUploadField(
|
||||||
txtwidth: MediaQuery.of(context).size.width * 0.26,
|
// hintText: hintText ?? "Upload Document",
|
||||||
onFileSelected: onFileSelected,
|
// txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||||
);
|
// onFileSelected: onFileSelected,
|
||||||
|
// );
|
||||||
if (isMobile) {
|
//
|
||||||
return Column(
|
// if (isMobile) {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
// return Column(
|
||||||
children: [
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
Text(label, style: _textStyle),
|
// children: [
|
||||||
const SizedBox(height: 8),
|
// Text(label, style: _textStyle),
|
||||||
uploadWidget,
|
// const SizedBox(height: 8),
|
||||||
const SizedBox(height: 16),
|
// uploadWidget,
|
||||||
],
|
// const SizedBox(height: 16),
|
||||||
);
|
// ],
|
||||||
} else {
|
// );
|
||||||
return Row(
|
// } else {
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
// return Row(
|
||||||
children: [
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
Expanded(child: Text(label, style: _textStyle)),
|
// children: [
|
||||||
const SizedBox(width: 10),
|
// Expanded(child: Text(label, style: _textStyle)),
|
||||||
uploadWidget,
|
// const SizedBox(width: 10),
|
||||||
],
|
// uploadWidget,
|
||||||
);
|
// ],
|
||||||
}
|
// );
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
Widget buildName(BuildContext context) {
|
Widget buildName(BuildContext context) {
|
||||||
return buildResponsiveField(
|
return buildResponsiveField(
|
||||||
@ -621,8 +673,9 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
|
|||||||
|
|
||||||
Widget buildVehicleType(BuildContext context) {
|
Widget buildVehicleType(BuildContext context) {
|
||||||
// Find the matching map from your list
|
// Find the matching map from your list
|
||||||
|
|
||||||
Map<String, dynamic>? selectedVehicle = filteredVechicleData.firstWhere(
|
Map<String, dynamic>? selectedVehicle = filteredVechicleData.firstWhere(
|
||||||
(item) => item['id'] == selectedVehicleTypeId,
|
(item) => item['id'].toString() == selectedVehicleType,
|
||||||
orElse: () => {},
|
orElse: () => {},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -698,6 +751,10 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget buildInsurer(BuildContext context) {
|
Widget buildInsurer(BuildContext context) {
|
||||||
|
Map<String, dynamic>? selectedInsurerd = filteredInsurersData.firstWhere(
|
||||||
|
(item) => item['id'].toString() == selectedInsurer,
|
||||||
|
orElse: () => {},
|
||||||
|
);
|
||||||
return buildResponsiveField(
|
return buildResponsiveField(
|
||||||
label: "Insurer",
|
label: "Insurer",
|
||||||
field: Container(
|
field: Container(
|
||||||
@ -708,7 +765,7 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
|
|||||||
// height: 40,
|
// height: 40,
|
||||||
child: DropdownSearch<Map<String, dynamic>>(
|
child: DropdownSearch<Map<String, dynamic>>(
|
||||||
key: dropDownKeyInsurer,
|
key: dropDownKeyInsurer,
|
||||||
selectedItem: null,
|
selectedItem: selectedInsurerd.isNotEmpty ? selectedInsurerd : null,
|
||||||
items: (filter, infiniteScrollProps) {
|
items: (filter, infiniteScrollProps) {
|
||||||
return filteredInsurersData;
|
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) {
|
Widget buildUploadRCDocument(BuildContext context) {
|
||||||
return buildResponsiveUploadField(
|
return buildResponsiveUploadField(
|
||||||
label: "Upload RC Document",
|
label: "Upload RC Document",
|
||||||
hintText: selectedRCFile,
|
hintText: selectedRCFile,
|
||||||
onFileSelected: (fileName, file) {
|
onFileSelected: (fileName, file) {
|
||||||
print("File picked: $fileName");
|
|
||||||
setState(() {
|
setState(() {
|
||||||
docUploadedRCFile = file;
|
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) {
|
Widget buildUploadIDDocument(BuildContext context) {
|
||||||
return buildResponsiveUploadField(
|
return buildResponsiveUploadField(
|
||||||
label: "Upload ID Proof",
|
label: "Upload ID Proof",
|
||||||
hintText: selectedIdProof,
|
hintText: selectedIdProof,
|
||||||
onFileSelected: (fileName, file) {
|
onFileSelected: (fileName, file) {
|
||||||
print("File picked: $fileName");
|
|
||||||
setState(() {
|
setState(() {
|
||||||
docUploadedIDProof = file;
|
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) {
|
Widget buildUploadPolicyDocument(BuildContext context) {
|
||||||
return buildResponsiveUploadField(
|
return buildResponsiveUploadField(
|
||||||
label: "Upload Previous Policy",
|
label: "Upload Previous Policy",
|
||||||
hintText: selectedPrevPolicy,
|
hintText: selectedPrevPolicy,
|
||||||
onFileSelected: (fileName, file) {
|
onFileSelected: (fileName, file) {
|
||||||
print("File picked: $fileName");
|
|
||||||
setState(() {
|
setState(() {
|
||||||
docUploadedPrevPolicy = file;
|
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/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.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 '../../../../core/services/api_service.dart';
|
||||||
import '../../../../data/services/auth_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';
|
import '../../../themes/indicators/text_field_theme.dart';
|
||||||
|
|
||||||
class PolicyTab extends ConsumerStatefulWidget {
|
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
|
@override
|
||||||
ConsumerState<PolicyTab> createState() => PolicyTabState();
|
ConsumerState<PolicyTab> createState() => PolicyTabState();
|
||||||
}
|
}
|
||||||
@ -40,6 +44,15 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
|
|||||||
'code',
|
'code',
|
||||||
'address',
|
'address',
|
||||||
'regNo',
|
'regNo',
|
||||||
|
|
||||||
|
'regNum',
|
||||||
|
'insurer',
|
||||||
|
'idv',
|
||||||
|
'insurerName',
|
||||||
|
'policyNo',
|
||||||
|
'paymentMode',
|
||||||
|
'premAmount',
|
||||||
|
'planType',
|
||||||
];
|
];
|
||||||
|
|
||||||
Map<String, TextEditingController> controllers = {};
|
Map<String, TextEditingController> controllers = {};
|
||||||
@ -77,12 +90,15 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final response = await apiService.fetchQuotationList(managerId);
|
// final response = await apiService.fetchQuotationList(managerId);
|
||||||
|
|
||||||
if (response['status'] == 'success') {
|
if (widget.data != null) {
|
||||||
print('quoationListData - ${response['data']}');
|
final data = List<Map<String, dynamic>>.from(widget.data as Iterable);
|
||||||
|
|
||||||
|
print('policyListData - ${widget.data}');
|
||||||
setState(() {
|
setState(() {
|
||||||
getQuotationData = List<Map<String, dynamic>>.from(response['data']);
|
getQuotationData = data;
|
||||||
|
// getQuotationData = List<Map<String, dynamic>>.from(response['data']);
|
||||||
originalData = getQuotationData;
|
originalData = getQuotationData;
|
||||||
filteredData = List.from(originalData);
|
filteredData = List.from(originalData);
|
||||||
// print('originalData - $getClaimPolicies');
|
// print('originalData - $getClaimPolicies');
|
||||||
@ -120,6 +136,80 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
|
|||||||
padding: EdgeInsets.all(26.0),
|
padding: EdgeInsets.all(26.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
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)),
|
SingleChildScrollView(child: buildFormFields(context)),
|
||||||
|
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
@ -159,9 +249,18 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text('', style: _headerStyle),
|
Container(child: buildClaimTable()),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {},
|
onPressed: () {
|
||||||
|
showAddDialog(
|
||||||
|
context: context,
|
||||||
|
title: "Claim",
|
||||||
|
onSubmit: (value) {
|
||||||
|
print("New Claim: $value");
|
||||||
|
// update claim list here
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
icon: Icon(Icons.add),
|
icon: Icon(Icons.add),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -189,9 +288,18 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text('', style: _headerStyle),
|
Container(child: buildEndrosmentTable()),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {},
|
onPressed: () {
|
||||||
|
showAddDialog(
|
||||||
|
context: context,
|
||||||
|
title: "Endorsement",
|
||||||
|
onSubmit: (value) {
|
||||||
|
print("New Claim: $value");
|
||||||
|
// update claim list here
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
icon: Icon(Icons.add),
|
icon: Icon(Icons.add),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -302,7 +410,7 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
|
|||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Expanded(child: Text(label, style: _textStyle)),
|
Text(label, style: _textStyle),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
field,
|
field,
|
||||||
const SizedBox(height: 16),
|
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(
|
static const _headerStyle = TextStyle(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
|||||||
@ -1,10 +1,15 @@
|
|||||||
|
import 'dart:convert';
|
||||||
import 'dart:io' as html;
|
import 'dart:io' as html;
|
||||||
import 'package:dropdown_search/dropdown_search.dart';
|
import 'package:dropdown_search/dropdown_search.dart';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.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 '../../../../core/services/api_service.dart';
|
||||||
import '../../../../data/services/auth_service.dart';
|
import '../../../../data/services/auth_service.dart';
|
||||||
|
import '../../../../data/utils/toastNotification.dart';
|
||||||
import '../../../../data/utils/validators.dart';
|
import '../../../../data/utils/validators.dart';
|
||||||
import '../../../layouts/responsive_layout.dart';
|
import '../../../layouts/responsive_layout.dart';
|
||||||
import '../../../providers/manager_provider.dart';
|
import '../../../providers/manager_provider.dart';
|
||||||
@ -15,7 +20,10 @@ import '../../../themes/indicators/upload_doc_theme.dart'
|
|||||||
hide ThemedUploadField;
|
hide ThemedUploadField;
|
||||||
|
|
||||||
class QuotationTab extends ConsumerStatefulWidget {
|
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
|
@override
|
||||||
ConsumerState<QuotationTab> createState() => QuotationTabState();
|
ConsumerState<QuotationTab> createState() => QuotationTabState();
|
||||||
}
|
}
|
||||||
@ -34,19 +42,25 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
|
|||||||
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
||||||
|
|
||||||
List<String> tabHeader = [
|
List<String> tabHeader = [
|
||||||
'name',
|
'regNum',
|
||||||
'email',
|
'insurer',
|
||||||
'mobile',
|
'idv',
|
||||||
'code',
|
'premAmount',
|
||||||
'address',
|
'planType',
|
||||||
'regNo',
|
'addit_doc',
|
||||||
|
'remarks',
|
||||||
|
|
||||||
|
// 'mobile',
|
||||||
|
// 'code',
|
||||||
|
// 'address',
|
||||||
|
// 'regNo',
|
||||||
];
|
];
|
||||||
late String isActive = "1";
|
late String isActive = "1";
|
||||||
html.File? docUploadedFile;
|
// html.File? docUploadedFile;
|
||||||
|
|
||||||
// PlatformFile? passportFile;
|
PlatformFile? docUploadedFile;
|
||||||
String? selectedFileNames;
|
String? selectedFileNames;
|
||||||
String? passportFileUrlFromApi;
|
String? docUploadedFileFromApi;
|
||||||
String? selectedId;
|
String? selectedId;
|
||||||
bool isLoading = false;
|
bool isLoading = false;
|
||||||
bool isquotation = false;
|
bool isquotation = false;
|
||||||
@ -64,8 +78,8 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
|
|||||||
|
|
||||||
Map<String, dynamic> dataDetails() {
|
Map<String, dynamic> dataDetails() {
|
||||||
final data = {
|
final data = {
|
||||||
"name": controllers["name"]?.text,
|
"regNum": controllers["regNum"]?.text,
|
||||||
"email": controllers["email"]?.text,
|
"insurer": controllers["insurer"]?.text,
|
||||||
"mobile": controllers["mobile"]?.text,
|
"mobile": controllers["mobile"]?.text,
|
||||||
"address": controllers["address"]?.text,
|
"address": controllers["address"]?.text,
|
||||||
"agent_code": controllers["code"]?.text,
|
"agent_code": controllers["code"]?.text,
|
||||||
@ -78,6 +92,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
|
|||||||
List<Map<String, dynamic>> getQuotationData = [];
|
List<Map<String, dynamic>> getQuotationData = [];
|
||||||
List<Map<String, dynamic>> originalData = [];
|
List<Map<String, dynamic>> originalData = [];
|
||||||
List<Map<String, dynamic>> filteredData = [];
|
List<Map<String, dynamic>> filteredData = [];
|
||||||
|
|
||||||
// bool isLoading = false;
|
// bool isLoading = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -103,19 +118,46 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
|
|||||||
print("APISERTOKEN - $_token");
|
print("APISERTOKEN - $_token");
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getQuotationList(int managerId) async {
|
void refresh() {
|
||||||
|
getQuotationList(managerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getQuotationList(managerId) async {
|
||||||
print('getClaimList called MagId - $managerId');
|
print('getClaimList called MagId - $managerId');
|
||||||
setState(() {
|
setState(() {
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
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') {
|
if (response['status'] == 'success') {
|
||||||
print('quoationListData - ${response['data']}');
|
final rawData = response['data'];
|
||||||
|
print('quoationListData1 - ${response['data']}');
|
||||||
setState(() {
|
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;
|
originalData = getQuotationData;
|
||||||
filteredData = List.from(originalData);
|
filteredData = List.from(originalData);
|
||||||
// print('originalData - $getClaimPolicies');
|
// 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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
@ -181,7 +314,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
|
|||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// handleSave();
|
handleActions('Rejected');
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
@ -202,7 +335,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
|
|||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// handleSave();
|
handleActions('Accepted');
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.symmetric(
|
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) {
|
Widget _buildDataTable(BuildContext context) {
|
||||||
if (filteredData.isEmpty) {
|
if (filteredData.isEmpty) {
|
||||||
return const SizedBox(
|
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() {
|
Widget _buildHeader() {
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -560,23 +799,20 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
|
|||||||
isquotation = false; // unselect
|
isquotation = false; // unselect
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
findAndUpdateById(selectedId);
|
||||||
print("Selected row id: $selectedId");
|
print("Selected row id: $selectedId");
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
Expanded(flex: 1, child: Text(item['id'] ?? '-', style: _dataBold)),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
child: Text(item['email'] ?? '-', style: _dataBold),
|
child: Text(item['reg_no'] ?? '-', style: _dataBold),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
child: Text(item['mobile'] ?? '-', style: _dataBold),
|
child: Text(item['insurer_name'] ?? '-', style: _dataBold),
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
flex: 1,
|
|
||||||
child: Text(item['insurance_plan_type'] ?? '-', style: _dataBold),
|
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@ -585,6 +821,17 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
|
|||||||
style: _dataBold,
|
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(
|
Expanded(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -628,6 +875,8 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
|
|||||||
isquotation = false; // unselect
|
isquotation = false; // unselect
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
findAndUpdateById(selectedId);
|
||||||
print("Selected row id: $selectedId");
|
print("Selected row id: $selectedId");
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -648,9 +897,22 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
|
|||||||
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text("New India", style: _cardBodyStyle),
|
Text(
|
||||||
const Text("TN64V3456", style: _cardheaderStyle),
|
item['insurer_name'] ?? '-',
|
||||||
const Text("Status: Rejected", style: _cardBodyStyle),
|
|
||||||
|
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,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text("Comprehensive", style: _cardBodyStyle),
|
Text(
|
||||||
const Text("IDV:₹145000", style: _cardBodyStyle),
|
item['insurance_plan_type_id'] ?? '-',
|
||||||
const Text("₹1000", style: _cardheaderStyle),
|
style: _cardBodyStyle,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
item['insured_declared_value'] ?? '-',
|
||||||
|
style: _cardBodyStyle,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Premium Amount - ${item['premium_amount']}' ?? '-',
|
||||||
|
style: _cardheaderStyle,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -4,33 +4,148 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
|
||||||
import '../../../../core/routing/routes.dart';
|
import '../../../../core/routing/routes.dart';
|
||||||
|
import '../../../../core/services/api_service.dart';
|
||||||
|
import '../../../providers/manager_provider.dart';
|
||||||
import 'enquiry_tab.dart';
|
import 'enquiry_tab.dart';
|
||||||
import 'quotation_tab.dart';
|
import 'quotation_tab.dart';
|
||||||
import 'policy_tab.dart';
|
import 'policy_tab.dart';
|
||||||
import '../../../layouts/main_layout.dart';
|
import '../../../layouts/main_layout.dart';
|
||||||
|
|
||||||
class TabEnquiryList extends ConsumerStatefulWidget {
|
class TabEnquiryList extends ConsumerStatefulWidget {
|
||||||
const TabEnquiryList({super.key});
|
String? id;
|
||||||
|
TabEnquiryList({super.key, this.id});
|
||||||
@override
|
@override
|
||||||
ConsumerState<TabEnquiryList> createState() => TabEnquiryListState();
|
ConsumerState<TabEnquiryList> createState() => TabEnquiryListState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class TabEnquiryListState extends ConsumerState<TabEnquiryList> {
|
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"];
|
@override
|
||||||
final List<Widget> tabWidgets = [EnquiryTab(), QuotationTab(), PolicyTab()];
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
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(
|
return MainLayout(
|
||||||
title: "Enquiry",
|
title: "Enquiry",
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: Column(
|
child: isLoading
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
? const Center(child: CircularProgressIndicator())
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
: 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: [
|
children: [
|
||||||
// Header
|
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
@ -57,31 +172,18 @@ class TabEnquiryListState extends ConsumerState<TabEnquiryList> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Row(
|
||||||
const SizedBox(height: 10),
|
|
||||||
|
|
||||||
// Tab Buttons
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
||||||
child: Row(
|
|
||||||
children: List.generate(tabs.length, (index) {
|
children: List.generate(tabs.length, (index) {
|
||||||
final bool isSelected = selectedIndex == index;
|
final isSelected = selectedIndex == index;
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(right: 12),
|
padding: const EdgeInsets.only(left: 10.0),
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
elevation: 2,
|
elevation: 2,
|
||||||
backgroundColor: isSelected
|
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(0xFF425B5B)
|
||||||
: const Color(0xFFEDFFFC),
|
: const Color(0xFFEDFFFC),
|
||||||
),
|
foregroundColor: isSelected ? Colors.white : Colors.black87,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(6),
|
borderRadius: BorderRadius.circular(6),
|
||||||
),
|
),
|
||||||
@ -91,37 +193,444 @@ class TabEnquiryListState extends ConsumerState<TabEnquiryList> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() => selectedIndex = index);
|
||||||
selectedIndex = index;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(tabs[index].title),
|
||||||
tabs[index],
|
|
||||||
style: GoogleFonts.inter(
|
|
||||||
fontWeight: isSelected
|
|
||||||
? FontWeight.w600
|
|
||||||
: FontWeight.w500,
|
|
||||||
fontSize: 15,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
|
|
||||||
const SizedBox(height: 16),
|
SizedBox(height: 10),
|
||||||
|
Expanded(child: tabs[selectedIndex].widget),
|
||||||
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:http/http.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
|
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
|
||||||
import '../../../../core/routing/routes.dart';
|
import '../../../../core/routing/routes.dart';
|
||||||
@ -139,8 +140,13 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
print('EDITStaff - ${data['id']}');
|
print('EDITStaff - ${data['id']}');
|
||||||
dynamic id = data['id'];
|
// dynamic id = data['id'];
|
||||||
// context.go('/staff/$id');
|
// context.go('/tabEnquiry/$id');
|
||||||
|
|
||||||
|
// update provider
|
||||||
|
final id = data['id'].toString();
|
||||||
|
ref.read(enquiryIdProvider.notifier).state = id;
|
||||||
|
context.go(AppRoutes.tabEnquiry);
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@ -262,10 +268,10 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
|
|||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// context.go(AppRoutes.agent / create);
|
// context.go(AppRoutes.agent / create);
|
||||||
context.go('/staff/create');
|
context.go('/tabEnquiry/tab');
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'Create New Staff',
|
'Create New Enquiry',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontWeight: FontWeight.w600,
|
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 '../../core/routing/routes.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
|
import '../providers/manager_provider.dart';
|
||||||
import '../providers/userRoleProvider.dart';
|
import '../providers/userRoleProvider.dart';
|
||||||
import 'drawerContentWrapper.dart';
|
import 'drawerContentWrapper.dart';
|
||||||
|
|
||||||
@ -70,6 +71,19 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
|
|||||||
],
|
],
|
||||||
|
|
||||||
if (key == 'Reports') ...[
|
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(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.go(AppRoutes.enquiryLst);
|
context.go(AppRoutes.enquiryLst);
|
||||||
@ -85,10 +99,10 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
|
|||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
print("Bf clicked");
|
context.go(AppRoutes.endosement);
|
||||||
},
|
},
|
||||||
child: const Text(
|
child: const Text(
|
||||||
"Claims",
|
"Endorsement",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@ -98,10 +112,39 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
|
|||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
print("Bf clicked");
|
context.go(AppRoutes.policylist);
|
||||||
},
|
},
|
||||||
child: const Text(
|
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(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@ -172,13 +215,31 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
DrawerLabel("Reports"),
|
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(
|
DrawerContentWrapper(
|
||||||
child: IconButton(
|
child: Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
return IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
ref.read(enquiryIdProvider.notifier).state = null;
|
||||||
context.go(AppRoutes.tabEnquiry);
|
context.go(AppRoutes.tabEnquiry);
|
||||||
},
|
},
|
||||||
icon: Icon(Icons.list_alt_rounded, size: 30, color: Colors.black),
|
icon: const Icon(
|
||||||
|
Icons.list_alt_rounded,
|
||||||
|
size: 30,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|||||||
36
pubspec.lock
36
pubspec.lock
@ -692,26 +692,26 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: leak_tracker
|
name: leak_tracker
|
||||||
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
|
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "11.0.2"
|
version: "10.0.9"
|
||||||
leak_tracker_flutter_testing:
|
leak_tracker_flutter_testing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: leak_tracker_flutter_testing
|
name: leak_tracker_flutter_testing
|
||||||
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
|
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.10"
|
version: "3.0.9"
|
||||||
leak_tracker_testing:
|
leak_tracker_testing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: leak_tracker_testing
|
name: leak_tracker_testing
|
||||||
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
|
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.2"
|
version: "3.0.1"
|
||||||
lints:
|
lints:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -732,10 +732,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: local_auth_android
|
name: local_auth_android
|
||||||
sha256: "1ee0e63fb8b5c6fa286796b5fb1570d256857c2f4a262127e728b36b80a570cf"
|
sha256: "48924f4a8b3cc45994ad5993e2e232d3b00788a305c1bf1c7db32cef281ce9a3"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.53"
|
version: "1.0.52"
|
||||||
local_auth_darwin:
|
local_auth_darwin:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1217,10 +1217,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
|
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.6"
|
version: "0.7.4"
|
||||||
toastification:
|
toastification:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1273,10 +1273,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_android
|
name: url_launcher_android
|
||||||
sha256: "07cffecb7d68cbc6437cd803d5f11a86fe06736735c3dfe46ff73bcb0f958eed"
|
sha256: "81777b08c498a292d93ff2feead633174c386291e35612f8da438d6e92c4447e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.3.21"
|
version: "6.3.20"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1337,18 +1337,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_math
|
name: vector_math
|
||||||
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
|
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.1.4"
|
||||||
vm_service:
|
vm_service:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
|
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "15.0.2"
|
version: "15.0.0"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1414,5 +1414,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.3"
|
version: "3.1.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.9.0 <4.0.0"
|
dart: ">=3.8.1 <4.0.0"
|
||||||
flutter: ">=3.35.0"
|
flutter: ">=3.32.0"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user