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/home/home_screen.dart';
|
||||||
import '../../presentation/screens/login/login_screen.dart';
|
import '../../presentation/screens/login/login_screen.dart';
|
||||||
import '../../presentation/screens/splash/splash_screen.dart';
|
import '../../presentation/screens/splash/splash_screen.dart';
|
||||||
|
import '../../presentation/screens/staff/Enquiry/enquiry_list.dart';
|
||||||
import '../../presentation/screens/staff/policy/policy.dart';
|
import '../../presentation/screens/staff/policy/policy.dart';
|
||||||
import '../../presentation/screens/staff/policy/policy_list.dart';
|
import '../../presentation/screens/staff/policy/policy_list.dart';
|
||||||
import '../../presentation/screens/staff/quotations/quotation.dart';
|
import '../../presentation/screens/staff/quotations/quotation.dart';
|
||||||
@ -145,6 +146,15 @@ final GoRouter appRouter = GoRouter(
|
|||||||
path: AppRoutes.policy,
|
path: AppRoutes.policy,
|
||||||
builder: (context, state) => const PolicyScreen(),
|
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 {
|
redirect: (context, state) async {
|
||||||
final loggedIn = await AuthService.isLoggedIn();
|
final loggedIn = await AuthService.isLoggedIn();
|
||||||
|
|||||||
@ -9,6 +9,7 @@ class AppRoutes {
|
|||||||
static const String staffLst = '/staffLst';
|
static const String staffLst = '/staffLst';
|
||||||
static const staff = '/staff/:id';
|
static const staff = '/staff/:id';
|
||||||
static const String enquiryLst = '/enquiryLst';
|
static const String enquiryLst = '/enquiryLst';
|
||||||
|
static const String enquiryForStaff = '/enquiryForStaff';
|
||||||
static const String tabEnquiry = '/tabEnquiry';
|
static const String tabEnquiry = '/tabEnquiry';
|
||||||
|
|
||||||
static const String claimlist = '/claimList';
|
static const String claimlist = '/claimList';
|
||||||
|
|||||||
@ -156,7 +156,14 @@ class ApiService {
|
|||||||
|
|
||||||
Future<void> getPdfDownload(String path, String id) async {
|
Future<void> getPdfDownload(String path, String id) async {
|
||||||
print('getPdfDownload 1');
|
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');
|
final url = Uri.parse('https://venbait.in/nhance/partner/dev/$path');
|
||||||
|
|
||||||
await _initializeToken();
|
await _initializeToken();
|
||||||
print('getPdfDownload 2');
|
print('getPdfDownload 2');
|
||||||
if (_token == null) throw Exception('Token not found. Please log in.');
|
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 {
|
} else {
|
||||||
|
ToastHelper.showInfoToast(context, 'No File Not Found');
|
||||||
throw Exception('Failed to download file');
|
throw Exception('Failed to download file');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -279,6 +289,34 @@ class ApiService {
|
|||||||
return response;
|
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 ----------------------------------------------
|
// -------------------------------- AGENT ----------------------------------------------
|
||||||
|
|
||||||
Future<Map<String, dynamic>> fetchAgentIncentiveList(agentId) async {
|
Future<Map<String, dynamic>> fetchAgentIncentiveList(agentId) async {
|
||||||
@ -544,6 +582,38 @@ class ApiService {
|
|||||||
return response;
|
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 -------------------------------------------------
|
// ----------------------------------- CLAIMS -------------------------------------------------
|
||||||
|
|
||||||
Future<Map<String, dynamic>> fetchClaimList(int id, role) async {
|
Future<Map<String, dynamic>> fetchClaimList(int id, role) async {
|
||||||
|
|||||||
@ -76,6 +76,17 @@ class Validators {
|
|||||||
return null;
|
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) {
|
static String? phone(String? value, String label) {
|
||||||
if (value == null || value.trim().isEmpty) {
|
if (value == null || value.trim().isEmpty) {
|
||||||
return "Required";
|
return "Required";
|
||||||
|
|||||||
@ -36,18 +36,18 @@ class MainLayout extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
drawer: const DrawerMenu(),
|
drawer: const DrawerMenu(),
|
||||||
body: body,
|
body: body,
|
||||||
bottomNavigationBar: MobileTabs(
|
bottomNavigationBar: MobileBottomMenu(
|
||||||
onTabChanged: (index) {
|
// onTabChanged: (index) {
|
||||||
debugPrint("Mobile tab changed to $index");
|
// debugPrint("Mobile tab changed to $index");
|
||||||
if (index == 0) {
|
// if (index == 0) {
|
||||||
context.go(AppRoutes.dashboard);
|
// context.go(AppRoutes.dashboard);
|
||||||
} else if (index == 1) {
|
// } else if (index == 1) {
|
||||||
context.go(AppRoutes.profile);
|
// context.go(AppRoutes.profile);
|
||||||
} else if (index == 2) {
|
// } else if (index == 2) {
|
||||||
// ref.read(enquiryIdProvider.notifier).state = null;
|
// // ref.read(enquiryIdProvider.notifier).state = null;
|
||||||
context.go(AppRoutes.enquiryLst);
|
// 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");
|
print("APISERTOKEN - $_token");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
// Dispose all TextEditingControllers
|
||||||
|
for (var controller in controllers.values) {
|
||||||
|
controller.dispose();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> getVehicleType() async {
|
Future<void> getVehicleType() async {
|
||||||
print('getClaimList called');
|
print('getClaimList called');
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|||||||
@ -102,6 +102,15 @@ class _AddDialogState extends State<AddDialog> {
|
|||||||
print("APISERTOKEN - $_token");
|
print("APISERTOKEN - $_token");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
// Dispose all TextEditingControllers
|
||||||
|
for (var controller in controllers.values) {
|
||||||
|
controller.dispose();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> getClaimsType() async {
|
Future<void> getClaimsType() async {
|
||||||
print('getClaimList called');
|
print('getClaimList called');
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -244,12 +253,6 @@ class _AddDialogState extends State<AddDialog> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
// controllers.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AlertDialog(
|
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 {
|
Future<void> _initializeToken() async {
|
||||||
_token = await AuthService.getToken();
|
_token = await AuthService.getToken();
|
||||||
print("APISERTOKEN - $_token");
|
print("APISERTOKEN - $_token");
|
||||||
|
|||||||
@ -123,6 +123,15 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
|
|||||||
getQuotationList(managerId);
|
getQuotationList(managerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
// Dispose all TextEditingControllers
|
||||||
|
for (var controller in controllers.values) {
|
||||||
|
controller.dispose();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> getQuotationList(managerId) async {
|
Future<void> getQuotationList(managerId) async {
|
||||||
print('getClaimList called MagId - $managerId');
|
print('getClaimList called MagId - $managerId');
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|||||||
@ -106,7 +106,7 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
|
|||||||
filteredData = getStaffData.where((item) {
|
filteredData = getStaffData.where((item) {
|
||||||
// final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive";
|
// final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive";
|
||||||
|
|
||||||
return (item['created_on'] ?? '').toLowerCase().contains(
|
return (_formatDate(item['created_on']) ?? '').toLowerCase().contains(
|
||||||
query.toLowerCase(),
|
query.toLowerCase(),
|
||||||
) ||
|
) ||
|
||||||
(item['reg_no'] ?? '').toLowerCase().contains(
|
(item['reg_no'] ?? '').toLowerCase().contains(
|
||||||
@ -142,10 +142,12 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
|
|||||||
print('EDITStaff - ${data['id']}');
|
print('EDITStaff - ${data['id']}');
|
||||||
// dynamic id = data['id'];
|
// dynamic id = data['id'];
|
||||||
// context.go('/tabEnquiry/$id');
|
// context.go('/tabEnquiry/$id');
|
||||||
|
setState(() {
|
||||||
// update provider
|
|
||||||
final id = data['id'].toString();
|
final id = data['id'].toString();
|
||||||
ref.read(enquiryIdProvider.notifier).state = id;
|
ref.read(enquiryIdProvider.notifier).state = id;
|
||||||
|
});
|
||||||
|
// update provider
|
||||||
|
|
||||||
context.go(AppRoutes.tabEnquiry);
|
context.go(AppRoutes.tabEnquiry);
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|||||||
@ -31,6 +31,8 @@ class claimListState extends ConsumerState<claimList> {
|
|||||||
List<Map<String, dynamic>> filteredData = [];
|
List<Map<String, dynamic>> filteredData = [];
|
||||||
bool isLoading = false;
|
bool isLoading = false;
|
||||||
|
|
||||||
|
final TextEditingController _searchStaffController = TextEditingController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -114,25 +116,23 @@ class claimListState extends ConsumerState<claimList> {
|
|||||||
(item['policy_no'] ?? '').toLowerCase().contains(
|
(item['policy_no'] ?? '').toLowerCase().contains(
|
||||||
query.toLowerCase(),
|
query.toLowerCase(),
|
||||||
) ||
|
) ||
|
||||||
(item['policy_end_date'] ?? '').toLowerCase().contains(
|
(item['claim_type_value'] ?? '').toLowerCase().contains(
|
||||||
query.toLowerCase(),
|
|
||||||
) ||
|
|
||||||
(item['claim_type'] ?? '').toLowerCase().contains(
|
|
||||||
query.toLowerCase(),
|
query.toLowerCase(),
|
||||||
) ||
|
) ||
|
||||||
(item['claim_number'] ?? '').toLowerCase().contains(
|
(item['claim_number'] ?? '').toLowerCase().contains(
|
||||||
query.toLowerCase(),
|
query.toLowerCase(),
|
||||||
);
|
) ||
|
||||||
|
(_formatDate(
|
||||||
|
item['policy_end_date'],
|
||||||
|
).toLowerCase()).contains(query.toLowerCase());
|
||||||
}).toList();
|
}).toList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
final TextEditingController _searchStaffController = TextEditingController();
|
|
||||||
|
|
||||||
String _formatDate(String rawDate) {
|
String _formatDate(String rawDate) {
|
||||||
try {
|
try {
|
||||||
final dateTime = DateTime.parse(rawDate);
|
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) {
|
} catch (e) {
|
||||||
return rawDate; // fallback if parsing fails
|
return rawDate; // fallback if parsing fails
|
||||||
}
|
}
|
||||||
@ -323,17 +323,17 @@ class claimListState extends ConsumerState<claimList> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 3,
|
||||||
child: Text('Claim Type', style: _headerStyle),
|
child: Text('Claim Type', style: _headerStyle),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text('Claim No.', style: _headerStyle),
|
child: Text('Claim No.', style: _headerStyle),
|
||||||
),
|
),
|
||||||
Expanded(
|
// Expanded(
|
||||||
flex: 1,
|
// flex: 1,
|
||||||
child: Text('Action', style: _headerStyle),
|
// child: Text('Action', style: _headerStyle),
|
||||||
),
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -425,86 +425,47 @@ class claimListState extends ConsumerState<claimList> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text(
|
||||||
item['reg_no'] != null
|
item['reg_no'] ?? '-', // fallback
|
||||||
? _formatDate(item['reg_no'])
|
|
||||||
: '-', // fallback
|
|
||||||
style: _dataBold,
|
style: _dataBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text(
|
||||||
item['insurer_name'] != null
|
item['insurer_name'] ?? '-', // fallback
|
||||||
? _formatDate(item['insurer_name'])
|
style: _dataBold,
|
||||||
: '-', // fallback
|
),
|
||||||
|
),
|
||||||
|
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,
|
style: _dataBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text(
|
||||||
_formatDate(item['policy_no']) ?? '-',
|
item['claim_number'] ?? '-', // fallback
|
||||||
style: _dataBold,
|
style: _dataBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
|
||||||
flex: 2,
|
// Expanded(
|
||||||
child: Text(
|
|
||||||
_formatDate(item['policy_end_date']) ?? '-',
|
|
||||||
style: _dataBold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
flex: 2,
|
|
||||||
child: Text(
|
|
||||||
item['claim_type'] != null
|
|
||||||
? _formatDate(item['claim_number'])
|
|
||||||
: '-', // fallback
|
|
||||||
style: _dataBold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
flex: 2,
|
|
||||||
child: Text(
|
|
||||||
item['claim_number'] != null
|
|
||||||
? _formatDate(item['claim_number'])
|
|
||||||
: '-', // fallback
|
|
||||||
style: _dataBold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
flex: 1,
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
PopupMenuButton<int>(
|
|
||||||
color: Colors.white,
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
offset: Offset(0, 30),
|
|
||||||
icon: Icon(
|
|
||||||
Icons.more_vert,
|
|
||||||
color: Color(0xFF475569),
|
|
||||||
size: 14,
|
|
||||||
),
|
|
||||||
itemBuilder: (context) => [
|
|
||||||
CustomPopupMenuEntry(
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.symmetric(
|
|
||||||
horizontal: 8,
|
|
||||||
vertical: 8,
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: _buildPopupMenuActions(context, item),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Expanded(s
|
|
||||||
// flex: 1,
|
// flex: 1,
|
||||||
// child: Row(
|
// child: Row(
|
||||||
// children: [
|
// children: [
|
||||||
@ -561,24 +522,24 @@ class claimListState extends ConsumerState<claimList> {
|
|||||||
item['reg_no'] != null ? _formatDate(item['reg_no']) : '-',
|
item['reg_no'] != null ? _formatDate(item['reg_no']) : '-',
|
||||||
style: _headerStyle,
|
style: _headerStyle,
|
||||||
),
|
),
|
||||||
PopupMenuButton<int>(
|
// PopupMenuButton<int>(
|
||||||
color: Colors.white,
|
// color: Colors.white,
|
||||||
padding: EdgeInsets.zero,
|
// padding: EdgeInsets.zero,
|
||||||
offset: Offset(0, 30),
|
// offset: Offset(0, 30),
|
||||||
icon: Icon(Icons.more_vert, color: Color(0xFF475569), size: 14),
|
// icon: Icon(Icons.more_vert, color: Color(0xFF475569), size: 14),
|
||||||
itemBuilder: (context) => [
|
// itemBuilder: (context) => [
|
||||||
CustomPopupMenuEntry(
|
// CustomPopupMenuEntry(
|
||||||
child: Container(
|
// child: Container(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
|
// padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
|
||||||
child: Column(
|
// child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
// mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
// mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: _buildPopupMenuActions(context, item),
|
// children: _buildPopupMenuActions(context, item),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const Divider(color: Color(0xffD9EBE8), thickness: 0.8),
|
const Divider(color: Color(0xffD9EBE8), thickness: 0.8),
|
||||||
@ -597,8 +558,8 @@ class claimListState extends ConsumerState<claimList> {
|
|||||||
//company
|
//company
|
||||||
const Text("Company", style: _cardheaderStyle),
|
const Text("Company", style: _cardheaderStyle),
|
||||||
Text(
|
Text(
|
||||||
item['reg_no'] != null
|
item['policy_end_date'] != null
|
||||||
? _formatDate(item['reg_no'])
|
? _formatDate(item['policy_end_date'])
|
||||||
: '-',
|
: '-',
|
||||||
style: _cardBodyStyle,
|
style: _cardBodyStyle,
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
@ -616,7 +577,7 @@ class claimListState extends ConsumerState<claimList> {
|
|||||||
//status
|
//status
|
||||||
const Text("Claim Type", style: _cardheaderStyle),
|
const Text("Claim Type", style: _cardheaderStyle),
|
||||||
Text(
|
Text(
|
||||||
item['claim_type'] ?? '-',
|
item['claim_type_value'] ?? '-',
|
||||||
style: _cardBodyStyle,
|
style: _cardBodyStyle,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
softWrap: true,
|
softWrap: true,
|
||||||
@ -638,10 +599,7 @@ class claimListState extends ConsumerState<claimList> {
|
|||||||
children: [
|
children: [
|
||||||
//date and time
|
//date and time
|
||||||
const Text("policy Number", style: _cardheaderStyle),
|
const Text("policy Number", style: _cardheaderStyle),
|
||||||
Text(
|
Text(item['policy_no'] ?? '-', style: _cardBodyStyle),
|
||||||
_formatDate(item['policy_no']) ?? '-',
|
|
||||||
style: _cardBodyStyle,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -184,7 +184,7 @@ class endosementState extends ConsumerState<endosement> {
|
|||||||
color: Color(0xFF425B5B),
|
color: Color(0xFF425B5B),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"Endosement",
|
"Endorsement",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -325,10 +325,10 @@ class endosementState extends ConsumerState<endosement> {
|
|||||||
style: _headerStyle,
|
style: _headerStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
// Expanded(
|
||||||
flex: 1,
|
// flex: 1,
|
||||||
child: Text('Action', style: _headerStyle),
|
// child: Text('Action', style: _headerStyle),
|
||||||
),
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -420,74 +420,65 @@ class endosementState extends ConsumerState<endosement> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text(
|
||||||
item['reg_no'] != null
|
item['reg_no'] ?? '-', // fallback
|
||||||
? _formatDate(item['reg_no'])
|
|
||||||
: '-', // fallback
|
|
||||||
style: _dataBold,
|
style: _dataBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text(
|
||||||
item['insurer_name'] != null
|
item['insurer_name'] ?? '-', // fallback
|
||||||
? _formatDate(item['insurer_name'])
|
|
||||||
: '-', // fallback
|
|
||||||
style: _dataBold,
|
style: _dataBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: Text(item['policy_number'] ?? '-', style: _dataBold),
|
||||||
|
),
|
||||||
|
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text(
|
||||||
_formatDate(item['policy_number']) ?? '-',
|
item['endorsement_type_value'] ?? '-',
|
||||||
style: _dataBold,
|
style: _dataBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text(item['endorsement_no'] ?? '-', style: _dataBold),
|
||||||
_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),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
// 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,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
//reg no
|
//reg no
|
||||||
Text(
|
Text(item['reg_no'] ?? '-', style: _headerStyle),
|
||||||
item['reg_no'] != null ? _formatDate(item['reg_no']) : '-',
|
// PopupMenuButton<int>(
|
||||||
style: _headerStyle,
|
// color: Colors.white,
|
||||||
),
|
// padding: EdgeInsets.zero,
|
||||||
PopupMenuButton<int>(
|
// offset: Offset(0, 30),
|
||||||
color: Colors.white,
|
// icon: Icon(Icons.more_vert, color: Color(0xFF475569), size: 14),
|
||||||
padding: EdgeInsets.zero,
|
// itemBuilder: (context) => [
|
||||||
offset: Offset(0, 30),
|
// CustomPopupMenuEntry(
|
||||||
icon: Icon(Icons.more_vert, color: Color(0xFF475569), size: 14),
|
// child: Container(
|
||||||
itemBuilder: (context) => [
|
// padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
|
||||||
CustomPopupMenuEntry(
|
// child: Column(
|
||||||
child: Container(
|
// mainAxisSize: MainAxisSize.min,
|
||||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
|
// mainAxisAlignment: MainAxisAlignment.center,
|
||||||
child: Column(
|
// children: _buildPopupMenuActions(context, item),
|
||||||
mainAxisSize: MainAxisSize.min,
|
// ),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
// ),
|
||||||
children: _buildPopupMenuActions(context, item),
|
// ),
|
||||||
),
|
// ],
|
||||||
),
|
// ),
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const Divider(color: Color(0xffD9EBE8), thickness: 0.8),
|
const Divider(color: Color(0xffD9EBE8), thickness: 0.8),
|
||||||
@ -549,9 +537,7 @@ class endosementState extends ConsumerState<endosement> {
|
|||||||
//company
|
//company
|
||||||
const Text("Company", style: _cardheaderStyle),
|
const Text("Company", style: _cardheaderStyle),
|
||||||
Text(
|
Text(
|
||||||
item['insurer_name'] != null
|
item['insurer_name'] ?? '-',
|
||||||
? _formatDate(item['insurer_name'])
|
|
||||||
: '-',
|
|
||||||
style: _cardBodyStyle,
|
style: _cardBodyStyle,
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
softWrap: true,
|
softWrap: true,
|
||||||
@ -568,7 +554,7 @@ class endosementState extends ConsumerState<endosement> {
|
|||||||
//status
|
//status
|
||||||
const Text("Endorsement Type", style: _cardheaderStyle),
|
const Text("Endorsement Type", style: _cardheaderStyle),
|
||||||
Text(
|
Text(
|
||||||
item['endorsement_type'] ?? '-',
|
item['endorsement_type_value'] ?? '-',
|
||||||
style: _cardBodyStyle,
|
style: _cardBodyStyle,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
softWrap: true,
|
softWrap: true,
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import '../../../../core/config/env.dart';
|
|||||||
import '../../../../core/services/api_service.dart';
|
import '../../../../core/services/api_service.dart';
|
||||||
import '../../../../data/services/auth_service.dart';
|
import '../../../../data/services/auth_service.dart';
|
||||||
import '../../../../data/utils/Pagination.dart';
|
import '../../../../data/utils/Pagination.dart';
|
||||||
|
import '../../../../data/utils/toastNotification.dart';
|
||||||
import '../../../../data/utils/validators.dart';
|
import '../../../../data/utils/validators.dart';
|
||||||
import '../../../layouts/main_layout.dart';
|
import '../../../layouts/main_layout.dart';
|
||||||
import '../../../providers/manager_provider.dart';
|
import '../../../providers/manager_provider.dart';
|
||||||
@ -237,6 +238,15 @@ class AgentState extends ConsumerState<Agent> {
|
|||||||
print("✅ Agent submitted successfully!");
|
print("✅ Agent submitted successfully!");
|
||||||
|
|
||||||
print("Response: ${response.body}");
|
print("Response: ${response.body}");
|
||||||
|
isUpdating
|
||||||
|
? ToastHelper.showSuccessToast(
|
||||||
|
context,
|
||||||
|
'Agent Updated Successfully',
|
||||||
|
)
|
||||||
|
: ToastHelper.showSuccessToast(
|
||||||
|
context,
|
||||||
|
'Agent Created Successfully',
|
||||||
|
);
|
||||||
context.go(AppRoutes.agentLst);
|
context.go(AppRoutes.agentLst);
|
||||||
} else {
|
} else {
|
||||||
final responseBody = jsonDecode(response.body);
|
final responseBody = jsonDecode(response.body);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
// import 'dart:io' as html;
|
// import 'dart:io' as html;
|
||||||
// import 'dart:nativewrappers/_internal/vm/lib/typed_data_patch.dart';
|
// import 'dart:nativewrappers/_internal/vm/lib/typed_data_patch.dart';
|
||||||
|
import 'dart:convert';
|
||||||
import 'dart:typed_data'; // Import for Uint8List
|
import 'dart:typed_data'; // Import for Uint8List
|
||||||
import 'package:dropdown_search/dropdown_search.dart';
|
import 'package:dropdown_search/dropdown_search.dart';
|
||||||
import 'package:file_picker/file_picker.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:google_fonts/google_fonts.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:intl/intl.dart';
|
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:nhance_partner/presentation/themes/indicators/text_field_theme.dart';
|
||||||
|
import 'package:toastification/toastification.dart';
|
||||||
import 'package:universal_html/html.dart' as html;
|
import 'package:universal_html/html.dart' as html;
|
||||||
|
|
||||||
import '../../../../core/config/env.dart';
|
import '../../../../core/config/env.dart';
|
||||||
@ -202,6 +205,9 @@ class UploadIncentiveModalState extends ConsumerState<UploadIncentiveModal> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> handleSave() async {
|
Future<void> handleSave() async {
|
||||||
|
if (agentId == null) {
|
||||||
|
ToastHelper.showErrorToast(context, 'Select Agent Name');
|
||||||
|
} else {
|
||||||
if (!_formKey.currentState!.validate()) return;
|
if (!_formKey.currentState!.validate()) return;
|
||||||
print("Handl1");
|
print("Handl1");
|
||||||
final dataSet = dataDetails();
|
final dataSet = dataDetails();
|
||||||
@ -211,7 +217,9 @@ class UploadIncentiveModalState extends ConsumerState<UploadIncentiveModal> {
|
|||||||
if (passportFile == null) {
|
if (passportFile == null) {
|
||||||
print("❌ No file selected!");
|
print("❌ No file selected!");
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(content: Text("Please select a file before submitting")),
|
const SnackBar(
|
||||||
|
content: Text("Please select a file before submitting"),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -222,6 +230,7 @@ class UploadIncentiveModalState extends ConsumerState<UploadIncentiveModal> {
|
|||||||
|
|
||||||
print("Handl2");
|
print("Handl2");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> uploadIncentiveData(Map<String, dynamic> dataSet) async {
|
Future<void> uploadIncentiveData(Map<String, dynamic> dataSet) async {
|
||||||
final uri = Uri.parse('${Env.apiUrl}agent/uploadAgentIncentiveFile');
|
final uri = Uri.parse('${Env.apiUrl}agent/uploadAgentIncentiveFile');
|
||||||
@ -303,6 +312,7 @@ class UploadIncentiveModalState extends ConsumerState<UploadIncentiveModal> {
|
|||||||
final response = await http.Response.fromStream(streamedResponse);
|
final response = await http.Response.fromStream(streamedResponse);
|
||||||
print("Response status: ${response.statusCode}");
|
print("Response status: ${response.statusCode}");
|
||||||
print("Response body: ${response.body}");
|
print("Response body: ${response.body}");
|
||||||
|
final responseBody = json.decode(response.body);
|
||||||
|
|
||||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||||
// dispose();
|
// dispose();
|
||||||
@ -313,7 +323,19 @@ class UploadIncentiveModalState extends ConsumerState<UploadIncentiveModal> {
|
|||||||
final data = dataDetails();
|
final data = dataDetails();
|
||||||
final agentId = data["agent_id"];
|
final agentId = data["agent_id"];
|
||||||
|
|
||||||
|
final status = responseBody['status'];
|
||||||
|
final message = responseBody['data'] ?? '';
|
||||||
|
|
||||||
|
if (status == 'success') {
|
||||||
|
ToastHelper.showSuccessToast(context, 'File uploaded successfully!');
|
||||||
getAgentIncenctiveFileList(agentId);
|
getAgentIncenctiveFileList(agentId);
|
||||||
|
} else {
|
||||||
|
ToastHelper.showErrorToast(
|
||||||
|
context,
|
||||||
|
message.isNotEmpty ? message : 'Something went wrong!',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// context.go(AppRoutes.agentLst);
|
// context.go(AppRoutes.agentLst);
|
||||||
} else {
|
} else {
|
||||||
print("❌ Submission failed. Status: ${response.statusCode}");
|
print("❌ Submission failed. Status: ${response.statusCode}");
|
||||||
|
|||||||
@ -485,37 +485,68 @@ class AgentListState extends ConsumerState<AgentList> {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
child: Row(
|
child: item['is_active'] == "1"
|
||||||
|
? Row(
|
||||||
children: [
|
children: [
|
||||||
PopupMenuButton<int>(
|
GestureDetector(
|
||||||
color: Colors.white,
|
onTap: () {
|
||||||
padding: EdgeInsets.zero,
|
// Navigator.pop(context);
|
||||||
offset: Offset(0, 30),
|
print('EDITStaff - ${item['id']}');
|
||||||
icon: Icon(
|
dynamic id = item['id'];
|
||||||
Icons.more_vert,
|
context.go('/agent/$id');
|
||||||
color: Color(0xFF475569),
|
},
|
||||||
size: 14,
|
child: Image.asset(
|
||||||
),
|
"assets/miscellaneous/Edit.png",
|
||||||
itemBuilder: (context) => [
|
height: 15,
|
||||||
if (item['is_active'] == "1")
|
width: 15,
|
||||||
CustomPopupMenuEntry(
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.symmetric(
|
|
||||||
horizontal: 8,
|
|
||||||
vertical: 8,
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: _buildPopupMenuActions(context, item),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
)
|
||||||
|
: 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,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
if (!isProfile) ...[
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
isProfile = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
icon: Icon(
|
||||||
|
Icons.arrow_back_ios_new_outlined,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 4),
|
||||||
|
],
|
||||||
Text(
|
Text(
|
||||||
isProfile ? '' : 'Incentive Files',
|
isProfile ? '' : 'Incentive Files',
|
||||||
style: _topheaderStyle,
|
style: _topheaderStyle,
|
||||||
@ -168,7 +182,7 @@ class ProfileState extends ConsumerState<Profile> {
|
|||||||
? Container(
|
? Container(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
padding: ResponsiveLayout.isMobile(context)
|
padding: ResponsiveLayout.isMobile(context)
|
||||||
? EdgeInsets.all(16.0)
|
? EdgeInsets.all(8.0)
|
||||||
: null,
|
: null,
|
||||||
child: isLoading
|
child: isLoading
|
||||||
? const Center(
|
? const Center(
|
||||||
@ -176,10 +190,10 @@ class ProfileState extends ConsumerState<Profile> {
|
|||||||
)
|
)
|
||||||
: Column(
|
: Column(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 25),
|
// const SizedBox(height: 25),
|
||||||
Container(
|
Container(
|
||||||
width: 70,
|
width: 60,
|
||||||
height: 70,
|
height: 60,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Color(0xFFD9D9D9),
|
color: Color(0xFFD9D9D9),
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(
|
||||||
@ -188,7 +202,7 @@ class ProfileState extends ConsumerState<Profile> {
|
|||||||
),
|
),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.person_outline,
|
Icons.person_outline,
|
||||||
size: 50,
|
size: 30,
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -669,7 +683,7 @@ class ProfileState extends ConsumerState<Profile> {
|
|||||||
static const _topheaderStyle = TextStyle(
|
static const _topheaderStyle = TextStyle(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
fontWeight: FontWeight.w600,
|
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:go_router/go_router.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:nhance_partner/core/routing/routes.dart';
|
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 'package:nhance_partner/presentation/themes/indicators/text_field_theme.dart';
|
||||||
|
|
||||||
import '../../../../core/config/env.dart';
|
import '../../../../core/config/env.dart';
|
||||||
@ -159,6 +160,16 @@ class StaffState extends ConsumerState<Staff> {
|
|||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
print("Staff submitted successfully!");
|
print("Staff submitted successfully!");
|
||||||
print("Response: ${response.body}");
|
print("Response: ${response.body}");
|
||||||
|
|
||||||
|
isUpdating
|
||||||
|
? ToastHelper.showSuccessToast(
|
||||||
|
context,
|
||||||
|
'Staff Updated Successfully',
|
||||||
|
)
|
||||||
|
: ToastHelper.showSuccessToast(
|
||||||
|
context,
|
||||||
|
'Staff Created Successfully',
|
||||||
|
);
|
||||||
context.go(AppRoutes.staffLst);
|
context.go(AppRoutes.staffLst);
|
||||||
} else {
|
} else {
|
||||||
final responseBody = jsonDecode(response.body);
|
final responseBody = jsonDecode(response.body);
|
||||||
|
|||||||
@ -434,37 +434,68 @@ class StaffListState extends ConsumerState<StaffList> {
|
|||||||
|
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
child: Row(
|
child: item['is_active'] == "1"
|
||||||
|
? Row(
|
||||||
children: [
|
children: [
|
||||||
PopupMenuButton<int>(
|
GestureDetector(
|
||||||
color: Colors.white,
|
onTap: () {
|
||||||
padding: EdgeInsets.zero,
|
// Navigator.pop(context);
|
||||||
offset: Offset(0, 30),
|
print('EDITStaff - ${item['id']}');
|
||||||
icon: Icon(
|
dynamic id = item['id'];
|
||||||
Icons.more_vert,
|
context.go('/staff/$id');
|
||||||
color: Color(0xFF475569),
|
},
|
||||||
size: 14,
|
child: Image.asset(
|
||||||
),
|
"assets/miscellaneous/Edit.png",
|
||||||
itemBuilder: (context) => [
|
height: 15,
|
||||||
if (item['is_active'] == "1")
|
width: 15,
|
||||||
CustomPopupMenuEntry(
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.symmetric(
|
|
||||||
horizontal: 8,
|
|
||||||
vertical: 8,
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: _buildPopupMenuActions(context, item),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
)
|
||||||
|
: 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:go_router/go_router.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
|
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
|
||||||
|
import 'package:nhance_partner/presentation/screens/staff/assignStaff.dart';
|
||||||
import '../../../../core/routing/routes.dart';
|
import '../../../../core/routing/routes.dart';
|
||||||
import '../../../../core/services/api_service.dart';
|
import '../../../../core/services/api_service.dart';
|
||||||
import '../../../../data/utils/Pagination.dart';
|
import '../../../../data/utils/Pagination.dart';
|
||||||
import '../../../layouts/main_layout.dart';
|
import '../../../layouts/main_layout.dart';
|
||||||
import '../../../layouts/responsive_layout.dart';
|
import '../../../layouts/responsive_layout.dart';
|
||||||
import '../../../providers/manager_provider.dart';
|
import '../../../providers/manager_provider.dart';
|
||||||
|
import '../../../providers/quotation_staff_proivder.dart';
|
||||||
import '../../../themes/indicators/export_btn.dart';
|
import '../../../themes/indicators/export_btn.dart';
|
||||||
import '../../../themes/indicators/search_field_theme.dart';
|
import '../../../themes/indicators/search_field_theme.dart';
|
||||||
import '../../../widgets/custom_action_popup.dart';
|
import '../../../widgets/custom_action_popup.dart';
|
||||||
|
|
||||||
|
|
||||||
class policylist extends ConsumerStatefulWidget {
|
class policylist extends ConsumerStatefulWidget {
|
||||||
const policylist({super.key});
|
const policylist({super.key});
|
||||||
@override
|
@override
|
||||||
@ -31,6 +32,7 @@ class policylistState extends ConsumerState<policylist> {
|
|||||||
List<Map<String, dynamic>> originalData = [];
|
List<Map<String, dynamic>> originalData = [];
|
||||||
List<Map<String, dynamic>> filteredData = [];
|
List<Map<String, dynamic>> filteredData = [];
|
||||||
bool isLoading = false;
|
bool isLoading = false;
|
||||||
|
dynamic roleId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -40,7 +42,7 @@ class policylistState extends ConsumerState<policylist> {
|
|||||||
|
|
||||||
Future.microtask(() {
|
Future.microtask(() {
|
||||||
final id = ref.read(managerIdProvider);
|
final id = ref.read(managerIdProvider);
|
||||||
final roleId = ref.read(userRoleProvider);
|
roleId = ref.read(userRoleProvider);
|
||||||
|
|
||||||
print("ENQroleId - $roleId");
|
print("ENQroleId - $roleId");
|
||||||
if (id != null) {
|
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 {
|
Future<void> getStaffList(int managerId, role) async {
|
||||||
print('getClaimList called MagId - $managerId - $role');
|
print('getClaimList called MagId - $managerId - $role');
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -56,7 +67,10 @@ class policylistState extends ConsumerState<policylist> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final response = await apiService.fetchPolicyList(managerId, role);
|
final response = await apiService.fetchPolicyDataOnlyList(
|
||||||
|
managerId,
|
||||||
|
role,
|
||||||
|
);
|
||||||
|
|
||||||
if (response['status'] == 'success') {
|
if (response['status'] == 'success') {
|
||||||
final data = response['data'];
|
final data = response['data'];
|
||||||
@ -94,6 +108,7 @@ class policylistState extends ConsumerState<policylist> {
|
|||||||
final sortedData = [...filteredData]
|
final sortedData = [...filteredData]
|
||||||
..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
|
..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
|
||||||
|
|
||||||
|
// final sortedData = [...filteredData];
|
||||||
final startIndex = (currentPage - 1) * itemsPerPage;
|
final startIndex = (currentPage - 1) * itemsPerPage;
|
||||||
final endIndex = (currentPage * itemsPerPage).clamp(0, sortedData.length);
|
final endIndex = (currentPage * itemsPerPage).clamp(0, sortedData.length);
|
||||||
|
|
||||||
@ -127,10 +142,14 @@ class policylistState extends ConsumerState<policylist> {
|
|||||||
(item['payment_mode'] ?? '').toLowerCase().contains(
|
(item['payment_mode'] ?? '').toLowerCase().contains(
|
||||||
query.toLowerCase(),
|
query.toLowerCase(),
|
||||||
) ||
|
) ||
|
||||||
(item['updated_on'] ?? '').toLowerCase().contains(
|
(_formatDate(item['updated_on']) ?? '').toLowerCase().contains(
|
||||||
query.toLowerCase(),
|
query.toLowerCase(),
|
||||||
) ||
|
) ||
|
||||||
(item['policy_number'] ?? '').toLowerCase().contains(query.toLowerCase());
|
(item['policy_number'] ?? '').toLowerCase().contains(
|
||||||
|
query.toLowerCase(),
|
||||||
|
) ||
|
||||||
|
(item['status'] ?? '').toLowerCase().contains(query.toLowerCase());
|
||||||
|
;
|
||||||
}).toList();
|
}).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 [
|
return [
|
||||||
GestureDetector(
|
if (roleId == 'manager') ...[
|
||||||
|
Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
print('EDITStaff - ${data['id']}');
|
showDialog(
|
||||||
dynamic id = data['id'];
|
context: context,
|
||||||
// context.go('/staff/$id');
|
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(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
// mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.edit_sharp, color: Color(0xFF319718), size: 18),
|
Image.asset(
|
||||||
|
"assets/miscellaneous/image_3.png",
|
||||||
|
// height: 45,
|
||||||
|
// width: 15,
|
||||||
|
),
|
||||||
|
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
Text('Edit'),
|
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'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,16 +426,17 @@ class policylistState extends ConsumerState<policylist> {
|
|||||||
),
|
),
|
||||||
child: const Row(
|
child: const Row(
|
||||||
children: [
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: Text('Date', style: _headerStyle),
|
||||||
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text('Reg.No', style: _headerStyle),
|
child: Text('Reg.No', style: _headerStyle),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text('Agents', style: _headerStyle),
|
||||||
'Agents',
|
|
||||||
style: _headerStyle,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
@ -345,18 +462,15 @@ class policylistState extends ConsumerState<policylist> {
|
|||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text('Policy Number', style: _headerStyle),
|
child: Text('Policy Number', style: _headerStyle),
|
||||||
),
|
),
|
||||||
|
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 3,
|
||||||
child: Text('Date', style: _headerStyle),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
flex: 2,
|
|
||||||
child: Text('Status', style: _headerStyle),
|
child: Text('Status', style: _headerStyle),
|
||||||
),
|
),
|
||||||
Expanded(
|
// Expanded(
|
||||||
flex: 1,
|
// flex: 1,
|
||||||
child: Text('Action', style: _headerStyle),
|
// child: Text('Action', style: _headerStyle),
|
||||||
),
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -444,7 +558,19 @@ class policylistState extends ConsumerState<policylist> {
|
|||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
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(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -501,52 +627,50 @@ class policylistState extends ConsumerState<policylist> {
|
|||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 3,
|
||||||
child: Text(
|
|
||||||
item['updated_on'] ?? '-',
|
|
||||||
style: _dataBold,
|
|
||||||
softWrap: true,
|
|
||||||
maxLines: 3,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
flex: 2,
|
|
||||||
child: Text(item['status'] ?? '-', style: _dataBold),
|
child: Text(item['status'] ?? '-', style: _dataBold),
|
||||||
),
|
),
|
||||||
|
|
||||||
Expanded(
|
// Expanded(
|
||||||
flex: 1,
|
// flex: 1,
|
||||||
child: Row(
|
// child: Row(
|
||||||
children: [
|
// children: [
|
||||||
PopupMenuButton<int>(
|
// PopupMenuButton<int>(
|
||||||
color: Colors.white,
|
// color: Colors.white,
|
||||||
padding: EdgeInsets.zero,
|
// padding: EdgeInsets.zero,
|
||||||
offset: Offset(0, 30),
|
// offset: Offset(0, 30),
|
||||||
icon: Icon(
|
// icon: Icon(
|
||||||
Icons.more_vert,
|
// Icons.more_vert,
|
||||||
color: Color(0xFF475569),
|
// color: Color(0xFF475569),
|
||||||
size: 14,
|
// size: 14,
|
||||||
),
|
// ),
|
||||||
itemBuilder: (context) => [
|
// itemBuilder: (context) => [
|
||||||
CustomPopupMenuEntry(
|
// CustomPopupMenuEntry(
|
||||||
child: Container(
|
// child: Container(
|
||||||
padding: EdgeInsets.symmetric(
|
// padding: EdgeInsets.symmetric(
|
||||||
horizontal: 8,
|
// horizontal: 8,
|
||||||
vertical: 8,
|
// vertical: 8,
|
||||||
),
|
// ),
|
||||||
child: Column(
|
// child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
// mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
// mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: _buildPopupMenuActions(context, item),
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
),
|
// children: _buildPopupMenuActions(
|
||||||
),
|
// context,
|
||||||
),
|
// item,
|
||||||
],
|
// item['id'],
|
||||||
),
|
// item['reg_no'],
|
||||||
],
|
// ),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -564,65 +688,84 @@ class policylistState extends ConsumerState<policylist> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
/// Top row: Reg.No + Action menu
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(item['reg_no'] ?? '-', style: _headerStyle),
|
Text(item['reg_no'] ?? '-', style: _headerStyle),
|
||||||
PopupMenuButton<int>(
|
// PopupMenuButton<int>(
|
||||||
color: Colors.white,
|
// color: Colors.white,
|
||||||
padding: EdgeInsets.zero,
|
// padding: EdgeInsets.zero,
|
||||||
offset: Offset(0, 30),
|
// offset: Offset(0, 30),
|
||||||
icon: Icon(Icons.more_vert, color: Color(0xFF475569), size: 14),
|
// icon: Icon(Icons.more_vert, color: Color(0xFF475569), size: 14),
|
||||||
itemBuilder: (context) => [
|
// itemBuilder: (context) => [
|
||||||
CustomPopupMenuEntry(
|
// CustomPopupMenuEntry(
|
||||||
child: Container(
|
// child: Container(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
|
// padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
|
||||||
child: Column(
|
// child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
// mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
// children: _buildPopupMenuActions(
|
||||||
children: _buildPopupMenuActions(context, item),
|
// context,
|
||||||
),
|
// item,
|
||||||
),
|
// item['id'],
|
||||||
),
|
// item['reg_no'],
|
||||||
],
|
// ),
|
||||||
),
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const Divider(color: Color(0xffD9EBE8), thickness: 0.8),
|
const Divider(color: Color(0xffD9EBE8), thickness: 0.8),
|
||||||
|
|
||||||
// Company + Vehicle Reg No
|
/// Company + Status
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
const Text("Company", style: _cardheaderStyle),
|
const Text("Company", style: _cardheaderStyle),
|
||||||
Text(
|
Text(item['insurer_name'] ?? '-', style: _cardBodyStyle),
|
||||||
item['insurer_name'] ?? '-',
|
|
||||||
style: _cardBodyStyle,
|
|
||||||
maxLines: 3,
|
|
||||||
softWrap: true,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 5),
|
const SizedBox(width: 5),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
const Text("Status", style: _cardheaderStyle),
|
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(
|
Text(
|
||||||
item['status'] ?? '-',
|
item['assigned_to_name'] ?? '-',
|
||||||
style: _cardBodyStyle,
|
style: _cardBodyStyle,
|
||||||
maxLines: 2,
|
|
||||||
softWrap: true,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -631,23 +774,74 @@ class policylistState extends ConsumerState<policylist> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 15),
|
const SizedBox(height: 15),
|
||||||
|
|
||||||
// Created On + Remarks
|
/// Insured Name + Premium
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
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(
|
Text(
|
||||||
_formatDate(item['created_on']) ?? '-',
|
_formatDate(item['updated_on']) ?? '-',
|
||||||
style: _cardBodyStyle,
|
style: _cardBodyStyle,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 5),
|
const SizedBox(width: 5),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -657,7 +851,6 @@ class policylistState extends ConsumerState<policylist> {
|
|||||||
item['remarks'] ?? '-',
|
item['remarks'] ?? '-',
|
||||||
style: _cardBodyStyle,
|
style: _cardBodyStyle,
|
||||||
maxLines: 3,
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FormField<String>(
|
return FormField<String>(
|
||||||
@ -64,22 +65,28 @@ class _ThemedDateFieldState extends State<ThemedDateField> {
|
|||||||
initialValue: widget.controller?.text,
|
initialValue: widget.controller?.text,
|
||||||
builder: (field) {
|
builder: (field) {
|
||||||
final hasError = field.hasError;
|
final hasError = field.hasError;
|
||||||
return Container(
|
|
||||||
width: widget.txtwidth ?? MediaQuery.of(context).size.width,
|
return Column(
|
||||||
height: widget.txtheight,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
child: InkWell(
|
children: [
|
||||||
|
InkWell(
|
||||||
onTap: () => pickDate(context, field),
|
onTap: () => pickDate(context, field),
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
width: widget.txtwidth ?? MediaQuery.of(context).size.width,
|
||||||
|
height: widget.txtheight,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 10,
|
||||||
|
horizontal: 15,
|
||||||
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: widget.backgroundColor ?? Colors.white,
|
color: widget.backgroundColor ?? Colors.white,
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: hasError
|
color: hasError
|
||||||
? (widget.errorBorderColor ?? Colors.red)
|
? (widget.errorBorderColor ?? Color(0xFFD83731))
|
||||||
: (widget.borderColor ?? Colors.grey.shade50),
|
: (widget.borderColor ?? Colors.grey.shade50),
|
||||||
width: 1.5,
|
width: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -91,8 +98,8 @@ class _ThemedDateFieldState extends State<ThemedDateField> {
|
|||||||
? widget.controller!.text
|
? widget.controller!.text
|
||||||
: widget.hintText ?? "Select Date",
|
: widget.hintText ?? "Select Date",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 13,
|
||||||
color: hasError ? Colors.red : Colors.black,
|
color: hasError ? Color(0xFFD83731) : Colors.black,
|
||||||
),
|
),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
@ -106,6 +113,18 @@ class _ThemedDateFieldState extends State<ThemedDateField> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
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,
|
required String fileName,
|
||||||
}) async {
|
}) async {
|
||||||
try {
|
try {
|
||||||
|
// Create Excel and delete default sheet
|
||||||
var excel = Excel.createExcel();
|
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
|
// Add headers
|
||||||
sheetObject.appendRow(headers.map((h) => TextCellValue(h)).toList());
|
sheetObject.appendRow(headers.map((h) => TextCellValue(h)).toList());
|
||||||
|
|
||||||
// Add data
|
// Add data
|
||||||
for (int i = 0; i < data.length; i++) {
|
for (var rowData in data) {
|
||||||
var row = <CellValue?>[];
|
var row = <CellValue?>[];
|
||||||
for (var key in headers) {
|
for (var key in headers) {
|
||||||
final value = data[i][key];
|
final value = rowData[key];
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
row.add(TextCellValue('-'));
|
row.add(TextCellValue('-'));
|
||||||
} else if (value is int) {
|
} else if (value is int) {
|
||||||
@ -106,7 +112,7 @@ class ExcelExporter {
|
|||||||
var bytes = excel.encode()!;
|
var bytes = excel.encode()!;
|
||||||
|
|
||||||
if (kIsWeb) {
|
if (kIsWeb) {
|
||||||
// ✅ Web: download as file
|
// Web: download
|
||||||
final blob = html.Blob([bytes]);
|
final blob = html.Blob([bytes]);
|
||||||
final url = html.Url.createObjectUrlFromBlob(blob);
|
final url = html.Url.createObjectUrlFromBlob(blob);
|
||||||
final anchor = html.AnchorElement(href: url)
|
final anchor = html.AnchorElement(href: url)
|
||||||
@ -114,7 +120,7 @@ class ExcelExporter {
|
|||||||
..click();
|
..click();
|
||||||
html.Url.revokeObjectUrl(url);
|
html.Url.revokeObjectUrl(url);
|
||||||
} else {
|
} else {
|
||||||
// ✅ Mobile/Desktop: save to file system
|
// Mobile/Desktop: save file
|
||||||
final dir = await getApplicationDocumentsDirectory();
|
final dir = await getApplicationDocumentsDirectory();
|
||||||
final file = File('${dir.path}/$fileName.xlsx');
|
final file = File('${dir.path}/$fileName.xlsx');
|
||||||
await file.writeAsBytes(bytes);
|
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
|
// ✅ dynamic hint color
|
||||||
color: const Color(0xFFC3C6CB),
|
color: const Color(0xFFC3C6CB),
|
||||||
),
|
),
|
||||||
// labelStyle: TextStyle(fontSize: 11, color: Colors.red),
|
labelStyle: TextStyle(fontSize: 12),
|
||||||
prefixIconConstraints: const BoxConstraints(
|
prefixIconConstraints: const BoxConstraints(
|
||||||
maxWidth: 25 + 16 + 10,
|
maxWidth: 25 + 16 + 10,
|
||||||
maxHeight: 25 + (8 * 2),
|
maxHeight: 25 + (8 * 2),
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import '../../core/routing/routes.dart';
|
import '../../core/routing/routes.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@ -22,8 +23,10 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
|
|||||||
_overlayEntry = OverlayEntry(
|
_overlayEntry = OverlayEntry(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return Positioned(
|
return Positioned(
|
||||||
left: offset.dx + size.width,
|
left: offset.dx + size.width - 5, // little spacing
|
||||||
top: offset.dy,
|
top: offset.dy + (size.height / 2) - 20,
|
||||||
|
// left: offset.dx + size.width,
|
||||||
|
// top: offset.dy,
|
||||||
child: MouseRegion(
|
child: MouseRegion(
|
||||||
onExit: (_) => _hidePopup(),
|
onExit: (_) => _hidePopup(),
|
||||||
child: Material(
|
child: Material(
|
||||||
@ -33,125 +36,144 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
|
|||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(6),
|
borderRadius: BorderRadius.circular(6),
|
||||||
color: Colors.white,
|
color: const Color(0xFFDDF5F1),
|
||||||
|
// color: Colors.white,
|
||||||
),
|
),
|
||||||
|
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisSize: MainAxisSize.min,
|
// mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
if (key == 'User') ...[
|
if (key == 'User') ...[
|
||||||
GestureDetector(
|
_buildPopupItem(
|
||||||
onTap: () {
|
label: "Agent",
|
||||||
print("Tappped Agent");
|
onTap: () => context.go(AppRoutes.agentLst),
|
||||||
context.go(AppRoutes.agentLst);
|
|
||||||
},
|
|
||||||
child: const Text(
|
|
||||||
"Agent",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
GestureDetector(
|
_buildPopupItem(
|
||||||
onTap: () {
|
label: "Staff",
|
||||||
print("Bf clicked");
|
onTap: () => context.go(AppRoutes.staffLst),
|
||||||
context.go(AppRoutes.staffLst);
|
|
||||||
},
|
|
||||||
child: const Text(
|
|
||||||
"Staff",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
if (key == 'Reports') ...[
|
||||||
|
_buildPopupItem(
|
||||||
|
label: "Claims",
|
||||||
|
onTap: () => context.go(AppRoutes.claimlist),
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
_buildPopupItem(
|
||||||
|
label: "Endorsement",
|
||||||
|
onTap: () => context.go(AppRoutes.endosement),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
_buildPopupItem(
|
||||||
|
label: "Policy",
|
||||||
|
onTap: () => context.go(AppRoutes.policylist),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
||||||
if (key == 'Reports') ...[
|
// if (key == 'User') ...[
|
||||||
GestureDetector(
|
// Row(
|
||||||
onTap: () {
|
// children: [
|
||||||
context.go(AppRoutes.claimlist);
|
// GestureDetector(
|
||||||
},
|
// onTap: () {
|
||||||
child: const Text(
|
// print("Tappped Agent");
|
||||||
"Claims",
|
// context.go(AppRoutes.agentLst);
|
||||||
style: TextStyle(
|
// },
|
||||||
fontSize: 16,
|
// child: Text("Agent", style: _cardTextStyle),
|
||||||
fontWeight: FontWeight.w400,
|
// ),
|
||||||
),
|
//
|
||||||
),
|
// 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),
|
// const SizedBox(height: 5),
|
||||||
// GestureDetector(
|
// GestureDetector(
|
||||||
// onTap: () {
|
// onTap: () {
|
||||||
// context.go(AppRoutes.enquiryLst);
|
// context.go(AppRoutes.endosement);
|
||||||
// },
|
// },
|
||||||
// child: const Text(
|
// child: Row(
|
||||||
// "Enquiries",
|
// children: [
|
||||||
// style: TextStyle(
|
// Text("Endorsement", style: _cardTextStyle),
|
||||||
// fontSize: 16,
|
//
|
||||||
// fontWeight: FontWeight.w400,
|
// 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,
|
||||||
// ),
|
// ),
|
||||||
const SizedBox(height: 5),
|
// ],
|
||||||
GestureDetector(
|
// ),
|
||||||
onTap: () {
|
// ),
|
||||||
context.go(AppRoutes.endosement);
|
// ],
|
||||||
},
|
|
||||||
child: const Text(
|
|
||||||
"Endorsement",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
context.go(AppRoutes.policylist);
|
|
||||||
},
|
|
||||||
child: const Text(
|
|
||||||
"Policy",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
context.go(AppRoutes.quotation);
|
|
||||||
},
|
|
||||||
child: const Text(
|
|
||||||
"Quotation",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
context.go(AppRoutes.policy);
|
|
||||||
},
|
|
||||||
child: const Text(
|
|
||||||
"Policy Form",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -183,13 +205,18 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
|
|||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 30),
|
SizedBox(height: 30),
|
||||||
DrawerContentWrapper(
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
context.go(AppRoutes.dashboard);
|
||||||
|
},
|
||||||
|
child: DrawerContentWrapper(
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
"assets/drawer/drawerImg1.png",
|
"assets/drawer/drawerImg1.png",
|
||||||
height: 25,
|
height: 25,
|
||||||
width: 25,
|
width: 25,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
DrawerLabel("Dashboard"),
|
DrawerLabel("Dashboard"),
|
||||||
|
|
||||||
Builder(
|
Builder(
|
||||||
@ -215,24 +242,16 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
DrawerLabel("Reports"),
|
DrawerLabel("Reports"),
|
||||||
// DrawerContentWrapper(
|
|
||||||
// child: IconButton(
|
|
||||||
// onPressed: () {
|
|
||||||
// // context.go('/tabEnquiry/tab');
|
|
||||||
// ref.read(enquiryIdProvider.notifier).state = 'tab';
|
|
||||||
// context.go(AppRoutes.tabEnquiry);
|
|
||||||
// },
|
|
||||||
// icon: Icon(Icons.list_alt_rounded, size: 30, color: Colors.black),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
DrawerContentWrapper(
|
DrawerContentWrapper(
|
||||||
child: Consumer(
|
child: Consumer(
|
||||||
builder: (context, ref, _) {
|
builder: (context, ref, _) {
|
||||||
return IconButton(
|
return IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (roleId == 'manager') {
|
print('roleI - $roleId');
|
||||||
} else if (roleId == 'agent') {
|
if (roleId == 'agent') {
|
||||||
context.go(AppRoutes.enquiryLst);
|
context.go(AppRoutes.enquiryLst);
|
||||||
|
} else {
|
||||||
|
context.go(AppRoutes.enquiryForStaff);
|
||||||
}
|
}
|
||||||
// ref.read(enquiryIdProvider.notifier).state = null;
|
// ref.read(enquiryIdProvider.notifier).state = null;
|
||||||
// context.go(AppRoutes.tabEnquiry);
|
// 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 {
|
class DrawerLabel extends StatelessWidget {
|
||||||
final String text;
|
final String text;
|
||||||
const DrawerLabel(this.text, {super.key});
|
const DrawerLabel(this.text, {super.key});
|
||||||
@ -286,9 +314,71 @@ class DrawerLabel extends StatelessWidget {
|
|||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
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),
|
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/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 {
|
import '../../core/routing/routes.dart';
|
||||||
final ValueChanged<int> onTabChanged;
|
import '../providers/userRoleProvider.dart';
|
||||||
const MobileTabs({super.key, required this.onTabChanged});
|
|
||||||
|
class MobileBottomMenu extends ConsumerStatefulWidget {
|
||||||
|
const MobileBottomMenu({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<MobileTabs> createState() => _MobileTabsState();
|
ConsumerState<MobileBottomMenu> createState() => _MobileBottomMenuState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MobileTabsState extends State<MobileTabs> {
|
class _MobileBottomMenuState extends ConsumerState<MobileBottomMenu> {
|
||||||
int _currentIndex = 0;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final roleId = ref.watch(userRoleProvider);
|
||||||
|
|
||||||
return BottomNavigationBar(
|
return BottomNavigationBar(
|
||||||
|
type: BottomNavigationBarType.fixed,
|
||||||
|
backgroundColor: const Color(0xFF425B5B),
|
||||||
|
selectedItemColor: Colors.white,
|
||||||
|
unselectedItemColor: Colors.white70,
|
||||||
currentIndex: _currentIndex,
|
currentIndex: _currentIndex,
|
||||||
onTap: (index) {
|
onTap: (index) {
|
||||||
setState(() => _currentIndex = 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: [
|
items: [
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
@ -28,18 +107,23 @@ class _MobileTabsState extends State<MobileTabs> {
|
|||||||
),
|
),
|
||||||
label: "Dashboard",
|
label: "Dashboard",
|
||||||
),
|
),
|
||||||
const BottomNavigationBarItem(
|
|
||||||
icon: Icon(Icons.person),
|
|
||||||
label: "Profile",
|
|
||||||
),
|
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Image.asset(
|
icon: Image.asset(
|
||||||
"assets/drawer/drawerImg2.png",
|
"assets/drawer/drawerImg2.png",
|
||||||
height: 20,
|
height: 20,
|
||||||
width: 20,
|
width: 20,
|
||||||
),
|
),
|
||||||
|
label: "Reports",
|
||||||
|
),
|
||||||
|
const BottomNavigationBarItem(
|
||||||
|
icon: Icon(Icons.list_alt_rounded, size: 24, color: Colors.black),
|
||||||
label: "Enquiry",
|
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