Enquiry_Staff_Module
This commit is contained in:
parent
cf5107f764
commit
4acdbca2b2
File diff suppressed because one or more lines are too long
BIN
assets/miscellaneous/Edit.png
Normal file
BIN
assets/miscellaneous/Edit.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 444 B |
BIN
assets/miscellaneous/Edit_muted.png
Normal file
BIN
assets/miscellaneous/Edit_muted.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 424 B |
BIN
assets/miscellaneous/image_1.png
Normal file
BIN
assets/miscellaneous/image_1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 289 B |
BIN
assets/miscellaneous/image_2.png
Normal file
BIN
assets/miscellaneous/image_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 291 B |
BIN
assets/miscellaneous/image_3.png
Normal file
BIN
assets/miscellaneous/image_3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 250 B |
BIN
assets/miscellaneous/success_img1.png
Normal file
BIN
assets/miscellaneous/success_img1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
@ -18,6 +18,7 @@ import '../../presentation/screens/UserManagement/Staff/staffList.dart';
|
||||
import '../../presentation/screens/home/home_screen.dart';
|
||||
import '../../presentation/screens/login/login_screen.dart';
|
||||
import '../../presentation/screens/splash/splash_screen.dart';
|
||||
import '../../presentation/screens/staff/Enquiry/enquiry_list.dart';
|
||||
import '../../presentation/screens/staff/policy/policy.dart';
|
||||
import '../../presentation/screens/staff/policy/policy_list.dart';
|
||||
import '../../presentation/screens/staff/quotations/quotation.dart';
|
||||
@ -145,6 +146,15 @@ final GoRouter appRouter = GoRouter(
|
||||
path: AppRoutes.policy,
|
||||
builder: (context, state) => const PolicyScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
path: AppRoutes.policy,
|
||||
builder: (context, state) => const PolicyScreen(),
|
||||
),
|
||||
|
||||
GoRoute(
|
||||
path: AppRoutes.enquiryForStaff,
|
||||
builder: (context, state) => const EnquiryStaff(),
|
||||
),
|
||||
],
|
||||
redirect: (context, state) async {
|
||||
final loggedIn = await AuthService.isLoggedIn();
|
||||
|
||||
@ -9,6 +9,7 @@ class AppRoutes {
|
||||
static const String staffLst = '/staffLst';
|
||||
static const staff = '/staff/:id';
|
||||
static const String enquiryLst = '/enquiryLst';
|
||||
static const String enquiryForStaff = '/enquiryForStaff';
|
||||
static const String tabEnquiry = '/tabEnquiry';
|
||||
|
||||
static const String claimlist = '/claimList';
|
||||
|
||||
@ -156,7 +156,14 @@ class ApiService {
|
||||
|
||||
Future<void> getPdfDownload(String path, String id) async {
|
||||
print('getPdfDownload 1');
|
||||
print('getPdfDownload 1 - $path');
|
||||
|
||||
if (path.isEmpty) {
|
||||
ToastHelper.showInfoToast(context, 'No file path found.');
|
||||
return;
|
||||
}
|
||||
final url = Uri.parse('https://venbait.in/nhance/partner/dev/$path');
|
||||
|
||||
await _initializeToken();
|
||||
print('getPdfDownload 2');
|
||||
if (_token == null) throw Exception('Token not found. Please log in.');
|
||||
@ -205,7 +212,10 @@ class ApiService {
|
||||
],
|
||||
),
|
||||
);
|
||||
} else if (response.statusCode == 500) {
|
||||
ToastHelper.showInfoToast(context, 'No File Not Found');
|
||||
} else {
|
||||
ToastHelper.showInfoToast(context, 'No File Not Found');
|
||||
throw Exception('Failed to download file');
|
||||
}
|
||||
}
|
||||
@ -279,6 +289,34 @@ class ApiService {
|
||||
return response;
|
||||
}
|
||||
|
||||
// ----------------------------------- Dashboard -------------------------------------------------
|
||||
Future<Map<String, dynamic>> fetchDashboard(int id, role) async {
|
||||
// print(_token);
|
||||
if (_token == null) {
|
||||
await _initializeToken();
|
||||
}
|
||||
|
||||
final url;
|
||||
|
||||
if (role == 'manager') {
|
||||
url = Uri.parse('${Env.apiUrl}dashboard/managerDashboard?manager_id=$id');
|
||||
} else if (role == 'staff') {
|
||||
url = Uri.parse('${Env.apiUrl}dashboard/staffDashboard?staff_id=$id');
|
||||
} else {
|
||||
url = Uri.parse('${Env.apiUrl}dashboard/agentDashboard?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;
|
||||
}
|
||||
|
||||
// -------------------------------- AGENT ----------------------------------------------
|
||||
|
||||
Future<Map<String, dynamic>> fetchAgentIncentiveList(agentId) async {
|
||||
@ -544,6 +582,38 @@ class ApiService {
|
||||
return response;
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> fetchPolicyDataOnlyList(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&only_policy_data=true',
|
||||
);
|
||||
} else {
|
||||
url = Uri.parse(
|
||||
'${Env.apiUrl}enquiry/enquiryList?staff_id=$id&only_policy_data=true',
|
||||
);
|
||||
}
|
||||
// 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 {
|
||||
|
||||
@ -76,6 +76,17 @@ class Validators {
|
||||
return null;
|
||||
}
|
||||
|
||||
static String? doubleNumber(String? value, String label) {
|
||||
if (value == null || value.trim().isEmpty) {
|
||||
return "$label is required";
|
||||
}
|
||||
// allow integers or decimals with optional fraction part
|
||||
if (!RegExp(r'^[0-9]+(\.[0-9]+)?$').hasMatch(value.trim())) {
|
||||
return "$label must be a valid number";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static String? phone(String? value, String label) {
|
||||
if (value == null || value.trim().isEmpty) {
|
||||
return "Required";
|
||||
|
||||
@ -36,18 +36,18 @@ class MainLayout extends StatelessWidget {
|
||||
),
|
||||
drawer: const DrawerMenu(),
|
||||
body: body,
|
||||
bottomNavigationBar: MobileTabs(
|
||||
onTabChanged: (index) {
|
||||
debugPrint("Mobile tab changed to $index");
|
||||
if (index == 0) {
|
||||
context.go(AppRoutes.dashboard);
|
||||
} else if (index == 1) {
|
||||
context.go(AppRoutes.profile);
|
||||
} else if (index == 2) {
|
||||
// ref.read(enquiryIdProvider.notifier).state = null;
|
||||
context.go(AppRoutes.enquiryLst);
|
||||
}
|
||||
},
|
||||
bottomNavigationBar: MobileBottomMenu(
|
||||
// onTabChanged: (index) {
|
||||
// debugPrint("Mobile tab changed to $index");
|
||||
// if (index == 0) {
|
||||
// context.go(AppRoutes.dashboard);
|
||||
// } else if (index == 1) {
|
||||
// context.go(AppRoutes.profile);
|
||||
// } else if (index == 2) {
|
||||
// // ref.read(enquiryIdProvider.notifier).state = null;
|
||||
// context.go(AppRoutes.enquiryLst);
|
||||
// }
|
||||
// },
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
3
lib/presentation/providers/quotation_staff_proivder.dart
Normal file
3
lib/presentation/providers/quotation_staff_proivder.dart
Normal file
@ -0,0 +1,3 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
final quotationStaffIdProvider = StateProvider<String?>((ref) => null);
|
||||
@ -140,6 +140,15 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
|
||||
print("APISERTOKEN - $_token");
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// Dispose all TextEditingControllers
|
||||
for (var controller in controllers.values) {
|
||||
controller.dispose();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> getVehicleType() async {
|
||||
print('getClaimList called');
|
||||
setState(() {
|
||||
|
||||
@ -102,6 +102,15 @@ class _AddDialogState extends State<AddDialog> {
|
||||
print("APISERTOKEN - $_token");
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// Dispose all TextEditingControllers
|
||||
for (var controller in controllers.values) {
|
||||
controller.dispose();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> getClaimsType() async {
|
||||
print('getClaimList called');
|
||||
setState(() {
|
||||
@ -244,12 +253,6 @@ class _AddDialogState extends State<AddDialog> {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// controllers.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
|
||||
@ -81,6 +81,15 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// Dispose all TextEditingControllers
|
||||
for (var controller in controllers.values) {
|
||||
controller.dispose();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _initializeToken() async {
|
||||
_token = await AuthService.getToken();
|
||||
print("APISERTOKEN - $_token");
|
||||
|
||||
@ -123,6 +123,15 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
|
||||
getQuotationList(managerId);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// Dispose all TextEditingControllers
|
||||
for (var controller in controllers.values) {
|
||||
controller.dispose();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> getQuotationList(managerId) async {
|
||||
print('getClaimList called MagId - $managerId');
|
||||
setState(() {
|
||||
|
||||
@ -106,7 +106,7 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
|
||||
filteredData = getStaffData.where((item) {
|
||||
// final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive";
|
||||
|
||||
return (item['created_on'] ?? '').toLowerCase().contains(
|
||||
return (_formatDate(item['created_on']) ?? '').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
(item['reg_no'] ?? '').toLowerCase().contains(
|
||||
@ -142,10 +142,12 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
|
||||
print('EDITStaff - ${data['id']}');
|
||||
// dynamic id = data['id'];
|
||||
// context.go('/tabEnquiry/$id');
|
||||
|
||||
setState(() {
|
||||
final id = data['id'].toString();
|
||||
ref.read(enquiryIdProvider.notifier).state = id;
|
||||
});
|
||||
// update provider
|
||||
final id = data['id'].toString();
|
||||
ref.read(enquiryIdProvider.notifier).state = id;
|
||||
|
||||
context.go(AppRoutes.tabEnquiry);
|
||||
},
|
||||
child: Row(
|
||||
|
||||
@ -31,6 +31,8 @@ class claimListState extends ConsumerState<claimList> {
|
||||
List<Map<String, dynamic>> filteredData = [];
|
||||
bool isLoading = false;
|
||||
|
||||
final TextEditingController _searchStaffController = TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -114,25 +116,23 @@ class claimListState extends ConsumerState<claimList> {
|
||||
(item['policy_no'] ?? '').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
(item['policy_end_date'] ?? '').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
(item['claim_type'] ?? '').toLowerCase().contains(
|
||||
(item['claim_type_value'] ?? '').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
(item['claim_number'] ?? '').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
);
|
||||
) ||
|
||||
(_formatDate(
|
||||
item['policy_end_date'],
|
||||
).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
|
||||
return DateFormat('dd/MM/yyyy').format(dateTime); // date only
|
||||
} catch (e) {
|
||||
return rawDate; // fallback if parsing fails
|
||||
}
|
||||
@ -323,17 +323,17 @@ class claimListState extends ConsumerState<claimList> {
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
flex: 3,
|
||||
child: Text('Claim Type', style: _headerStyle),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text('Claim No.', style: _headerStyle),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text('Action', style: _headerStyle),
|
||||
),
|
||||
// Expanded(
|
||||
// flex: 1,
|
||||
// child: Text('Action', style: _headerStyle),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -425,86 +425,47 @@ class claimListState extends ConsumerState<claimList> {
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
item['reg_no'] != null
|
||||
? _formatDate(item['reg_no'])
|
||||
: '-', // fallback
|
||||
item['reg_no'] ?? '-', // fallback
|
||||
style: _dataBold,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
item['insurer_name'] != null
|
||||
? _formatDate(item['insurer_name'])
|
||||
: '-', // fallback
|
||||
item['insurer_name'] ?? '-', // fallback
|
||||
style: _dataBold,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(item['policy_no'] ?? '-', style: _dataBold),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
// _formatDate(item['policy_end_date']) ?? '-',
|
||||
item['policy_end_date'] != null
|
||||
? _formatDate(item['policy_end_date'])
|
||||
: '-',
|
||||
style: _dataBold,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(
|
||||
item['claim_type_value'] ?? '-', // fallback
|
||||
style: _dataBold,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
_formatDate(item['policy_no']) ?? '-',
|
||||
item['claim_number'] ?? '-', // fallback
|
||||
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
|
||||
|
||||
// Expanded(
|
||||
// flex: 1,
|
||||
// child: Row(
|
||||
// children: [
|
||||
@ -561,24 +522,24 @@ class claimListState extends ConsumerState<claimList> {
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// 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),
|
||||
@ -597,8 +558,8 @@ class claimListState extends ConsumerState<claimList> {
|
||||
//company
|
||||
const Text("Company", style: _cardheaderStyle),
|
||||
Text(
|
||||
item['reg_no'] != null
|
||||
? _formatDate(item['reg_no'])
|
||||
item['policy_end_date'] != null
|
||||
? _formatDate(item['policy_end_date'])
|
||||
: '-',
|
||||
style: _cardBodyStyle,
|
||||
maxLines: 3,
|
||||
@ -616,7 +577,7 @@ class claimListState extends ConsumerState<claimList> {
|
||||
//status
|
||||
const Text("Claim Type", style: _cardheaderStyle),
|
||||
Text(
|
||||
item['claim_type'] ?? '-',
|
||||
item['claim_type_value'] ?? '-',
|
||||
style: _cardBodyStyle,
|
||||
maxLines: 2,
|
||||
softWrap: true,
|
||||
@ -638,10 +599,7 @@ class claimListState extends ConsumerState<claimList> {
|
||||
children: [
|
||||
//date and time
|
||||
const Text("policy Number", style: _cardheaderStyle),
|
||||
Text(
|
||||
_formatDate(item['policy_no']) ?? '-',
|
||||
style: _cardBodyStyle,
|
||||
),
|
||||
Text(item['policy_no'] ?? '-', style: _cardBodyStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@ -184,7 +184,7 @@ class endosementState extends ConsumerState<endosement> {
|
||||
color: Color(0xFF425B5B),
|
||||
),
|
||||
Text(
|
||||
"Endosement",
|
||||
"Endorsement",
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
@ -325,10 +325,10 @@ class endosementState extends ConsumerState<endosement> {
|
||||
style: _headerStyle,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text('Action', style: _headerStyle),
|
||||
),
|
||||
// Expanded(
|
||||
// flex: 1,
|
||||
// child: Text('Action', style: _headerStyle),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -420,74 +420,65 @@ class endosementState extends ConsumerState<endosement> {
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
item['reg_no'] != null
|
||||
? _formatDate(item['reg_no'])
|
||||
: '-', // fallback
|
||||
item['reg_no'] ?? '-', // fallback
|
||||
style: _dataBold,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
item['insurer_name'] != null
|
||||
? _formatDate(item['insurer_name'])
|
||||
: '-', // fallback
|
||||
item['insurer_name'] ?? '-', // fallback
|
||||
style: _dataBold,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(item['policy_number'] ?? '-', style: _dataBold),
|
||||
),
|
||||
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
_formatDate(item['policy_number']) ?? '-',
|
||||
item['endorsement_type_value'] ?? '-',
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Text(item['endorsement_no'] ?? '-', 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),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
);
|
||||
@ -509,28 +500,25 @@ class endosementState extends ConsumerState<endosement> {
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
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),
|
||||
@ -549,9 +537,7 @@ class endosementState extends ConsumerState<endosement> {
|
||||
//company
|
||||
const Text("Company", style: _cardheaderStyle),
|
||||
Text(
|
||||
item['insurer_name'] != null
|
||||
? _formatDate(item['insurer_name'])
|
||||
: '-',
|
||||
item['insurer_name'] ?? '-',
|
||||
style: _cardBodyStyle,
|
||||
maxLines: 3,
|
||||
softWrap: true,
|
||||
@ -568,7 +554,7 @@ class endosementState extends ConsumerState<endosement> {
|
||||
//status
|
||||
const Text("Endorsement Type", style: _cardheaderStyle),
|
||||
Text(
|
||||
item['endorsement_type'] ?? '-',
|
||||
item['endorsement_type_value'] ?? '-',
|
||||
style: _cardBodyStyle,
|
||||
maxLines: 2,
|
||||
softWrap: true,
|
||||
|
||||
@ -15,6 +15,7 @@ import '../../../../core/config/env.dart';
|
||||
import '../../../../core/services/api_service.dart';
|
||||
import '../../../../data/services/auth_service.dart';
|
||||
import '../../../../data/utils/Pagination.dart';
|
||||
import '../../../../data/utils/toastNotification.dart';
|
||||
import '../../../../data/utils/validators.dart';
|
||||
import '../../../layouts/main_layout.dart';
|
||||
import '../../../providers/manager_provider.dart';
|
||||
@ -237,6 +238,15 @@ class AgentState extends ConsumerState<Agent> {
|
||||
print("✅ Agent submitted successfully!");
|
||||
|
||||
print("Response: ${response.body}");
|
||||
isUpdating
|
||||
? ToastHelper.showSuccessToast(
|
||||
context,
|
||||
'Agent Updated Successfully',
|
||||
)
|
||||
: ToastHelper.showSuccessToast(
|
||||
context,
|
||||
'Agent Created Successfully',
|
||||
);
|
||||
context.go(AppRoutes.agentLst);
|
||||
} else {
|
||||
final responseBody = jsonDecode(response.body);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// import 'dart:io' as html;
|
||||
// import 'dart:nativewrappers/_internal/vm/lib/typed_data_patch.dart';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data'; // Import for Uint8List
|
||||
import 'package:dropdown_search/dropdown_search.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
@ -8,7 +9,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:nhance_partner/data/utils/toastNotification.dart';
|
||||
import 'package:nhance_partner/presentation/themes/indicators/text_field_theme.dart';
|
||||
import 'package:toastification/toastification.dart';
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
|
||||
import '../../../../core/config/env.dart';
|
||||
@ -202,25 +205,31 @@ class UploadIncentiveModalState extends ConsumerState<UploadIncentiveModal> {
|
||||
}
|
||||
|
||||
Future<void> handleSave() async {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
print("Handl1");
|
||||
final dataSet = dataDetails();
|
||||
print("dataSetAgent - $dataSet");
|
||||
print("Handl13f");
|
||||
if (agentId == null) {
|
||||
ToastHelper.showErrorToast(context, 'Select Agent Name');
|
||||
} else {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
print("Handl1");
|
||||
final dataSet = dataDetails();
|
||||
print("dataSetAgent - $dataSet");
|
||||
print("Handl13f");
|
||||
|
||||
if (passportFile == null) {
|
||||
print("❌ No file selected!");
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("Please select a file before submitting")),
|
||||
);
|
||||
return;
|
||||
if (passportFile == null) {
|
||||
print("❌ No file selected!");
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text("Please select a file before submitting"),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
uploadIncentiveData(dataSet);
|
||||
});
|
||||
|
||||
print("Handl2");
|
||||
}
|
||||
|
||||
setState(() {
|
||||
uploadIncentiveData(dataSet);
|
||||
});
|
||||
|
||||
print("Handl2");
|
||||
}
|
||||
|
||||
Future<void> uploadIncentiveData(Map<String, dynamic> dataSet) async {
|
||||
@ -303,6 +312,7 @@ class UploadIncentiveModalState extends ConsumerState<UploadIncentiveModal> {
|
||||
final response = await http.Response.fromStream(streamedResponse);
|
||||
print("Response status: ${response.statusCode}");
|
||||
print("Response body: ${response.body}");
|
||||
final responseBody = json.decode(response.body);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
// dispose();
|
||||
@ -313,7 +323,19 @@ class UploadIncentiveModalState extends ConsumerState<UploadIncentiveModal> {
|
||||
final data = dataDetails();
|
||||
final agentId = data["agent_id"];
|
||||
|
||||
getAgentIncenctiveFileList(agentId);
|
||||
final status = responseBody['status'];
|
||||
final message = responseBody['data'] ?? '';
|
||||
|
||||
if (status == 'success') {
|
||||
ToastHelper.showSuccessToast(context, 'File uploaded successfully!');
|
||||
getAgentIncenctiveFileList(agentId);
|
||||
} else {
|
||||
ToastHelper.showErrorToast(
|
||||
context,
|
||||
message.isNotEmpty ? message : 'Something went wrong!',
|
||||
);
|
||||
}
|
||||
|
||||
// context.go(AppRoutes.agentLst);
|
||||
} else {
|
||||
print("❌ Submission failed. Status: ${response.statusCode}");
|
||||
|
||||
@ -485,37 +485,68 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
),
|
||||
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) => [
|
||||
if (item['is_active'] == "1")
|
||||
CustomPopupMenuEntry(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 8,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: _buildPopupMenuActions(context, item),
|
||||
),
|
||||
child: item['is_active'] == "1"
|
||||
? Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
// Navigator.pop(context);
|
||||
print('EDITStaff - ${item['id']}');
|
||||
dynamic id = item['id'];
|
||||
context.go('/agent/$id');
|
||||
},
|
||||
child: Image.asset(
|
||||
"assets/miscellaneous/Edit.png",
|
||||
height: 15,
|
||||
width: 15,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
children: [
|
||||
Image.asset(
|
||||
"assets/miscellaneous/Edit_muted.png",
|
||||
height: 15,
|
||||
width: 15,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// 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) => [
|
||||
// if (item['is_active'] == "1")
|
||||
// CustomPopupMenuEntry(
|
||||
// child: Container(
|
||||
// padding: EdgeInsets.symmetric(
|
||||
// horizontal: 8,
|
||||
// vertical: 8,
|
||||
// ),
|
||||
// child: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// children: _buildPopupMenuActions(context, item),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@ -155,8 +155,22 @@ class ProfileState extends ConsumerState<Profile> {
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
if (!isProfile) ...[
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isProfile = true;
|
||||
});
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.arrow_back_ios_new_outlined,
|
||||
size: 16,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 4),
|
||||
],
|
||||
Text(
|
||||
isProfile ? '' : 'Incentive Files',
|
||||
style: _topheaderStyle,
|
||||
@ -168,7 +182,7 @@ class ProfileState extends ConsumerState<Profile> {
|
||||
? Container(
|
||||
color: Colors.white,
|
||||
padding: ResponsiveLayout.isMobile(context)
|
||||
? EdgeInsets.all(16.0)
|
||||
? EdgeInsets.all(8.0)
|
||||
: null,
|
||||
child: isLoading
|
||||
? const Center(
|
||||
@ -176,10 +190,10 @@ class ProfileState extends ConsumerState<Profile> {
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
const SizedBox(height: 25),
|
||||
// const SizedBox(height: 25),
|
||||
Container(
|
||||
width: 70,
|
||||
height: 70,
|
||||
width: 60,
|
||||
height: 60,
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xFFD9D9D9),
|
||||
borderRadius: BorderRadius.circular(
|
||||
@ -188,7 +202,7 @@ class ProfileState extends ConsumerState<Profile> {
|
||||
),
|
||||
child: Icon(
|
||||
Icons.person_outline,
|
||||
size: 50,
|
||||
size: 30,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
@ -669,7 +683,7 @@ class ProfileState extends ConsumerState<Profile> {
|
||||
static const _topheaderStyle = TextStyle(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 19,
|
||||
fontSize: 14,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:nhance_partner/core/routing/routes.dart';
|
||||
import 'package:nhance_partner/data/utils/toastNotification.dart';
|
||||
import 'package:nhance_partner/presentation/themes/indicators/text_field_theme.dart';
|
||||
|
||||
import '../../../../core/config/env.dart';
|
||||
@ -159,6 +160,16 @@ class StaffState extends ConsumerState<Staff> {
|
||||
if (response.statusCode == 200) {
|
||||
print("Staff submitted successfully!");
|
||||
print("Response: ${response.body}");
|
||||
|
||||
isUpdating
|
||||
? ToastHelper.showSuccessToast(
|
||||
context,
|
||||
'Staff Updated Successfully',
|
||||
)
|
||||
: ToastHelper.showSuccessToast(
|
||||
context,
|
||||
'Staff Created Successfully',
|
||||
);
|
||||
context.go(AppRoutes.staffLst);
|
||||
} else {
|
||||
final responseBody = jsonDecode(response.body);
|
||||
|
||||
@ -434,37 +434,68 @@ class StaffListState extends ConsumerState<StaffList> {
|
||||
|
||||
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) => [
|
||||
if (item['is_active'] == "1")
|
||||
CustomPopupMenuEntry(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 8,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: _buildPopupMenuActions(context, item),
|
||||
),
|
||||
child: item['is_active'] == "1"
|
||||
? Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
// Navigator.pop(context);
|
||||
print('EDITStaff - ${item['id']}');
|
||||
dynamic id = item['id'];
|
||||
context.go('/staff/$id');
|
||||
},
|
||||
child: Image.asset(
|
||||
"assets/miscellaneous/Edit.png",
|
||||
height: 15,
|
||||
width: 15,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
children: [
|
||||
Image.asset(
|
||||
"assets/miscellaneous/Edit_muted.png",
|
||||
height: 15,
|
||||
width: 15,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// 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) => [
|
||||
// if (item['is_active'] == "1")
|
||||
// CustomPopupMenuEntry(
|
||||
// child: Container(
|
||||
// padding: EdgeInsets.symmetric(
|
||||
// horizontal: 8,
|
||||
// vertical: 8,
|
||||
// ),
|
||||
// child: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// children: _buildPopupMenuActions(context, item),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
914
lib/presentation/screens/staff/Enquiry/enquiry_list.dart
Normal file
914
lib/presentation/screens/staff/Enquiry/enquiry_list.dart
Normal file
@ -0,0 +1,914 @@
|
||||
// import 'dart:io' as html;
|
||||
import 'package:http/http.dart' as http;
|
||||
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 'package:intl/intl.dart';
|
||||
|
||||
import '../../../../core/config/env.dart';
|
||||
import '../../../../core/routing/routes.dart';
|
||||
import '../../../../core/services/api_service.dart';
|
||||
import '../../../../data/services/auth_service.dart';
|
||||
|
||||
import 'package:toastification/toastification.dart';
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
|
||||
import '../../../../core/routing/routes.dart';
|
||||
import '../../../../core/services/api_service.dart';
|
||||
import '../../../../data/services/auth_service.dart';
|
||||
import '../../../../data/utils/Pagination.dart';
|
||||
import '../../../../data/utils/toastNotification.dart';
|
||||
import '../../../../data/utils/validators.dart';
|
||||
|
||||
import '../../../layouts/main_layout.dart';
|
||||
import '../../../layouts/responsive_layout.dart';
|
||||
import '../../../providers/manager_provider.dart';
|
||||
import '../../../providers/quotation_staff_proivder.dart';
|
||||
import '../../../providers/userRoleProvider.dart';
|
||||
import '../../../themes/indicators/customizd_file_upload.dart';
|
||||
import '../../../themes/indicators/date_field_theme.dart';
|
||||
import '../../../themes/indicators/export_btn.dart';
|
||||
import '../../../themes/indicators/search_field_theme.dart';
|
||||
import '../../../themes/indicators/text_field_theme.dart';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
|
||||
import '../../../widgets/custom_action_popup.dart';
|
||||
import '../assignStaff.dart';
|
||||
|
||||
class EnquiryStaff extends ConsumerStatefulWidget {
|
||||
const EnquiryStaff({super.key});
|
||||
@override
|
||||
ConsumerState<EnquiryStaff> createState() => EnquiryStaffState();
|
||||
}
|
||||
|
||||
class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
|
||||
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;
|
||||
dynamic roleId;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
apiService = ApiService();
|
||||
|
||||
Future.microtask(() {
|
||||
final id = ref.read(managerIdProvider);
|
||||
roleId = ref.read(userRoleProvider);
|
||||
|
||||
print("ENQroleId - $roleId");
|
||||
if (id != null) {
|
||||
getStaffList(id, roleId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void refresh() {
|
||||
final id = ref.read(managerIdProvider);
|
||||
final roleId = ref.read(userRoleProvider);
|
||||
|
||||
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 sortedData = [...filteredData];
|
||||
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(),
|
||||
) ||
|
||||
(_formatDate(item['updated_on']) ?? '').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
(item['policy_number'] ?? '').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
(item['status'] ?? '').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,
|
||||
id,
|
||||
regNum,
|
||||
) {
|
||||
return [
|
||||
if (roleId == 'manager') ...[
|
||||
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(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
ref.read(quotationStaffIdProvider.notifier).state = id;
|
||||
context.go(AppRoutes.quotation);
|
||||
},
|
||||
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_1.png",
|
||||
height: 15,
|
||||
width: 15,
|
||||
),
|
||||
|
||||
const SizedBox(width: 10),
|
||||
((data['status'] == 'Policy Created') ||
|
||||
(data['status'] == 'Quotation Accepted'))
|
||||
? const Text('View Quotation')
|
||||
: const Text('Create Quotation'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
if (data['status'] == 'Quotation Accepted' ||
|
||||
data['status'] == 'Policy Created')
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
ref.read(quotationStaffIdProvider.notifier).state = id;
|
||||
context.go(AppRoutes.policy);
|
||||
},
|
||||
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_2.png",
|
||||
height: 15,
|
||||
width: 15,
|
||||
),
|
||||
|
||||
const SizedBox(width: 10),
|
||||
data['status'] == 'Policy Created'
|
||||
? Text('View Policy')
|
||||
: Text('Create Policy'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MainLayout(
|
||||
title: "Enquiries",
|
||||
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(
|
||||
"Enquiries",
|
||||
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('Date', style: _headerStyle),
|
||||
),
|
||||
|
||||
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: 3,
|
||||
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(
|
||||
_formatDate(item['updated_on']) ?? '-',
|
||||
style: _dataBold,
|
||||
softWrap: true,
|
||||
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: 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: 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'],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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: [
|
||||
/// Top row: Reg.No + Action menu
|
||||
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,
|
||||
children: _buildPopupMenuActions(
|
||||
context,
|
||||
item,
|
||||
item['id'],
|
||||
item['reg_no'],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(color: Color(0xffD9EBE8), thickness: 0.8),
|
||||
|
||||
/// Company + Status
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Company", style: _cardheaderStyle),
|
||||
Text(item['insurer_name'] ?? '-', style: _cardBodyStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Status", style: _cardheaderStyle),
|
||||
Text(item['status'] ?? '-', style: _cardBodyStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
/// Agents + Assigned To
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Agent", style: _cardheaderStyle),
|
||||
Text(item['agent_name'] ?? '-', style: _cardBodyStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Assigned To", style: _cardheaderStyle),
|
||||
Text(
|
||||
item['assigned_to_name'] ?? '-',
|
||||
style: _cardBodyStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
/// Insured Name + Premium
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Insured Name", style: _cardheaderStyle),
|
||||
Text(item['insured_name'] ?? '-', style: _cardBodyStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Premium", style: _cardheaderStyle),
|
||||
Text(item['premium_amount'] ?? '-', style: _cardBodyStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
/// Payment Mode + Policy Number
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Payment Mode", style: _cardheaderStyle),
|
||||
Text(item['payment_mode'] ?? '-', style: _cardBodyStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Policy Number", style: _cardheaderStyle),
|
||||
Text(item['policy_number'] ?? '-', style: _cardBodyStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
/// Date + Remarks
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Date", style: _cardheaderStyle),
|
||||
Text(
|
||||
_formatDate(item['updated_on']) ?? '-',
|
||||
style: _cardBodyStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Remarks", style: _cardheaderStyle),
|
||||
Text(
|
||||
item['remarks'] ?? '-',
|
||||
style: _cardBodyStyle,
|
||||
maxLines: 3,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
455
lib/presentation/screens/staff/assignStaff.dart
Normal file
455
lib/presentation/screens/staff/assignStaff.dart
Normal file
@ -0,0 +1,455 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:dropdown_search/dropdown_search.dart';
|
||||
import 'package:flutter/material.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';
|
||||
import '../../../../core/services/api_service.dart';
|
||||
import '../../../../data/services/auth_service.dart';
|
||||
import '../../../../data/utils/toastNotification.dart';
|
||||
import '../../../../data/utils/validators.dart';
|
||||
import '../../layouts/responsive_layout.dart';
|
||||
import '../../themes/indicators/input_field_decoration.dart';
|
||||
import '../../themes/indicators/text_field_theme.dart';
|
||||
|
||||
// 🔹 Custom Dialog Widget
|
||||
class AssignStaffDialog extends StatefulWidget {
|
||||
final dynamic userId;
|
||||
final dynamic regNum;
|
||||
final dynamic enquiryPrimaryId;
|
||||
final void Function(String value) onSubmit;
|
||||
|
||||
const AssignStaffDialog({
|
||||
super.key,
|
||||
|
||||
required this.onSubmit,
|
||||
required this.regNum,
|
||||
required this.userId,
|
||||
required this.enquiryPrimaryId,
|
||||
});
|
||||
|
||||
@override
|
||||
State<AssignStaffDialog> createState() => _AddDialogState();
|
||||
}
|
||||
|
||||
class _AddDialogState extends State<AssignStaffDialog> {
|
||||
late ApiService apiService;
|
||||
String? _token;
|
||||
|
||||
bool isLoading = false;
|
||||
bool showSuccess = false;
|
||||
late TextEditingController controller;
|
||||
Map<String, TextEditingController> controllers = {};
|
||||
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final _formKeyEndrosment = GlobalKey<FormState>();
|
||||
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKey =
|
||||
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
||||
|
||||
List<String> tabHeader = ['regNum'];
|
||||
|
||||
List<Map<String, dynamic>> getStaffDetailsData = [];
|
||||
List<Map<String, dynamic>> filteredStaffData = [];
|
||||
|
||||
String? selectedStaff;
|
||||
String? selectedRegNum;
|
||||
String? selectedStaffName;
|
||||
|
||||
Map<String, dynamic> dataDetails() {
|
||||
final data = {
|
||||
"id": widget.enquiryPrimaryId,
|
||||
"assigned_to": selectedStaff,
|
||||
"updated_by": widget.userId,
|
||||
};
|
||||
return data;
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
apiService = ApiService();
|
||||
for (String field in tabHeader) {
|
||||
controllers[field] = TextEditingController();
|
||||
}
|
||||
|
||||
controllers["regNum"]?.text = widget.regNum;
|
||||
selectedRegNum = widget.regNum;
|
||||
|
||||
// 🔹 Init logic here (API calls, token fetch, etc.)
|
||||
_initializeToken();
|
||||
getStaffDetails();
|
||||
}
|
||||
|
||||
Future<void> _initializeToken() async {
|
||||
_token = await AuthService.getToken();
|
||||
print("APISERTOKEN - $_token");
|
||||
}
|
||||
|
||||
Future<void> getStaffDetails() async {
|
||||
print('getStaffDetails called');
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
|
||||
try {
|
||||
final response = await apiService.fetchMasterDropDown('Staffs');
|
||||
|
||||
if (response['status'] == 200) {
|
||||
print('getStaffDetails - ${response['data']}');
|
||||
setState(() {
|
||||
getStaffDetailsData = List<Map<String, dynamic>>.from(
|
||||
response['data'],
|
||||
);
|
||||
print('API Data - $getStaffDetailsData');
|
||||
|
||||
filteredStaffData = List.from(getStaffDetailsData);
|
||||
print('originalData - $filteredStaffData');
|
||||
});
|
||||
} else {
|
||||
getStaffDetailsData = [];
|
||||
filteredStaffData = [];
|
||||
}
|
||||
} catch (e) {
|
||||
print('Exception occurred: $e');
|
||||
} finally {
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void handleDone() {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
setState(() {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
dataDetails();
|
||||
final dataSet = dataDetails();
|
||||
print("dataSetAgent - $dataSet");
|
||||
// print("managerId - $managerId ,userId - $userId ");
|
||||
createUserData(dataSet);
|
||||
} else {
|
||||
// isDi sable = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> createUserData(data) async {
|
||||
// final bool isUpdating = widget.id != null && widget.id != 'create';
|
||||
final String apiUrldata;
|
||||
|
||||
apiUrldata = '${Env.apiUrl}enquiry/enquiryAssignUpdate';
|
||||
|
||||
// final token = await getToken(); // Fetch token
|
||||
|
||||
if (_token == null) {
|
||||
throw Exception('Token not found. Please log in.');
|
||||
}
|
||||
|
||||
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("Staff submitted successfully!");
|
||||
print("Response: ${response.body}");
|
||||
ToastHelper.showSuccessToast(context, 'Saved Successfully');
|
||||
|
||||
setState(() {
|
||||
showSuccess = true;
|
||||
});
|
||||
|
||||
// Navigator.of(context).pop();
|
||||
//
|
||||
widget.onSubmit("success");
|
||||
// context.go(AppRoutes.staffLst);
|
||||
} 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 Staff: $e");
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// controllers.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
backgroundColor: Colors.white,
|
||||
content: showSuccess
|
||||
? Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF1F1F1),
|
||||
borderRadius: BorderRadius.circular(5.0),
|
||||
),
|
||||
child: const Icon(Icons.close, size: 18),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
successContent(context),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Header row
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Assign Vehicle Policy',
|
||||
style: GoogleFonts.inter(
|
||||
color: const Color(0xFF374141),
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF1F1F1),
|
||||
borderRadius: BorderRadius.circular(5.0),
|
||||
),
|
||||
child: const Icon(Icons.close, size: 18),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 🔹 Switch content dynamically
|
||||
claims(context),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
if (!showSuccess)
|
||||
Center(
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
handleDone();
|
||||
// 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(
|
||||
'Assign Policy',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// 🔹 Example: Claims widget
|
||||
Widget claims(BuildContext context) {
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
buildRegistrationNumber(context),
|
||||
buildSelectStaffMem(context),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget successContent(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
"assets/miscellaneous/success_img1.png",
|
||||
height: 60,
|
||||
width: 60,
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
Text('Vehicle policy successfully assigned ', style: _successText),
|
||||
Text(
|
||||
'to $selectedStaffName for vehicle $selectedRegNum',
|
||||
style: _successText,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// ------------------------- Widget Part -----------------------------------
|
||||
Widget buildRegistrationNumber(context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Registration Number", style: _textStyle),
|
||||
SizedBox(height: 10),
|
||||
ThemedFormField(
|
||||
controller: controllers['regNum']!,
|
||||
backgroundColor: Color(0xFFEDF6F5),
|
||||
// validator: (value) => Validators.requiredField(value, "name"),
|
||||
txtwidth: ResponsiveLayout.isMobile(context)
|
||||
? null
|
||||
: MediaQuery.of(context).size.width * 0.26,
|
||||
readOnly: true,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildSelectStaffMem(ctx) {
|
||||
// Map<String, dynamic>? selectedVehicle = filteredStaffData.firstWhere(
|
||||
// (item) => item['id'].toString() == selectedStaff,
|
||||
// orElse: () => {},
|
||||
// );
|
||||
|
||||
Map<String, dynamic>? selectedVehicle;
|
||||
try {
|
||||
selectedVehicle = filteredStaffData.firstWhere(
|
||||
(item) => item['id'].toString() == selectedStaff,
|
||||
);
|
||||
} catch (e) {
|
||||
selectedVehicle = null; // ✅ fallback
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Select Staff Member", style: _textStyle),
|
||||
SizedBox(height: 10),
|
||||
Container(
|
||||
color: Colors.white,
|
||||
width: ResponsiveLayout.isMobile(context)
|
||||
? null
|
||||
: MediaQuery.of(context).size.width * 0.26,
|
||||
// height: 40,
|
||||
child: DropdownSearch<Map<String, dynamic>>(
|
||||
key: dropDownKey,
|
||||
// selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null,
|
||||
selectedItem: selectedVehicle,
|
||||
items: (filter, infiniteScrollProps) {
|
||||
return filteredStaffData;
|
||||
},
|
||||
|
||||
itemAsString: (val) => val['name'].toString(),
|
||||
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 Staff Member",
|
||||
).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 Staff ...",
|
||||
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 Staff : ${val['name']}");
|
||||
print("Id: ${val['id']}");
|
||||
selectedStaffName = val['name'];
|
||||
selectedStaff = val['id'];
|
||||
// controllers['agentId']?.text = val['agent_code'];
|
||||
// agentId = agent['id'];
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// ------------------- STyle ---------------------------------
|
||||
|
||||
static final TextStyle _textStyle = TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
);
|
||||
|
||||
static final TextStyle _successText = TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF177126),
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -4,17 +4,18 @@ 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 'package:nhance_partner/presentation/screens/staff/assignStaff.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 '../../../providers/quotation_staff_proivder.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
|
||||
@ -31,6 +32,7 @@ class policylistState extends ConsumerState<policylist> {
|
||||
List<Map<String, dynamic>> originalData = [];
|
||||
List<Map<String, dynamic>> filteredData = [];
|
||||
bool isLoading = false;
|
||||
dynamic roleId;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -40,7 +42,7 @@ class policylistState extends ConsumerState<policylist> {
|
||||
|
||||
Future.microtask(() {
|
||||
final id = ref.read(managerIdProvider);
|
||||
final roleId = ref.read(userRoleProvider);
|
||||
roleId = ref.read(userRoleProvider);
|
||||
|
||||
print("ENQroleId - $roleId");
|
||||
if (id != null) {
|
||||
@ -49,6 +51,15 @@ class policylistState extends ConsumerState<policylist> {
|
||||
});
|
||||
}
|
||||
|
||||
void refresh() {
|
||||
final id = ref.read(managerIdProvider);
|
||||
final roleId = ref.read(userRoleProvider);
|
||||
|
||||
if (id != null) {
|
||||
getStaffList(id, roleId);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getStaffList(int managerId, role) async {
|
||||
print('getClaimList called MagId - $managerId - $role');
|
||||
setState(() {
|
||||
@ -56,7 +67,10 @@ class policylistState extends ConsumerState<policylist> {
|
||||
});
|
||||
|
||||
try {
|
||||
final response = await apiService.fetchPolicyList(managerId, role);
|
||||
final response = await apiService.fetchPolicyDataOnlyList(
|
||||
managerId,
|
||||
role,
|
||||
);
|
||||
|
||||
if (response['status'] == 'success') {
|
||||
final data = response['data'];
|
||||
@ -94,6 +108,7 @@ class policylistState extends ConsumerState<policylist> {
|
||||
final sortedData = [...filteredData]
|
||||
..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
|
||||
|
||||
// final sortedData = [...filteredData];
|
||||
final startIndex = (currentPage - 1) * itemsPerPage;
|
||||
final endIndex = (currentPage * itemsPerPage).clamp(0, sortedData.length);
|
||||
|
||||
@ -107,8 +122,8 @@ class policylistState extends ConsumerState<policylist> {
|
||||
// final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive";
|
||||
|
||||
return (item['agent_name'] ?? '').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
(item['reg_no'] ?? '').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
@ -127,10 +142,14 @@ class policylistState extends ConsumerState<policylist> {
|
||||
(item['payment_mode'] ?? '').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
(item['updated_on'] ?? '').toLowerCase().contains(
|
||||
(_formatDate(item['updated_on']) ?? '').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
(item['policy_number'] ?? '').toLowerCase().contains(query.toLowerCase());
|
||||
(item['policy_number'] ?? '').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
(item['status'] ?? '').toLowerCase().contains(query.toLowerCase());
|
||||
;
|
||||
}).toList();
|
||||
});
|
||||
}
|
||||
@ -146,24 +165,121 @@ class policylistState extends ConsumerState<policylist> {
|
||||
}
|
||||
}
|
||||
|
||||
List<Widget> _buildPopupMenuActions(BuildContext context, dynamic data) {
|
||||
List<Widget> _buildPopupMenuActions(
|
||||
BuildContext context,
|
||||
dynamic data,
|
||||
id,
|
||||
regNum,
|
||||
) {
|
||||
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'),
|
||||
],
|
||||
if (roleId == 'manager') ...[
|
||||
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(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
ref.read(quotationStaffIdProvider.notifier).state = id;
|
||||
context.go(AppRoutes.quotation);
|
||||
},
|
||||
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_1.png",
|
||||
height: 15,
|
||||
width: 15,
|
||||
),
|
||||
|
||||
const SizedBox(width: 10),
|
||||
((data['status'] == 'Policy Created') ||
|
||||
(data['status'] == 'Quotation Accepted'))
|
||||
? const Text('View Quotation')
|
||||
: const Text('Create Quotation'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
if (data['status'] == 'Quotation Accepted' ||
|
||||
data['status'] == 'Policy Created')
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
ref.read(quotationStaffIdProvider.notifier).state = id;
|
||||
context.go(AppRoutes.policy);
|
||||
},
|
||||
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_2.png",
|
||||
height: 15,
|
||||
width: 15,
|
||||
),
|
||||
|
||||
const SizedBox(width: 10),
|
||||
data['status'] == 'Policy Created'
|
||||
? Text('View Policy')
|
||||
: Text('Create Policy'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@ -299,67 +415,65 @@ class policylistState extends ConsumerState<policylist> {
|
||||
),
|
||||
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,
|
||||
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('Date', 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(
|
||||
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: 3,
|
||||
child: Text('Status', style: _headerStyle),
|
||||
),
|
||||
// Expanded(
|
||||
// flex: 1,
|
||||
// child: Text('Action', style: _headerStyle),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(child: _buildDataTable(context)),
|
||||
],
|
||||
),
|
||||
@ -407,7 +521,7 @@ class policylistState extends ConsumerState<policylist> {
|
||||
return ListView.builder(
|
||||
itemCount: ResponsiveLayout.isMobile(context)
|
||||
? sortedData
|
||||
.length // only cards for mobile
|
||||
.length // only cards for mobile
|
||||
: sortedData.length + 1, // +1 for header in desktop
|
||||
itemBuilder: (context, index) {
|
||||
if (!ResponsiveLayout.isMobile(context) && index == 0) {
|
||||
@ -416,7 +530,7 @@ class policylistState extends ConsumerState<policylist> {
|
||||
|
||||
final startIndex = (currentPage - 1) * itemsPerPage;
|
||||
final item =
|
||||
sortedData[index - (ResponsiveLayout.isMobile(context) ? 0 : 1)];
|
||||
sortedData[index - (ResponsiveLayout.isMobile(context) ? 0 : 1)];
|
||||
final sno = startIndex + index;
|
||||
|
||||
return !ResponsiveLayout.isMobile(context)
|
||||
@ -444,7 +558,19 @@ class policylistState extends ConsumerState<policylist> {
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(flex: 2, child: Text('reg_no' ?? '-', style: _dataBold)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
_formatDate(item['updated_on']) ?? '-',
|
||||
style: _dataBold,
|
||||
softWrap: true,
|
||||
maxLines: 3,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(item['reg_no'] ?? '-', style: _dataBold),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
@ -501,52 +627,50 @@ class policylistState extends ConsumerState<policylist> {
|
||||
maxLines: 3,
|
||||
),
|
||||
),
|
||||
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
item['updated_on'] ?? '-',
|
||||
style: _dataBold,
|
||||
softWrap: true,
|
||||
maxLines: 3,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
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.center,
|
||||
children: _buildPopupMenuActions(context, item),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// 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'],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
);
|
||||
@ -564,65 +688,84 @@ class policylistState extends ConsumerState<policylist> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
/// Top row: Reg.No + Action menu
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// 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,
|
||||
// children: _buildPopupMenuActions(
|
||||
// context,
|
||||
// item,
|
||||
// item['id'],
|
||||
// item['reg_no'],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
],
|
||||
),
|
||||
const Divider(color: Color(0xffD9EBE8), thickness: 0.8),
|
||||
|
||||
// Company + Vehicle Reg No
|
||||
/// Company + Status
|
||||
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,
|
||||
),
|
||||
Text(item['insurer_name'] ?? '-', style: _cardBodyStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
const SizedBox(width: 5),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Status", style: _cardheaderStyle),
|
||||
Text(item['status'] ?? '-', style: _cardBodyStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
/// Agents + Assigned To
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Agent", style: _cardheaderStyle),
|
||||
Text(item['agent_name'] ?? '-', style: _cardBodyStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Assigned To", style: _cardheaderStyle),
|
||||
Text(
|
||||
item['status'] ?? '-',
|
||||
item['assigned_to_name'] ?? '-',
|
||||
style: _cardBodyStyle,
|
||||
maxLines: 2,
|
||||
softWrap: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -631,23 +774,74 @@ class policylistState extends ConsumerState<policylist> {
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
// Created On + Remarks
|
||||
/// Insured Name + Premium
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Received Date & Time", style: _cardheaderStyle),
|
||||
const Text("Insured Name", style: _cardheaderStyle),
|
||||
Text(item['insured_name'] ?? '-', style: _cardBodyStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Premium", style: _cardheaderStyle),
|
||||
Text(item['premium_amount'] ?? '-', style: _cardBodyStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
/// Payment Mode + Policy Number
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Payment Mode", style: _cardheaderStyle),
|
||||
Text(item['payment_mode'] ?? '-', style: _cardBodyStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Policy Number", style: _cardheaderStyle),
|
||||
Text(item['policy_number'] ?? '-', style: _cardBodyStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
/// Date + Remarks
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Date", style: _cardheaderStyle),
|
||||
Text(
|
||||
_formatDate(item['created_on']) ?? '-',
|
||||
_formatDate(item['updated_on']) ?? '-',
|
||||
style: _cardBodyStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
const SizedBox(width: 5),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -657,7 +851,6 @@ class policylistState extends ConsumerState<policylist> {
|
||||
item['remarks'] ?? '-',
|
||||
style: _cardBodyStyle,
|
||||
maxLines: 3,
|
||||
softWrap: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@ -0,0 +1,604 @@
|
||||
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;
|
||||
import 'package:toastification/toastification.dart';
|
||||
|
||||
import '../../../../core/config/env.dart';
|
||||
import '../../../../core/services/api_service.dart';
|
||||
import '../../../../data/services/auth_service.dart';
|
||||
import '../../../../data/utils/toastNotification.dart';
|
||||
import '../../../../data/utils/validators.dart';
|
||||
import '../../../layouts/responsive_layout.dart';
|
||||
import '../../../themes/indicators/customizd_file_upload.dart';
|
||||
import '../../../themes/indicators/input_field_decoration.dart';
|
||||
import '../../../themes/indicators/text_field_theme.dart';
|
||||
|
||||
// 🔹 Custom Dialog Widget
|
||||
class createQuotatDialog extends StatefulWidget {
|
||||
final dynamic userId;
|
||||
final dynamic managerId;
|
||||
final dynamic selectedQuotationFrmListId;
|
||||
final dynamic selectedEnquiryId;
|
||||
final Map<String, dynamic>? selectedQuotationFrmListdata;
|
||||
final void Function(String value) onSubmit;
|
||||
|
||||
const createQuotatDialog({
|
||||
super.key,
|
||||
required this.onSubmit,
|
||||
required this.userId,
|
||||
this.selectedQuotationFrmListdata,
|
||||
this.selectedQuotationFrmListId,
|
||||
required this.managerId,
|
||||
required this.selectedEnquiryId,
|
||||
});
|
||||
|
||||
@override
|
||||
State<createQuotatDialog> createState() => createQuotatDialogState();
|
||||
}
|
||||
|
||||
class createQuotatDialogState extends State<createQuotatDialog> {
|
||||
late ApiService apiService;
|
||||
String? _token;
|
||||
|
||||
String? selectedFileNames;
|
||||
|
||||
bool isLoading = false;
|
||||
late TextEditingController controller;
|
||||
Map<String, TextEditingController> controllers = {};
|
||||
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
String? docUploadedFileUrlFromApi;
|
||||
String? selectedId;
|
||||
PlatformFile? docUploadedFile;
|
||||
|
||||
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKey =
|
||||
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
||||
|
||||
List<String> tabHeader = ['idv', 'premium_Amount'];
|
||||
|
||||
List<Map<String, dynamic>> getInsuranceTypeData = [];
|
||||
List<Map<String, dynamic>> filteredInsuranceData = [];
|
||||
|
||||
String? selectedInsPlanType;
|
||||
String? selectedEndorsement;
|
||||
|
||||
Map<String, dynamic> dataDetails() {
|
||||
final data = {
|
||||
"enquiry_id": widget.selectedEnquiryId,
|
||||
"insured_declared_value": controllers["idv"]?.text,
|
||||
"premium_amount": controllers["premium_Amount"]?.text,
|
||||
"insurance_plan_type_id": selectedInsPlanType,
|
||||
// "additional_uploaded_file_name": "extra_doc.pdf",
|
||||
// "created_by": widget.userId,
|
||||
"manager_id": widget.managerId,
|
||||
};
|
||||
return data;
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
apiService = ApiService();
|
||||
for (String field in tabHeader) {
|
||||
controllers[field] = TextEditingController();
|
||||
}
|
||||
|
||||
// 🔹 Init logic here (API calls, token fetch, etc.)
|
||||
_initializeToken();
|
||||
getInsuranceType();
|
||||
updateData();
|
||||
}
|
||||
|
||||
Future<void> _initializeToken() async {
|
||||
_token = await AuthService.getToken();
|
||||
print("APISERTOKEN - $_token");
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// Dispose all TextEditingControllers
|
||||
for (var controller in controllers.values) {
|
||||
controller.dispose();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void updateData() {
|
||||
if (widget.selectedQuotationFrmListId != null &&
|
||||
widget.selectedQuotationFrmListdata!.isNotEmpty) {
|
||||
print('checkData -- ${widget.selectedQuotationFrmListdata}');
|
||||
selectedId = widget.selectedQuotationFrmListId!;
|
||||
// Pre-fill controllers
|
||||
controllers["idv"]?.text =
|
||||
widget.selectedQuotationFrmListdata!['insured_declared_value']
|
||||
?.toString() ??
|
||||
'';
|
||||
controllers["premium_Amount"]?.text =
|
||||
widget.selectedQuotationFrmListdata!['premium_amount']?.toString() ??
|
||||
'';
|
||||
|
||||
selectedInsPlanType = widget
|
||||
.selectedQuotationFrmListdata!['insurance_plan_type_id']
|
||||
?.toString();
|
||||
|
||||
String? apiDocPath =
|
||||
widget.selectedQuotationFrmListdata!["additional_uploaded_file_name"];
|
||||
if (apiDocPath != null && apiDocPath.isNotEmpty) {
|
||||
print('apiDocPath - $apiDocPath');
|
||||
selectedFileNames = apiDocPath.split('/').last;
|
||||
print('selectedFileNames - $selectedFileNames');
|
||||
docUploadedFileUrlFromApi = apiDocPath;
|
||||
print('passportFileUrlFromApi - $docUploadedFileUrlFromApi');
|
||||
docUploadedFile = null;
|
||||
} else {
|
||||
selectedFileNames = null;
|
||||
docUploadedFile = null;
|
||||
docUploadedFileUrlFromApi = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getInsuranceType() async {
|
||||
print('getClaimList called');
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
|
||||
try {
|
||||
final response = await apiService.fetchMasterDropDown('InsuranceType');
|
||||
|
||||
if (response['status'] == 200) {
|
||||
print('getInsuranceTypeData - ${response['data']}');
|
||||
setState(() {
|
||||
getInsuranceTypeData = List<Map<String, dynamic>>.from(
|
||||
response['data'],
|
||||
);
|
||||
print('API Data - $getInsuranceTypeData');
|
||||
|
||||
filteredInsuranceData = List.from(getInsuranceTypeData);
|
||||
print('originalData - $filteredInsuranceData');
|
||||
});
|
||||
} else {
|
||||
getInsuranceTypeData = [];
|
||||
filteredInsuranceData = [];
|
||||
}
|
||||
} catch (e) {
|
||||
print('Exception occurred: $e');
|
||||
} finally {
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void handleDone() {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
setState(() {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
dataDetails();
|
||||
final dataSet = dataDetails();
|
||||
print("dataSetAgent - $dataSet");
|
||||
// print("managerId - $managerId ,userId - $userId ");
|
||||
createUserData(dataSet);
|
||||
} else {
|
||||
// isDi sable = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> createUserData(Map<String, dynamic> userData) async {
|
||||
// final bool isUpdating = widget.selectedQuotationFrmListId != null;
|
||||
// final id = widget.selectedQuotationFrmListId!;
|
||||
|
||||
final bool isUpdating = widget.selectedQuotationFrmListId != null;
|
||||
final id = widget.selectedQuotationFrmListId; // keep nullable
|
||||
|
||||
print('id - $id');
|
||||
final uri = Uri.parse(
|
||||
// isUpdating
|
||||
// ? 'https://venbait.in/nhance/partner/dev/api/agent/updateAgent'
|
||||
// : 'https://venbait.in/nhance/partner/dev/api/agent/createAgent',
|
||||
isUpdating
|
||||
? '${Env.apiUrl}quotation/updateQuotation'
|
||||
: '${Env.apiUrl}quotation/createQuotation',
|
||||
);
|
||||
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';
|
||||
|
||||
// If updating, spoof the method Laravel-style
|
||||
if (isUpdating) {
|
||||
print('Updatrinf');
|
||||
// request.fields['_method'] = 'PUT';
|
||||
request.fields['id'] = id!;
|
||||
request.fields['updated_by'] = widget.userId!.toString();
|
||||
} else {
|
||||
print('Not Updatrinf');
|
||||
request.fields['created_by'] = widget.userId!.toString();
|
||||
}
|
||||
|
||||
print("USerDAta - $userData");
|
||||
|
||||
// userData.forEach((key, value) {
|
||||
// request.fields[key] = value.toString();
|
||||
// print("✅ Encoded travel_details2: ${request.fields[key]}");
|
||||
// });
|
||||
|
||||
userData.forEach((key, value) {
|
||||
// if (key != 'certificate_file_name') {
|
||||
request.fields[key] = value.toString();
|
||||
print("✅ Encoded $key: ${request.fields[key]}");
|
||||
// }
|
||||
});
|
||||
|
||||
if (docUploadedFile != null) {
|
||||
try {
|
||||
if (docUploadedFile!.bytes != null) {
|
||||
final multipartFile = http.MultipartFile.fromBytes(
|
||||
'additional_uploaded_file_name',
|
||||
docUploadedFile!.bytes!,
|
||||
filename: docUploadedFile!.name,
|
||||
);
|
||||
request.files.add(multipartFile);
|
||||
} else if (docUploadedFile!.path != null) {
|
||||
final multipartFile = await http.MultipartFile.fromPath(
|
||||
'additional_uploaded_file_name',
|
||||
docUploadedFile!.path!,
|
||||
filename: docUploadedFile!.name,
|
||||
);
|
||||
request.files.add(multipartFile);
|
||||
}
|
||||
print("📎 File attached: ${docUploadedFile!.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) {
|
||||
// dispose();
|
||||
print("✅ Agent submitted successfully!");
|
||||
|
||||
print("Response: ${response.body}");
|
||||
widget.onSubmit('Success');
|
||||
Navigator.of(context).pop();
|
||||
} else {
|
||||
final responseBody = jsonDecode(response.body);
|
||||
dynamic msg = responseBody['data'];
|
||||
print("❌ Submission failed. Status: ${response.statusCode}");
|
||||
print("Body: ${response.body}");
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text("Agent User Creation Failed"),
|
||||
content: Text(
|
||||
msg,
|
||||
// "There was a problem in creating user. Please try again.",
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text("OK"),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
print("🔥 Error submitting user: $e");
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
backgroundColor: Colors.white,
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Header row
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
widget.selectedQuotationFrmListId != null
|
||||
? 'Update Quotation'
|
||||
: 'Create Quotation',
|
||||
style: GoogleFonts.inter(
|
||||
color: const Color(0xFF374141),
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF1F1F1),
|
||||
borderRadius: BorderRadius.circular(5.0),
|
||||
),
|
||||
child: const Icon(Icons.close, size: 18),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 🔹 Switch content dynamically
|
||||
buildFormFields(context),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
handleDone();
|
||||
// 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)),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildFormFields(BuildContext context) {
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
buildIdv(context),
|
||||
buildInsurancePlanType(context),
|
||||
buildPremiumAmnt(context),
|
||||
buildDocuments(context),
|
||||
|
||||
// if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10),
|
||||
// _buildResponsiveRow(
|
||||
// context,
|
||||
// buildAdditonalDocuments(context),
|
||||
// buildRemarks(context),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// ------------------------- Claims Part -----------------------------------
|
||||
|
||||
Widget buildIdv(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('IDV *', style: _textStyle),
|
||||
SizedBox(height: 10),
|
||||
ThemedFormField(
|
||||
controller: controllers['idv']!,
|
||||
validator: (value) => Validators.doubleNumber(value, "IDV"),
|
||||
// validator: (value) => Validators.number(value, "IDV"),
|
||||
backgroundColor: Color(0xFFEDF6F5),
|
||||
// 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['premium_Amount']!,
|
||||
backgroundColor: Color(0xFFEDF6F5),
|
||||
validator: (value) => Validators.doubleNumber(value, "PremiumAmount"),
|
||||
// validator: (value) => Validators.number(value, "PremiumAmount "),
|
||||
txtwidth: ResponsiveLayout.isMobile(context)
|
||||
? null
|
||||
: MediaQuery.of(context).size.width * 0.26,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildInsurancePlanType(context) {
|
||||
Map<String, dynamic>? selectedVehicle = filteredInsuranceData.firstWhere(
|
||||
(item) => item['id'].toString() == selectedInsPlanType,
|
||||
orElse: () => {},
|
||||
);
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Plan Type *", style: _textStyle),
|
||||
SizedBox(height: 10),
|
||||
Container(
|
||||
color: Colors.white,
|
||||
width: ResponsiveLayout.isMobile(context)
|
||||
? null
|
||||
: MediaQuery.of(context).size.width * 0.26,
|
||||
// height: 40,
|
||||
child: DropdownSearch<Map<String, dynamic>>(
|
||||
key: dropDownKey,
|
||||
selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null,
|
||||
items: (filter, infiniteScrollProps) {
|
||||
return filteredInsuranceData;
|
||||
},
|
||||
|
||||
itemAsString: (val) => val['insurance_plan_type'].toString(),
|
||||
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 Plan Type",
|
||||
).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 Plan Type...",
|
||||
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 ClaimsType : ${val['insurance_plan_type']}");
|
||||
print("Id: ${val['id']}");
|
||||
selectedInsPlanType = val['id'];
|
||||
// controllers['agentId']?.text = val['agent_code'];
|
||||
// agentId = agent['id'];
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildDocuments(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Quotation Documents ', style: _textStyle),
|
||||
const SizedBox(height: 10),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
ThemedUploadField(
|
||||
hintText: selectedFileNames ?? "Upload Document",
|
||||
txtwidth: ResponsiveLayout.isMobile(context)
|
||||
? null
|
||||
: MediaQuery.of(context).size.width * 0.26,
|
||||
backgroundColor: Color(0xFFEDF6F5),
|
||||
onFileSelected: (fileName, file) {
|
||||
print("Picked file: $fileName (${file.size} bytes)");
|
||||
setState(() {
|
||||
docUploadedFile = file;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
|
||||
if (docUploadedFileUrlFromApi != null)
|
||||
Container(
|
||||
// color: Colors.white,
|
||||
child: Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => apiService.downloadFile(
|
||||
apiUrl:
|
||||
'api/quotation/downloadAdditionalUploadedFile?id=$selectedId',
|
||||
apiId: selectedId,
|
||||
localFile: docUploadedFile,
|
||||
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,
|
||||
fontWeight: FontWeight.w600,
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -57,6 +57,7 @@ class _ThemedDateFieldState extends State<ThemedDateField> {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FormField<String>(
|
||||
@ -64,48 +65,66 @@ class _ThemedDateFieldState extends State<ThemedDateField> {
|
||||
initialValue: widget.controller?.text,
|
||||
builder: (field) {
|
||||
final hasError = field.hasError;
|
||||
return Container(
|
||||
width: widget.txtwidth ?? MediaQuery.of(context).size.width,
|
||||
height: widget.txtheight,
|
||||
child: InkWell(
|
||||
onTap: () => pickDate(context, field),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
||||
decoration: BoxDecoration(
|
||||
color: widget.backgroundColor ?? Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: hasError
|
||||
? (widget.errorBorderColor ?? Colors.red)
|
||||
: (widget.borderColor ?? Colors.grey.shade50),
|
||||
width: 1.5,
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () => pickDate(context, field),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: Container(
|
||||
width: widget.txtwidth ?? MediaQuery.of(context).size.width,
|
||||
height: widget.txtheight,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10,
|
||||
horizontal: 15,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: widget.backgroundColor ?? Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: hasError
|
||||
? (widget.errorBorderColor ?? Color(0xFFD83731))
|
||||
: (widget.borderColor ?? Colors.grey.shade50),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.controller?.text.isNotEmpty == true
|
||||
? widget.controller!.text
|
||||
: widget.hintText ?? "Select Date",
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: hasError ? Color(0xFFD83731) : Colors.black,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
Icons.calendar_today,
|
||||
size: 16,
|
||||
color: Colors.black,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.controller?.text.isNotEmpty == true
|
||||
? widget.controller!.text
|
||||
: widget.hintText ?? "Select Date",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: hasError ? Colors.red : Colors.black,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
Icons.calendar_today,
|
||||
size: 16,
|
||||
color: Colors.black,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (hasError)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 5, left: 5),
|
||||
child: Text(
|
||||
field.errorText ?? '',
|
||||
style: const TextStyle(
|
||||
color: Color(0xFFD83731),
|
||||
fontSize: 10,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@ -79,17 +79,23 @@ class ExcelExporter {
|
||||
required String fileName,
|
||||
}) async {
|
||||
try {
|
||||
// Create Excel and delete default sheet
|
||||
var excel = Excel.createExcel();
|
||||
Sheet sheetObject = excel[sheetName];
|
||||
if (excel.sheets.containsKey('Sheet1')) {
|
||||
excel.delete('Sheet1');
|
||||
}
|
||||
|
||||
// Create your sheet
|
||||
Sheet sheetObject = excel[sheetName]; // now this is the only sheet
|
||||
|
||||
// Add headers
|
||||
sheetObject.appendRow(headers.map((h) => TextCellValue(h)).toList());
|
||||
|
||||
// Add data
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
for (var rowData in data) {
|
||||
var row = <CellValue?>[];
|
||||
for (var key in headers) {
|
||||
final value = data[i][key];
|
||||
final value = rowData[key];
|
||||
if (value == null) {
|
||||
row.add(TextCellValue('-'));
|
||||
} else if (value is int) {
|
||||
@ -106,7 +112,7 @@ class ExcelExporter {
|
||||
var bytes = excel.encode()!;
|
||||
|
||||
if (kIsWeb) {
|
||||
// ✅ Web: download as file
|
||||
// Web: download
|
||||
final blob = html.Blob([bytes]);
|
||||
final url = html.Url.createObjectUrlFromBlob(blob);
|
||||
final anchor = html.AnchorElement(href: url)
|
||||
@ -114,7 +120,7 @@ class ExcelExporter {
|
||||
..click();
|
||||
html.Url.revokeObjectUrl(url);
|
||||
} else {
|
||||
// ✅ Mobile/Desktop: save to file system
|
||||
// Mobile/Desktop: save file
|
||||
final dir = await getApplicationDocumentsDirectory();
|
||||
final file = File('${dir.path}/$fileName.xlsx');
|
||||
await file.writeAsBytes(bytes);
|
||||
@ -125,3 +131,63 @@ class ExcelExporter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// class ExcelExporter {
|
||||
// static Future<void> exportToExcel({
|
||||
// required String sheetName,
|
||||
// required List<Map<String, dynamic>> data,
|
||||
// required List<String> headers,
|
||||
// required String fileName,
|
||||
// }) async {
|
||||
// try {
|
||||
// // var excel = Excel.createExcel();
|
||||
// // Sheet sheetObject = excel[sheetName];
|
||||
//
|
||||
// // Delete default sheet
|
||||
// var excel = Excel.createExcel();
|
||||
// excel.delete('Sheet1'); // remove default
|
||||
// Sheet sheetObject = excel[sheetName];
|
||||
//
|
||||
// // Add headers
|
||||
// sheetObject.appendRow(headers.map((h) => TextCellValue(h)).toList());
|
||||
//
|
||||
// // Add data
|
||||
// for (int i = 0; i < data.length; i++) {
|
||||
// var row = <CellValue?>[];
|
||||
// for (var key in headers) {
|
||||
// final value = data[i][key];
|
||||
// if (value == null) {
|
||||
// row.add(TextCellValue('-'));
|
||||
// } else if (value is int) {
|
||||
// row.add(IntCellValue(value));
|
||||
// } else if (value is double) {
|
||||
// row.add(DoubleCellValue(value));
|
||||
// } else {
|
||||
// row.add(TextCellValue(value.toString()));
|
||||
// }
|
||||
// }
|
||||
// sheetObject.appendRow(row);
|
||||
// }
|
||||
//
|
||||
// var bytes = excel.encode()!;
|
||||
//
|
||||
// if (kIsWeb) {
|
||||
// // ✅ Web: download as file
|
||||
// final blob = html.Blob([bytes]);
|
||||
// final url = html.Url.createObjectUrlFromBlob(blob);
|
||||
// final anchor = html.AnchorElement(href: url)
|
||||
// ..setAttribute("download", "$fileName.xlsx")
|
||||
// ..click();
|
||||
// html.Url.revokeObjectUrl(url);
|
||||
// } else {
|
||||
// // ✅ Mobile/Desktop: save to file system
|
||||
// final dir = await getApplicationDocumentsDirectory();
|
||||
// final file = File('${dir.path}/$fileName.xlsx');
|
||||
// await file.writeAsBytes(bytes);
|
||||
// await OpenFile.open(file.path);
|
||||
// }
|
||||
// } catch (e) {
|
||||
// print("Error exporting Excel: $e");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
@ -103,7 +103,7 @@ class ThemedFormField extends HookWidget {
|
||||
// ✅ dynamic hint color
|
||||
color: const Color(0xFFC3C6CB),
|
||||
),
|
||||
// labelStyle: TextStyle(fontSize: 11, color: Colors.red),
|
||||
labelStyle: TextStyle(fontSize: 12),
|
||||
prefixIconConstraints: const BoxConstraints(
|
||||
maxWidth: 25 + 16 + 10,
|
||||
maxHeight: 25 + (8 * 2),
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import '../../core/routing/routes.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
@ -22,8 +23,10 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
|
||||
_overlayEntry = OverlayEntry(
|
||||
builder: (context) {
|
||||
return Positioned(
|
||||
left: offset.dx + size.width,
|
||||
top: offset.dy,
|
||||
left: offset.dx + size.width - 5, // little spacing
|
||||
top: offset.dy + (size.height / 2) - 20,
|
||||
// left: offset.dx + size.width,
|
||||
// top: offset.dy,
|
||||
child: MouseRegion(
|
||||
onExit: (_) => _hidePopup(),
|
||||
child: Material(
|
||||
@ -33,125 +36,144 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
color: Colors.white,
|
||||
color: const Color(0xFFDDF5F1),
|
||||
// color: Colors.white,
|
||||
),
|
||||
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (key == 'User') ...[
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
print("Tappped Agent");
|
||||
context.go(AppRoutes.agentLst);
|
||||
},
|
||||
child: const Text(
|
||||
"Agent",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
_buildPopupItem(
|
||||
label: "Agent",
|
||||
onTap: () => context.go(AppRoutes.agentLst),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
print("Bf clicked");
|
||||
context.go(AppRoutes.staffLst);
|
||||
},
|
||||
child: const Text(
|
||||
"Staff",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
_buildPopupItem(
|
||||
label: "Staff",
|
||||
onTap: () => context.go(AppRoutes.staffLst),
|
||||
),
|
||||
],
|
||||
|
||||
if (key == 'Reports') ...[
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.go(AppRoutes.claimlist);
|
||||
},
|
||||
child: const Text(
|
||||
"Claims",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
// const SizedBox(height: 5),
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// context.go(AppRoutes.enquiryLst);
|
||||
// },
|
||||
// child: const Text(
|
||||
// "Enquiries",
|
||||
// style: TextStyle(
|
||||
// fontSize: 16,
|
||||
// fontWeight: FontWeight.w400,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
const SizedBox(height: 5),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.go(AppRoutes.endosement);
|
||||
},
|
||||
child: const Text(
|
||||
"Endorsement",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
_buildPopupItem(
|
||||
label: "Claims",
|
||||
onTap: () => context.go(AppRoutes.claimlist),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.go(AppRoutes.policylist);
|
||||
},
|
||||
child: const Text(
|
||||
"Policy",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
_buildPopupItem(
|
||||
label: "Endorsement",
|
||||
onTap: () => context.go(AppRoutes.endosement),
|
||||
),
|
||||
|
||||
const SizedBox(height: 5),
|
||||
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.go(AppRoutes.quotation);
|
||||
},
|
||||
child: const Text(
|
||||
"Quotation",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 5),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.go(AppRoutes.policy);
|
||||
},
|
||||
child: const Text(
|
||||
"Policy Form",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
_buildPopupItem(
|
||||
label: "Policy",
|
||||
onTap: () => context.go(AppRoutes.policylist),
|
||||
),
|
||||
],
|
||||
|
||||
// if (key == 'User') ...[
|
||||
// Row(
|
||||
// children: [
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// print("Tappped Agent");
|
||||
// context.go(AppRoutes.agentLst);
|
||||
// },
|
||||
// child: Text("Agent", style: _cardTextStyle),
|
||||
// ),
|
||||
//
|
||||
// Icon(
|
||||
// Icons.arrow_forward_ios_rounded,
|
||||
// size: 12,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// const SizedBox(height: 5),
|
||||
// Row(
|
||||
// children: [
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// print("Bf clicked");
|
||||
// context.go(AppRoutes.staffLst);
|
||||
// },
|
||||
// child: Text("Staff", style: _cardTextStyle),
|
||||
// ),
|
||||
//
|
||||
// Icon(
|
||||
// Icons.arrow_forward_ios_rounded,
|
||||
// size: 12,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ],
|
||||
//
|
||||
// if (key == 'Reports') ...[
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// context.go(AppRoutes.claimlist);
|
||||
// },
|
||||
// child: Row(
|
||||
// children: [
|
||||
// Text("Claims", style: _cardTextStyle),
|
||||
// Icon(
|
||||
// Icons.arrow_forward_ios_rounded,
|
||||
// size: 12,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// // const SizedBox(height: 5),
|
||||
// // GestureDetector(
|
||||
// // onTap: () {
|
||||
// // context.go(AppRoutes.enquiryLst);
|
||||
// // },
|
||||
// // child: const Text(
|
||||
// // "Enquiries",
|
||||
// // style: TextStyle(
|
||||
// // fontSize: 16,
|
||||
// // fontWeight: FontWeight.w400,
|
||||
// // ),
|
||||
// // ),
|
||||
// // ),
|
||||
// const SizedBox(height: 5),
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// context.go(AppRoutes.endosement);
|
||||
// },
|
||||
// child: Row(
|
||||
// children: [
|
||||
// Text("Endorsement", style: _cardTextStyle),
|
||||
//
|
||||
// Icon(
|
||||
// Icons.arrow_forward_ios_rounded,
|
||||
// size: 12,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 5),
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// context.go(AppRoutes.policylist);
|
||||
// },
|
||||
// child: Row(
|
||||
// children: [
|
||||
// Text("Policy", style: _cardTextStyle),
|
||||
//
|
||||
// Icon(
|
||||
// Icons.arrow_forward_ios_rounded,
|
||||
// size: 12,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -183,11 +205,16 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
|
||||
padding: EdgeInsets.zero,
|
||||
children: [
|
||||
SizedBox(height: 30),
|
||||
DrawerContentWrapper(
|
||||
child: Image.asset(
|
||||
"assets/drawer/drawerImg1.png",
|
||||
height: 25,
|
||||
width: 25,
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.go(AppRoutes.dashboard);
|
||||
},
|
||||
child: DrawerContentWrapper(
|
||||
child: Image.asset(
|
||||
"assets/drawer/drawerImg1.png",
|
||||
height: 25,
|
||||
width: 25,
|
||||
),
|
||||
),
|
||||
),
|
||||
DrawerLabel("Dashboard"),
|
||||
@ -215,24 +242,16 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
|
||||
},
|
||||
),
|
||||
DrawerLabel("Reports"),
|
||||
// DrawerContentWrapper(
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// // context.go('/tabEnquiry/tab');
|
||||
// ref.read(enquiryIdProvider.notifier).state = 'tab';
|
||||
// context.go(AppRoutes.tabEnquiry);
|
||||
// },
|
||||
// icon: Icon(Icons.list_alt_rounded, size: 30, color: Colors.black),
|
||||
// ),
|
||||
// ),
|
||||
DrawerContentWrapper(
|
||||
child: Consumer(
|
||||
builder: (context, ref, _) {
|
||||
return IconButton(
|
||||
onPressed: () {
|
||||
if (roleId == 'manager') {
|
||||
} else if (roleId == 'agent') {
|
||||
print('roleI - $roleId');
|
||||
if (roleId == 'agent') {
|
||||
context.go(AppRoutes.enquiryLst);
|
||||
} else {
|
||||
context.go(AppRoutes.enquiryForStaff);
|
||||
}
|
||||
// ref.read(enquiryIdProvider.notifier).state = null;
|
||||
// context.go(AppRoutes.tabEnquiry);
|
||||
@ -277,6 +296,15 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildPopupItem({required String label, required VoidCallback onTap}) {
|
||||
return _HoverableContainer(
|
||||
label: label,
|
||||
onTap: onTap,
|
||||
normalColor: Color(0xFFDDF5F1),
|
||||
hoverColor: Colors.white, // change to your desired hover color
|
||||
);
|
||||
}
|
||||
|
||||
class DrawerLabel extends StatelessWidget {
|
||||
final String text;
|
||||
const DrawerLabel(this.text, {super.key});
|
||||
@ -286,9 +314,71 @@ class DrawerLabel extends StatelessWidget {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(text, style: const TextStyle(color: Colors.white, fontSize: 11.5)),
|
||||
Text(
|
||||
text,
|
||||
style: GoogleFonts.inter(color: Colors.white, fontSize: 11.5),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _HoverableContainer extends StatefulWidget {
|
||||
final String label;
|
||||
final VoidCallback onTap;
|
||||
final Color normalColor;
|
||||
final Color hoverColor;
|
||||
|
||||
const _HoverableContainer({
|
||||
super.key,
|
||||
required this.label,
|
||||
required this.onTap,
|
||||
required this.normalColor,
|
||||
required this.hoverColor,
|
||||
});
|
||||
|
||||
@override
|
||||
_HoverableContainerState createState() => _HoverableContainerState();
|
||||
}
|
||||
|
||||
class _HoverableContainerState extends State<_HoverableContainer> {
|
||||
bool _isHovered = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MouseRegion(
|
||||
onEnter: (_) => setState(() => _isHovered = true),
|
||||
onExit: (_) => setState(() => _isHovered = false),
|
||||
child: GestureDetector(
|
||||
onTap: widget.onTap,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: _isHovered ? widget.hoverColor : widget.normalColor,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Container(
|
||||
width: 110,
|
||||
child: Text(widget.label, style: _cardTextStyle),
|
||||
),
|
||||
const Icon(
|
||||
Icons.arrow_forward_ios_rounded,
|
||||
size: 12,
|
||||
color: Colors.black,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TextStyle _cardTextStyle = GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
|
||||
@ -1,23 +1,102 @@
|
||||
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';
|
||||
|
||||
class MobileTabs extends StatefulWidget {
|
||||
final ValueChanged<int> onTabChanged;
|
||||
const MobileTabs({super.key, required this.onTabChanged});
|
||||
import '../../core/routing/routes.dart';
|
||||
import '../providers/userRoleProvider.dart';
|
||||
|
||||
class MobileBottomMenu extends ConsumerStatefulWidget {
|
||||
const MobileBottomMenu({super.key});
|
||||
|
||||
@override
|
||||
State<MobileTabs> createState() => _MobileTabsState();
|
||||
ConsumerState<MobileBottomMenu> createState() => _MobileBottomMenuState();
|
||||
}
|
||||
|
||||
class _MobileTabsState extends State<MobileTabs> {
|
||||
class _MobileBottomMenuState extends ConsumerState<MobileBottomMenu> {
|
||||
int _currentIndex = 0;
|
||||
|
||||
void _showOptionsSheet(List<Map<String, dynamic>> options) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: const Color(0xFFDDF5F1),
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||
),
|
||||
builder: (_) => ListView.separated(
|
||||
padding: const EdgeInsets.all(16),
|
||||
shrinkWrap: true,
|
||||
itemCount: options.length,
|
||||
separatorBuilder: (_, __) => const SizedBox(height: 8),
|
||||
itemBuilder: (_, index) {
|
||||
final item = options[index];
|
||||
return ListTile(
|
||||
title: Text(
|
||||
item['label'],
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
trailing: const Icon(Icons.arrow_forward_ios_rounded, size: 16),
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
context.go(item['route']);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final roleId = ref.watch(userRoleProvider);
|
||||
|
||||
return BottomNavigationBar(
|
||||
type: BottomNavigationBarType.fixed,
|
||||
backgroundColor: const Color(0xFF425B5B),
|
||||
selectedItemColor: Colors.white,
|
||||
unselectedItemColor: Colors.white70,
|
||||
currentIndex: _currentIndex,
|
||||
onTap: (index) {
|
||||
setState(() => _currentIndex = index);
|
||||
widget.onTabChanged(index);
|
||||
|
||||
switch (index) {
|
||||
case 0:
|
||||
context.go(AppRoutes.dashboard);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Reports tapped → show bottom sheet
|
||||
_showOptionsSheet([
|
||||
{'label': 'Claims', 'route': AppRoutes.claimlist},
|
||||
{'label': 'Endorsement', 'route': AppRoutes.endosement},
|
||||
{'label': 'Policy', 'route': AppRoutes.policylist},
|
||||
]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Enquiry
|
||||
if (roleId == 'agent') {
|
||||
context.go(AppRoutes.enquiryLst);
|
||||
} else {
|
||||
context.go(AppRoutes.enquiryForStaff);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// User options only for manager
|
||||
if (roleId == 'manager') {
|
||||
_showOptionsSheet([
|
||||
{'label': 'Agent', 'route': AppRoutes.agentLst},
|
||||
{'label': 'Staff', 'route': AppRoutes.staffLst},
|
||||
]);
|
||||
} else {
|
||||
context.go(AppRoutes.profile);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
items: [
|
||||
BottomNavigationBarItem(
|
||||
@ -28,18 +107,23 @@ class _MobileTabsState extends State<MobileTabs> {
|
||||
),
|
||||
label: "Dashboard",
|
||||
),
|
||||
const BottomNavigationBarItem(
|
||||
icon: Icon(Icons.person),
|
||||
label: "Profile",
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Image.asset(
|
||||
"assets/drawer/drawerImg2.png",
|
||||
height: 20,
|
||||
width: 20,
|
||||
),
|
||||
label: "Reports",
|
||||
),
|
||||
const BottomNavigationBarItem(
|
||||
icon: Icon(Icons.list_alt_rounded, size: 24, color: Colors.black),
|
||||
label: "Enquiry",
|
||||
),
|
||||
|
||||
const BottomNavigationBarItem(
|
||||
icon: Icon(Icons.person_add_alt, size: 24, color: Colors.black),
|
||||
label: "User",
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user