UI_Enq_Dashboard_Filter

This commit is contained in:
venbaittech 2025-10-25 16:05:43 +05:30
parent 3a0c29265b
commit 647f5ff05d
35 changed files with 2327 additions and 1588 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,18 @@
class Env { class Env {
static const String envName = String.fromEnvironment('ENV', defaultValue: 'dev'); static const String envName = String.fromEnvironment(
static const String apiUrl = String.fromEnvironment('API_URL', defaultValue: 'https://venbait.in/nhance/partner/dev/api/'); 'ENV',
static const String baseUrl = String.fromEnvironment('BASE_URL', defaultValue: '/nhance/partner/app'); defaultValue: 'dev',
static const String App_Signature = String.fromEnvironment('App_Signature', defaultValue: 'nhance-partner-2025-signature-35468846JRhH551HK'); );
static const String apiUrl = String.fromEnvironment(
'API_URL',
defaultValue: 'https://venbait.in/nhance/partner/dev/api/',
);
static const String baseUrl = String.fromEnvironment(
'BASE_URL',
defaultValue: '/nhance/partner/app',
);
static const String App_Signature = String.fromEnvironment(
'App_Signature',
defaultValue: 'nhance-partner-2025-signature-35468846JRhH551HK',
);
} }

View File

@ -27,7 +27,8 @@ import '../../presentation/screens/staff/policy/policy_list.dart';
import '../../presentation/screens/staff/quotations/quotation.dart'; import '../../presentation/screens/staff/quotations/quotation.dart';
final GoRouter appRouter = GoRouter( final GoRouter appRouter = GoRouter(
initialLocation: AppRoutes.home, initialLocation: AppRoutes.login,
// initialLocation: AppRoutes.home,
routes: [ routes: [
GoRoute( GoRoute(
path: AppRoutes.splash, path: AppRoutes.splash,
@ -37,10 +38,10 @@ final GoRouter appRouter = GoRouter(
path: AppRoutes.login, path: AppRoutes.login,
builder: (context, state) => const LoginScreen(), builder: (context, state) => const LoginScreen(),
), ),
GoRoute( // GoRoute(
path: AppRoutes.home, // path: AppRoutes.home,
builder: (context, state) => const HomeScreen(), // builder: (context, state) => const HomeScreen(),
), // ),
GoRoute( GoRoute(
path: AppRoutes.dashboard, path: AppRoutes.dashboard,
builder: (context, state) => const DashboardScreen(), builder: (context, state) => const DashboardScreen(),
@ -193,7 +194,7 @@ final GoRouter appRouter = GoRouter(
if (loggedIn && goingToLogin) { if (loggedIn && goingToLogin) {
// Logged in but going to login send to "next" if present // Logged in but going to login send to "next" if present
final next = state.uri.queryParameters['next']; final next = state.uri.queryParameters['next'];
return next ?? AppRoutes.home; return next ?? AppRoutes.login;
} }
// if (!loggedIn && !goingToLogin) return AppRoutes.login; // if (!loggedIn && !goingToLogin) return AppRoutes.login;

View File

@ -1,6 +1,7 @@
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.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/data/services/auth_service.dart'; import 'package:nhance_partner/data/services/auth_service.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -10,6 +11,8 @@ import '../config/env.dart';
import 'package:universal_html/html.dart' as html; import 'package:universal_html/html.dart' as html;
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import '../routing/routes.dart';
class ApiService { class ApiService {
late final BuildContext context; late final BuildContext context;
@ -20,12 +23,14 @@ class ApiService {
print("APISERTOKEN - $_token"); print("APISERTOKEN - $_token");
} }
Future<void> _clearLocalStorageAndRedirect() async { Future<void> clearLocalStorageAndRedirect() async {
final prefs = await SharedPreferences.getInstance(); // final prefs = await SharedPreferences.getInstance();
await prefs.clear(); // await prefs.clear();
// Assuming you have access to the context // Assuming you have access to the context
ToastHelper.showErrorToast(context, 'Session Out'); ToastHelper.showErrorToast(context, 'Session Out');
Navigator.pushNamed(context, 'login'); // Navigator.pushNamed(context, 'login');
AuthService.clearToken();
context.go(AppRoutes.login);
} }
Future<Map<String, dynamic>> _makeGetRequest( Future<Map<String, dynamic>> _makeGetRequest(
@ -46,7 +51,7 @@ class ApiService {
// if (response.statusCode == 200) { // if (response.statusCode == 200) {
// return jsonDecode(response.body); // return jsonDecode(response.body);
// } else if (response.statusCode == 401) { // } else if (response.statusCode == 401) {
// await _clearLocalStorageAndRedirect(); // await clearLocalStorageAndRedirect();
// return {}; // return {};
// } else { // } else {
// throw Exception('Failed to load data'); // throw Exception('Failed to load data');
@ -61,6 +66,9 @@ class ApiService {
if (response.statusCode == 200) { if (response.statusCode == 200) {
return response; // return full http.Response, not Map return response; // return full http.Response, not Map
} else if (response.statusCode == 403) {
await clearLocalStorageAndRedirect();
return http.Response('Forbidden', 403);
} else { } else {
throw Exception('Failed request: ${response.statusCode}'); throw Exception('Failed request: ${response.statusCode}');
} }
@ -83,8 +91,8 @@ class ApiService {
Future<Map<String, dynamic>> _handleResponse(http.Response response) async { Future<Map<String, dynamic>> _handleResponse(http.Response response) async {
if (response.statusCode == 200) { if (response.statusCode == 200) {
return jsonDecode(response.body); return jsonDecode(response.body);
} else if (response.statusCode == 401) { } else if (response.statusCode == 401 || response.statusCode == 403) {
await _clearLocalStorageAndRedirect(); await clearLocalStorageAndRedirect();
return {}; return {};
} else { } else {
throw Exception('Failed to load data'); throw Exception('Failed to load data');
@ -107,7 +115,7 @@ class ApiService {
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGethttpRequest(url, headers); final response = await _makeGethttpRequest(url, headers);
@ -200,7 +208,8 @@ class ApiService {
final headers = { final headers = {
'Authorization': 'Bearer $_token', 'Authorization': 'Bearer $_token',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', // 'App-Signature': Env.App_Signature,
'app-signature': Env.App_Signature,
}; };
final response = await _makeGethttpRequest(url, headers); final response = await _makeGethttpRequest(url, headers);
@ -260,6 +269,8 @@ class ApiService {
], ],
), ),
); );
} else if (response.statusCode == 403) {
await clearLocalStorageAndRedirect();
} else if (response.statusCode == 500) { } else if (response.statusCode == 500) {
ToastHelper.showInfoToast(context, 'No File Not Found'); ToastHelper.showInfoToast(context, 'No File Not Found');
} else { } else {
@ -303,6 +314,7 @@ class ApiService {
} }
Future<Map<String, dynamic>> updateStatus(id, status, role) async { Future<Map<String, dynamic>> updateStatus(id, status, role) async {
print('updateStatusupdateStatus');
final Map<String, dynamic> data = { final Map<String, dynamic> data = {
"id": int.parse(id), "id": int.parse(id),
"is_active": int.parse(status), "is_active": int.parse(status),
@ -330,7 +342,8 @@ class ApiService {
final headers = { final headers = {
'Authorization': 'Bearer $_token', 'Authorization': 'Bearer $_token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
// 'app-signature': 'nhance-partner-2025-signature-35468846JRhH551HK',
}; };
final response = await _makePostRequestJson(url, data, headers); final response = await _makePostRequestJson(url, data, headers);
@ -362,7 +375,7 @@ class ApiService {
// ); // );
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
@ -386,7 +399,7 @@ class ApiService {
// ); // );
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -404,7 +417,7 @@ class ApiService {
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -423,7 +436,7 @@ class ApiService {
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -442,7 +455,7 @@ class ApiService {
final url = Uri.parse('${Env.apiUrl}agent/findAgent?id=$id'); final url = Uri.parse('${Env.apiUrl}agent/findAgent?id=$id');
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -461,7 +474,7 @@ class ApiService {
final url = Uri.parse('${Env.apiUrl}agent/deleteAgentIncentiveFile?id=$id'); final url = Uri.parse('${Env.apiUrl}agent/deleteAgentIncentiveFile?id=$id');
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -490,7 +503,7 @@ class ApiService {
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -509,7 +522,7 @@ class ApiService {
final url = Uri.parse('${Env.apiUrl}staff/findStaff?id=$id'); final url = Uri.parse('${Env.apiUrl}staff/findStaff?id=$id');
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -543,7 +556,7 @@ class ApiService {
// ); // );
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -554,6 +567,8 @@ class ApiService {
String role, { String role, {
String? fromDate, String? fromDate,
String? toDate, String? toDate,
String? selectedStatus,
String? selectedStaffId,
}) async { }) async {
if (_token == null) { if (_token == null) {
await _initializeToken(); await _initializeToken();
@ -573,13 +588,16 @@ class ApiService {
query = 'agent_id=$id'; query = 'agent_id=$id';
} }
// final url = Uri.parse(
// '${Env.apiUrl}enquiry/enquiryList?$query&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}',
// );
final url = Uri.parse( final url = Uri.parse(
'${Env.apiUrl}enquiry/enquiryList?$query&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}', '${Env.apiUrl}enquiry/enquiryList?$query&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}&status=$selectedStatus&staff_id=$selectedStaffId',
); );
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
@ -588,6 +606,7 @@ class ApiService {
Future<Map<String, dynamic>> fetchAttndanceOFAllStaffList({ Future<Map<String, dynamic>> fetchAttndanceOFAllStaffList({
required String month, required String month,
required dynamic mangerId,
}) async { }) async {
if (_token == null) { if (_token == null) {
await _initializeToken(); await _initializeToken();
@ -600,12 +619,12 @@ class ApiService {
// } // }
final url = Uri.parse( final url = Uri.parse(
'${Env.apiUrl}staff/monthlyLoginCount?month=${month ?? ''}', '${Env.apiUrl}staff/monthlyLoginCount?month=${month ?? ''}&manager_id=$mangerId',
); );
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
@ -628,7 +647,7 @@ class ApiService {
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
@ -643,7 +662,7 @@ class ApiService {
final url = Uri.parse('${Env.apiUrl}enquiry/enquiryList?enquiry_id=$id'); final url = Uri.parse('${Env.apiUrl}enquiry/enquiryList?enquiry_id=$id');
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -661,7 +680,7 @@ class ApiService {
); );
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
print('findEnqQuotePolicyVie2w 3'); print('findEnqQuotePolicyVie2w 3');
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
@ -694,7 +713,7 @@ class ApiService {
); );
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -708,7 +727,7 @@ class ApiService {
final url = Uri.parse('${Env.apiUrl}quotation/findQuotation?id=$id'); final url = Uri.parse('${Env.apiUrl}quotation/findQuotation?id=$id');
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -721,17 +740,18 @@ class ApiService {
role, { role, {
String? fromDate, String? fromDate,
String? toDate, String? toDate,
String? selectedStatus,
String? selectedStaffId,
}) async { }) async {
// print(_token); // print(_token);
if (_token == null) { if (_token == null) {
await _initializeToken(); await _initializeToken();
} }
final userId = '1';
final url; final url;
final String query; final String query;
final String val = 'Proposal Created';
if (role == 'manager') { if (role == 'manager') {
query = 'manager_id=$id'; query = 'manager_id=$id';
} else if (role == 'staff') { } else if (role == 'staff') {
@ -740,8 +760,12 @@ class ApiService {
query = 'agent_id=$id'; query = 'agent_id=$id';
} }
// url = Uri.parse(
// '${Env.apiUrl}enquiry/enquiryList?$query&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}',
// );
url = Uri.parse( url = Uri.parse(
'${Env.apiUrl}enquiry/enquiryList?$query&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}', '${Env.apiUrl}enquiry/enquiryList?$query&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}&status=$selectedStatus&staff_id=$selectedStaffId',
); );
// if (role == 'manager') { // if (role == 'manager') {
@ -757,7 +781,7 @@ class ApiService {
// ); // );
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -768,6 +792,7 @@ class ApiService {
role, { role, {
String? fromDate, String? fromDate,
String? toDate, String? toDate,
String? selectedStaffId,
}) async { }) async {
// print(_token); // print(_token);
if (_token == null) { if (_token == null) {
@ -787,7 +812,7 @@ class ApiService {
} }
final url = Uri.parse( final url = Uri.parse(
'${Env.apiUrl}enquiry/enquiryList?$query&only_policy_data=true&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}', '${Env.apiUrl}enquiry/enquiryList?$query&only_policy_data=true&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}&staff_id=$selectedStaffId',
); );
// if (role == 'manager') { // if (role == 'manager') {
@ -809,7 +834,7 @@ class ApiService {
// ); // );
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -840,7 +865,7 @@ class ApiService {
// ); // );
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -855,7 +880,7 @@ class ApiService {
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -888,7 +913,7 @@ class ApiService {
// ); // );
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -905,7 +930,7 @@ class ApiService {
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -941,7 +966,7 @@ class ApiService {
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
return response; return response;
@ -961,7 +986,7 @@ class ApiService {
print('fetchHandlerNameDropDown 2'); print('fetchHandlerNameDropDown 2');
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
print('fetchHandlerNameDropDown 3'); print('fetchHandlerNameDropDown 3');
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
@ -985,7 +1010,7 @@ class ApiService {
print('fetchHandlerNameDropDown 2'); print('fetchHandlerNameDropDown 2');
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
print('fetchHandlerNameDropDown 3'); print('fetchHandlerNameDropDown 3');
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);
@ -1007,7 +1032,7 @@ class ApiService {
print('fetchAGENTNameDropDown 2'); print('fetchAGENTNameDropDown 2');
final headers = { final headers = {
'Authorization': 'Bearer $_token' ?? '', 'Authorization': 'Bearer $_token' ?? '',
'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}; };
print('fetchAGENTNameDropDown 3'); print('fetchAGENTNameDropDown 3');
final response = await _makeGetRequest(url, headers); final response = await _makeGetRequest(url, headers);

View File

@ -11,3 +11,7 @@ final staffIndiviualAttendanceIdProvider = StateProvider<String?>(
final staffIndiviualAttendanceNameIdProvider = StateProvider<String?>( final staffIndiviualAttendanceNameIdProvider = StateProvider<String?>(
(ref) => null, (ref) => null,
); );
final dashboardKeyProvider = StateProvider<int?>((ref) => null);
final dashboardStatusProvider = StateProvider<String?>((ref) => null);
final dashboardStaffIdProvider = StateProvider<String?>((ref) => null);

View File

@ -468,8 +468,7 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
// Use MultipartRequest (POST only) // Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri); final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $_token'; request.headers['Authorization'] = 'Bearer $_token';
request.headers['app-signature'] = request.headers['app-signature'] = Env.App_Signature;
'nhance-partner-2025-signature-35468846JRhH551HK';
// If updating, spoof the method Laravel-style // If updating, spoof the method Laravel-style
if (isUpdating) { if (isUpdating) {
@ -532,6 +531,8 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
} }
} }
setState(() => isSaving = false); setState(() => isSaving = false);
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else { } else {
print("❌ Submission failed. Status: ${response.statusCode}"); print("❌ Submission failed. Status: ${response.statusCode}");
print("Body: ${response.body}"); print("Body: ${response.body}");
@ -755,7 +756,7 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
Widget buildName(BuildContext context) { Widget buildName(BuildContext context) {
return buildResponsiveField( return buildResponsiveField(
label: "Full Name *", label: "Insured Name *",
field: ThemedFormField( field: ThemedFormField(
controller: controllers['name']!, controller: controllers['name']!,
@ -773,6 +774,9 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
field: ThemedFormField( field: ThemedFormField(
controller: controllers['email']!, controller: controllers['email']!,
validator: (value) => Validators.email(value, "email"), validator: (value) => Validators.email(value, "email"),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_@.]')),
],
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
: MediaQuery.of(context).size.width * 0.26, : MediaQuery.of(context).size.width * 0.26,
@ -786,6 +790,7 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
field: ThemedFormField( field: ThemedFormField(
controller: controllers['mobile']!, controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"), validator: (value) => Validators.phone(value, "phNumber"),
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'[ 0-9]'))],
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
: MediaQuery.of(context).size.width * 0.26, : MediaQuery.of(context).size.width * 0.26,
@ -795,7 +800,7 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
Widget buildId(BuildContext context) { Widget buildId(BuildContext context) {
return buildResponsiveField( return buildResponsiveField(
label: "Registration Number *", label: "Vehicle Number *",
field: ThemedFormField( field: ThemedFormField(
controller: controllers['regNo']!, controller: controllers['regNo']!,
inputFormatters: [ inputFormatters: [

View File

@ -216,55 +216,6 @@ class _AddDialogState extends State<AddDialog> {
} }
} }
Future<void> createUserData1(data, val) async {
// final bool isUpdating = widget.id != null && widget.id != 'create';
final String apiUrldata;
apiUrldata = (val == 'Claims')
? '${Env.apiUrl}claim/createClaim'
: '${Env.apiUrl}endorsement/createEndorsement';
// 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');
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");
}
}
Future<void> createUserData(data, val) async { Future<void> createUserData(data, val) async {
final Uri uri = (val == 'Claims') final Uri uri = (val == 'Claims')
? Uri.parse('${Env.apiUrl}claim/createClaim') ? Uri.parse('${Env.apiUrl}claim/createClaim')
@ -277,8 +228,7 @@ class _AddDialogState extends State<AddDialog> {
// Use MultipartRequest (POST only) // Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri); final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $_token'; request.headers['Authorization'] = 'Bearer $_token';
request.headers['app-signature'] = request.headers['app-signature'] = Env.App_Signature;
'nhance-partner-2025-signature-35468846JRhH551HK';
print("USerDAta - $data"); print("USerDAta - $data");
@ -360,6 +310,8 @@ class _AddDialogState extends State<AddDialog> {
Navigator.of(context).pop(); Navigator.of(context).pop();
widget.onSubmit("success"); widget.onSubmit("success");
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else { } else {
final responseBody = jsonDecode(response.body); final responseBody = jsonDecode(response.body);
dynamic msg = responseBody['data']; dynamic msg = responseBody['data'];

View File

@ -712,9 +712,10 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
Widget buildName(BuildContext context) { Widget buildName(BuildContext context) {
return buildResponsiveField( return buildResponsiveField(
label: "Registration Number", label: "Vehicle Number",
field: ThemedFormField( field: ThemedFormField(
controller: controllers['regNum']!, controller: controllers['regNum']!,
readOnly: true,
// validator: (value) => Validators.requiredField(value, "name"), // validator: (value) => Validators.requiredField(value, "name"),
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
@ -725,9 +726,10 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
Widget buildInsusrer(BuildContext context) { Widget buildInsusrer(BuildContext context) {
return buildResponsiveField( return buildResponsiveField(
label: "Insusrer", label: "Insurer",
field: ThemedFormField( field: ThemedFormField(
controller: controllers['insurer']!, controller: controllers['insurer']!,
readOnly: true,
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
: MediaQuery.of(context).size.width * 0.26, : MediaQuery.of(context).size.width * 0.26,
@ -740,7 +742,8 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
label: "IDV", label: "IDV",
field: ThemedFormField( field: ThemedFormField(
controller: controllers['idv']!, controller: controllers['idv']!,
validator: (value) => Validators.phone(value, "phNumber"), readOnly: true,
// validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
: MediaQuery.of(context).size.width * 0.26, : MediaQuery.of(context).size.width * 0.26,
@ -753,6 +756,7 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
label: "Insured Name", label: "Insured Name",
field: ThemedFormField( field: ThemedFormField(
controller: controllers['insurerName']!, controller: controllers['insurerName']!,
readOnly: true,
// validator: (value) => Validators.phone(value, "phNumber"), // validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
@ -766,6 +770,7 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
label: "Policy Number", label: "Policy Number",
field: ThemedFormField( field: ThemedFormField(
controller: controllers['policyNo']!, controller: controllers['policyNo']!,
readOnly: true,
// validator: (value) => Validators.phone(value, "phNumber"), // validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
@ -778,6 +783,7 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
return buildResponsiveField( return buildResponsiveField(
label: "Payment Mode", label: "Payment Mode",
field: ThemedFormField( field: ThemedFormField(
readOnly: true,
controller: controllers['paymentMode']!, controller: controllers['paymentMode']!,
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
@ -791,7 +797,8 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
label: "Plan Type", label: "Plan Type",
field: ThemedFormField( field: ThemedFormField(
controller: controllers['planType']!, controller: controllers['planType']!,
validator: (value) => Validators.phone(value, "phNumber"), readOnly: true,
// validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
: MediaQuery.of(context).size.width * 0.26, : MediaQuery.of(context).size.width * 0.26,
@ -804,7 +811,8 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
label: "Premium Amount", label: "Premium Amount",
field: ThemedFormField( field: ThemedFormField(
controller: controllers['premAmount']!, controller: controllers['premAmount']!,
validator: (value) => Validators.phone(value, "phNumber"), readOnly: true,
// validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
: MediaQuery.of(context).size.width * 0.26, : MediaQuery.of(context).size.width * 0.26,

View File

@ -4,6 +4,7 @@ import 'package:dropdown_search/dropdown_search.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart'; import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
@ -297,7 +298,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
headers: { headers: {
'Authorization': 'Bearer $_token', 'Authorization': 'Bearer $_token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}, },
body: jsonEncode(data), // Convert map to JSON body: jsonEncode(data), // Convert map to JSON
); );
@ -321,6 +322,8 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
// tabKey.currentState?.loadQuotationTab(widget.id ?? ""); // tabKey.currentState?.loadQuotationTab(widget.id ?? "");
// }); // });
// context.go(AppRoutes.staffLst); // context.go(AppRoutes.staffLst);
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else { } else {
final responseBody = jsonDecode(response.body); final responseBody = jsonDecode(response.body);
dynamic msg = responseBody['data']; dynamic msg = responseBody['data'];
@ -349,8 +352,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
// Use MultipartRequest (POST only) // Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri); final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $_token'; request.headers['Authorization'] = 'Bearer $_token';
request.headers['app-signature'] = request.headers['app-signature'] = Env.App_Signature;
'nhance-partner-2025-signature-35468846JRhH551HK';
print("USerDAta - $userData"); print("USerDAta - $userData");
@ -408,6 +410,8 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
await widget.onRefresh!(); await widget.onRefresh!();
} }
// context.go(AppRoutes.agentLst); // context.go(AppRoutes.agentLst);
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else { } else {
final responseBody = jsonDecode(response.body); final responseBody = jsonDecode(response.body);
dynamic msg = responseBody['data']; dynamic msg = responseBody['data'];
@ -643,7 +647,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
Widget buildName(BuildContext context) { Widget buildName(BuildContext context) {
return buildResponsiveField( return buildResponsiveField(
label: "Registration Number", label: "Vehicle Number",
field: ThemedFormField( field: ThemedFormField(
controller: controllers['regNum']!, controller: controllers['regNum']!,
readOnly: true, readOnly: true,
@ -657,7 +661,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
Widget buildInsusrer(BuildContext context) { Widget buildInsusrer(BuildContext context) {
return buildResponsiveField( return buildResponsiveField(
label: "Insusrer", label: "Insurer",
field: ThemedFormField( field: ThemedFormField(
controller: controllers['insurer']!, controller: controllers['insurer']!,
readOnly: true, readOnly: true,
@ -674,6 +678,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
field: ThemedFormField( field: ThemedFormField(
controller: controllers['idv']!, controller: controllers['idv']!,
readOnly: true, readOnly: true,
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
: MediaQuery.of(context).size.width * 0.26, : MediaQuery.of(context).size.width * 0.26,
@ -709,7 +714,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
Widget buildDocuments(BuildContext context) { Widget buildDocuments(BuildContext context) {
return buildResponsiveUploadField( return buildResponsiveUploadField(
label: 'Quotation Documents', label: 'Proposal Documents',
hintText: selectedFileNames, hintText: selectedFileNames,
onFileSelected: (fileName, file) { onFileSelected: (fileName, file) {
setState(() { setState(() {
@ -915,7 +920,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
Widget buildId(BuildContext context) { Widget buildId(BuildContext context) {
return buildResponsiveField( return buildResponsiveField(
label: "Registration Number *", label: "Vehicle Number *",
field: ThemedFormField( field: ThemedFormField(
controller: controllers['regNo']!, controller: controllers['regNo']!,
validator: (value) => Validators.requiredField(value, "regNo"), validator: (value) => Validators.requiredField(value, "regNo"),
@ -936,10 +941,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
child: const Row( child: const Row(
children: [ children: [
Expanded(flex: 1, child: Text(' ', style: _headerStyle)), Expanded(flex: 1, child: Text(' ', style: _headerStyle)),
Expanded( Expanded(flex: 1, child: Text('Vehicle Number', style: _headerStyle)),
flex: 1,
child: Text('Registration Number', style: _headerStyle),
),
Expanded(flex: 1, child: Text('Insurer', style: _headerStyle)), Expanded(flex: 1, child: Text('Insurer', style: _headerStyle)),
Expanded(flex: 1, child: Text('IDV', style: _headerStyle)), Expanded(flex: 1, child: Text('IDV', style: _headerStyle)),
Expanded(flex: 1, child: Text('Plan Type', style: _headerStyle)), Expanded(flex: 1, child: Text('Plan Type', style: _headerStyle)),

View File

@ -50,7 +50,7 @@ class TabEnquiryListState extends ConsumerState<TabEnquiryList> {
setState(() => isLoading = false); setState(() => isLoading = false);
tabs = [ tabs = [
TabItem("Enquiry", EnquiryTab()), TabItem("Enquiry", EnquiryTab()),
TabItem("Quotation", QuotationTab()), TabItem("Proposal", QuotationTab()),
TabItem("Policy", PolicyTab()), TabItem("Policy", PolicyTab()),
]; ];
} }
@ -86,7 +86,7 @@ class TabEnquiryListState extends ConsumerState<TabEnquiryList> {
EnquiryTab(data: enquiryData?["enquiry"], id: id ?? ""), EnquiryTab(data: enquiryData?["enquiry"], id: id ?? ""),
), ),
TabItem( TabItem(
"Quotation", "Proposal",
QuotationTab( QuotationTab(
data: data:
(enquiryData?["quotations"] as List<dynamic>?) (enquiryData?["quotations"] as List<dynamic>?)
@ -121,7 +121,7 @@ class TabEnquiryListState extends ConsumerState<TabEnquiryList> {
// ), // ),
), ),
// TabItem("Quotation", QuotationTab(data: enquiryData?["quotations"])), // TabItem("Proposal", QuotationTab(data: enquiryData?["quotations"])),
// TabItem("Policy", PolicyTab()), // TabItem("Policy", PolicyTab()),
]; ];
}); });
@ -141,7 +141,7 @@ class TabEnquiryListState extends ConsumerState<TabEnquiryList> {
EnquiryTab(data: enquiryData?["enquiry"], id: id ?? ""), EnquiryTab(data: enquiryData?["enquiry"], id: id ?? ""),
), ),
TabItem( TabItem(
"Quotation", "Proposal",
QuotationTab( QuotationTab(
data: data:
(enquiryData?["quotations"] as List<dynamic>?) (enquiryData?["quotations"] as List<dynamic>?)

View File

@ -32,6 +32,9 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
late ApiService apiService; late ApiService apiService;
dynamic roleId; dynamic roleId;
dynamic userId; dynamic userId;
dynamic SelectedStatus;
dynamic SelectedStaffId;
late final String? selectedStatusVal;
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
// List<Map<String, dynamic>> dataVal = []; // List<Map<String, dynamic>> dataVal = [];
@ -82,26 +85,27 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
} }
void filterDateRange() { void filterDateRange() {
// Validate the form first print('SelectedStatus - $SelectedStatus');
if (!_formKey.currentState!.validate()) { // // Validate the form first
// stop execution if validation fails // if (!_formKey.currentState!.validate()) {
return; // // stop execution if validation fails
} // return;
// }
//
// final fromDateText = controllers['startDate']?.text ?? '';
// final toDateText = controllers['endDate']?.text ?? '';
final fromDateText = controllers['startDate']?.text ?? ''; // // Optional: double-check End >= Start
final toDateText = controllers['endDate']?.text ?? ''; // final fromDate = DateFormat('dd-MM-yyyy').parse(fromDateText);
// final toDate = DateFormat('dd-MM-yyyy').parse(toDateText);
// Optional: double-check End >= Start //
final fromDate = DateFormat('dd-MM-yyyy').parse(fromDateText); // if (toDate.isBefore(fromDate)) {
final toDate = DateFormat('dd-MM-yyyy').parse(toDateText); // // This is already caught by the validator, but extra safety
// ScaffoldMessenger.of(context).showSnackBar(
if (toDate.isBefore(fromDate)) { // SnackBar(content: Text("End Date cannot be earlier than Start Date")),
// This is already caught by the validator, but extra safety // );
ScaffoldMessenger.of(context).showSnackBar( // return;
SnackBar(content: Text("End Date cannot be earlier than Start Date")), // }
);
return;
}
// Call your API // Call your API
getStaffList(userId, roleId); getStaffList(userId, roleId);
@ -109,6 +113,8 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
void refrshfilterDateRange() { void refrshfilterDateRange() {
setState(() { setState(() {
SelectedStatus = '';
SelectedStaffId = null;
controllers['startDate']!.clear(); controllers['startDate']!.clear();
controllers['endDate']!.clear(); controllers['endDate']!.clear();
@ -184,6 +190,8 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
role, role,
fromDate: controllers['startDate']?.text ?? '', fromDate: controllers['startDate']?.text ?? '',
toDate: controllers['endDate']?.text ?? '', toDate: controllers['endDate']?.text ?? '',
selectedStatus: SelectedStatus != null ? SelectedStatus : '',
selectedStaffId: SelectedStaffId ?? '',
); );
if (response['status'] == 'success') { if (response['status'] == 'success') {
@ -384,7 +392,7 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
), ),
const SizedBox(width: 5), // spacing between icon and text const SizedBox(width: 5), // spacing between icon and text
Text( Text(
"Enquiries", "Enquiries ",
style: GoogleFonts.inter( style: GoogleFonts.inter(
fontSize: ResponsiveLayout.isMobile(context) ? 14 : 18, fontSize: ResponsiveLayout.isMobile(context) ? 14 : 18,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -451,8 +459,20 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),
color: Color(0xffD9EBE8), color: Color(0xffD9EBE8),
child: DateFilterRow( child: DateFilterRow(
key: ValueKey(SelectedStatus ?? ''),
role: roleId,
id: userId,
onFilterStaff: (val) {
print('Selected Filterd STAFF Id - $val');
SelectedStaffId = val;
},
selectedStaffId: SelectedStaffId,
selectedStatusVal: SelectedStatus,
startController: controllers['startDate']!, startController: controllers['startDate']!,
endController: controllers['endDate']!, endController: controllers['endDate']!,
onStatusChanged: (val) {
SelectedStatus = val; // update parent
},
formKey: _formKey, formKey: _formKey,
isMobile: ResponsiveLayout.isMobile(context), isMobile: ResponsiveLayout.isMobile(context),
onFilter: () { onFilter: () {
@ -476,8 +496,21 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
children: [ children: [
if (!ResponsiveLayout.isMobile(context)) ...[ if (!ResponsiveLayout.isMobile(context)) ...[
DateFilterRow( DateFilterRow(
role: roleId,
id: userId,
key: ValueKey(SelectedStatus ?? ''),
onFilterStaff: (val) {
print('Selected Filterd STAFF Id - $val');
SelectedStaffId = val;
},
selectedStaffId: SelectedStaffId,
selectedStatusVal: SelectedStatus,
startController: controllers['startDate']!, startController: controllers['startDate']!,
endController: controllers['endDate']!, endController: controllers['endDate']!,
onStatusChanged: (val) {
SelectedStatus = val; // update parent
},
formKey: _formKey, formKey: _formKey,
isMobile: ResponsiveLayout.isMobile(context), isMobile: ResponsiveLayout.isMobile(context),
onFilter: () { onFilter: () {
@ -500,7 +533,7 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
controller: _searchStaffController, controller: _searchStaffController,
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? MediaQuery.of(context).size.width * 0.6 ? MediaQuery.of(context).size.width * 0.6
: MediaQuery.of(context).size.width * 0.2, : MediaQuery.of(context).size.width * 0.13,
), ),
ResponsiveLayout.isMobile(context) ResponsiveLayout.isMobile(context)
? Spacer() ? Spacer()

View File

@ -282,7 +282,13 @@ class ClaimsSubListState extends ConsumerState<ClaimsSubList> {
), ),
Expanded( Expanded(
flex: 2, flex: 2,
child: Text(item['claim_status_value'] ?? '-', style: _dataBold), child: Text(
item['claim_status_value'] != null
? '${item['claim_status_value'][0].toUpperCase()}${item['claim_status_value'].substring(1).toLowerCase()}'
: '-',
style: _dataBold,
),
// child: Text(item['claim_status_value'] ?? '-', style: _dataBold),
), ),
// Expanded( // Expanded(

View File

@ -144,6 +144,7 @@ class AttendanceAllDetailsState extends ConsumerState<AttendanceAllDetails> {
try { try {
final response = await apiService.fetchAttndanceOFAllStaffList( final response = await apiService.fetchAttndanceOFAllStaffList(
month: monthForApi, month: monthForApi,
mangerId: managerId,
// toDate: controllers['endDate']?.text ?? '', // toDate: controllers['endDate']?.text ?? '',
); );

View File

@ -441,7 +441,7 @@ class IndividualAttendanceDetailsState
Expanded(flex: 2, child: Text('Date', style: _headerStyle)), Expanded(flex: 2, child: Text('Date', style: _headerStyle)),
Expanded(flex: 2, child: Text('Login', style: _headerStyle)), Expanded(flex: 2, child: Text('Login', style: _headerStyle)),
Expanded(flex: 2, child: Text('Login Time', style: _headerStyle)), Expanded(flex: 2, child: Text('Logout', style: _headerStyle)),
Expanded( Expanded(
flex: 2, flex: 2,
child: Text('Number Of Hours', style: _headerStyle), child: Text('Number Of Hours', style: _headerStyle),

View File

@ -5,6 +5,7 @@ import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
@ -151,8 +152,7 @@ class AgentState extends ConsumerState<Agent> {
// Use MultipartRequest (POST only) // Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri); final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $_token'; request.headers['Authorization'] = 'Bearer $_token';
request.headers['app-signature'] = request.headers['app-signature'] = Env.App_Signature;
'nhance-partner-2025-signature-35468846JRhH551HK';
// If updating, spoof the method Laravel-style // If updating, spoof the method Laravel-style
if (isUpdating) { if (isUpdating) {
@ -248,6 +248,8 @@ class AgentState extends ConsumerState<Agent> {
'Partner Created Successfully', 'Partner Created Successfully',
); );
context.go(AppRoutes.agentLst); context.go(AppRoutes.agentLst);
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else { } else {
final responseBody = jsonDecode(response.body); final responseBody = jsonDecode(response.body);
dynamic msg = responseBody['data']; dynamic msg = responseBody['data'];
@ -491,6 +493,9 @@ class AgentState extends ConsumerState<Agent> {
ThemedFormField( ThemedFormField(
controller: controllers['email']!, controller: controllers['email']!,
validator: (value) => Validators.email(value, "email"), validator: (value) => Validators.email(value, "email"),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_@.]')),
],
txtwidth: MediaQuery.of(context).size.width * 0.26, txtwidth: MediaQuery.of(context).size.width * 0.26,
), ),
], ],
@ -506,6 +511,9 @@ class AgentState extends ConsumerState<Agent> {
ThemedFormField( ThemedFormField(
controller: controllers['mobile']!, controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"), validator: (value) => Validators.phone(value, "phNumber"),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[ 0-9]')),
],
txtwidth: MediaQuery.of(context).size.width * 0.26, txtwidth: MediaQuery.of(context).size.width * 0.26,
), ),
], ],

View File

@ -241,8 +241,7 @@ class UploadIncentiveModalState extends ConsumerState<UploadIncentiveModal> {
// Use MultipartRequest (POST only) // Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri); final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $_token'; request.headers['Authorization'] = 'Bearer $_token';
request.headers['app-signature'] = request.headers['app-signature'] = Env.App_Signature;
'nhance-partner-2025-signature-35468846JRhH551HK';
print("USerDAta - $dataSet"); print("USerDAta - $dataSet");
@ -337,6 +336,8 @@ class UploadIncentiveModalState extends ConsumerState<UploadIncentiveModal> {
} }
// context.go(AppRoutes.agentLst); // context.go(AppRoutes.agentLst);
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else { } else {
print("❌ Submission failed. Status: ${response.statusCode}"); print("❌ Submission failed. Status: ${response.statusCode}");
print("📨 Body: ${response.body}"); print("📨 Body: ${response.body}");

View File

@ -209,7 +209,10 @@ class ProfileState extends ConsumerState<Profile> {
), ),
Text( Text(
// profileData?['role'] ?? '-', // profileData?['role'] ?? '-',
role ?? '-', (role == 'agent')
? 'partner'
: role ?? '-',
// role ?? '-',
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
@ -248,7 +251,8 @@ class ProfileState extends ConsumerState<Profile> {
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
if (profileData?['role_id'] != '1' && if (profileData?['role_id'] != '1' &&
profileData?['role_id'] != '2') ...[ profileData?['role_id'] != '2' &&
profileData?['role_id'] != '3') ...[
Row( Row(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment.start,
@ -272,7 +276,7 @@ class ProfileState extends ConsumerState<Profile> {
const SizedBox(height: 20), const SizedBox(height: 20),
], ],
if (profileData?['role_id'] != 2) ...[ if (profileData?['role_id'] != 3) ...[
Container( Container(
padding: const EdgeInsets.all(6), padding: const EdgeInsets.all(6),
color: Color(0xffEDF6F5), color: Color(0xffEDF6F5),
@ -281,11 +285,12 @@ class ProfileState extends ConsumerState<Profile> {
print("Download - $latestId"); print("Download - $latestId");
dynamic path; dynamic path;
if (roleId == 1) { if (roleId == 1 &&
roleId == 2 &&
roleId == 3) {
path = path =
'api/agent/downloadManagerIncentiveFile?id=$latestId'; 'api/staff/downloadManagerIncentiveFile?id=$latestId';
} else if (roleId != 1 && } else {
roleId != 2) {
path = path =
'api/agent/downloadAgentIncentiveFile?id=$latestId'; 'api/agent/downloadAgentIncentiveFile?id=$latestId';
} }
@ -375,11 +380,12 @@ class ProfileState extends ConsumerState<Profile> {
dynamic path; dynamic path;
if (roleId == 1) { if (roleId == 1 &&
roleId == 2 &&
roleId == 3) {
path = path =
'api/agent/downloadManagerIncentiveFile?id=$selectedId'; 'api/staff/downloadManagerIncentiveFile?id=$selectedId';
} else if (roleId != 1 && } else {
roleId != 2) {
path = path =
'api/agent/downloadAgentIncentiveFile?id=$selectedId'; 'api/agent/downloadAgentIncentiveFile?id=$selectedId';
} }
@ -508,7 +514,8 @@ class ProfileState extends ConsumerState<Profile> {
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
if (profileData?['role_id'] != '1' && if (profileData?['role_id'] != '1' &&
profileData?['role_id'] != '2') ...[ profileData?['role_id'] != '2' &&
profileData?['role_id'] != '3') ...[
Row( Row(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment.start,
@ -532,7 +539,7 @@ class ProfileState extends ConsumerState<Profile> {
const SizedBox(height: 20), const SizedBox(height: 20),
], ],
if (profileData?['role_id'] != 2) ...[ if (profileData?['role_id'] != 3) ...[
Container( Container(
padding: const EdgeInsets.all(6), padding: const EdgeInsets.all(6),
color: Color(0xffEDF6F5), color: Color(0xffEDF6F5),
@ -541,11 +548,14 @@ class ProfileState extends ConsumerState<Profile> {
print("Download - $latestId"); print("Download - $latestId");
dynamic path; dynamic path;
if (roleId == 1) { if (roleId == 1 &&
roleId == 2 &&
roleId == 3) {
print('teRole - $roleId');
path = path =
'api/agent/downloadManagerIncentiveFile?id=$latestId'; 'api/staff/downloadManagerIncentiveFile?id=$latestId';
} else if (roleId != 1 && } else {
roleId != 2) {
path = path =
'api/agent/downloadAgentIncentiveFile?id=$latestId'; 'api/agent/downloadAgentIncentiveFile?id=$latestId';
} }
@ -635,11 +645,12 @@ class ProfileState extends ConsumerState<Profile> {
dynamic path; dynamic path;
if (roleId == 1) { if (roleId == 1 &&
roleId == 2 &&
roleId == 3) {
path = path =
'api/agent/downloadManagerIncentiveFile?id=$selectedId'; 'api/staff/downloadManagerIncentiveFile?id=$selectedId';
} else if (roleId != 1 && } else {
roleId != 2) {
path = path =
'api/agent/downloadAgentIncentiveFile?id=$selectedId'; 'api/agent/downloadAgentIncentiveFile?id=$selectedId';
} }

View File

@ -227,7 +227,7 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
style: _headerStyle, style: _headerStyle,
), ),
Text( Text(
role ?? '-', (role == 'agent') ? 'partner' : role ?? '-',
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
@ -300,7 +300,7 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
if (roleId == 1) { if (roleId == 1) {
path = path =
'api/agent/downloadManagerIncentiveFile?id=$latestId'; 'api/staff/downloadManagerIncentiveFile?id=$latestId';
} else if (roleId != 1 && roleId != 2) { } else if (roleId != 1 && roleId != 2) {
path = path =
'api/agent/downloadAgentIncentiveFile?id=$latestId'; 'api/agent/downloadAgentIncentiveFile?id=$latestId';
@ -383,7 +383,7 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
if (roleId == 1) { if (roleId == 1) {
path = path =
'api/agent/downloadManagerIncentiveFile?id=$selectedId'; 'api/staff/downloadManagerIncentiveFile?id=$selectedId';
} else if (roleId != 1 && roleId != 2) { } else if (roleId != 1 && roleId != 2) {
path = path =
'api/agent/downloadAgentIncentiveFile?id=$selectedId'; 'api/agent/downloadAgentIncentiveFile?id=$selectedId';

View File

@ -4,6 +4,7 @@ import 'dart:typed_data'; // Import for Uint8List
import 'package:dropdown_search/dropdown_search.dart'; import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
@ -183,7 +184,7 @@ class StaffState extends ConsumerState<Staff> {
headers: { headers: {
'Authorization': 'Bearer $_token', 'Authorization': 'Bearer $_token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}, },
body: jsonEncode(data), // Convert map to JSON body: jsonEncode(data), // Convert map to JSON
); );
@ -202,6 +203,8 @@ class StaffState extends ConsumerState<Staff> {
'Staff Created Successfully', 'Staff Created Successfully',
); );
context.go(AppRoutes.staffLst); context.go(AppRoutes.staffLst);
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else { } else {
final responseBody = jsonDecode(response.body); final responseBody = jsonDecode(response.body);
dynamic msg = responseBody['data']; dynamic msg = responseBody['data'];
@ -475,6 +478,9 @@ class StaffState extends ConsumerState<Staff> {
ThemedFormField( ThemedFormField(
controller: controllers['email']!, controller: controllers['email']!,
validator: (value) => Validators.email(value, "email"), validator: (value) => Validators.email(value, "email"),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_@.]')),
],
txtwidth: MediaQuery.of(context).size.width * 0.26, txtwidth: MediaQuery.of(context).size.width * 0.26,
), ),
], ],
@ -490,6 +496,9 @@ class StaffState extends ConsumerState<Staff> {
ThemedFormField( ThemedFormField(
controller: controllers['mobile']!, controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"), validator: (value) => Validators.phone(value, "phNumber"),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[ 0-9]')),
],
txtwidth: MediaQuery.of(context).size.width * 0.26, txtwidth: MediaQuery.of(context).size.width * 0.26,
), ),
], ],

View File

@ -1344,29 +1344,70 @@ class othersPendings extends StatelessWidget {
), ),
Expanded( Expanded(
flex: 2, flex: 2,
child: Text( child: InkWell(
row['awaiting_quotation'] ?? "", onTap: () {
// row['total_approval_pending'] ?? "", print(
textAlign: TextAlign.center, 'Awaiting Proposal : ${row['awaiting_quotation']}',
style: _tableDataStyle, );
handleDashboardNavigation(
context,
status: "Awaiting Proposal",
staffId: row['staff_id'],
role: role,
);
},
child: Text(
row['awaiting_quotation'] ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
), ),
), ),
Expanded( Expanded(
flex: 2, flex: 2,
child: Text( child: InkWell(
row['pending_quotation_approval'] ?? "", onTap: () async {
// row['total_approval_pending'] ?? "", print(
textAlign: TextAlign.center, 'Awaiting Approval : ${row['pending_quotation_approval']} - ${row['staff_id']}',
style: _tableDataStyle, );
handleDashboardNavigation(
context,
status: "Proposal Created",
staffId: row['staff_id'],
role: role,
);
},
child: Text(
row['pending_quotation_approval'] ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
), ),
), ),
Expanded( Expanded(
flex: 2, flex: 2,
child: Text( child: InkWell(
row['awaiting_policy'] ?? "", onTap: () {
// row['total_approval_pending'] ?? "", print(
textAlign: TextAlign.center, 'Awaiting Policy : ${row['awaiting_policy']}',
style: _tableDataStyle, );
handleDashboardNavigation(
context,
status: "Proposal Accepted",
staffId: row['staff_id'],
role: role,
);
},
child: Text(
row['awaiting_policy'] ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
), ),
), ),
// Expanded( // Expanded(
@ -1884,6 +1925,34 @@ class UnassignedEnq extends StatelessWidget {
} }
} }
Future<void> handleDashboardNavigation(
BuildContext context, {
required String status,
required String staffId,
required String role,
}) async {
print('Dashboard Tap => Status: $status | Staff: $staffId');
final prefs = await SharedPreferences.getInstance();
// Clear any old data
await prefs.remove('dashboardKeyProvider');
await prefs.remove('dashboardStatusProvider');
await prefs.remove('dashboardStaffIdProvider');
// Save new values
await prefs.setString('dashboardKeyProvider', 'fromDashboard');
await prefs.setString('dashboardStatusProvider', status);
await prefs.setString('dashboardStaffIdProvider', staffId);
// Navigate
if (role == 'manager') {
context.go(AppRoutes.enquiryForStaff);
} else {
context.go(AppRoutes.enquiryHandlerLst);
}
}
final _headerStyle = GoogleFonts.inter( final _headerStyle = GoogleFonts.inter(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
fontSize: 14, fontSize: 14,

View File

@ -39,6 +39,9 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
late ApiService apiService; late ApiService apiService;
dynamic userId; dynamic userId;
dynamic managerId; dynamic managerId;
dynamic dashboardKey;
dynamic SelectedStatus;
dynamic SelectedStaffId;
dynamic handlerId; dynamic handlerId;
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
@ -62,16 +65,44 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
controllers[field] = TextEditingController(); controllers[field] = TextEditingController();
} }
Future.microtask(() { Future.microtask(() async {
final id = ref.read(managerIdProvider); final id = ref.read(managerIdProvider);
roleId = ref.read(userRoleProvider); roleId = ref.read(userRoleProvider);
userId = ref.read(userIdProvider); userId = ref.read(userIdProvider);
managerId = ref.read(managerIdProvider); managerId = ref.read(managerIdProvider);
// dashboardKey = ref.read(dashboardKeyProvider);
// final dashboardStatus = ref.read(dashboardStatusProvider);
// final dashboardStaffId = ref.read(dashboardStaffIdProvider);
final prefs = await SharedPreferences.getInstance();
dashboardKey = prefs.getString('dashboardKeyProvider');
final dashboardStatus = prefs.getString('dashboardStatusProvider');
final dashboardStaffId = prefs.getString('dashboardStaffIdProvider');
// handlerId = ref.read(handlerIdProvider); // handlerId = ref.read(handlerIdProvider);
print('handlerIdENQ - $handlerId'); print('handlerIdENQ - $handlerId');
print("C72 => r : $roleId | mId: $id | uId: $userId !mID : $managerId "); print("C72 => r : $roleId | mId: $id | uId: $userId !mID : $managerId ");
if (managerId != null) {
print('dashboardKey - $dashboardKey');
print('dashboardStatus - $dashboardStatus');
print('dashboardStaffId - $dashboardStaffId');
if (managerId != null &&
dashboardKey != null &&
dashboardKey == 'fromDashboard' &&
dashboardStatus != null &&
dashboardStaffId != null) {
print("DASHBOARD STATus-$dashboardStatus -- $dashboardStaffId -");
SelectedStatus = dashboardStatus;
SelectedStaffId = dashboardStaffId;
getStaffList(
managerId,
roleId,
SelectedStatus: dashboardStatus,
SelectedStaffId: dashboardStaffId,
);
} else {
print('ELSE');
getStaffList(managerId, roleId); getStaffList(managerId, roleId);
} }
}); });
@ -89,26 +120,27 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
} }
void filterDateRange() { void filterDateRange() {
// Validate the form first // print('SelectedStatus - $SelectedStatus');
if (!_formKey.currentState!.validate()) { // // Validate the form first
// stop execution if validation fails // if (!_formKey.currentState!.validate()) {
return; // // stop execution if validation fails
} // return;
// }
final fromDateText = controllers['startDate']?.text ?? ''; //
final toDateText = controllers['endDate']?.text ?? ''; // final fromDateText = controllers['startDate']?.text ?? '';
// final toDateText = controllers['endDate']?.text ?? '';
// Optional: double-check End >= Start //
final fromDate = DateFormat('dd-MM-yyyy').parse(fromDateText); // // Optional: double-check End >= Start
final toDate = DateFormat('dd-MM-yyyy').parse(toDateText); // final fromDate = DateFormat('dd-MM-yyyy').parse(fromDateText);
// final toDate = DateFormat('dd-MM-yyyy').parse(toDateText);
if (toDate.isBefore(fromDate)) { //
// This is already caught by the validator, but extra safety // if (toDate.isBefore(fromDate)) {
ScaffoldMessenger.of(context).showSnackBar( // // This is already caught by the validator, but extra safety
SnackBar(content: Text("End Date cannot be earlier than Start Date")), // ScaffoldMessenger.of(context).showSnackBar(
); // SnackBar(content: Text("End Date cannot be earlier than Start Date")),
return; // );
} // return;
// }
// Call your API // Call your API
getStaffList(managerId, roleId); getStaffList(managerId, roleId);
@ -116,6 +148,8 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
void refrshfilterDateRange() { void refrshfilterDateRange() {
setState(() { setState(() {
SelectedStatus = '';
SelectedStaffId = null;
controllers['startDate']!.clear(); controllers['startDate']!.clear();
controllers['endDate']!.clear(); controllers['endDate']!.clear();
@ -132,6 +166,8 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
role, { role, {
String fromDate = '', String fromDate = '',
String toDate = '', String toDate = '',
String SelectedStatus = '',
String SelectedStaffId = '',
}) async { }) async {
print('A72 => Fns called => $managerId | $role'); print('A72 => Fns called => $managerId | $role');
setState(() { setState(() {
@ -144,6 +180,8 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
role, role,
fromDate: controllers['startDate']?.text ?? '', fromDate: controllers['startDate']?.text ?? '',
toDate: controllers['endDate']?.text ?? '', toDate: controllers['endDate']?.text ?? '',
selectedStatus: SelectedStatus != null ? SelectedStatus : '',
selectedStaffId: SelectedStaffId ?? '',
); );
if (response['status'] == 'success') { if (response['status'] == 'success') {
@ -516,13 +554,17 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
Tooltip( Tooltip(
message: 'Back', message: 'Back',
child: IconButton( child: IconButton(
icon: const Icon(Icons.arrow_left_sharp), icon: const Icon(Icons.arrow_left_sharp, size: 25),
onPressed: () { onPressed: () async {
context.go(AppRoutes.dashboard); context.go(AppRoutes.dashboard);
final prefs = await SharedPreferences.getInstance();
await prefs.remove('dashboardKeyProvider');
await prefs.remove('dashboardStatusProvider');
await prefs.remove('dashboardStaffIdProvider');
}, },
splashRadius: 28, splashRadius: 18,
padding: const EdgeInsets.all(4),
hoverColor: Colors.black12, hoverColor: Colors.black12,
padding: const EdgeInsets.all(8),
constraints: const BoxConstraints(), constraints: const BoxConstraints(),
), ),
), ),
@ -538,7 +580,7 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
), ),
), ),
), ),
SizedBox(height: 10), SizedBox(height: 5),
ResponsiveLayout.isMobile(context) ResponsiveLayout.isMobile(context)
? Container( ? Container(
height: MediaQuery.of(context).size.height * 0.69, height: MediaQuery.of(context).size.height * 0.69,
@ -604,10 +646,23 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),
color: Color(0xffD9EBE8), color: Color(0xffD9EBE8),
child: DateFilterRow( child: DateFilterRow(
key: ValueKey(SelectedStatus ?? ''),
onFilterStaff: (val) {
print('Selected Filterd STAFF Id - $val');
SelectedStaffId = val;
},
selectedStaffId: SelectedStaffId,
role: roleId,
id: userId,
selectedStatusVal: SelectedStatus,
startController: controllers['startDate']!, startController: controllers['startDate']!,
endController: controllers['endDate']!, endController: controllers['endDate']!,
formKey: _formKey, formKey: _formKey,
isMobile: ResponsiveLayout.isMobile(context), isMobile: ResponsiveLayout.isMobile(context),
onStatusChanged: (val) {
SelectedStatus = val; // update parent
},
onFilter: () { onFilter: () {
// call your filter logic // call your filter logic
filterDateRange(); filterDateRange();
@ -624,13 +679,25 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
// height: 40, // height: 40,
// color: Colors.pink, // color: Colors.pink,
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
if (!ResponsiveLayout.isMobile(context)) ...[ if (!ResponsiveLayout.isMobile(context)) ...[
DateFilterRow( DateFilterRow(
key: ValueKey(SelectedStatus ?? ''),
role: roleId,
id: userId,
selectedStatusVal: SelectedStatus,
onFilterStaff: (val) {
print('Selected Filterd STAFF Id - $val');
SelectedStaffId = val;
},
selectedStaffId: SelectedStaffId,
startController: controllers['startDate']!, startController: controllers['startDate']!,
endController: controllers['endDate']!, endController: controllers['endDate']!,
onStatusChanged: (val) {
SelectedStatus = val; // update parent
},
formKey: _formKey, formKey: _formKey,
isMobile: ResponsiveLayout.isMobile(context), isMobile: ResponsiveLayout.isMobile(context),
onFilter: () { onFilter: () {
@ -653,7 +720,7 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
controller: _searchStaffController, controller: _searchStaffController,
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? MediaQuery.of(context).size.width * 0.7 ? MediaQuery.of(context).size.width * 0.7
: MediaQuery.of(context).size.width * 0.2, : MediaQuery.of(context).size.width * 0.13,
), ),
ResponsiveLayout.isMobile(context) ResponsiveLayout.isMobile(context)

View File

@ -250,7 +250,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
body: json.encode(payload), body: json.encode(payload),
headers: { headers: {
HttpHeaders.contentTypeHeader: 'application/json', HttpHeaders.contentTypeHeader: 'application/json',
'App-Signature': Env.App_Signature, 'app-signature': Env.App_Signature,
}, },
); );
@ -311,7 +311,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
body: json.encode(payload), body: json.encode(payload),
headers: { headers: {
HttpHeaders.contentTypeHeader: 'application/json', HttpHeaders.contentTypeHeader: 'application/json',
'App-Signature': Env.App_Signature, 'app-signature': Env.App_Signature,
}, },
); );
@ -939,6 +939,11 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
Validators.email(value, "Email"), Validators.email(value, "Email"),
// imgPath: "MiscIconAssetPath.person", // imgPath: "MiscIconAssetPath.person",
controller: _emailController, controller: _emailController,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9_@.]'),
),
],
), ),
if (switcherStatus == 1) if (switcherStatus == 1)
ThemedFormField( ThemedFormField(
@ -948,6 +953,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
Validators.phone(value, "Phone"), Validators.phone(value, "Phone"),
// imgPath: "MiscIconAssetPath.person", // imgPath: "MiscIconAssetPath.person",
controller: _PhoneNumberController, controller: _PhoneNumberController,
// txtwidth: MediaQuery.of(context).size.width * 0.5, // txtwidth: MediaQuery.of(context).size.width * 0.5,
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
maxLength: 10, maxLength: 10,

View File

@ -54,6 +54,8 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
late ApiService apiService; late ApiService apiService;
dynamic userId; dynamic userId;
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
dynamic SelectedStatus;
dynamic SelectedStaffId;
// List<Map<String, dynamic>> dataVal = []; // List<Map<String, dynamic>> dataVal = [];
List<Map<String, dynamic>> getStaffData = []; List<Map<String, dynamic>> getStaffData = [];
@ -99,33 +101,64 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
} }
void filterDateRange() { void filterDateRange() {
print('SelectedStatus - $SelectedStatus');
print('SelectedStaffId - $SelectedStaffId');
// Validate the form first // Validate the form first
if (!_formKey.currentState!.validate()) { // if (!_formKey.currentState!.validate()) {
// stop execution if validation fails // // stop execution if validation fails
return; // return;
} // }
final fromDateText = controllers['startDate']?.text ?? ''; // final fromDateText = controllers['startDate']?.text ?? '';
final toDateText = controllers['endDate']?.text ?? ''; // final toDateText = controllers['endDate']?.text ?? '';
//
// print("fromDateText - $fromDateText");
// print("toDateText - $toDateText");
// Optional: double-check End >= Start // Optional: double-check End >= Start
final fromDate = DateFormat('dd-MM-yyyy').parse(fromDateText); // final fromDate = DateFormat('dd-MM-yyyy').parse(fromDateText);
final toDate = DateFormat('dd-MM-yyyy').parse(toDateText); // final toDate = DateFormat('dd-MM-yyyy').parse(toDateText);
//
if (toDate.isBefore(fromDate)) { // if (toDate.isBefore(fromDate)) {
// This is already caught by the validator, but extra safety // // This is already caught by the validator, but extra safety
ScaffoldMessenger.of(context).showSnackBar( // ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("End Date cannot be earlier than Start Date")), // SnackBar(content: Text("End Date cannot be earlier than Start Date")),
); // );
return; // return;
} // }
// DateTime? fromDate;
// DateTime? toDate;
//
// // Only parse if the date text is not empty
// if (fromDateText.isNotEmpty) {
// fromDate = DateFormat('dd-MM-yyyy').parse(fromDateText);
// }
// if (toDateText.isNotEmpty) {
// toDate = DateFormat('dd-MM-yyyy').parse(toDateText);
// }
//
// // Check if both dates are given before comparing
// if (fromDate != null && toDate != null && toDate.isBefore(fromDate)) {
// ScaffoldMessenger.of(context).showSnackBar(
// const SnackBar(
// content: Text("End Date cannot be earlier than Start Date"),
// ),
// );
// return;
// }
// Call your API // Call your API
getStaffList(userId, roleId); getStaffList(userId, roleId);
} }
void refrshfilterDateRange() { void refrshfilterDateRange() {
print('refrshfilterDateRange--1');
setState(() { setState(() {
SelectedStatus = '';
SelectedStaffId = null;
print('refrshselectedStaff - $SelectedStaffId');
print('refrshfilterDateRange--1 - $SelectedStatus');
controllers['startDate']!.clear(); controllers['startDate']!.clear();
controllers['endDate']!.clear(); controllers['endDate']!.clear();
@ -154,6 +187,8 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
role, role,
fromDate: controllers['startDate']?.text ?? '', fromDate: controllers['startDate']?.text ?? '',
toDate: controllers['endDate']?.text ?? '', toDate: controllers['endDate']?.text ?? '',
selectedStatus: SelectedStatus ?? '',
selectedStaffId: SelectedStaffId ?? '',
); );
print('FromDate : $fromDate'); print('FromDate : $fromDate');
@ -169,8 +204,9 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
print('ToDate : $toDate'); print('ToDate : $toDate');
setState(() { setState(() {
controllers['startDate']?.text = fromDate; controllers['startDate']?.text = fromDate;
print('1');
controllers['endDate']?.text = toDate; controllers['endDate']?.text = toDate;
print('2');
if (data is List) { if (data is List) {
// Already a list of maps // Already a list of maps
getStaffData = List<Map<String, dynamic>>.from(data); getStaffData = List<Map<String, dynamic>>.from(data);
@ -180,9 +216,12 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
} else { } else {
getStaffData = []; getStaffData = [];
} }
print('3');
// getStaffData = List<Map<String, dynamic>>.from(response['data']); // getStaffData = List<Map<String, dynamic>>.from(response['data']);
originalData = getStaffData; originalData = getStaffData;
print('4');
filteredData = List.from(originalData); filteredData = List.from(originalData);
print('5');
// print('originalData - $getClaimPolicies'); // print('originalData - $getClaimPolicies');
}); });
} else { } else {
@ -351,97 +390,97 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
// ), // ),
// ), // ),
// ], // ],
Material( // Material(
color: Colors.transparent, // color: Colors.transparent,
child: InkWell( // child: InkWell(
onTap: () async { // onTap: () async {
Navigator.pop(context); // Navigator.pop(context);
final prefs = await SharedPreferences.getInstance(); // final prefs = await SharedPreferences.getInstance();
//
// Remove old value (if any) // // Remove old value (if any)
await prefs.remove('enqStaffDataId'); // await prefs.remove('enqStaffDataId');
//
// Save the new id // // Save the new id
await prefs.setString('enqStaffDataId', id.toString()); // await prefs.setString('enqStaffDataId', id.toString());
//
// Read it back if needed // // Read it back if needed
// final dynamic? enqStaffDataId = prefs.getString('enqStaffDataId'); // // final dynamic? enqStaffDataId = prefs.getString('enqStaffDataId');
//
// Update provider too // // Update provider too
// ref.read(quotationStaffIdProvider.notifier).state = enqStaffDataId; // // ref.read(quotationStaffIdProvider.notifier).state = enqStaffDataId;
ref.read(quotationStaffIdProvider.notifier).state = id; // ref.read(quotationStaffIdProvider.notifier).state = id;
//
context.go(AppRoutes.quotation); // context.go(AppRoutes.quotation);
}, // },
hoverColor: Color(0xFFE3F1F0), // hoverColor: Color(0xFFE3F1F0),
splashColor: Color(0xFFE3F1F0), // splashColor: Color(0xFFE3F1F0),
borderRadius: BorderRadius.circular(6), // borderRadius: BorderRadius.circular(6),
child: Padding( // child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), // padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
child: Row( // child: Row(
// mainAxisSize: MainAxisSize.min, // // mainAxisSize: MainAxisSize.min,
children: [ // children: [
Image.asset( // Image.asset(
"assets/miscellaneous/image_1.png", // "assets/miscellaneous/image_1.png",
height: 15, // height: 15,
width: 15, // width: 15,
), // ),
//
const SizedBox(width: 10), // const SizedBox(width: 10),
((data['status'] == 'Policy Created') || // ((data['status'] == 'Policy Created') ||
(data['status'] == 'Quotation Accepted')) // (data['status'] == 'Quotation Accepted'))
? const Text('View Quotation') // ? const Text('View Quotation')
: const Text('Create Quotation'), // : const Text('Create Quotation'),
], // ],
), // ),
), // ),
), // ),
), // ),
//
if (data['status'] == 'Quotation Accepted' || // if (data['status'] == 'Quotation Accepted' ||
data['status'] == 'Policy Created') // data['status'] == 'Policy Created')
Material( // Material(
color: Colors.transparent, // color: Colors.transparent,
child: InkWell( // child: InkWell(
onTap: () async { // onTap: () async {
Navigator.pop(context); // Navigator.pop(context);
//
final prefs = await SharedPreferences.getInstance(); // final prefs = await SharedPreferences.getInstance();
//
// Remove old value (if any) // // Remove old value (if any)
await prefs.remove('enqStaffDataId'); // await prefs.remove('enqStaffDataId');
//
// Save the new id // // Save the new id
await prefs.setString('enqStaffDataId', id.toString()); // await prefs.setString('enqStaffDataId', id.toString());
//
// Update provider too // // Update provider too
//
ref.read(quotationStaffIdProvider.notifier).state = id; // ref.read(quotationStaffIdProvider.notifier).state = id;
context.go(AppRoutes.policy); // context.go(AppRoutes.policy);
}, // },
hoverColor: Color(0xFFE3F1F0), // hoverColor: Color(0xFFE3F1F0),
splashColor: Color(0xFFE3F1F0), // splashColor: Color(0xFFE3F1F0),
borderRadius: BorderRadius.circular(6), // borderRadius: BorderRadius.circular(6),
child: Padding( // child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), // padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
child: Row( // child: Row(
// mainAxisSize: MainAxisSize.min, // // mainAxisSize: MainAxisSize.min,
children: [ // children: [
Image.asset( // Image.asset(
"assets/miscellaneous/image_2.png", // "assets/miscellaneous/image_2.png",
height: 15, // height: 15,
width: 15, // width: 15,
), // ),
//
const SizedBox(width: 10), // const SizedBox(width: 10),
data['status'] == 'Policy Created' // data['status'] == 'Policy Created'
? Text('View Policy') // ? Text('View Policy')
: Text('Create Policy'), // : Text('Create Policy'),
], // ],
), // ),
), // ),
), // ),
), // ),
]; ];
} }
@ -491,13 +530,13 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
Tooltip( Tooltip(
message: 'Back', message: 'Back',
child: IconButton( child: IconButton(
icon: const Icon(Icons.arrow_left_sharp), icon: const Icon(Icons.arrow_left_sharp, size: 25),
onPressed: () { onPressed: () {
context.go(AppRoutes.dashboard); context.go(AppRoutes.dashboard);
}, },
splashRadius: 28, splashRadius: 18,
hoverColor: Colors.black12, hoverColor: Colors.black12,
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(4),
constraints: const BoxConstraints(), constraints: const BoxConstraints(),
), ),
), ),
@ -579,8 +618,21 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),
color: Color(0xffD9EBE8), color: Color(0xffD9EBE8),
child: DateFilterRow( child: DateFilterRow(
key: ValueKey((SelectedStatus ?? '') || (SelectedStaffId ?? '')),
onFilterStaff: (val) {
print('Selected Filterd STAFF Id - $val');
SelectedStaffId = val;
},
selectedStaffId: SelectedStaffId,
role: roleId,
id: userId,
selectedStatusVal: SelectedStatus,
startController: controllers['startDate']!, startController: controllers['startDate']!,
endController: controllers['endDate']!, endController: controllers['endDate']!,
onStatusChanged: (val) {
SelectedStatus = val; // update parent
},
formKey: _formKey, formKey: _formKey,
isMobile: ResponsiveLayout.isMobile(context), isMobile: ResponsiveLayout.isMobile(context),
onFilter: () { onFilter: () {
@ -599,15 +651,27 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
// height: 40, // height: 40,
// color: Colors.pink, // color: Colors.pink,
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
if (!ResponsiveLayout.isMobile(context)) ...[ if (!ResponsiveLayout.isMobile(context)) ...[
DateFilterRow( DateFilterRow(
key: ValueKey(SelectedStatus ?? ''),
role: roleId,
id: userId,
onFilterStaff: (val) {
print('Selected Filterd STAFF Id - $val');
SelectedStaffId = val;
},
selectedStaffId: SelectedStaffId,
selectedStatusVal: SelectedStatus,
startController: controllers['startDate']!, startController: controllers['startDate']!,
endController: controllers['endDate']!, endController: controllers['endDate']!,
formKey: _formKey, formKey: _formKey,
isMobile: ResponsiveLayout.isMobile(context), isMobile: ResponsiveLayout.isMobile(context),
onStatusChanged: (val) {
SelectedStatus = val; // update parent
},
onFilter: () { onFilter: () {
// call your filter logic // call your filter logic
filterDateRange(); filterDateRange();
@ -693,7 +757,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
], ],
), ),
), ),
// SizedBox(height: 10), SizedBox(height: 8),
if (!ResponsiveLayout.isMobile(context)) if (!ResponsiveLayout.isMobile(context))
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@ -859,7 +923,19 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
color: Colors.white, color: Colors.white,
); );
}, },
child: Text(item['reg_no'] ?? '-', style: _dataBold), child: Tooltip(
message:
'Click and Download Enquiry Files', // what appears on hover/long press
waitDuration: const Duration(milliseconds: 500), // optional
showDuration: const Duration(seconds: 2), // optional
child: Text(
item['reg_no'] ?? '-',
style: _dataBold,
overflow: TextOverflow
.ellipsis, // optional, if text might overflow
),
),
// child: Text(item['reg_no'] ?? '-', style: _dataBold),
), ),
), ),
), ),
@ -901,7 +977,17 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
ref.read(quotationStaffIdProvider.notifier).state = enqId; ref.read(quotationStaffIdProvider.notifier).state = enqId;
buildStatusActions(context, status, enqId); buildStatusActions(context, status, enqId);
}, },
child: Text(item['status'] ?? '-', style: _dataBold), child: Tooltip(
message: 'Click to View or Process Enquiry', //
waitDuration: const Duration(milliseconds: 500), // optional
showDuration: const Duration(seconds: 2), // optional
child: Text(
item['status'] ?? '-',
style: _dataBold,
overflow: TextOverflow.ellipsis, //
),
),
// child: Text(item['status'] ?? '-', style: _dataBold),
), ),
), ),
], ],

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@ import 'package:dropdown_search/dropdown_search.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
@ -130,6 +131,7 @@ class CreateQuotationFormState extends ConsumerState<CreateQuotationForm> {
} }
void reset() { void reset() {
print('RESET');
_formKey.currentState?.reset(); _formKey.currentState?.reset();
// Clear all TextEditingControllers // Clear all TextEditingControllers
for (var controller in controllers.values) { for (var controller in controllers.values) {
@ -303,8 +305,7 @@ class CreateQuotationFormState extends ConsumerState<CreateQuotationForm> {
// Use MultipartRequest (POST only) // Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri); final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $_token'; request.headers['Authorization'] = 'Bearer $_token';
request.headers['app-signature'] = request.headers['app-signature'] = Env.App_Signature;
'nhance-partner-2025-signature-35468846JRhH551HK';
// If updating, spoof the method Laravel-style // If updating, spoof the method Laravel-style
if (isUpdating) { if (isUpdating) {
@ -370,6 +371,8 @@ class CreateQuotationFormState extends ConsumerState<CreateQuotationForm> {
widget.onSubmit('Success'); widget.onSubmit('Success');
reset(); reset();
// Navigator.of(context).pop(); // Navigator.of(context).pop();
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else { } else {
final responseBody = jsonDecode(response.body); final responseBody = jsonDecode(response.body);
dynamic msg = responseBody['data']; dynamic msg = responseBody['data'];
@ -479,6 +482,9 @@ class CreateQuotationFormState extends ConsumerState<CreateQuotationForm> {
SizedBox(height: 10), SizedBox(height: 10),
ThemedFormField( ThemedFormField(
controller: controllers['idv']!, controller: controllers['idv']!,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')),
],
validator: (value) => Validators.doubleNumber(value, "IDV"), validator: (value) => Validators.doubleNumber(value, "IDV"),
// validator: (value) => Validators.number(value, "IDV"), // validator: (value) => Validators.number(value, "IDV"),
backgroundColor: Color(0xFFEDF6F5), backgroundColor: Color(0xFFEDF6F5),
@ -591,6 +597,9 @@ class CreateQuotationFormState extends ConsumerState<CreateQuotationForm> {
ThemedFormField( ThemedFormField(
controller: controllers['premium_Amount']!, controller: controllers['premium_Amount']!,
backgroundColor: Color(0xFFEDF6F5), backgroundColor: Color(0xFFEDF6F5),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')),
],
validator: (value) => Validators.doubleNumber(value, "PremiumAmount"), validator: (value) => Validators.doubleNumber(value, "PremiumAmount"),
// validator: (value) => Validators.number(value, "PremiumAmount "), // validator: (value) => Validators.number(value, "PremiumAmount "),
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)

View File

@ -428,8 +428,7 @@ class PolicyStaffTabState extends ConsumerState<PolicyStaffTab> {
// Use MultipartRequest (POST only) // Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri); final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $_token'; request.headers['Authorization'] = 'Bearer $_token';
request.headers['app-signature'] = request.headers['app-signature'] = Env.App_Signature;
'nhance-partner-2025-signature-35468846JRhH551HK';
// If updating, spoof the method Laravel-style // If updating, spoof the method Laravel-style
if (isUpdating) { if (isUpdating) {
@ -482,6 +481,8 @@ class PolicyStaffTabState extends ConsumerState<PolicyStaffTab> {
ref.read(enquiryIdProvider.notifier).state = null; ref.read(enquiryIdProvider.notifier).state = null;
context.go(AppRoutes.enquiryForStaff); context.go(AppRoutes.enquiryForStaff);
} }
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else { } else {
print("❌ Submission failed. Status: ${response.statusCode}"); print("❌ Submission failed. Status: ${response.statusCode}");
print("Body: ${response.body}"); print("Body: ${response.body}");
@ -879,7 +880,7 @@ class PolicyStaffTabState extends ConsumerState<PolicyStaffTab> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('Registration Number*', style: _textStyle), Text('Vehicle Number*', style: _textStyle),
SizedBox(height: 10), SizedBox(height: 10),
ThemedFormField( ThemedFormField(
controller: controllers['regNum']!, controller: controllers['regNum']!,

View File

@ -176,6 +176,11 @@ class QuotationStaffTabState extends ConsumerState<QuotationStaffTab> {
void refresh() { void refresh() {
print("refresh--"); print("refresh--");
setState(() {
selectedQuotationFrmListId = null;
selectedQuotationFrmListData = null;
});
if (enqQuotation != null) { if (enqQuotation != null) {
_loadData(enqQuotation); _loadData(enqQuotation);
} }
@ -307,7 +312,7 @@ class QuotationStaffTabState extends ConsumerState<QuotationStaffTab> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('Registration Number', style: _textStyle), Text('Vehicle Number', style: _textStyle),
SizedBox(height: 10), SizedBox(height: 10),
ThemedFormField( ThemedFormField(
controller: controllers['regNum']!, controller: controllers['regNum']!,
@ -364,7 +369,7 @@ class QuotationStaffTabState extends ConsumerState<QuotationStaffTab> {
Widget buildId(BuildContext context) { Widget buildId(BuildContext context) {
return buildResponsiveField( return buildResponsiveField(
label: "Registration Number *", label: "Vehicle Number *",
field: ThemedFormField( field: ThemedFormField(
controller: controllers['regNo']!, controller: controllers['regNo']!,
validator: (value) => Validators.requiredField(value, "regNo"), validator: (value) => Validators.requiredField(value, "regNo"),
@ -426,10 +431,7 @@ class QuotationStaffTabState extends ConsumerState<QuotationStaffTab> {
child: Row( child: Row(
children: [ children: [
// Expanded(flex: 3, child: Text(' ', style: _headerStyle)), // Expanded(flex: 3, child: Text(' ', style: _headerStyle)),
Expanded( Expanded(flex: 2, child: Text('Vehicle Number', style: _headerStyle)),
flex: 2,
child: Text('Registration Number', style: _headerStyle),
),
Expanded(flex: 3, child: Text('Insurer', style: _headerStyle)), Expanded(flex: 3, child: Text('Insurer', style: _headerStyle)),
Expanded(flex: 2, child: Text('IDV', style: _headerStyle)), Expanded(flex: 2, child: Text('IDV', style: _headerStyle)),
Expanded(flex: 2, child: Text('Plan Type', style: _headerStyle)), Expanded(flex: 2, child: Text('Plan Type', style: _headerStyle)),

View File

@ -211,7 +211,7 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
headers: { headers: {
'Authorization': 'Bearer $_token', 'Authorization': 'Bearer $_token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'nhance-partner-2025-signature-35468846JRhH551HK', 'app-signature': Env.App_Signature,
}, },
body: jsonEncode(data), // Convert map to JSON body: jsonEncode(data), // Convert map to JSON
); );
@ -229,6 +229,8 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
// //
widget.onSubmit("success"); widget.onSubmit("success");
// context.go(AppRoutes.staffLst); // context.go(AppRoutes.staffLst);
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else { } else {
final responseBody = jsonDecode(response.body); final responseBody = jsonDecode(response.body);
dynamic msg = responseBody['data']; dynamic msg = responseBody['data'];
@ -387,7 +389,7 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text("Registration Number", style: _textStyle), Text("Vehicle Number", style: _textStyle),
SizedBox(height: 10), SizedBox(height: 10),
ThemedFormField( ThemedFormField(
controller: controllers['regNum']!, controller: controllers['regNum']!,

View File

@ -434,8 +434,7 @@ class PolicyScreenState extends ConsumerState<PolicyScreen> {
// Use MultipartRequest (POST only) // Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri); final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $_token'; request.headers['Authorization'] = 'Bearer $_token';
request.headers['app-signature'] = request.headers['app-signature'] = Env.App_Signature;
'nhance-partner-2025-signature-35468846JRhH551HK';
// If updating, spoof the method Laravel-style // If updating, spoof the method Laravel-style
if (isUpdating) { if (isUpdating) {
@ -1011,7 +1010,7 @@ class PolicyScreenState extends ConsumerState<PolicyScreen> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('Registration Number*', style: _textStyle), Text('Vehicle Number*', style: _textStyle),
SizedBox(height: 10), SizedBox(height: 10),
ThemedFormField( ThemedFormField(
controller: controllers['regNum']!, controller: controllers['regNum']!,

View File

@ -29,6 +29,8 @@ class policylistState extends ConsumerState<policylist> {
int itemsPerPage = 10; int itemsPerPage = 10;
late ApiService apiService; late ApiService apiService;
dynamic userId; dynamic userId;
dynamic SelectedStatus;
dynamic SelectedStaffId;
// List<Map<String, dynamic>> dataVal = []; // List<Map<String, dynamic>> dataVal = [];
List<Map<String, dynamic>> getStaffData = []; List<Map<String, dynamic>> getStaffData = [];
List<Map<String, dynamic>> originalData = []; List<Map<String, dynamic>> originalData = [];
@ -89,6 +91,7 @@ class policylistState extends ConsumerState<policylist> {
role, role,
fromDate: controllers['startDate']?.text ?? '', fromDate: controllers['startDate']?.text ?? '',
toDate: controllers['endDate']?.text ?? '', toDate: controllers['endDate']?.text ?? '',
selectedStaffId: SelectedStaffId ?? '',
); );
if (response['status'] == 'success') { if (response['status'] == 'success') {
@ -149,25 +152,25 @@ class policylistState extends ConsumerState<policylist> {
void filterDateRange() { void filterDateRange() {
// Validate the form first // Validate the form first
if (!_formKey.currentState!.validate()) { // if (!_formKey.currentState!.validate()) {
// stop execution if validation fails // // stop execution if validation fails
return; // return;
} // }
//
final fromDateText = controllers['startDate']?.text ?? ''; // final fromDateText = controllers['startDate']?.text ?? '';
final toDateText = controllers['endDate']?.text ?? ''; // final toDateText = controllers['endDate']?.text ?? '';
//
// Optional: double-check End >= Start // // Optional: double-check End >= Start
final fromDate = DateFormat('dd-MM-yyyy').parse(fromDateText); // final fromDate = DateFormat('dd-MM-yyyy').parse(fromDateText);
final toDate = DateFormat('dd-MM-yyyy').parse(toDateText); // final toDate = DateFormat('dd-MM-yyyy').parse(toDateText);
//
if (toDate.isBefore(fromDate)) { // if (toDate.isBefore(fromDate)) {
// This is already caught by the validator, but extra safety // // This is already caught by the validator, but extra safety
ScaffoldMessenger.of(context).showSnackBar( // ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("End Date cannot be earlier than Start Date")), // SnackBar(content: Text("End Date cannot be earlier than Start Date")),
); // );
return; // return;
} // }
// Call your API // Call your API
getStaffList(userId, roleId); getStaffList(userId, roleId);
@ -175,6 +178,7 @@ class policylistState extends ConsumerState<policylist> {
void refrshfilterDateRange() { void refrshfilterDateRange() {
setState(() { setState(() {
SelectedStaffId = null;
controllers['startDate']!.clear(); controllers['startDate']!.clear();
controllers['endDate']!.clear(); controllers['endDate']!.clear();
@ -465,8 +469,19 @@ class policylistState extends ConsumerState<policylist> {
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),
color: Color(0xffD9EBE8), color: Color(0xffD9EBE8),
child: DateFilterRow( child: DateFilterRow(
dataFrom: 'Policy',
role: roleId,
id: userId,
onFilterStaff: (val) {
print('Selected Filterd STAFF Id - $val');
SelectedStaffId = val;
},
selectedStaffId: SelectedStaffId,
startController: controllers['startDate']!, startController: controllers['startDate']!,
endController: controllers['endDate']!, endController: controllers['endDate']!,
onStatusChanged: (val) {
SelectedStatus = val; // update parent
},
formKey: _formKey, formKey: _formKey,
isMobile: ResponsiveLayout.isMobile(context), isMobile: ResponsiveLayout.isMobile(context),
onFilter: () { onFilter: () {
@ -490,8 +505,19 @@ class policylistState extends ConsumerState<policylist> {
children: [ children: [
if (!ResponsiveLayout.isMobile(context)) ...[ if (!ResponsiveLayout.isMobile(context)) ...[
DateFilterRow( DateFilterRow(
dataFrom: 'Policy',
role: roleId,
id: userId,
onFilterStaff: (val) {
print('Selected Filterd STAFF Id - $val');
SelectedStaffId = val;
},
selectedStaffId: SelectedStaffId,
startController: controllers['startDate']!, startController: controllers['startDate']!,
endController: controllers['endDate']!, endController: controllers['endDate']!,
onStatusChanged: (val) {
SelectedStatus = val; // update parent
},
formKey: _formKey, formKey: _formKey,
isMobile: ResponsiveLayout.isMobile(context), isMobile: ResponsiveLayout.isMobile(context),
onFilter: () { onFilter: () {

View File

@ -3,6 +3,7 @@ import 'dart:convert';
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';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.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:toastification/toastification.dart'; import 'package:toastification/toastification.dart';
@ -262,8 +263,7 @@ class createQuotatDialogState extends State<createQuotatDialog> {
// Use MultipartRequest (POST only) // Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri); final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $_token'; request.headers['Authorization'] = 'Bearer $_token';
request.headers['app-signature'] = request.headers['app-signature'] = Env.App_Signature;
'nhance-partner-2025-signature-35468846JRhH551HK';
// If updating, spoof the method Laravel-style // If updating, spoof the method Laravel-style
if (isUpdating) { if (isUpdating) {
@ -458,6 +458,9 @@ class createQuotatDialogState extends State<createQuotatDialog> {
ThemedFormField( ThemedFormField(
controller: controllers['idv']!, controller: controllers['idv']!,
validator: (value) => Validators.doubleNumber(value, "IDV"), validator: (value) => Validators.doubleNumber(value, "IDV"),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')),
],
// validator: (value) => Validators.number(value, "IDV"), // validator: (value) => Validators.number(value, "IDV"),
backgroundColor: Color(0xFFEDF6F5), backgroundColor: Color(0xFFEDF6F5),
// readOnly: true, // readOnly: true,

View File

@ -653,7 +653,7 @@ class QuotationScreenState extends ConsumerState<QuotationScreen> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('Registration Number', style: _textStyle), Text('Vehicle Number', style: _textStyle),
SizedBox(height: 10), SizedBox(height: 10),
ThemedFormField( ThemedFormField(
controller: controllers['regNum']!, controller: controllers['regNum']!,
@ -710,7 +710,7 @@ class QuotationScreenState extends ConsumerState<QuotationScreen> {
Widget buildId(BuildContext context) { Widget buildId(BuildContext context) {
return buildResponsiveField( return buildResponsiveField(
label: "Registration Number *", label: "Vehicle Number *",
field: ThemedFormField( field: ThemedFormField(
controller: controllers['regNo']!, controller: controllers['regNo']!,
validator: (value) => Validators.requiredField(value, "regNo"), validator: (value) => Validators.requiredField(value, "regNo"),
@ -773,10 +773,7 @@ class QuotationScreenState extends ConsumerState<QuotationScreen> {
child: Row( child: Row(
children: [ children: [
// Expanded(flex: 3, child: Text(' ', style: _headerStyle)), // Expanded(flex: 3, child: Text(' ', style: _headerStyle)),
Expanded( Expanded(flex: 2, child: Text('Vehicle Number', style: _headerStyle)),
flex: 2,
child: Text('Registration Number', style: _headerStyle),
),
Expanded(flex: 4, child: Text('Insurer', style: _headerStyle)), Expanded(flex: 4, child: Text('Insurer', style: _headerStyle)),
Expanded(flex: 2, child: Text('IDV', style: _headerStyle)), Expanded(flex: 2, child: Text('IDV', style: _headerStyle)),
Expanded(flex: 2, child: Text('Plan Type', style: _headerStyle)), Expanded(flex: 2, child: Text('Plan Type', style: _headerStyle)),

View File

@ -143,7 +143,10 @@ class ThemedFormField extends HookWidget {
readOnly: readOnly, // now supported readOnly: readOnly, // now supported
keyboardType: keyboardType, // e.g. TextInputType.number keyboardType: keyboardType, // e.g. TextInputType.number
maxLength: maxLength, // max length maxLength: maxLength, // max length
inputFormatters: inputFormatters, inputFormatters:
inputFormatters ??
[FilteringTextInputFormatter.allow(RegExp(r'[a-z A-Z]'))],
// allow multiline if user sets maxLines / minLines // allow multiline if user sets maxLines / minLines
minLines: (keyboardType == TextInputType.multiline) ? 3 : 1, minLines: (keyboardType == TextInputType.multiline) ? 3 : 1,
maxLines: (keyboardType == TextInputType.multiline) ? null : 1, maxLines: (keyboardType == TextInputType.multiline) ? null : 1,

View File

@ -1,15 +1,53 @@
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import '../../core/services/api_service.dart';
import '../layouts/responsive_layout.dart'; import '../layouts/responsive_layout.dart';
import '../providers/manager_provider.dart';
import '../providers/userRoleProvider.dart';
import '../themes/indicators/date_field_theme.dart'; import '../themes/indicators/date_field_theme.dart';
import '../themes/indicators/input_field_decoration.dart';
class DateFilterRow extends StatelessWidget { // class DateFilterRow extends StatelessWidget {
// final TextEditingController startController;
// final String? selectedStatusVal;
// final TextEditingController endController;
// final ValueChanged<String?>? onStatusChanged;
// final String? dataFrom;
// final VoidCallback onFilter;
// final VoidCallback onRefresh;
// final GlobalKey<FormState> formKey;
// final bool isMobile;
//
// DateFilterRow({
// super.key,
// required this.startController,
// required this.endController,
// required this.onFilter,
// required this.onRefresh,
// required this.onStatusChanged,
// this.selectedStatusVal,
// required this.formKey,
// this.isMobile = false,
// this.dataFrom,
// });
class DateFilterRow extends ConsumerStatefulWidget {
final TextEditingController startController; final TextEditingController startController;
final String? selectedStatusVal;
final String? selectedStaffId;
final TextEditingController endController; final TextEditingController endController;
final ValueChanged<String?>? onStatusChanged;
final ValueChanged<String?>? onFilterStaff;
final String? dataFrom;
final VoidCallback onFilter; final VoidCallback onFilter;
final VoidCallback onRefresh; final VoidCallback onRefresh;
final GlobalKey<FormState> formKey; final GlobalKey<FormState> formKey;
final bool isMobile; final bool isMobile;
final role;
final id;
const DateFilterRow({ const DateFilterRow({
super.key, super.key,
@ -17,10 +55,93 @@ class DateFilterRow extends StatelessWidget {
required this.endController, required this.endController,
required this.onFilter, required this.onFilter,
required this.onRefresh, required this.onRefresh,
required this.onStatusChanged,
required this.onFilterStaff,
required this.selectedStaffId,
this.selectedStatusVal,
required this.formKey, required this.formKey,
required this.role,
required this.id,
this.isMobile = false, this.isMobile = false,
this.dataFrom,
}); });
@override
ConsumerState<DateFilterRow> createState() => _DateFilterRowState();
}
class _DateFilterRowState extends ConsumerState<DateFilterRow> {
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKey =
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
late ApiService apiService;
List<Map<String, dynamic>> getStaffDetailsData = [];
List<Map<String, dynamic>> filteredStaffData = [];
String? selectedStaff;
String? selectedStaffName;
dynamic role;
bool isLoading = false;
@override
void initState() {
super.initState();
apiService = ApiService();
Future.microtask(() {
final managerId = ref.watch(managerIdProvider);
final userID = ref.watch(userIdProvider);
// final handlerId = ref.watch(handlerIdProvider);
role = ref.watch(userRoleProvider);
print("managerId - $managerId");
if (userID != null && role != null) {
print('hansles');
getStaffDetails(userID);
}
});
// Future.microtask(() {
// print("CUSTuserID - ${widget.id}, CUSTrole -${widget.role}");
// if (widget.role != null && widget.id != null) {
// print('hansles');
// getStaffDetails(widget.id);
// }
// });
}
Future<void> getStaffDetails(int id) async {
print('getStaffDetails called By handler');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchStaffUserList(id, role);
if (response['status'] == 'success') {
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;
});
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final spacing = 10.0; final spacing = 10.0;
@ -51,6 +172,16 @@ class DateFilterRow extends StatelessWidget {
SizedBox(width: spacing), SizedBox(width: spacing),
buildEndDate(context), buildEndDate(context),
SizedBox(width: spacing), SizedBox(width: spacing),
if (widget.dataFrom == null && widget.dataFrom != 'Policy') ...[
buildStatusSearch(context),
SizedBox(width: spacing),
],
if (widget.role == 'manager' || widget.role == 'handler') ...[
buildSelectStaffMem(context),
SizedBox(width: spacing),
],
]; ];
final buttons = [ final buttons = [
@ -67,8 +198,8 @@ class DateFilterRow extends StatelessWidget {
child: IconButton( child: IconButton(
icon: const Icon(Icons.filter_alt_outlined), icon: const Icon(Icons.filter_alt_outlined),
onPressed: () { onPressed: () {
if (formKey.currentState!.validate()) { if (widget.formKey.currentState!.validate()) {
onFilter(); widget.onFilter();
} }
}, },
), ),
@ -80,7 +211,7 @@ class DateFilterRow extends StatelessWidget {
child: Tooltip( child: Tooltip(
message: 'Refresh', message: 'Refresh',
child: IconButton( child: IconButton(
onPressed: onRefresh, onPressed: widget.onRefresh,
icon: const Icon(Icons.refresh), icon: const Icon(Icons.refresh),
), ),
), ),
@ -101,15 +232,15 @@ class DateFilterRow extends StatelessWidget {
} }
return Form( return Form(
key: formKey, key: widget.formKey,
child: isMobile child: widget.isMobile
? Column( ? Column(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: getRowChildren(isMobile, spacing), children: getRowChildren(widget.isMobile, spacing),
) )
: Row( : Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: getRowChildren(isMobile, spacing), children: getRowChildren(widget.isMobile, spacing),
), ),
); );
} }
@ -124,15 +255,15 @@ class DateFilterRow extends StatelessWidget {
hintText: "Select Date", hintText: "Select Date",
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
: MediaQuery.of(context).size.width * 0.16, : MediaQuery.of(context).size.width * 0.1,
// txtheight: 50, // txtheight: 50,
// backgroundColor: const Color(0xFFECECEC), // backgroundColor: const Color(0xFFECECEC),
// validator: (value) => Validators.requiredField(value, "date"), // validator: (value) => Validators.requiredField(value, "date"),
controller: startController, controller: widget.startController,
onDateSelected: (date) { onDateSelected: (date) {
print("Picked Date: $date"); print("Picked Date: $date");
startController.text = DateFormat('dd-MM-yyyy').format(date); widget.startController.text = DateFormat('dd-MM-yyyy').format(date);
// controllers['date']?.text = date as String; // controllers['date']?.text = date as String;
}, },
), ),
@ -150,17 +281,16 @@ class DateFilterRow extends StatelessWidget {
hintText: "Select Date", hintText: "Select Date",
txtwidth: ResponsiveLayout.isMobile(context) txtwidth: ResponsiveLayout.isMobile(context)
? null ? null
: MediaQuery.of(context).size.width * 0.16, : MediaQuery.of(context).size.width * 0.1,
// txtheight: 50, // txtheight: 50,
// backgroundColor: const Color(0xFFECECEC), // backgroundColor: const Color(0xFFECECEC),
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { final fromText = widget.startController.text ?? '';
return "End Date is required";
}
final fromText = startController.text ?? '';
if (fromText.isNotEmpty) { if (fromText.isNotEmpty) {
final startDate = DateFormat('dd-MM-yyyy').parse(fromText); final startDate = DateFormat('dd-MM-yyyy').parse(fromText);
if (value == null || value.isEmpty) {
return "End Date is required";
}
final endDate = DateFormat('dd-MM-yyyy').parse(value); final endDate = DateFormat('dd-MM-yyyy').parse(value);
if (endDate.isBefore(startDate)) { if (endDate.isBefore(startDate)) {
@ -169,11 +299,11 @@ class DateFilterRow extends StatelessWidget {
} }
return null; // no error return null; // no error
}, },
controller: endController, controller: widget.endController,
lastDate: DateTime.now(), lastDate: DateTime.now(),
onDateSelected: (date) { onDateSelected: (date) {
print("Picked Date: $date"); print("Picked Date: $date");
endController.text = DateFormat('dd-MM-yyyy').format(date); widget.endController.text = DateFormat('dd-MM-yyyy').format(date);
// controllers['date']?.text = date as String; // controllers['date']?.text = date as String;
}, },
), ),
@ -181,6 +311,256 @@ class DateFilterRow extends StatelessWidget {
); );
} }
Widget buildStatusSearch(BuildContext context) {
final List<Map<String, dynamic>> statusOptions = [
{'id': 1, 'status': 'Awaiting Proposal'},
{'id': 2, 'status': 'Proposal Created'},
{'id': 3, 'status': 'Proposal Accepted'},
{'id': 4, 'status': 'Proposal Rejected'},
{'id': 5, 'status': 'Policy Created'},
];
Map<String, dynamic>? selectedStatusMap = statusOptions
.where((element) => element['status'] == widget.selectedStatusVal)
.cast<Map<String, dynamic>>()
.toList()
.firstOrNull;
Map<String, dynamic>? selectedItem = statusOptions
.cast<Map<String, dynamic>>()
.firstWhere(
(e) => e['status'] == widget.selectedStatusVal,
orElse: () => {}, // return empty map
);
if (selectedItem.isEmpty) selectedItem = null;
// Map<String, dynamic>? selectedStatus; // Default: no selection
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Status', style: _textStyle),
SizedBox(height: 5),
SizedBox(
height: 40,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(color: Colors.grey.shade100),
// color: Colors.black,
),
width: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.14,
child: DropdownSearch<Map<String, dynamic>>(
// selectedItem: selectedStatus,
selectedItem: selectedStatusMap,
// selectedItem: statusOptions.firstWhere(
// (element) => element['status'] == selectedStatusVal,
// orElse: () => null, // return null if not found
// ),
items: (filter, infiniteScrollProps) => statusOptions,
itemAsString: (val) => val['status'].toString(),
compareFn: (item, selectedItem) =>
item['id'] == selectedItem['id'],
// validator: (val) {
// if (val == null) {
// return "Please select a status";
// }
// return null;
// },
decoratorProps: DropDownDecoratorProps(
decoration: AppInputDecorations.dropdownDecoration(
label: "Select Status",
).copyWith(filled: true, fillColor: Colors.white),
),
// popupProps: PopupProps.menu(
// fit: FlexFit.loose,
// constraints: BoxConstraints(maxHeight: 200),
// menuProps: MenuProps(backgroundColor: Colors.white),
// showSearchBox: false, // 👈 no search box since it's static
//
// ),
popupProps: PopupProps.menu(
fit: FlexFit.loose,
constraints: const BoxConstraints(maxHeight: 200),
menuProps: const MenuProps(backgroundColor: Colors.white),
showSearchBox: false,
itemBuilder: (context, item, isDisabled, isSelected) {
// 4 parameters
return Container(
// color: isSelected ? Colors.blue.withOpacity(0.1) : null,
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
child: Text(
item['status'].toString(),
style: GoogleFonts.inter(
fontSize: 13,
color: Colors.black,
),
),
);
},
),
onChanged: (val) {
if (val != null) {
print("Selected Status: ${val['status']}");
if (widget.onStatusChanged != null)
widget.onStatusChanged!(val['status']);
}
},
),
),
),
],
);
}
Widget buildSelectStaffMem(BuildContext context) {
// 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
// }
Map<String, dynamic>? selectedVehicle;
if (widget.selectedStaffId == null) {
selectedVehicle = null;
} else if (widget.selectedStaffId != null) {
selectedVehicle = filteredStaffData.firstWhere(
(item) => item['id'] == widget.selectedStaffId,
orElse: () => {}, // empty map
);
if (selectedVehicle.isEmpty) selectedVehicle = null;
} else if (selectedStaff != null) {
selectedVehicle = filteredStaffData.firstWhere(
(item) => item['id'] == selectedStaff,
orElse: () => {}, // empty map
);
if (selectedVehicle.isEmpty) selectedVehicle = null;
} else {
selectedVehicle = null;
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Staff Name", style: _textStyle),
SizedBox(height: 10),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(color: Colors.grey.shade100),
// color: Colors.black,
),
width: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.13,
height: 40,
child: DropdownSearch<Map<String, dynamic>>(
// key: dropDownKey,
key: ValueKey(selectedStaff),
// 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
decoratorProps: DropDownDecoratorProps(
decoration:
AppInputDecorations.dropdownDecoration(
label: "Select Staff ",
).copyWith(
filled: true,
fillColor:
Colors.white, // 👈 makes the dropdown input white
),
),
popupProps: PopupProps.menu(
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 250),
menuProps: MenuProps(
backgroundColor:
Colors.white, // 👈 sets dropdown background to white
),
showSearchBox: true,
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
hintText: "Search Staff ...",
hintStyle: GoogleFonts.inter(
fontSize: 12,
color: Colors.black,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
), // 👈 Normal border
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
width: 1.5,
), // 👈 Focused border
),
),
),
itemBuilder: (context, item, isDisabled, isSelected) {
// 4 parameters
return Container(
// color: isSelected ? Colors.blue.withOpacity(0.1) : null,
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 3,
),
child: Text(
item['name'].toString(),
style: GoogleFonts.inter(fontSize: 13, color: Colors.black),
),
);
},
// constraints: BoxConstraints(),
),
onChanged: (val) {
if (val != null) {
print("Selected Staff : ${val['name']}");
print("Id: ${val['id']}");
selectedStaffName = val['name'];
selectedStaff = val['id'];
if (widget.onFilterStaff != null)
widget.onFilterStaff!(val['id']);
// controllers['agentId']?.text = val['agent_code'];
// agentId = agent['id'];
}
},
),
),
],
);
}
static const _textStyle = TextStyle( static const _textStyle = TextStyle(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -188,25 +568,27 @@ class DateFilterRow extends StatelessWidget {
Widget buildStartDate1() { Widget buildStartDate1() {
return ThemedDateField( return ThemedDateField(
controller: startController, controller: widget.startController,
hintText: 'Select Start Date', hintText: 'Select Start Date',
validator: (value) => validator: (value) =>
value == null || value.isEmpty ? "Start Date required" : null, value == null || value.isEmpty ? "Start Date required" : null,
onDateSelected: (date) => onDateSelected: (date) =>
startController.text = DateFormat('dd-MM-yyyy').format(date), widget.startController.text = DateFormat('dd-MM-yyyy').format(date),
); );
} }
Widget buildEndDate1() { Widget buildEndDate1() {
return ThemedDateField( return ThemedDateField(
controller: endController, controller: widget.endController,
hintText: 'Select End Date', hintText: 'Select End Date',
lastDate: DateTime.now(), lastDate: DateTime.now(),
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) return "End Date required"; if (value == null || value.isEmpty) return "End Date required";
if (startController.text.isNotEmpty) { if (widget.startController.text.isNotEmpty) {
final start = DateFormat('dd-MM-yyyy').parse(startController.text); final start = DateFormat(
'dd-MM-yyyy',
).parse(widget.startController.text);
final end = DateFormat('dd-MM-yyyy').parse(value); final end = DateFormat('dd-MM-yyyy').parse(value);
if (end.isBefore(start)) if (end.isBefore(start))
return "End Date cannot be earlier than Start Date"; return "End Date cannot be earlier than Start Date";
@ -214,7 +596,7 @@ class DateFilterRow extends StatelessWidget {
return null; return null;
}, },
onDateSelected: (date) => onDateSelected: (date) =>
endController.text = DateFormat('dd-MM-yyyy').format(date), widget.endController.text = DateFormat('dd-MM-yyyy').format(date),
); );
} }
} }

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:shared_preferences/shared_preferences.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';
@ -112,8 +113,13 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
width: 25, width: 25,
), ),
label: "Dashboard", label: "Dashboard",
onTap: () { onTap: () async {
_hidePopup(); _hidePopup();
final prefs = await SharedPreferences.getInstance();
await prefs.remove('dashboardKeyProvider');
await prefs.remove('dashboardStatusProvider');
await prefs.remove('dashboardStaffIdProvider');
context.go(AppRoutes.dashboard); context.go(AppRoutes.dashboard);
}, },
), ),
@ -123,7 +129,11 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
context: context, context: context,
icon: Icon(Icons.list_alt_rounded, size: 30, color: Colors.black), icon: Icon(Icons.list_alt_rounded, size: 30, color: Colors.black),
label: "Enquiry", label: "Enquiry",
onTap: () { onTap: () async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('dashboardKeyProvider');
await prefs.remove('dashboardStatusProvider');
await prefs.remove('dashboardStaffIdProvider');
_hidePopup(); _hidePopup();
if (roleId == 'agent') { if (roleId == 'agent') {
context.go(AppRoutes.enquiryLst); context.go(AppRoutes.enquiryLst);