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 {
static const String envName = String.fromEnvironment('ENV', defaultValue: 'dev');
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');
static const String envName = String.fromEnvironment(
'ENV',
defaultValue: 'dev',
);
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';
final GoRouter appRouter = GoRouter(
initialLocation: AppRoutes.home,
initialLocation: AppRoutes.login,
// initialLocation: AppRoutes.home,
routes: [
GoRoute(
path: AppRoutes.splash,
@ -37,10 +38,10 @@ final GoRouter appRouter = GoRouter(
path: AppRoutes.login,
builder: (context, state) => const LoginScreen(),
),
GoRoute(
path: AppRoutes.home,
builder: (context, state) => const HomeScreen(),
),
// GoRoute(
// path: AppRoutes.home,
// builder: (context, state) => const HomeScreen(),
// ),
GoRoute(
path: AppRoutes.dashboard,
builder: (context, state) => const DashboardScreen(),
@ -193,7 +194,7 @@ final GoRouter appRouter = GoRouter(
if (loggedIn && goingToLogin) {
// Logged in but going to login send to "next" if present
final next = state.uri.queryParameters['next'];
return next ?? AppRoutes.home;
return next ?? AppRoutes.login;
}
// if (!loggedIn && !goingToLogin) return AppRoutes.login;

View File

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

View File

@ -11,3 +11,7 @@ final staffIndiviualAttendanceIdProvider = StateProvider<String?>(
final staffIndiviualAttendanceNameIdProvider = StateProvider<String?>(
(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)
final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $_token';
request.headers['app-signature'] =
'nhance-partner-2025-signature-35468846JRhH551HK';
request.headers['app-signature'] = Env.App_Signature;
// If updating, spoof the method Laravel-style
if (isUpdating) {
@ -532,6 +531,8 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
}
}
setState(() => isSaving = false);
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else {
print("❌ Submission failed. Status: ${response.statusCode}");
print("Body: ${response.body}");
@ -755,7 +756,7 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
Widget buildName(BuildContext context) {
return buildResponsiveField(
label: "Full Name *",
label: "Insured Name *",
field: ThemedFormField(
controller: controllers['name']!,
@ -773,6 +774,9 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
field: ThemedFormField(
controller: controllers['email']!,
validator: (value) => Validators.email(value, "email"),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_@.]')),
],
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
@ -786,6 +790,7 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
field: ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'[ 0-9]'))],
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
@ -795,7 +800,7 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
Widget buildId(BuildContext context) {
return buildResponsiveField(
label: "Registration Number *",
label: "Vehicle Number *",
field: ThemedFormField(
controller: controllers['regNo']!,
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 {
final Uri uri = (val == 'Claims')
? Uri.parse('${Env.apiUrl}claim/createClaim')
@ -277,8 +228,7 @@ class _AddDialogState extends State<AddDialog> {
// Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $_token';
request.headers['app-signature'] =
'nhance-partner-2025-signature-35468846JRhH551HK';
request.headers['app-signature'] = Env.App_Signature;
print("USerDAta - $data");
@ -360,6 +310,8 @@ class _AddDialogState extends State<AddDialog> {
Navigator.of(context).pop();
widget.onSubmit("success");
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else {
final responseBody = jsonDecode(response.body);
dynamic msg = responseBody['data'];

View File

@ -712,9 +712,10 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
Widget buildName(BuildContext context) {
return buildResponsiveField(
label: "Registration Number",
label: "Vehicle Number",
field: ThemedFormField(
controller: controllers['regNum']!,
readOnly: true,
// validator: (value) => Validators.requiredField(value, "name"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
@ -725,9 +726,10 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
Widget buildInsusrer(BuildContext context) {
return buildResponsiveField(
label: "Insusrer",
label: "Insurer",
field: ThemedFormField(
controller: controllers['insurer']!,
readOnly: true,
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
@ -740,7 +742,8 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
label: "IDV",
field: ThemedFormField(
controller: controllers['idv']!,
validator: (value) => Validators.phone(value, "phNumber"),
readOnly: true,
// validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
@ -753,6 +756,7 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
label: "Insured Name",
field: ThemedFormField(
controller: controllers['insurerName']!,
readOnly: true,
// validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
@ -766,6 +770,7 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
label: "Policy Number",
field: ThemedFormField(
controller: controllers['policyNo']!,
readOnly: true,
// validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
@ -778,6 +783,7 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
return buildResponsiveField(
label: "Payment Mode",
field: ThemedFormField(
readOnly: true,
controller: controllers['paymentMode']!,
txtwidth: ResponsiveLayout.isMobile(context)
? null
@ -791,7 +797,8 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
label: "Plan Type",
field: ThemedFormField(
controller: controllers['planType']!,
validator: (value) => Validators.phone(value, "phNumber"),
readOnly: true,
// validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
@ -804,7 +811,8 @@ class PolicyTabState extends ConsumerState<PolicyTab> {
label: "Premium Amount",
field: ThemedFormField(
controller: controllers['premAmount']!,
validator: (value) => Validators.phone(value, "phNumber"),
readOnly: true,
// validator: (value) => Validators.phone(value, "phNumber"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: 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:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http;
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
@ -297,7 +298,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
headers: {
'Authorization': 'Bearer $_token',
'Content-Type': 'application/json',
'app-signature': 'nhance-partner-2025-signature-35468846JRhH551HK',
'app-signature': Env.App_Signature,
},
body: jsonEncode(data), // Convert map to JSON
);
@ -321,6 +322,8 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
// tabKey.currentState?.loadQuotationTab(widget.id ?? "");
// });
// context.go(AppRoutes.staffLst);
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else {
final responseBody = jsonDecode(response.body);
dynamic msg = responseBody['data'];
@ -349,8 +352,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
// Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $_token';
request.headers['app-signature'] =
'nhance-partner-2025-signature-35468846JRhH551HK';
request.headers['app-signature'] = Env.App_Signature;
print("USerDAta - $userData");
@ -408,6 +410,8 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
await widget.onRefresh!();
}
// context.go(AppRoutes.agentLst);
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else {
final responseBody = jsonDecode(response.body);
dynamic msg = responseBody['data'];
@ -643,7 +647,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
Widget buildName(BuildContext context) {
return buildResponsiveField(
label: "Registration Number",
label: "Vehicle Number",
field: ThemedFormField(
controller: controllers['regNum']!,
readOnly: true,
@ -657,7 +661,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
Widget buildInsusrer(BuildContext context) {
return buildResponsiveField(
label: "Insusrer",
label: "Insurer",
field: ThemedFormField(
controller: controllers['insurer']!,
readOnly: true,
@ -674,6 +678,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
field: ThemedFormField(
controller: controllers['idv']!,
readOnly: true,
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
@ -709,7 +714,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
Widget buildDocuments(BuildContext context) {
return buildResponsiveUploadField(
label: 'Quotation Documents',
label: 'Proposal Documents',
hintText: selectedFileNames,
onFileSelected: (fileName, file) {
setState(() {
@ -915,7 +920,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
Widget buildId(BuildContext context) {
return buildResponsiveField(
label: "Registration Number *",
label: "Vehicle Number *",
field: ThemedFormField(
controller: controllers['regNo']!,
validator: (value) => Validators.requiredField(value, "regNo"),
@ -936,10 +941,7 @@ class QuotationTabState extends ConsumerState<QuotationTab> {
child: const Row(
children: [
Expanded(flex: 1, child: Text(' ', style: _headerStyle)),
Expanded(
flex: 1,
child: Text('Registration Number', style: _headerStyle),
),
Expanded(flex: 1, child: Text('Vehicle Number', style: _headerStyle)),
Expanded(flex: 1, child: Text('Insurer', style: _headerStyle)),
Expanded(flex: 1, child: Text('IDV', 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);
tabs = [
TabItem("Enquiry", EnquiryTab()),
TabItem("Quotation", QuotationTab()),
TabItem("Proposal", QuotationTab()),
TabItem("Policy", PolicyTab()),
];
}
@ -86,7 +86,7 @@ class TabEnquiryListState extends ConsumerState<TabEnquiryList> {
EnquiryTab(data: enquiryData?["enquiry"], id: id ?? ""),
),
TabItem(
"Quotation",
"Proposal",
QuotationTab(
data:
(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()),
];
});
@ -141,7 +141,7 @@ class TabEnquiryListState extends ConsumerState<TabEnquiryList> {
EnquiryTab(data: enquiryData?["enquiry"], id: id ?? ""),
),
TabItem(
"Quotation",
"Proposal",
QuotationTab(
data:
(enquiryData?["quotations"] as List<dynamic>?)

View File

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

View File

@ -282,7 +282,13 @@ class ClaimsSubListState extends ConsumerState<ClaimsSubList> {
),
Expanded(
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(

View File

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

View File

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

View File

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

View File

@ -227,7 +227,7 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
style: _headerStyle,
),
Text(
role ?? '-',
(role == 'agent') ? 'partner' : role ?? '-',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
@ -300,7 +300,7 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
if (roleId == 1) {
path =
'api/agent/downloadManagerIncentiveFile?id=$latestId';
'api/staff/downloadManagerIncentiveFile?id=$latestId';
} else if (roleId != 1 && roleId != 2) {
path =
'api/agent/downloadAgentIncentiveFile?id=$latestId';
@ -383,7 +383,7 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
if (roleId == 1) {
path =
'api/agent/downloadManagerIncentiveFile?id=$selectedId';
'api/staff/downloadManagerIncentiveFile?id=$selectedId';
} else if (roleId != 1 && roleId != 2) {
path =
'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:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:http/http.dart' as http;
@ -183,7 +184,7 @@ class StaffState extends ConsumerState<Staff> {
headers: {
'Authorization': 'Bearer $_token',
'Content-Type': 'application/json',
'app-signature': 'nhance-partner-2025-signature-35468846JRhH551HK',
'app-signature': Env.App_Signature,
},
body: jsonEncode(data), // Convert map to JSON
);
@ -202,6 +203,8 @@ class StaffState extends ConsumerState<Staff> {
'Staff Created Successfully',
);
context.go(AppRoutes.staffLst);
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else {
final responseBody = jsonDecode(response.body);
dynamic msg = responseBody['data'];
@ -475,6 +478,9 @@ class StaffState extends ConsumerState<Staff> {
ThemedFormField(
controller: controllers['email']!,
validator: (value) => Validators.email(value, "email"),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_@.]')),
],
txtwidth: MediaQuery.of(context).size.width * 0.26,
),
],
@ -490,6 +496,9 @@ class StaffState extends ConsumerState<Staff> {
ThemedFormField(
controller: controllers['mobile']!,
validator: (value) => Validators.phone(value, "phNumber"),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[ 0-9]')),
],
txtwidth: MediaQuery.of(context).size.width * 0.26,
),
],

View File

@ -1344,29 +1344,70 @@ class othersPendings extends StatelessWidget {
),
Expanded(
flex: 2,
child: Text(
row['awaiting_quotation'] ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
child: InkWell(
onTap: () {
print(
'Awaiting Proposal : ${row['awaiting_quotation']}',
);
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(
flex: 2,
child: Text(
row['pending_quotation_approval'] ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
child: InkWell(
onTap: () async {
print(
'Awaiting Approval : ${row['pending_quotation_approval']} - ${row['staff_id']}',
);
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(
flex: 2,
child: Text(
row['awaiting_policy'] ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
child: InkWell(
onTap: () {
print(
'Awaiting Policy : ${row['awaiting_policy']}',
);
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(
@ -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(
fontWeight: FontWeight.w600,
fontSize: 14,

View File

@ -39,6 +39,9 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
late ApiService apiService;
dynamic userId;
dynamic managerId;
dynamic dashboardKey;
dynamic SelectedStatus;
dynamic SelectedStaffId;
dynamic handlerId;
final _formKey = GlobalKey<FormState>();
@ -62,16 +65,44 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
controllers[field] = TextEditingController();
}
Future.microtask(() {
Future.microtask(() async {
final id = ref.read(managerIdProvider);
roleId = ref.read(userRoleProvider);
userId = ref.read(userIdProvider);
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);
print('handlerIdENQ - $handlerId');
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);
}
});
@ -89,26 +120,27 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
}
void filterDateRange() {
// Validate the form first
if (!_formKey.currentState!.validate()) {
// stop execution if validation fails
return;
}
final fromDateText = controllers['startDate']?.text ?? '';
final toDateText = controllers['endDate']?.text ?? '';
// Optional: double-check End >= Start
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
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("End Date cannot be earlier than Start Date")),
);
return;
}
// print('SelectedStatus - $SelectedStatus');
// // Validate the form first
// if (!_formKey.currentState!.validate()) {
// // stop execution if validation fails
// return;
// }
//
// final fromDateText = controllers['startDate']?.text ?? '';
// final toDateText = controllers['endDate']?.text ?? '';
//
// // Optional: double-check End >= Start
// 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
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(content: Text("End Date cannot be earlier than Start Date")),
// );
// return;
// }
// Call your API
getStaffList(managerId, roleId);
@ -116,6 +148,8 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
void refrshfilterDateRange() {
setState(() {
SelectedStatus = '';
SelectedStaffId = null;
controllers['startDate']!.clear();
controllers['endDate']!.clear();
@ -132,6 +166,8 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
role, {
String fromDate = '',
String toDate = '',
String SelectedStatus = '',
String SelectedStaffId = '',
}) async {
print('A72 => Fns called => $managerId | $role');
setState(() {
@ -144,6 +180,8 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
role,
fromDate: controllers['startDate']?.text ?? '',
toDate: controllers['endDate']?.text ?? '',
selectedStatus: SelectedStatus != null ? SelectedStatus : '',
selectedStaffId: SelectedStaffId ?? '',
);
if (response['status'] == 'success') {
@ -516,13 +554,17 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
Tooltip(
message: 'Back',
child: IconButton(
icon: const Icon(Icons.arrow_left_sharp),
onPressed: () {
icon: const Icon(Icons.arrow_left_sharp, size: 25),
onPressed: () async {
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,
padding: const EdgeInsets.all(8),
constraints: const BoxConstraints(),
),
),
@ -538,7 +580,7 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
),
),
),
SizedBox(height: 10),
SizedBox(height: 5),
ResponsiveLayout.isMobile(context)
? Container(
height: MediaQuery.of(context).size.height * 0.69,
@ -604,10 +646,23 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
padding: EdgeInsets.all(8.0),
color: Color(0xffD9EBE8),
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']!,
endController: controllers['endDate']!,
formKey: _formKey,
isMobile: ResponsiveLayout.isMobile(context),
onStatusChanged: (val) {
SelectedStatus = val; // update parent
},
onFilter: () {
// call your filter logic
filterDateRange();
@ -624,13 +679,25 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
// height: 40,
// color: Colors.pink,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.start,
children: [
if (!ResponsiveLayout.isMobile(context)) ...[
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']!,
endController: controllers['endDate']!,
onStatusChanged: (val) {
SelectedStatus = val; // update parent
},
formKey: _formKey,
isMobile: ResponsiveLayout.isMobile(context),
onFilter: () {
@ -653,7 +720,7 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
controller: _searchStaffController,
txtwidth: ResponsiveLayout.isMobile(context)
? MediaQuery.of(context).size.width * 0.7
: MediaQuery.of(context).size.width * 0.2,
: MediaQuery.of(context).size.width * 0.13,
),
ResponsiveLayout.isMobile(context)

View File

@ -250,7 +250,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
body: json.encode(payload),
headers: {
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),
headers: {
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"),
// imgPath: "MiscIconAssetPath.person",
controller: _emailController,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9_@.]'),
),
],
),
if (switcherStatus == 1)
ThemedFormField(
@ -948,6 +953,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
Validators.phone(value, "Phone"),
// imgPath: "MiscIconAssetPath.person",
controller: _PhoneNumberController,
// txtwidth: MediaQuery.of(context).size.width * 0.5,
keyboardType: TextInputType.number,
maxLength: 10,

View File

@ -54,6 +54,8 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
late ApiService apiService;
dynamic userId;
final _formKey = GlobalKey<FormState>();
dynamic SelectedStatus;
dynamic SelectedStaffId;
// List<Map<String, dynamic>> dataVal = [];
List<Map<String, dynamic>> getStaffData = [];
@ -99,33 +101,64 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
}
void filterDateRange() {
print('SelectedStatus - $SelectedStatus');
print('SelectedStaffId - $SelectedStaffId');
// Validate the form first
if (!_formKey.currentState!.validate()) {
// stop execution if validation fails
return;
}
// if (!_formKey.currentState!.validate()) {
// // 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 ?? '';
//
// print("fromDateText - $fromDateText");
// print("toDateText - $toDateText");
// Optional: double-check End >= Start
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
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("End Date cannot be earlier than Start Date")),
);
return;
}
// 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
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(content: Text("End Date cannot be earlier than Start Date")),
// );
// 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
getStaffList(userId, roleId);
}
void refrshfilterDateRange() {
print('refrshfilterDateRange--1');
setState(() {
SelectedStatus = '';
SelectedStaffId = null;
print('refrshselectedStaff - $SelectedStaffId');
print('refrshfilterDateRange--1 - $SelectedStatus');
controllers['startDate']!.clear();
controllers['endDate']!.clear();
@ -154,6 +187,8 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
role,
fromDate: controllers['startDate']?.text ?? '',
toDate: controllers['endDate']?.text ?? '',
selectedStatus: SelectedStatus ?? '',
selectedStaffId: SelectedStaffId ?? '',
);
print('FromDate : $fromDate');
@ -169,8 +204,9 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
print('ToDate : $toDate');
setState(() {
controllers['startDate']?.text = fromDate;
print('1');
controllers['endDate']?.text = toDate;
print('2');
if (data is List) {
// Already a list of maps
getStaffData = List<Map<String, dynamic>>.from(data);
@ -180,9 +216,12 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
} else {
getStaffData = [];
}
print('3');
// getStaffData = List<Map<String, dynamic>>.from(response['data']);
originalData = getStaffData;
print('4');
filteredData = List.from(originalData);
print('5');
// print('originalData - $getClaimPolicies');
});
} else {
@ -351,97 +390,97 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
// ),
// ),
// ],
Material(
color: Colors.transparent,
child: InkWell(
onTap: () async {
Navigator.pop(context);
final prefs = await SharedPreferences.getInstance();
// Remove old value (if any)
await prefs.remove('enqStaffDataId');
// Save the new id
await prefs.setString('enqStaffDataId', id.toString());
// Read it back if needed
// final dynamic? enqStaffDataId = prefs.getString('enqStaffDataId');
// Update provider too
// ref.read(quotationStaffIdProvider.notifier).state = enqStaffDataId;
ref.read(quotationStaffIdProvider.notifier).state = id;
context.go(AppRoutes.quotation);
},
hoverColor: Color(0xFFE3F1F0),
splashColor: Color(0xFFE3F1F0),
borderRadius: BorderRadius.circular(6),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
child: Row(
// mainAxisSize: MainAxisSize.min,
children: [
Image.asset(
"assets/miscellaneous/image_1.png",
height: 15,
width: 15,
),
const SizedBox(width: 10),
((data['status'] == 'Policy Created') ||
(data['status'] == 'Quotation Accepted'))
? const Text('View Quotation')
: const Text('Create Quotation'),
],
),
),
),
),
if (data['status'] == 'Quotation Accepted' ||
data['status'] == 'Policy Created')
Material(
color: Colors.transparent,
child: InkWell(
onTap: () async {
Navigator.pop(context);
final prefs = await SharedPreferences.getInstance();
// Remove old value (if any)
await prefs.remove('enqStaffDataId');
// Save the new id
await prefs.setString('enqStaffDataId', id.toString());
// Update provider too
ref.read(quotationStaffIdProvider.notifier).state = id;
context.go(AppRoutes.policy);
},
hoverColor: Color(0xFFE3F1F0),
splashColor: Color(0xFFE3F1F0),
borderRadius: BorderRadius.circular(6),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
child: Row(
// mainAxisSize: MainAxisSize.min,
children: [
Image.asset(
"assets/miscellaneous/image_2.png",
height: 15,
width: 15,
),
const SizedBox(width: 10),
data['status'] == 'Policy Created'
? Text('View Policy')
: Text('Create Policy'),
],
),
),
),
),
// Material(
// color: Colors.transparent,
// child: InkWell(
// onTap: () async {
// Navigator.pop(context);
// final prefs = await SharedPreferences.getInstance();
//
// // Remove old value (if any)
// await prefs.remove('enqStaffDataId');
//
// // Save the new id
// await prefs.setString('enqStaffDataId', id.toString());
//
// // Read it back if needed
// // final dynamic? enqStaffDataId = prefs.getString('enqStaffDataId');
//
// // Update provider too
// // ref.read(quotationStaffIdProvider.notifier).state = enqStaffDataId;
// ref.read(quotationStaffIdProvider.notifier).state = id;
//
// context.go(AppRoutes.quotation);
// },
// hoverColor: Color(0xFFE3F1F0),
// splashColor: Color(0xFFE3F1F0),
// borderRadius: BorderRadius.circular(6),
// child: Padding(
// padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
// child: Row(
// // mainAxisSize: MainAxisSize.min,
// children: [
// Image.asset(
// "assets/miscellaneous/image_1.png",
// height: 15,
// width: 15,
// ),
//
// const SizedBox(width: 10),
// ((data['status'] == 'Policy Created') ||
// (data['status'] == 'Quotation Accepted'))
// ? const Text('View Quotation')
// : const Text('Create Quotation'),
// ],
// ),
// ),
// ),
// ),
//
// if (data['status'] == 'Quotation Accepted' ||
// data['status'] == 'Policy Created')
// Material(
// color: Colors.transparent,
// child: InkWell(
// onTap: () async {
// Navigator.pop(context);
//
// final prefs = await SharedPreferences.getInstance();
//
// // Remove old value (if any)
// await prefs.remove('enqStaffDataId');
//
// // Save the new id
// await prefs.setString('enqStaffDataId', id.toString());
//
// // Update provider too
//
// ref.read(quotationStaffIdProvider.notifier).state = id;
// context.go(AppRoutes.policy);
// },
// hoverColor: Color(0xFFE3F1F0),
// splashColor: Color(0xFFE3F1F0),
// borderRadius: BorderRadius.circular(6),
// child: Padding(
// padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
// child: Row(
// // mainAxisSize: MainAxisSize.min,
// children: [
// Image.asset(
// "assets/miscellaneous/image_2.png",
// height: 15,
// width: 15,
// ),
//
// const SizedBox(width: 10),
// data['status'] == 'Policy Created'
// ? Text('View Policy')
// : Text('Create Policy'),
// ],
// ),
// ),
// ),
// ),
];
}
@ -491,13 +530,13 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
Tooltip(
message: 'Back',
child: IconButton(
icon: const Icon(Icons.arrow_left_sharp),
icon: const Icon(Icons.arrow_left_sharp, size: 25),
onPressed: () {
context.go(AppRoutes.dashboard);
},
splashRadius: 28,
splashRadius: 18,
hoverColor: Colors.black12,
padding: const EdgeInsets.all(8),
padding: const EdgeInsets.all(4),
constraints: const BoxConstraints(),
),
),
@ -579,8 +618,21 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
padding: EdgeInsets.all(8.0),
color: Color(0xffD9EBE8),
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']!,
endController: controllers['endDate']!,
onStatusChanged: (val) {
SelectedStatus = val; // update parent
},
formKey: _formKey,
isMobile: ResponsiveLayout.isMobile(context),
onFilter: () {
@ -599,15 +651,27 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
// height: 40,
// color: Colors.pink,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.start,
children: [
if (!ResponsiveLayout.isMobile(context)) ...[
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']!,
endController: controllers['endDate']!,
formKey: _formKey,
isMobile: ResponsiveLayout.isMobile(context),
onStatusChanged: (val) {
SelectedStatus = val; // update parent
},
onFilter: () {
// call your filter logic
filterDateRange();
@ -693,7 +757,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
],
),
),
// SizedBox(height: 10),
SizedBox(height: 8),
if (!ResponsiveLayout.isMobile(context))
Container(
decoration: BoxDecoration(
@ -859,7 +923,19 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
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;
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:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
@ -130,6 +131,7 @@ class CreateQuotationFormState extends ConsumerState<CreateQuotationForm> {
}
void reset() {
print('RESET');
_formKey.currentState?.reset();
// Clear all TextEditingControllers
for (var controller in controllers.values) {
@ -303,8 +305,7 @@ class CreateQuotationFormState extends ConsumerState<CreateQuotationForm> {
// Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $_token';
request.headers['app-signature'] =
'nhance-partner-2025-signature-35468846JRhH551HK';
request.headers['app-signature'] = Env.App_Signature;
// If updating, spoof the method Laravel-style
if (isUpdating) {
@ -370,6 +371,8 @@ class CreateQuotationFormState extends ConsumerState<CreateQuotationForm> {
widget.onSubmit('Success');
reset();
// Navigator.of(context).pop();
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else {
final responseBody = jsonDecode(response.body);
dynamic msg = responseBody['data'];
@ -479,6 +482,9 @@ class CreateQuotationFormState extends ConsumerState<CreateQuotationForm> {
SizedBox(height: 10),
ThemedFormField(
controller: controllers['idv']!,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')),
],
validator: (value) => Validators.doubleNumber(value, "IDV"),
// validator: (value) => Validators.number(value, "IDV"),
backgroundColor: Color(0xFFEDF6F5),
@ -591,6 +597,9 @@ class CreateQuotationFormState extends ConsumerState<CreateQuotationForm> {
ThemedFormField(
controller: controllers['premium_Amount']!,
backgroundColor: Color(0xFFEDF6F5),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')),
],
validator: (value) => Validators.doubleNumber(value, "PremiumAmount"),
// validator: (value) => Validators.number(value, "PremiumAmount "),
txtwidth: ResponsiveLayout.isMobile(context)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -653,7 +653,7 @@ class QuotationScreenState extends ConsumerState<QuotationScreen> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Registration Number', style: _textStyle),
Text('Vehicle Number', style: _textStyle),
SizedBox(height: 10),
ThemedFormField(
controller: controllers['regNum']!,
@ -710,7 +710,7 @@ class QuotationScreenState extends ConsumerState<QuotationScreen> {
Widget buildId(BuildContext context) {
return buildResponsiveField(
label: "Registration Number *",
label: "Vehicle Number *",
field: ThemedFormField(
controller: controllers['regNo']!,
validator: (value) => Validators.requiredField(value, "regNo"),
@ -773,10 +773,7 @@ class QuotationScreenState extends ConsumerState<QuotationScreen> {
child: Row(
children: [
// Expanded(flex: 3, child: Text(' ', style: _headerStyle)),
Expanded(
flex: 2,
child: Text('Registration Number', style: _headerStyle),
),
Expanded(flex: 2, child: Text('Vehicle Number', style: _headerStyle)),
Expanded(flex: 4, child: Text('Insurer', style: _headerStyle)),
Expanded(flex: 2, child: Text('IDV', 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
keyboardType: keyboardType, // e.g. TextInputType.number
maxLength: maxLength, // max length
inputFormatters: inputFormatters,
inputFormatters:
inputFormatters ??
[FilteringTextInputFormatter.allow(RegExp(r'[a-z A-Z]'))],
// allow multiline if user sets maxLines / minLines
minLines: (keyboardType == TextInputType.multiline) ? 3 : 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_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import '../../core/services/api_service.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/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 String? selectedStatusVal;
final String? selectedStaffId;
final TextEditingController endController;
final ValueChanged<String?>? onStatusChanged;
final ValueChanged<String?>? onFilterStaff;
final String? dataFrom;
final VoidCallback onFilter;
final VoidCallback onRefresh;
final GlobalKey<FormState> formKey;
final bool isMobile;
final role;
final id;
const DateFilterRow({
super.key,
@ -17,10 +55,93 @@ class DateFilterRow extends StatelessWidget {
required this.endController,
required this.onFilter,
required this.onRefresh,
required this.onStatusChanged,
required this.onFilterStaff,
required this.selectedStaffId,
this.selectedStatusVal,
required this.formKey,
required this.role,
required this.id,
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
Widget build(BuildContext context) {
final spacing = 10.0;
@ -51,6 +172,16 @@ class DateFilterRow extends StatelessWidget {
SizedBox(width: spacing),
buildEndDate(context),
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 = [
@ -67,8 +198,8 @@ class DateFilterRow extends StatelessWidget {
child: IconButton(
icon: const Icon(Icons.filter_alt_outlined),
onPressed: () {
if (formKey.currentState!.validate()) {
onFilter();
if (widget.formKey.currentState!.validate()) {
widget.onFilter();
}
},
),
@ -80,7 +211,7 @@ class DateFilterRow extends StatelessWidget {
child: Tooltip(
message: 'Refresh',
child: IconButton(
onPressed: onRefresh,
onPressed: widget.onRefresh,
icon: const Icon(Icons.refresh),
),
),
@ -101,15 +232,15 @@ class DateFilterRow extends StatelessWidget {
}
return Form(
key: formKey,
child: isMobile
key: widget.formKey,
child: widget.isMobile
? Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: getRowChildren(isMobile, spacing),
children: getRowChildren(widget.isMobile, spacing),
)
: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: getRowChildren(isMobile, spacing),
children: getRowChildren(widget.isMobile, spacing),
),
);
}
@ -124,15 +255,15 @@ class DateFilterRow extends StatelessWidget {
hintText: "Select Date",
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.16,
: MediaQuery.of(context).size.width * 0.1,
// txtheight: 50,
// backgroundColor: const Color(0xFFECECEC),
// validator: (value) => Validators.requiredField(value, "date"),
controller: startController,
controller: widget.startController,
onDateSelected: (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;
},
),
@ -150,17 +281,16 @@ class DateFilterRow extends StatelessWidget {
hintText: "Select Date",
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.16,
: MediaQuery.of(context).size.width * 0.1,
// txtheight: 50,
// backgroundColor: const Color(0xFFECECEC),
validator: (value) {
if (value == null || value.isEmpty) {
return "End Date is required";
}
final fromText = startController.text ?? '';
final fromText = widget.startController.text ?? '';
if (fromText.isNotEmpty) {
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);
if (endDate.isBefore(startDate)) {
@ -169,11 +299,11 @@ class DateFilterRow extends StatelessWidget {
}
return null; // no error
},
controller: endController,
controller: widget.endController,
lastDate: DateTime.now(),
onDateSelected: (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;
},
),
@ -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(
fontSize: 12,
fontWeight: FontWeight.w600,
@ -188,25 +568,27 @@ class DateFilterRow extends StatelessWidget {
Widget buildStartDate1() {
return ThemedDateField(
controller: startController,
controller: widget.startController,
hintText: 'Select Start Date',
validator: (value) =>
value == null || value.isEmpty ? "Start Date required" : null,
onDateSelected: (date) =>
startController.text = DateFormat('dd-MM-yyyy').format(date),
widget.startController.text = DateFormat('dd-MM-yyyy').format(date),
);
}
Widget buildEndDate1() {
return ThemedDateField(
controller: endController,
controller: widget.endController,
hintText: 'Select End Date',
lastDate: DateTime.now(),
validator: (value) {
if (value == null || value.isEmpty) return "End Date required";
if (startController.text.isNotEmpty) {
final start = DateFormat('dd-MM-yyyy').parse(startController.text);
if (widget.startController.text.isNotEmpty) {
final start = DateFormat(
'dd-MM-yyyy',
).parse(widget.startController.text);
final end = DateFormat('dd-MM-yyyy').parse(value);
if (end.isBefore(start))
return "End Date cannot be earlier than Start Date";
@ -214,7 +596,7 @@ class DateFilterRow extends StatelessWidget {
return null;
},
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_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../core/routing/routes.dart';
import 'package:go_router/go_router.dart';
@ -112,8 +113,13 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
width: 25,
),
label: "Dashboard",
onTap: () {
onTap: () async {
_hidePopup();
final prefs = await SharedPreferences.getInstance();
await prefs.remove('dashboardKeyProvider');
await prefs.remove('dashboardStatusProvider');
await prefs.remove('dashboardStaffIdProvider');
context.go(AppRoutes.dashboard);
},
),
@ -123,7 +129,11 @@ class DrawerMenuState extends ConsumerState<DrawerMenu> {
context: context,
icon: Icon(Icons.list_alt_rounded, size: 30, color: Colors.black),
label: "Enquiry",
onTap: () {
onTap: () async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('dashboardKeyProvider');
await prefs.remove('dashboardStatusProvider');
await prefs.remove('dashboardStaffIdProvider');
_hidePopup();
if (roleId == 'agent') {
context.go(AppRoutes.enquiryLst);