Handler Role

This commit is contained in:
venbaittech 2025-10-13 14:18:33 +05:30
parent 2de35505ab
commit b778e133a8
16 changed files with 3834 additions and 530 deletions

View File

@ -5,6 +5,7 @@ import 'package:nhance_partner/core/routing/routes.dart';
import 'package:nhance_partner/presentation/screens/Enquiry/enquiryList.dart';
import 'package:nhance_partner/presentation/screens/UserManagement/Profile/profile_web.dart';
import 'package:nhance_partner/presentation/screens/dashboard/dashboard.dart';
import 'package:nhance_partner/presentation/screens/handler/enquiryList.dart';
import '../../data/services/auth_service.dart';
import '../../presentation/providers/manager_provider.dart';
import '../../presentation/screens/Enquiry/enquiry/tabs.dart';
@ -155,6 +156,10 @@ final GoRouter appRouter = GoRouter(
path: AppRoutes.enquiryForStaff,
builder: (context, state) => const EnquiryStaff(),
),
GoRoute(
path: AppRoutes.enquiryHandlerLst,
builder: (context, state) => const EnquiryHandler(),
),
],
redirect: (context, state) async {
final loggedIn = await AuthService.isLoggedIn();

View File

@ -12,6 +12,8 @@ class AppRoutes {
static const String enquiryForStaff = '/enquiryForStaff';
static const String tabEnquiry = '/tabEnquiry';
static const String enquiryHandlerLst = '/enquiryHandlerLst';
static const String claimlist = '/claimList';
static const String endosement = '/endosement';
static const String policylist = '/policylist';

View File

@ -348,6 +348,8 @@ class ApiService {
if (role == 'manager') {
url = Uri.parse('${Env.apiUrl}dashboard/managerDashboard?manager_id=$id');
} else if (role == 'handler') {
url = Uri.parse('${Env.apiUrl}dashboard/handlerDashboard?handler_id=$id');
} else if (role == 'staff') {
url = Uri.parse('${Env.apiUrl}dashboard/staffDashboard?staff_id=$id');
} else {
@ -465,7 +467,7 @@ class ApiService {
// ------------------------------------ STAFF -----------------------------------------------------
Future<Map<String, dynamic>> fetchStaffUserList(int managerId) async {
Future<Map<String, dynamic>> fetchStaffUserList(int managerId, role) async {
// print(_token);
if (_token == null) {
await _initializeToken();
@ -475,9 +477,15 @@ class ApiService {
// 'https://venbait.in/nhance/partner/dev/api/staff/staffList?manager_id=${managerId}',
// );
final url = Uri.parse(
'${Env.apiUrl}staff/staffList?manager_id=${managerId}',
);
dynamic url;
if (role == 'manager') {
print('manager');
url = Uri.parse('${Env.apiUrl}staff/staffList?manager_id=${managerId}');
} else {
print('handler');
url = Uri.parse('${Env.apiUrl}staff/staffList?handler_id=${managerId}');
}
final headers = {
'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK',
@ -871,4 +879,50 @@ class ApiService {
final response = await _makeGetRequest(url, headers);
return response;
}
Future<Map<String, dynamic>> fetchHandlerNameDropDown(id) async {
print('fetchHandlerNameDropDown');
if (_token == null) {
await _initializeToken();
}
dynamic url;
print('fetchHandlerNameDropDown 1');
url = Uri.parse(
'${Env.apiUrl}staff/handlerListForStaffCreationDropdown?manager_id=$id',
);
print('fetchHandlerNameDropDown 2');
final headers = {
'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK',
};
print('fetchHandlerNameDropDown 3');
final response = await _makeGetRequest(url, headers);
print('fetchHandlerNameDropDown 4 - $response');
return response;
}
Future<Map<String, dynamic>> fetchStaffListForEnquiryAssignDropDown(
id,
) async {
print('fetchHandlerNameDropDown');
if (_token == null) {
await _initializeToken();
}
dynamic url;
print('fetchHandlerNameDropDown 1');
url = Uri.parse(
'${Env.apiUrl}/staff/staffListForEnquiryAssignDropdown?handler_id=$id',
);
print('fetchHandlerNameDropDown 2');
final headers = {
'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK',
};
print('fetchHandlerNameDropDown 3');
final response = await _makeGetRequest(url, headers);
print('fetchHandlerNameDropDown 4 - $response');
return response;
}
}

View File

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

View File

@ -1,6 +1,7 @@
import 'dart:convert';
import 'package:dropdown_search/dropdown_search.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
@ -12,6 +13,7 @@ import '../../../../data/services/auth_service.dart';
import '../../../../data/utils/toastNotification.dart';
import '../../../../data/utils/validators.dart';
import '../../../layouts/responsive_layout.dart';
import '../../../themes/indicators/customizd_file_upload.dart';
import '../../../themes/indicators/input_field_decoration.dart';
import '../../../themes/indicators/text_field_theme.dart';
@ -41,6 +43,16 @@ class _AddDialogState extends State<AddDialog> {
late TextEditingController controller;
Map<String, TextEditingController> controllers = {};
String? selectedClaimFileNames;
String? passportFileUrlFromApi;
String? selectedClaimId;
PlatformFile? docUploadedFile;
String? selectedFileNames;
String? passportEndorsFileUrlFromApi;
String? selectedEndorsId;
PlatformFile? docUploadedEndorsFile;
final _formKeyClaims = GlobalKey<FormState>();
final _formKeyEndrosment = GlobalKey<FormState>();
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKey =
@ -204,7 +216,7 @@ class _AddDialogState extends State<AddDialog> {
}
}
Future<void> createUserData(data, val) async {
Future<void> createUserData1(data, val) async {
// final bool isUpdating = widget.id != null && widget.id != 'create';
final String apiUrldata;
@ -253,6 +265,115 @@ class _AddDialogState extends State<AddDialog> {
}
}
Future<void> createUserData(data, val) async {
final Uri uri = (val == 'Claims')
? Uri.parse('${Env.apiUrl}claim/createClaim')
: Uri.parse('${Env.apiUrl}endorsement/createEndorsement');
if (_token == null) {
throw Exception('Token not found. Please log in.');
}
// Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $_token';
request.headers['app-signature'] =
'nhance-partner-2025-signature-35468846JRhH551HK';
print("USerDAta - $data");
// userData.forEach((key, value) {
// request.fields[key] = value.toString();
// print("✅ Encoded travel_details2: ${request.fields[key]}");
// });
data.forEach((key, value) {
// if (key != 'certificate_file_name') {
request.fields[key] = value.toString();
print("✅ Encoded $key: ${request.fields[key]}");
// }
});
if (val == 'Claims') {
// Attach file if selected
if (docUploadedFile != null) {
try {
if (docUploadedFile!.bytes != null) {
final multipartFile = http.MultipartFile.fromBytes(
'claim_file_name',
docUploadedFile!.bytes!,
filename: docUploadedFile!.name,
);
request.files.add(multipartFile);
}
// else if (docUploadedFile!.path != null) {
// final multipartFile = await http.MultipartFile.fromPath(
// 'certificate_file_name',
// docUploadedFile!.path!,
// filename: docUploadedFile!.name,
// );
// request.files.add(multipartFile);
// }
print("📎 File attached: ${docUploadedFile!.name}");
} catch (e) {
print("❌ Failed to attach file: $e");
}
}
} else {
// Attach file if selected
if (docUploadedEndorsFile != null) {
try {
if (docUploadedEndorsFile!.bytes != null) {
final multipartFile = http.MultipartFile.fromBytes(
'endorsement_file_name',
docUploadedEndorsFile!.bytes!,
filename: docUploadedEndorsFile!.name,
);
request.files.add(multipartFile);
}
// else if (docUploadedEndorsFile!.path != null) {
// final multipartFile = await http.MultipartFile.fromPath(
// 'endorsement_file_name',
// docUploadedEndorsFile!.path!,
// filename: docUploadedEndorsFile!.name,
// );
// request.files.add(multipartFile);
// }
print("📎 File attached: ${docUploadedEndorsFile!.name}");
} catch (e) {
print("❌ Failed to attach file: $e");
}
}
}
print(" Sending request with fields: ${request.fields}");
try {
final streamedResponse = await request.send();
final response = await http.Response.fromStream(streamedResponse);
print("Response status: ${response.statusCode}");
print("Response body: ${response.body}");
if (response.statusCode == 200 || response.statusCode == 201) {
print("✅ Partner submitted successfully!");
print("Response: ${response.body}");
ToastHelper.showSuccessToast(context, 'Saved Successfully');
Navigator.of(context).pop();
widget.onSubmit("success");
} else {
final responseBody = jsonDecode(response.body);
dynamic msg = responseBody['data'];
print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}");
ToastHelper.showErrorToast(context, 'Failed To Save');
}
} catch (e) {
print("🔥 Error submitting user: $e");
}
}
@override
Widget build(BuildContext context) {
return AlertDialog(
@ -296,24 +417,19 @@ class _AddDialogState extends State<AddDialog> {
],
),
actions: [
Center(
child: GestureDetector(
onTap: () {
handleDone(widget.title);
// widget.onSubmit(controller.text.trim());
// Navigator.of(context).pop();
},
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 25.0,
vertical: 8,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
color: const Color(0xFF425B5B),
),
child: const Text('Done', style: TextStyle(color: Colors.white)),
GestureDetector(
onTap: () {
handleDone(widget.title);
// widget.onSubmit(controller.text.trim());
// Navigator.of(context).pop();
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 25.0, vertical: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
color: const Color(0xFF425B5B),
),
child: const Text('Save', style: TextStyle(color: Colors.white)),
),
),
],
@ -328,6 +444,7 @@ class _AddDialogState extends State<AddDialog> {
children: [
buildClaimType(context),
buildPolicyNumber(context),
buildUploadDocumentClaims(context),
buildClaimsDesc(context),
],
),
@ -339,7 +456,11 @@ class _AddDialogState extends State<AddDialog> {
return Form(
key: _formKeyEndrosment,
child: Column(
children: [buildEndrosType(context), buildEndrosRemarks(context)],
children: [
buildEndrosType(context),
buildUploadDocumentEndorsment(context),
buildEndrosRemarks(context),
],
),
);
}
@ -472,7 +593,88 @@ class _AddDialogState extends State<AddDialog> {
);
}
// ------------------------- Endrosment Part -----------------------------------
Widget buildUploadDocumentClaims(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Upload Document", style: _textStyle),
SizedBox(width: 10),
ThemedUploadField(
backgroundColor: Color(0xFFEDF6F5),
hintText: selectedClaimFileNames ?? "Upload Document",
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
onFileSelected: (fileName, file) {
print("Picked file: $fileName (${file.size} bytes)");
setState(() {
docUploadedFile = file;
});
},
),
// Column(
// mainAxisAlignment: MainAxisAlignment.end,
// crossAxisAlignment: CrossAxisAlignment.end,
// children: [
// ThemedUploadField(
// hintText: selectedClaimFileNames ?? "Upload Document",
// txtwidth: MediaQuery.of(context).size.width * 0.26,
// onFileSelected: (fileName, file) {
// print("Picked file: $fileName (${file.size} bytes)");
// setState(() {
// docUploadedFile = file;
// });
// },
// ),
// // const SizedBox(height: 5),
// //
// // if (docUploadedFile != null || passportFileUrlFromApi != null)
// // Container(
// // // color: Colors.white,
// // child: Row(
// // children: [
// // GestureDetector(
// // onTap: () => apiService.downloadFile(
// // apiUrl:
// // 'api/agent/downloadAgentCertificateFile?agent_id=$selectedClaimId',
// // apiId: selectedClaimId,
// // localFile: docUploadedFile,
// // fileName: selectedClaimFileNames,
// // ),
// // child: Container(
// // padding: const EdgeInsets.all(5),
// // decoration: BoxDecoration(
// // borderRadius: BorderRadius.circular(5),
// // color: Color(0xFF425B5B),
// // // color: Colors.green.shade300,
// // ),
// // 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),
// // ],
// // ),
// // ),
// // ),
// // ],
// // ),
// // ),
// ],
// ),
],
);
}
//------------------------- Endrosment Part -----------------------------------
Widget buildEndrosType(context) {
Map<String, dynamic>? selectedEndorsementd = filteredEndrosmentData
@ -586,10 +788,91 @@ class _AddDialogState extends State<AddDialog> {
);
}
Widget buildUploadDocumentEndorsment(context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Upload Document", style: _textStyle),
SizedBox(width: 10),
ThemedUploadField(
backgroundColor: Color(0xFFEDF6F5),
hintText: selectedFileNames ?? "Upload Document",
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
onFileSelected: (fileName, file) {
print("Picked file: $fileName (${file.size} bytes)");
setState(() {
docUploadedEndorsFile = file;
});
},
),
// Column(
// mainAxisAlignment: MainAxisAlignment.end,
// crossAxisAlignment: CrossAxisAlignment.end,
// children: [
// ThemedUploadField(
// hintText: selectedFileNames ?? "Upload Document",
// txtwidth: MediaQuery.of(context).size.width * 0.26,
// onFileSelected: (fileName, file) {
// print("Picked file: $fileName (${file.size} bytes)");
// setState(() {
// docUploadedEndorsFile = file;
// });
// },
// ),
// // const SizedBox(height: 5),
// //
// // if (docUploadedEndorsFile != null || passportEndorsFileUrlFromApi != null)
// // Container(
// // // color: Colors.white,
// // child: Row(
// // children: [
// //
// // GestureDetector(
// // onTap: () => apiService.downloadFile(
// // apiUrl:
// // 'api/agent/downloadAgentCertificateFile?agent_id=$selectedEndorsId',
// // apiId: selectedEndorsId,
// // localFile: docUploadedEndorsFile,
// // fileName: selectedFileNames,
// // ),
// // child: Container(
// // padding: const EdgeInsets.all(5),
// // decoration: BoxDecoration(
// // borderRadius: BorderRadius.circular(5),
// // color: Color(0xFF425B5B),
// // // color: Colors.green.shade300,
// // ),
// // 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),
// // ],
// // ),
// // ),
// // ),
// // ],
// // ),
// // ),
// ],
// ),
],
);
}
// ------------------- STyle ---------------------------------
static final TextStyle _textStyle = TextStyle(
fontSize: 14,
fontSize: 12,
fontWeight: FontWeight.w600,
);
}

View File

@ -3,6 +3,7 @@ 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 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../../../core/routing/routes.dart';
@ -28,6 +29,7 @@ class TabEnquiryListState extends ConsumerState<TabEnquiryList> {
bool isLoading = true;
late ApiService apiService;
ScrollController _scrollController = ScrollController();
dynamic role;
@override
void initState() {
@ -40,7 +42,7 @@ class TabEnquiryListState extends ConsumerState<TabEnquiryList> {
Future.microtask(() {
final id = ref.read(enquiryIdProvider);
role = ref.read(userRoleProvider);
print("IntialID - $id");
if (id != null) {
_loadData(id);
@ -228,8 +230,14 @@ class TabEnquiryListState extends ConsumerState<TabEnquiryList> {
child: GestureDetector(
onTap: () {
// context.go(AppRoutes.dashboard);
ref.read(enquiryIdProvider.notifier).state = null;
context.go(AppRoutes.enquiryLst);
if (role == 'handler') {
ref.read(enquiryIdProvider.notifier).state = null;
context.go(AppRoutes.enquiryHandlerLst);
} else {
ref.read(enquiryIdProvider.notifier).state = null;
context.go(AppRoutes.enquiryLst);
}
},
child: Row(
children: [
@ -421,8 +429,15 @@ class TabEnquiryListState extends ConsumerState<TabEnquiryList> {
Tooltip(
message: 'Back',
child: IconButton(
icon: const Icon(Icons.arrow_left_sharp,size: 35,color: Color(0xFF425B5B)),
onPressed: () { ref.read(enquiryIdProvider.notifier).state = null; context.go(AppRoutes.enquiryLst); },
icon: const Icon(
Icons.arrow_left_sharp,
size: 35,
color: Color(0xFF425B5B),
),
onPressed: () {
ref.read(enquiryIdProvider.notifier).state = null;
context.go(AppRoutes.enquiryLst);
},
splashRadius: 28,
hoverColor: Colors.black12,
padding: const EdgeInsets.all(8),

View File

@ -1,6 +1,7 @@
import 'dart:convert';
// import 'dart:io' as html;
import 'dart:typed_data'; // Import for Uint8List
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@ -15,10 +16,13 @@ import '../../../../core/services/api_service.dart';
import '../../../../data/services/auth_service.dart';
import '../../../../data/utils/validators.dart';
import '../../../layouts/main_layout.dart';
import '../../../layouts/responsive_layout.dart';
import '../../../providers/manager_provider.dart';
import 'package:universal_html/html.dart' as html;
import '../../../themes/indicators/input_field_decoration.dart';
class Staff extends ConsumerStatefulWidget {
final String? id;
const Staff({super.key, this.id});
@ -29,6 +33,13 @@ class Staff extends ConsumerStatefulWidget {
class StaffState extends ConsumerState<Staff> {
final _formKey = GlobalKey<FormState>();
late ApiService apiService;
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKey =
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
final GlobalKey<DropdownSearchState<Map<String, dynamic>>>
dropDownKeyHandler = GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
List<String> tabHeader = ['name', 'email', 'mobile', 'code'];
late String isActive = "1";
html.File? passportFile;
@ -36,6 +47,16 @@ class StaffState extends ConsumerState<Staff> {
String? passportFileUrlFromApi;
String? selectedId;
String? _token;
bool isLoading = false;
bool showHandler = false;
String? selectedRole;
List<Map<String, dynamic>> filteredRolesData = [];
List<Map<String, dynamic>> getRolesData = [];
String? selectedHandler;
List<Map<String, dynamic>> filteredHandlersData = [];
List<Map<String, dynamic>> getHandlersData = [];
Map<String, TextEditingController> controllers = {};
@ -47,9 +68,10 @@ class StaffState extends ConsumerState<Staff> {
"name": controllers["name"]?.text,
"email": controllers["email"]?.text,
"mobile": controllers["mobile"]?.text,
"emp_id": controllers["code"]?.text,
// "emp_id": controllers["code"]?.text,
"is_active": isActive,
"role_id": "2", // By default role 2 Staff, No fields Required
"role_id": selectedRole, // By default role 2 Staff, No fields Required
"handler_id": selectedHandler,
"manager_id": userId,
};
return data;
@ -63,12 +85,18 @@ class StaffState extends ConsumerState<Staff> {
controllers[field] = TextEditingController();
}
_initializeToken();
updateData();
getRole();
Future.microtask(() {
managerId = ref.watch(managerIdProvider);
userId = ref.watch(userIdProvider);
if (managerId != null) {
print('hansles');
getHandlers(managerId);
}
});
_initializeToken();
updateData();
}
Future<void> _initializeToken() async {
@ -88,7 +116,10 @@ class StaffState extends ConsumerState<Staff> {
controllers['name']?.text = data['name'] ?? '';
controllers['email']?.text = data['email'] ?? '';
controllers['mobile']?.text = data['mobile'] ?? '';
controllers['code']?.text = data['emp_id'] ?? '';
selectedRole = data['role_id'] ?? '';
selectedHandler = data['handler_id'] ?? '';
// controllers['code']?.text = data['emp_id'] ?? '';
isActive = data["is_active"];
String? apiDocPath = data["certificate_file_name"];
@ -201,6 +232,69 @@ class StaffState extends ConsumerState<Staff> {
}
}
Future<void> getRole() async {
print('Handlers called');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchMasterDropDown('staffRole');
if (response['status'] == 200) {
print('getRole - ${response['data']}');
setState(() {
getRolesData = List<Map<String, dynamic>>.from(response['data']);
print('API Data - $getRolesData');
filteredRolesData = List.from(getRolesData);
print('originalData - $filteredRolesData');
});
} else {
getRolesData = [];
filteredRolesData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
Future<void> getHandlers(managerId) async {
print('Handlers called');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchHandlerNameDropDown(managerId);
if (response['code'] == 200 || response['status'] == 'success') {
print('getHandlers -');
print('getHandlers - ${response['data']}');
setState(() {
getHandlersData = List<Map<String, dynamic>>.from(response['data']);
print('API HandlersData - $getHandlersData');
filteredHandlersData = List.from(getHandlersData);
print('HandlersoriginalData - $filteredHandlersData');
});
} else {
getHandlersData = [];
filteredHandlersData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
@override
void dispose() {
for (var controller in controllers.values) {
@ -331,11 +425,20 @@ class StaffState extends ConsumerState<Staff> {
children: [
Expanded(child: buildPhNumber()),
SizedBox(width: 25),
Expanded(child: buildId()),
Expanded(child: buildRole(context)),
],
),
SizedBox(height: 20),
if (showHandler) ...[
Row(
children: [
Expanded(child: buildHandler(context)),
SizedBox(width: 25),
Expanded(child: SizedBox.shrink()),
],
),
],
// Row(
// children: [
// Expanded(child: buildAddress()),
@ -408,16 +511,217 @@ class StaffState extends ConsumerState<Staff> {
);
}
Widget buildAddress() {
// Widget buildAddress() {
// return Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text("Role*", style: _textStyle),
// SizedBox(width: 10),
// ThemedFormField(
// controller: controllers['address']!,
//
// txtwidth: MediaQuery.of(context).size.width * 0.26,
// ),
// ],
// );
// }
Widget buildRole(BuildContext context) {
Map<String, dynamic>? selectedroleVal = filteredRolesData.firstWhere(
(item) => item['id'].toString() == selectedRole,
orElse: () => {},
);
if (selectedroleVal.isNotEmpty &&
selectedroleVal['role'] != null &&
selectedroleVal['role'] == 'Staff') {
showHandler = true;
} else {
showHandler = false;
}
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Role*", style: _textStyle),
Text("Role *", style: _textStyle),
SizedBox(width: 10),
ThemedFormField(
controller: controllers['address']!,
Container(
decoration: BoxDecoration(
// color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
),
width: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
// height: 40,
child: DropdownSearch<Map<String, dynamic>>(
key: dropDownKey,
selectedItem: selectedroleVal.isNotEmpty ? selectedroleVal : null,
items: (filter, infiniteScrollProps) {
return filteredRolesData;
},
txtwidth: MediaQuery.of(context).size.width * 0.26,
itemAsString: (val) => val['role'].toString(), // what to show
compareFn: (item, selectedItem) =>
item['id'] == selectedItem['id'], // compare by id
validator: (val) {
if (val == null) {
return "Required"; // error message
}
return null;
},
decoratorProps: DropDownDecoratorProps(
decoration:
AppInputDecorations.dropdownDecoration(
label: "Select Role",
).copyWith(
filled: true,
fillColor:
Colors.white, // 👈 makes the dropdown input white
),
),
popupProps: PopupProps.menu(
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 250),
menuProps: MenuProps(
backgroundColor:
Colors.white, // 👈 sets dropdown background to white
),
showSearchBox: true,
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
hintText: "Search Role...",
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
), // 👈 Normal border
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
width: 1.5,
), // 👈 Focused border
),
),
),
// constraints: BoxConstraints(),
),
onChanged: (val) {
if (val != null) {
print("Selected Role : ${val['role']}");
print("Id: ${val['id']}");
selectedRole = val['id'];
if (val['role'] == 'Staff') {
setState(() {
showHandler = true;
});
} else {
setState(() {
showHandler = false;
});
}
// controllers['agentId']?.text = val['agent_code'];
// agentId = agent['id'];
}
},
),
),
],
);
}
Widget buildHandler(BuildContext context) {
Map<String, dynamic>? selectedHandlered = filteredHandlersData.firstWhere(
(item) => item['id'].toString() == selectedHandler,
orElse: () => {},
);
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Handler Name *", style: _textStyle),
SizedBox(width: 10),
Container(
decoration: BoxDecoration(
// color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
),
width: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
// height: 40,
child: DropdownSearch<Map<String, dynamic>>(
key: dropDownKeyHandler,
selectedItem: selectedHandlered.isNotEmpty
? selectedHandlered
: null,
items: (filter, infiniteScrollProps) {
return filteredHandlersData;
},
itemAsString: (val) => val['name'].toString(), // what to show
compareFn: (item, selectedItem) =>
item['id'] == selectedItem['id'], // compare by id
validator: (val) {
if (val == null) {
return "Required"; // error message
}
return null;
},
decoratorProps: DropDownDecoratorProps(
decoration:
AppInputDecorations.dropdownDecoration(
label: "Select Handler",
).copyWith(
filled: true,
fillColor:
Colors.white, // 👈 makes the dropdown input white
),
),
popupProps: PopupProps.menu(
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 250),
menuProps: MenuProps(
backgroundColor:
Colors.white, // 👈 sets dropdown background to white
),
showSearchBox: true,
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
hintText: "Search Handler...",
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
), // 👈 Normal border
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
width: 1.5,
), // 👈 Focused border
),
),
),
// constraints: BoxConstraints(),
),
onChanged: (val) {
if (val != null) {
print("Selected Handler : ${val['name']}");
print("Id: ${val['id']}");
selectedHandler = val['id'];
// controllers['agentId']?.text = val['agent_code'];
// agentId = agent['id'];
}
},
),
),
],
);

View File

@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
import '../../../../core/routing/routes.dart';
import '../../../../core/services/api_service.dart';
@ -26,6 +27,8 @@ class StaffListState extends ConsumerState<StaffList> {
int itemsPerPage = 10;
late ApiService apiService;
dynamic managerId;
dynamic role;
dynamic prefid;
// List<Map<String, dynamic>> dataVal = [];
List<Map<String, dynamic>> getStaffData = [];
List<Map<String, dynamic>> originalData = [];
@ -39,10 +42,14 @@ class StaffListState extends ConsumerState<StaffList> {
apiService = ApiService();
Future.microtask(() {
final id = ref.read(managerIdProvider);
print("E43 => mId: $id");
if (id != null) {
getStaffList(id);
final data1 = ref.read(managerIdProvider);
final data2 = ref.read(handlerIdProvider);
print("Edata1 => mId: $data1 -2 : $data2");
prefid = data2 ?? data1;
role = ref.read(userRoleProvider);
print("E43 => mId: $prefid");
if (prefid != null && role != null) {
getStaffList(prefid, role);
}
});
// getStaffList();
@ -83,16 +90,18 @@ class StaffListState extends ConsumerState<StaffList> {
return (item['name'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['email'] ?? '-').toLowerCase().contains(query.toLowerCase()) ||
(item['email'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['mobile'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['address'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['emp_id'] ?? item['agent_code'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['emp_id'] ?? item['agent_code'] ?? '-')
.toLowerCase()
.contains(query.toLowerCase()) ||
isActiveStatus.contains(query.toLowerCase());
}).toList();
});
@ -100,14 +109,15 @@ class StaffListState extends ConsumerState<StaffList> {
final TextEditingController _searchStaffController = TextEditingController();
Future<void> getStaffList(int managerId) async {
print('E104 => Fns called => $managerId');
Future<void> getStaffList(int id, role) async {
print('E104 => Fns called => $id');
print('E104 => Fns role => $role');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchStaffUserList(managerId);
final response = await apiService.fetchStaffUserList(id, role);
if (response['status'] == 'success') {
print('E113 => getStaffListData => ${response['data']}');
@ -184,8 +194,14 @@ class StaffListState extends ConsumerState<StaffList> {
Tooltip(
message: 'Back',
child: IconButton(
icon: const Icon(Icons.arrow_left_sharp,size: 25,color: Color(0xFF425B5B)),
onPressed: () { context.go(AppRoutes.dashboard); },
icon: const Icon(
Icons.arrow_left_sharp,
size: 25,
color: Color(0xFF425B5B),
),
onPressed: () {
context.go(AppRoutes.dashboard);
},
splashRadius: 18,
hoverColor: Colors.black12,
padding: const EdgeInsets.all(4),
@ -244,7 +260,7 @@ class StaffListState extends ConsumerState<StaffList> {
"name",
"email",
"mobile",
"emp_id",
"role",
"is_active",
],
),
@ -300,6 +316,10 @@ class StaffListState extends ConsumerState<StaffList> {
flex: 2,
child: Text('Staff Name', style: _headerStyle),
),
Expanded(
flex: 1,
child: Text('Role', style: _headerStyle),
),
Expanded(
flex: 3,
child: Text('Email', style: _headerStyle),
@ -308,10 +328,7 @@ class StaffListState extends ConsumerState<StaffList> {
flex: 2,
child: Text('Phone Number', style: _headerStyle),
),
Expanded(
flex: 1,
child: Text('Employee Id', style: _headerStyle),
),
Expanded(
flex: 1,
child: Text('Status', style: _headerStyle),
@ -404,6 +421,8 @@ class StaffListState extends ConsumerState<StaffList> {
children: [
Expanded(flex: 1, child: Text('$sno' ?? '-', style: _dataBold)),
Expanded(flex: 2, child: Text(item['name'] ?? '-', style: _dataBold)),
Expanded(flex: 1, child: Text(item['role'] ?? '-', style: _dataBold)),
Expanded(
flex: 3,
child: Text(item['email'] ?? '-', style: _dataBold),
@ -412,10 +431,6 @@ class StaffListState extends ConsumerState<StaffList> {
flex: 2,
child: Text(item['mobile'] ?? '-', style: _dataBold),
),
Expanded(
flex: 1,
child: Text(item['emp_id'] ?? '-', style: _dataBold),
),
Expanded(
flex: 1,

View File

@ -68,6 +68,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
int selectedTabIndex = 0;
List<Map<String, dynamic>> currentList = [];
List<Map<String, dynamic>> staffQuotationsPendingList = []; // cross verify
List<Map<String, dynamic>> quotationsPendingList = []; // cross verify
List<Map<String, dynamic>> policiesPendingList = []; // cross verify
List<Map<String, dynamic>> awaitingApprovalList = []; // cross verify
@ -262,6 +263,16 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
});
}
if (data['staff_level_pending_summary'] != null) {
print('staff_level_pending_summary -');
staffQuotationsPendingList = List<Map<String, dynamic>>.from(
(data['staff_level_pending_summary'] as List).map(
(item) => Map<String, dynamic>.from(item),
),
);
print('staff_level_pending_summary - $staffQuotationsPendingList');
}
if (data['quotations_pending'] != null) {
quotationsPendingList = List<Map<String, dynamic>>.from(
(data['quotations_pending'] as List).map(
@ -490,7 +501,8 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
scrollDirection: Axis.vertical,
child: Column(
children: [
if (role != 'staff')
// if (role != 'staff')
if (role != 'staff' && role != 'handler')
Row(
children: [
Expanded(
@ -535,133 +547,145 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
: (role == 'manager')
? MediaQuery.of(context).size.height * 0.5
: MediaQuery.of(context).size.height *
0.85, // 350 adjust height as needed
child: Row(
children: [
Expanded(
child: (role == 'agent')
? agentPendings(
0.5, // 350 adjust height as needed
child: (role == 'manager' || role == 'handler')
? Row(
children: [
Expanded(
child: othersPendings(
title:
"Awaiting Quotation (${quotationsPendingList.length})",
data: quotationsPendingList,
role: role!,
onEdit: (row) {
handleEdit(
row,
); // parent method is called
},
onStaffEdit: (row, flag) {
handleStaffEdit(row, flag);
},
)
: (role == 'manager')
? othersPendings(
title:
"Awaiting Quotation (${quotationsPendingList.length})",
data: quotationsPendingList,
"Staff Proposal Pending List (${staffQuotationsPendingList.length})",
data: staffQuotationsPendingList,
stringFlag: "Quotation",
)
: agentPendings(
title:
"Awaiting Quotation (${quotationsPendingList.length})",
data: quotationsPendingList,
role: role!,
onEdit: (row) {
handleEdit(
row,
); // parent method is called
},
),
),
],
)
: Row(
children: [
Expanded(
child: (role == 'agent')
? agentPendings(
title:
"Awaiting Quotation (${quotationsPendingList.length})",
data: quotationsPendingList,
role: role!,
onEdit: (row) {
handleEdit(
row,
); // parent method is called
},
onStaffEdit: (row, flag) {
handleStaffEdit(row, flag);
},
)
: (role == 'manager')
? SizedBox.shrink()
: agentPendings(
title:
"Awaiting Quotation (${quotationsPendingList.length})",
data: quotationsPendingList,
role: role!,
onEdit: (row) {
handleEdit(
row,
); // parent method is called
},
onStaffEdit: (row, flag) {
handleStaffEdit(row, flag);
},
),
),
const SizedBox(width: 16),
Expanded(
child: (role == 'agent')
? agentPendings(
title:
"Awaiting Approval (${awaitingApprovalList.length})",
data: awaitingApprovalList,
role: role!,
onEdit: (row) {
handleEdit(
row,
); // parent method is called
},
onStaffEdit: (row, flag) {
handleStaffEdit(row, flag);
},
)
: (role == 'manager')
? awaitingApproval(
title:
"Awaiting Approval (${awaitingApprovalList.length})",
data: awaitingApprovalList,
stringFlag: "Quotation",
)
: agentPendings(
title:
"Awaiting Approval (${awaitingApprovalList.length})",
data: awaitingApprovalList,
role: role!,
onEdit: (row) {
handleEdit(
row,
); // parent method is called
},
onStaffEdit: (row, flag) {
handleStaffEdit(row, flag);
},
),
),
const SizedBox(width: 16),
Expanded(
child: (role == 'agent')
? agentPendings(
title:
"Awaiting Policy (${policiesPendingList.length})",
data: policiesPendingList,
stringFlag: "Policies",
role: role!,
onEdit: (row) {
handleEdit(
row,
); // parent method is called
},
onStaffEdit: (row, flag) {
handleStaffEdit(row, flag);
},
)
: (role == 'manager')
? othersPendings(
title:
"Awaiting Policy (${policiesPendingList.length})",
data: policiesPendingList,
stringFlag: "Policies",
)
: agentPendings(
title:
"Awaiting Policy (${policiesPendingList.length})",
data: policiesPendingList,
stringFlag: "Policies",
role: role!,
onEdit: (row) {
handleEdit(
row,
); // parent method is called
},
onStaffEdit: (row, flag) {
handleStaffEdit(row, flag);
},
),
),
],
),
onStaffEdit: (row, flag) {
handleStaffEdit(row, flag);
},
),
),
const SizedBox(width: 16),
Expanded(
child: (role == 'agent')
? agentPendings(
title:
"Awaiting Approval (${awaitingApprovalList.length})",
data: awaitingApprovalList,
role: role!,
onEdit: (row) {
handleEdit(
row,
); // parent method is called
},
onStaffEdit: (row, flag) {
handleStaffEdit(row, flag);
},
)
: (role == 'manager')
? SizedBox.shrink()
// othersPendings(
// title:
// "Awaiting Quotation (${quotationsPendingList.length})",
// data: quotationsPendingList,
// stringFlag: "Quotation",
// )
: agentPendings(
title:
"Awaiting Approval (${awaitingApprovalList.length})",
data: awaitingApprovalList,
role: role!,
onEdit: (row) {
handleEdit(
row,
); // parent method is called
},
onStaffEdit: (row, flag) {
handleStaffEdit(row, flag);
},
),
),
const SizedBox(width: 16),
Expanded(
child: (role == 'agent')
? agentPendings(
title:
"Awaiting Policy (${policiesPendingList.length})",
data: policiesPendingList,
stringFlag: "Policies",
role: role!,
onEdit: (row) {
handleEdit(
row,
); // parent method is called
},
onStaffEdit: (row, flag) {
handleStaffEdit(row, flag);
},
)
: (role == 'staff')
?
// ? othersPendings(
// title:
// "Awaiting Quotation (${quotationsPendingList.length})",
// data: quotationsPendingList,
// stringFlag: "Quotation",
// )
agentPendings(
title:
"Awaiting Policy (${policiesPendingList.length})",
data: policiesPendingList,
stringFlag: "Policies",
role: role!,
onEdit: (row) {
handleEdit(
row,
); // parent method is called
},
onStaffEdit: (row, flag) {
handleStaffEdit(row, flag);
},
)
: SizedBox.shrink(),
),
],
),
),
const SizedBox(height: 10),
if (role == 'manager')
if (role == 'manager' || role == 'handler')
SizedBox(
// replace Expanded
height: 350, // adjust height as needed
@ -670,7 +694,8 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
Expanded(
child: UnassignedEnq(
key: UniqueKey(),
title: "Unassigned Enquires",
title: "Unassigned Enquiries",
role: role!,
data: unAssignedEnqList,
onRefresh: refresh,
),
@ -1094,11 +1119,13 @@ class agentPendings extends StatelessWidget {
class othersPendings extends StatelessWidget {
final String title;
final String stringFlag;
String role;
final List<Map<String, dynamic>> data;
othersPendings({
Key? key,
required this.title,
required this.role,
required this.data,
required this.stringFlag,
}) : super(key: key);
@ -1137,6 +1164,16 @@ class othersPendings extends StatelessWidget {
// style: _headerStyle,
// ),
// ),
if (role == 'manager') ...[
Expanded(
flex: 2,
child: Text(
"Handler Name",
textAlign: TextAlign.center,
style: _headerStyle,
),
),
],
Expanded(
flex: 2,
child: Text(
@ -1145,25 +1182,49 @@ class othersPendings extends StatelessWidget {
style: _headerStyle,
),
),
Expanded(
flex: 2,
child: Text(
// stringFlag + " Issued",
'Pending Count',
'Num Of Enquiry Assigned',
textAlign: TextAlign.center,
style: _headerStyle,
),
),
Expanded(
flex: 2,
child: Text(
'Awaiting Proposal',
textAlign: TextAlign.center,
style: _headerStyle,
),
),
Expanded(
flex: 2,
child: Text(
'Awaiting Approval',
textAlign: TextAlign.center,
style: _headerStyle,
),
),
Expanded(
flex: 2,
child: Text(
'Awaiting Policy',
textAlign: TextAlign.center,
style: _headerStyle,
),
),
Expanded(
flex: 2,
child: Text(
// stringFlag + " Issued",
'Policy Created',
textAlign: TextAlign.center,
style: _headerStyle,
),
),
// (stringFlag == "Policies")
// ? Expanded(
// flex: 2,
// child: Text(
// "Total Premium Value",
// textAlign: TextAlign.center,
// style: _headerStyle,
// ),
// )
// : const SizedBox.shrink(),
],
),
),
@ -1204,6 +1265,17 @@ class othersPendings extends StatelessWidget {
// style: _tableDataStyle,
// ),
// ),
if (role == 'manager') ...[
Expanded(
flex: 2,
child: Text(
row['handler_name'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
),
],
Expanded(
flex: 2,
child: Text(
@ -1217,25 +1289,48 @@ class othersPendings extends StatelessWidget {
Expanded(
flex: 2,
child: Text(
issuedCount,
row['total_assigned'] ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
),
Expanded(
flex: 2,
child: Text(
row['awaiting_quotation'] ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
),
Expanded(
flex: 2,
child: Text(
row['pending_quotation_approval'] ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
),
Expanded(
flex: 2,
child: Text(
row['awaiting_policy'] ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
),
Expanded(
flex: 2,
child: Text(
row['policy_created'] ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
),
// stringFlag == "Policies"
// ? Expanded(
// flex: 2,
// child: Text(
// formatToCroresLakhsAndThousands(permiumValue),
// textAlign: TextAlign.center,
// style: GoogleFonts.inter(
// fontSize: 14,
// fontWeight: FontWeight.w500,
// ),
// ),
// )
// : const SizedBox.shrink(),
],
),
);
@ -1553,12 +1648,14 @@ class UnassignedEnq extends StatelessWidget {
final String title;
final List<Map<String, dynamic>> data;
final VoidCallback? onRefresh;
String role;
UnassignedEnq({
Key? key,
required this.title,
required this.data,
this.onRefresh,
required this.role,
}) : super(key: key);
@override
@ -1647,26 +1744,28 @@ class UnassignedEnq extends StatelessWidget {
// color: Colors.green ,
// width: 2,
// ),
onTap: () {
// Print the id when row is clicked
print("Clicked ID: ${row['id']}");
// You can also navigate or perform any action here
onTap: (role == 'handler')
? () {
// Print the id when row is clicked
print("Clicked ID: ${row['id']}");
// You can also navigate or perform any action here
showDialog(
context: context,
builder: (ctx) => AssignStaffDialog(
enquiryPrimaryId: row['id'],
regNum: row['reg_no'],
userId: 1,
onSubmit: (value) {
debugPrint("New assignY: $value");
if (onRefresh != null) {
onRefresh!(); // call the parent's refresh
}
},
),
);
},
showDialog(
context: context,
builder: (ctx) => AssignStaffDialog(
enquiryPrimaryId: row['id'],
regNum: row['reg_no'],
userId: 1,
onSubmit: (value) {
debugPrint("New assignY: $value");
if (onRefresh != null) {
onRefresh!(); // call the parent's refresh
}
},
),
);
}
: null,
child: Container(
// height: 5200,
margin: const EdgeInsets.symmetric(vertical: 5),

File diff suppressed because it is too large Load Diff

View File

@ -136,6 +136,8 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
if (roleId.toString() == "1") {
role = "manager";
} else if (roleId.toString() == "2") {
role = "handler";
} else if (roleId.toString() == "3") {
role = "staff";
} else {
role = "agent"; // fallback if unexpected value
@ -171,6 +173,20 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
print("⚠️ Manager ID is null or invalid");
}
// Handler ID
final dynamic handlerIdRaw = data['manager_id'];
final int? handlerId = handlerIdRaw is int
? handlerIdRaw
: int.tryParse(handlerIdRaw.toString());
if (handlerId != null) {
ref.read(handlerIdProvider.notifier).state = handlerId;
print("✅ handlerId ID saved globally: $handlerId");
await prefs.setInt('handlerId', handlerId);
} else {
print("⚠️ handlerId ID is null or invalid");
}
// User ID
final dynamic userIdRaw = data['id'];
final int? userId = userIdRaw is int
@ -966,7 +982,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
width: double.infinity,
height: 50,
child: CommonButton(
text: "Login as Agent",
text: "Login as Partner",
backgroundColor: Color(0xFF436462),
onPressed: () async {
setState(() {

View File

@ -287,48 +287,47 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
regNum,
) {
return [
if (roleId == 'manager' && data['status'] == 'Awaiting Quotation') ...[
Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
Navigator.pop(context);
showDialog(
context: context,
builder: (ctx) => AssignStaffDialog(
enquiryPrimaryId: id,
regNum: regNum,
userId: 1,
onSubmit: (value) {
debugPrint("New assignY: $value");
refresh();
},
),
);
},
hoverColor: Color(0xFFE3F1F0),
splashColor: Color(0xFFE3F1F0),
borderRadius: BorderRadius.circular(6),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
child: Row(
// mainAxisSize: MainAxisSize.min,
children: [
Image.asset(
"assets/miscellaneous/image_3.png",
// height: 45,
// width: 15,
),
SizedBox(width: 10),
Text('Assign Staff'),
],
),
),
),
),
],
// if (roleId == 'manager' && data['status'] == 'Awaiting Quotation') ...[
// Material(
// color: Colors.transparent,
// child: InkWell(
// onTap: () {
// Navigator.pop(context);
// showDialog(
// context: context,
// builder: (ctx) => AssignStaffDialog(
// enquiryPrimaryId: id,
// regNum: regNum,
// userId: 1,
// onSubmit: (value) {
// debugPrint("New assignY: $value");
// refresh();
// },
// ),
// );
// },
// hoverColor: Color(0xFFE3F1F0),
// splashColor: Color(0xFFE3F1F0),
// borderRadius: BorderRadius.circular(6),
// child: Padding(
// padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
// child: Row(
// // mainAxisSize: MainAxisSize.min,
// children: [
// Image.asset(
// "assets/miscellaneous/image_3.png",
// // height: 45,
// // width: 15,
// ),
//
// SizedBox(width: 10),
// Text('Assign Staff'),
// ],
// ),
// ),
// ),
// ),
// ],
Material(
color: Colors.transparent,
child: InkWell(
@ -435,7 +434,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 40,
height: 30,
width: MediaQuery.of(context).size.width,
child: GestureDetector(
onTap: () {
@ -470,7 +469,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
),
),
),
SizedBox(height: 10),
SizedBox(height: 5),
ResponsiveLayout.isMobile(context)
? Container(
height: MediaQuery.of(context).size.height * 0.69,
@ -647,49 +646,10 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
"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),
// SizedBox(height: 10),
if (!ResponsiveLayout.isMobile(context))
Container(
decoration: BoxDecoration(
@ -701,38 +661,23 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
children: [
Expanded(
flex: 3,
child: Text('Created Date', style: _headerStyle),
child: Text('Received Date & Time', style: _headerStyle),
),
Expanded(flex: 2, child: Text('Partner ', style: _headerStyle)),
Expanded(flex: 4, child: Text('Insurer', style: _headerStyle)),
Expanded(
flex: 3,
child: Text('Vehicle No', style: _headerStyle),
),
Expanded(
flex: 3,
child: Text('Updated Date', style: _headerStyle),
child: Text('Insured Name', style: _headerStyle),
),
Expanded(flex: 2, child: Text('Reg.No', style: _headerStyle)),
Expanded(flex: 2, child: Text('Partner', style: _headerStyle)),
Expanded(
flex: 2,
child: Text('Assigned To', style: _headerStyle),
),
Expanded(flex: 3, child: Text('Insurer', style: _headerStyle)),
Expanded(
flex: 3,
child: Padding(
padding: EdgeInsets.only(left: 8.0),
child: Text('Insured Name', style: _headerStyle),
),
child: Text('Assigned Date & Time', 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: 3, child: Text('Status', style: _headerStyle)),
Expanded(flex: 1, child: Text('Action', style: _headerStyle)),
],
),
),
@ -836,6 +781,51 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
maxLines: 3,
),
),
Expanded(
flex: 2,
child: Text(
item['agent_name'] ?? '-',
style: _dataBold,
softWrap: true,
maxLines: 2,
),
),
Expanded(
flex: 4,
child: Text(
item['insurer_name'] ?? '-',
style: _dataBold,
softWrap: true,
maxLines: 3,
),
),
Expanded(
flex: 3,
child: InkWell(
hoverColor: Color(0xffD9EBE8),
focusColor: Color(0xffD9EBE8),
splashColor: Color(0xffD9EBE8),
highlightColor: Color(0xffD9EBE8),
onTap: () {
dynamic id = item['id'];
print("ENQID : $id ");
},
child: Text(item['reg_no'] ?? '-', style: _dataBold),
),
),
Expanded(
flex: 3,
child: Text(
item['insured_name'] ?? '-',
style: _dataBold,
softWrap: true,
maxLines: 3,
),
),
Expanded(
flex: 3,
child: Text(
@ -845,112 +835,81 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
maxLines: 3,
),
),
Expanded(
flex: 2,
child: Text(item['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: 3,
child: Text(
item['insurer_name'] ?? '-',
style: _dataBold,
softWrap: true,
maxLines: 3,
),
),
Expanded(
flex: 3,
child: Center(
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: 3,
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.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: _buildPopupMenuActions(
context,
item,
item['id'],
item['reg_no'],
),
),
),
),
],
),
],
),
),
// Expanded(
// flex: 2,
// child: Text(item['assigned_to_name'] ?? '-', style: _dataBold),
// ),
//
// 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: 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.start,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: _buildPopupMenuActions(
// context,
// item,
// item['id'],
// item['reg_no'],
// ),
// ),
// ),
// ),
// ],
// ),
// ],
// ),
// ),
],
),
);

File diff suppressed because it is too large Load Diff

View File

@ -2,8 +2,10 @@ import 'dart:convert';
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
import 'package:toastification/toastification.dart';
import '../../../../core/config/env.dart';
@ -12,11 +14,12 @@ import '../../../../data/services/auth_service.dart';
import '../../../../data/utils/toastNotification.dart';
import '../../../../data/utils/validators.dart';
import '../../layouts/responsive_layout.dart';
import '../../providers/manager_provider.dart';
import '../../themes/indicators/input_field_decoration.dart';
import '../../themes/indicators/text_field_theme.dart';
// 🔹 Custom Dialog Widget
class AssignStaffDialog extends StatefulWidget {
class AssignStaffDialog extends ConsumerStatefulWidget {
final dynamic userId;
final dynamic regNum;
final dynamic enquiryPrimaryId;
@ -32,10 +35,11 @@ class AssignStaffDialog extends StatefulWidget {
});
@override
State<AssignStaffDialog> createState() => _AddDialogState();
// State<AssignStaffDialog> createState() => _AddDialogState();
ConsumerState<AssignStaffDialog> createState() => _AddDialogState();
}
class _AddDialogState extends State<AssignStaffDialog> {
class _AddDialogState extends ConsumerState<AssignStaffDialog> {
late ApiService apiService;
String? _token;
@ -44,11 +48,18 @@ class _AddDialogState extends State<AssignStaffDialog> {
late TextEditingController controller;
Map<String, TextEditingController> controllers = {};
List<Map<String, dynamic>> getInsurersData = [];
List<Map<String, dynamic>> filteredInsurersData = [];
String? selectedInsurer;
final _formKey = GlobalKey<FormState>();
final _formKeyEndrosment = GlobalKey<FormState>();
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKey =
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
final GlobalKey<DropdownSearchState<Map<String, dynamic>>>
dropDownKeyInsurer = GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
List<String> tabHeader = ['regNum'];
List<Map<String, dynamic>> getStaffDetailsData = [];
@ -62,6 +73,7 @@ class _AddDialogState extends State<AssignStaffDialog> {
final data = {
"id": widget.enquiryPrimaryId,
"assigned_to": selectedStaff,
"insurer_id": selectedInsurer,
"updated_by": widget.userId,
};
return data;
@ -80,7 +92,16 @@ class _AddDialogState extends State<AssignStaffDialog> {
// 🔹 Init logic here (API calls, token fetch, etc.)
_initializeToken();
getStaffDetails();
// getStaffDetails(1);
getInsurers();
Future.microtask(() {
final managerId = ref.watch(managerIdProvider);
final handlerId = ref.watch(handlerIdProvider);
if (handlerId != null) {
print('hansles');
getStaffDetails(handlerId);
}
});
}
Future<void> _initializeToken() async {
@ -88,14 +109,47 @@ class _AddDialogState extends State<AssignStaffDialog> {
print("APISERTOKEN - $_token");
}
Future<void> getStaffDetails() async {
Future<void> getInsurers() async {
print('Insurers called');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchMasterDropDown('Insurers');
if (response['status'] == 200) {
print('getInsurers - ${response['data']}');
setState(() {
getInsurersData = List<Map<String, dynamic>>.from(response['data']);
print('API Data - $getInsurersData');
filteredInsurersData = List.from(getInsurersData);
print('originalData - $filteredInsurersData');
});
} else {
getInsurersData = [];
filteredInsurersData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
Future<void> getStaffDetails(int id) async {
print('getStaffDetails called');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchMasterDropDown('Staffs');
final response = await apiService.fetchStaffListForEnquiryAssignDropDown(
id,
);
if (response['status'] == 200) {
print('getStaffDetails - ${response['data']}');
@ -301,6 +355,7 @@ class _AddDialogState extends State<AssignStaffDialog> {
children: [
buildRegistrationNumber(context),
buildSelectStaffMem(context),
buildInsurer(context),
],
),
);
@ -364,7 +419,7 @@ class _AddDialogState extends State<AssignStaffDialog> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Select Staff Member", style: _textStyle),
Text("Select Staff Member *", style: _textStyle),
SizedBox(height: 10),
Container(
color: Colors.white,
@ -446,10 +501,101 @@ class _AddDialogState extends State<AssignStaffDialog> {
);
}
Widget buildInsurer(BuildContext context) {
Map<String, dynamic>? selectedInsurerd = filteredInsurersData.firstWhere(
(item) => item['id'].toString() == selectedInsurer,
orElse: () => {},
);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Insurer *', style: _textStyle),
SizedBox(height: 10),
Container(
decoration: BoxDecoration(
color: Colors.white,
// borderRadius: BorderRadius.circular(10.0),
),
width: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
// height: 40,
child: DropdownSearch<Map<String, dynamic>>(
key: dropDownKeyInsurer,
selectedItem: selectedInsurerd.isNotEmpty ? selectedInsurerd : null,
items: (filter, infiniteScrollProps) {
return filteredInsurersData;
},
itemAsString: (val) => val['name'].toString(), // what to show
compareFn: (item, selectedItem) =>
item['id'] == selectedItem['id'], // compare by id
validator: (val) {
if (val == null) {
return "Required"; // error message
}
return null;
},
decoratorProps: DropDownDecoratorProps(
decoration:
AppInputDecorations.dropdownDecoration(
label: "Select Insurer",
).copyWith(
filled: true,
fillColor: Color(
0xFFEDF6F5,
), // 👈 makes the dropdown input white
),
),
popupProps: PopupProps.menu(
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 250),
menuProps: MenuProps(
backgroundColor:
Colors.white, // 👈 sets dropdown background to white
),
showSearchBox: true,
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
hintText: "Search Insurer...",
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
), // 👈 Normal border
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
width: 1.5,
), // 👈 Focused border
),
),
),
// constraints: BoxConstraints(),
),
onChanged: (val) {
if (val != null) {
print("Selected Insurer : ${val['name']}");
print("Id: ${val['id']}");
selectedInsurer = val['id'];
// controllers['agentId']?.text = val['agent_code'];
// agentId = agent['id'];
}
},
),
),
],
);
}
// ------------------- STyle ---------------------------------
static final TextStyle _textStyle = TextStyle(
fontSize: 14,
fontSize: 12,
fontWeight: FontWeight.w600,
);

View File

@ -66,7 +66,7 @@ class createQuotatDialogState extends State<createQuotatDialog> {
final GlobalKey<DropdownSearchState<Map<String, dynamic>>>
dropDownKeyInsurer = GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
List<String> tabHeader = ['idv', 'premium_Amount'];
List<String> tabHeader = ['idv', 'premium_Amount', 'insurer'];
List<Map<String, dynamic>> getInsuranceTypeData = [];
List<Map<String, dynamic>> filteredInsuranceData = [];
@ -99,7 +99,7 @@ class createQuotatDialogState extends State<createQuotatDialog> {
// 🔹 Init logic here (API calls, token fetch, etc.)
_initializeToken();
getInsuranceType();
getInsurers();
// getInsurers();
updateData();
}
@ -135,8 +135,8 @@ class createQuotatDialogState extends State<createQuotatDialog> {
.selectedQuotationFrmListdata!['insurance_plan_type_id']
?.toString();
selectedInsurer =
widget.selectedQuotationFrmListdata!['insurer_id']?.toString() ?? '';
// selectedInsurer =
// widget.selectedQuotationFrmListdata!['insurer_id']?.toString() ?? '';
String? apiDocPath =
widget.selectedQuotationFrmListdata!["additional_uploaded_file_name"];
@ -465,96 +465,115 @@ class createQuotatDialogState extends State<createQuotatDialog> {
}
Widget buildInsurer(BuildContext context) {
Map<String, dynamic>? selectedInsurerd = filteredInsurersData.firstWhere(
(item) => item['id'].toString() == selectedInsurer,
orElse: () => {},
);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Insurer *', style: _textStyle),
SizedBox(height: 10),
Container(
decoration: BoxDecoration(
color: Colors.white,
// borderRadius: BorderRadius.circular(10.0),
),
width: ResponsiveLayout.isMobile(context)
ThemedFormField(
controller: controllers['insurer']!,
validator: (value) => Validators.requiredField(value, "insurer"),
backgroundColor: Color(0xFFEDF6F5),
readOnly: true,
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
// height: 40,
child: DropdownSearch<Map<String, dynamic>>(
key: dropDownKeyInsurer,
selectedItem: selectedInsurerd.isNotEmpty ? selectedInsurerd : null,
items: (filter, infiniteScrollProps) {
return filteredInsurersData;
},
itemAsString: (val) => val['name'].toString(), // what to show
compareFn: (item, selectedItem) =>
item['id'] == selectedItem['id'], // compare by id
validator: (val) {
if (val == null) {
return "Required"; // error message
}
return null;
},
decoratorProps: DropDownDecoratorProps(
decoration:
AppInputDecorations.dropdownDecoration(
label: "Select Insurer",
).copyWith(
filled: true,
fillColor: Color(
0xFFEDF6F5,
), // 👈 makes the dropdown input white
),
),
popupProps: PopupProps.menu(
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 250),
menuProps: MenuProps(
backgroundColor:
Colors.white, // 👈 sets dropdown background to white
),
showSearchBox: true,
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
hintText: "Search Insurer...",
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
), // 👈 Normal border
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
width: 1.5,
), // 👈 Focused border
),
),
),
// constraints: BoxConstraints(),
),
onChanged: (val) {
if (val != null) {
print("Selected Insurer : ${val['name']}");
print("Id: ${val['id']}");
selectedInsurer = val['id'];
// controllers['agentId']?.text = val['agent_code'];
// agentId = agent['id'];
}
},
),
),
],
);
}
// Widget buildInsurer(BuildContext context) {
// Map<String, dynamic>? selectedInsurerd = filteredInsurersData.firstWhere(
// (item) => item['id'].toString() == selectedInsurer,
// orElse: () => {},
// );
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text('Insurer *', style: _textStyle),
// SizedBox(height: 10),
// Container(
// decoration: BoxDecoration(
// color: Colors.white,
// // borderRadius: BorderRadius.circular(10.0),
// ),
// width: ResponsiveLayout.isMobile(context)
// ? null
// : MediaQuery.of(context).size.width * 0.26,
// // height: 40,
// child: DropdownSearch<Map<String, dynamic>>(
// key: dropDownKeyInsurer,
// selectedItem: selectedInsurerd.isNotEmpty ? selectedInsurerd : null,
// items: (filter, infiniteScrollProps) {
// return filteredInsurersData;
// },
//
// itemAsString: (val) => val['name'].toString(), // what to show
// compareFn: (item, selectedItem) =>
// item['id'] == selectedItem['id'], // compare by id
// validator: (val) {
// if (val == null) {
// return "Required"; // error message
// }
// return null;
// },
// decoratorProps: DropDownDecoratorProps(
// decoration:
// AppInputDecorations.dropdownDecoration(
// label: "Select Insurer",
// ).copyWith(
// filled: true,
// fillColor: Color(
// 0xFFEDF6F5,
// ), // 👈 makes the dropdown input white
// ),
// ),
//
// popupProps: PopupProps.menu(
// fit: FlexFit.loose,
// constraints: BoxConstraints(maxHeight: 250),
// menuProps: MenuProps(
// backgroundColor:
// Colors.white, // 👈 sets dropdown background to white
// ),
// showSearchBox: true,
// searchFieldProps: TextFieldProps(
// decoration: InputDecoration(
// filled: true,
// fillColor: Colors.white,
// hintText: "Search Insurer...",
// enabledBorder: OutlineInputBorder(
// borderSide: BorderSide(
// color: Colors.white,
// ), // 👈 Normal border
// ),
// focusedBorder: OutlineInputBorder(
// borderSide: BorderSide(
// color: Colors.white,
// width: 1.5,
// ), // 👈 Focused border
// ),
// ),
// ),
// // constraints: BoxConstraints(),
// ),
//
// onChanged: (val) {
// if (val != null) {
// print("Selected Insurer : ${val['name']}");
// print("Id: ${val['id']}");
// selectedInsurer = val['id'];
// // controllers['agentId']?.text = val['agent_code'];
// // agentId = agent['id'];
// }
// },
// ),
// ),
// ],
// );
// }
Widget buildPremiumAmnt(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,

View File

@ -127,6 +127,8 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
_hidePopup();
if (roleId == 'agent') {
context.go(AppRoutes.enquiryLst);
} else if (roleId == 'handler') {
context.go(AppRoutes.enquiryHandlerLst);
} else {
context.go(AppRoutes.enquiryForStaff);
}