pos policy_validation invoice
This commit is contained in:
parent
b9f2032d3b
commit
bd4465caa5
File diff suppressed because one or more lines are too long
@ -18,6 +18,7 @@ import '../../presentation/screens/StaffAttendance/attendanceAllDetails.dart';
|
||||
import '../../presentation/screens/StaffAttendance/individual_Attendance.dart';
|
||||
import '../../presentation/screens/UserManagement/Agent/agent.dart';
|
||||
import '../../presentation/screens/UserManagement/Agent/agentList.dart';
|
||||
import '../../presentation/screens/UserManagement/POS/pos_list.dart';
|
||||
import '../../presentation/screens/UserManagement/Profile/profile_mobile.dart';
|
||||
import '../../presentation/screens/UserManagement/SalesExecutive/salesExecutive.dart';
|
||||
import '../../presentation/screens/UserManagement/SalesExecutive/salesExecutiveList.dart';
|
||||
@ -85,57 +86,61 @@ final GoRouter appRouter = GoRouter(
|
||||
builder: (context, state) => const AgentList(),
|
||||
),
|
||||
|
||||
GoRoute(
|
||||
path: '/agent/:id',
|
||||
builder: (context, state) {
|
||||
final id = state.pathParameters['id']!;
|
||||
|
||||
// if "create", open empty form
|
||||
if (id == 'create') {
|
||||
return const Agent(); // create mode
|
||||
} else {
|
||||
return Agent(id: id); // update mode
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
// GoRoute(
|
||||
// path: '/agent/:id',
|
||||
// builder: (context, state) {
|
||||
// final id = state.pathParameters['id']!;
|
||||
//
|
||||
// // if "create", open empty form
|
||||
// if (id == 'create') {
|
||||
// return const Agent(); // create mode
|
||||
// } else {
|
||||
// return Agent(id: id); // update mode
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
GoRoute(
|
||||
path: AppRoutes.staffLst,
|
||||
// builder: (context, state) => const Agent(),
|
||||
builder: (context, state) => const StaffList(),
|
||||
),
|
||||
|
||||
// GoRoute(
|
||||
// path: '/staff/:id',
|
||||
// builder: (context, state) {
|
||||
// final id = state.pathParameters['id']!;
|
||||
// // if "create", open empty form
|
||||
// if (id == 'create') {
|
||||
// return const Staff(); // create mode
|
||||
// } else {
|
||||
// return Staff(id: id); // update mode
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
GoRoute(
|
||||
path: '/staff/:id',
|
||||
builder: (context, state) {
|
||||
final id = state.pathParameters['id']!;
|
||||
// if "create", open empty form
|
||||
if (id == 'create') {
|
||||
return const Staff(); // create mode
|
||||
} else {
|
||||
return Staff(id: id); // update mode
|
||||
}
|
||||
},
|
||||
path: AppRoutes.posLst,
|
||||
// builder: (context, state) => const Agent(),
|
||||
builder: (context, state) => const PosList(),
|
||||
),
|
||||
|
||||
GoRoute(
|
||||
path: AppRoutes.salesExecutiveLst,
|
||||
// builder: (context, state) => const Agent(),
|
||||
builder: (context, state) => const SalesExecutiveList(),
|
||||
),
|
||||
|
||||
GoRoute(
|
||||
path: '/salesExecutive/:id',
|
||||
builder: (context, state) {
|
||||
final id = state.pathParameters['id']!;
|
||||
// if "create", open empty form
|
||||
if (id == 'create') {
|
||||
return const SalesExecutive(); // create mode
|
||||
} else {
|
||||
return SalesExecutive(id: id); // update mode
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
// GoRoute(
|
||||
// path: '/salesExecutive/:id',
|
||||
// builder: (context, state) {
|
||||
// final id = state.pathParameters['id']!;
|
||||
// // if "create", open empty form
|
||||
// if (id == 'create') {
|
||||
// return const SalesExecutive(); // create mode
|
||||
// } else {
|
||||
// return SalesExecutive(id: id); // update mode
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
GoRoute(
|
||||
path: AppRoutes.enquiryLst,
|
||||
builder: (context, state) => const EnquiryList(),
|
||||
@ -194,8 +199,10 @@ final GoRouter appRouter = GoRouter(
|
||||
|
||||
return CustomTransitionPage(
|
||||
key: state.pageKey,
|
||||
opaque: true, // ⭐ required for open animation
|
||||
barrierColor: Colors.black.withOpacity(0.3), // optional dim background
|
||||
opaque: true, // ⭐ required for open animation
|
||||
barrierColor: Colors.black.withOpacity(
|
||||
0.3,
|
||||
), // optional dim background
|
||||
fullscreenDialog: true,
|
||||
|
||||
transitionDuration: const Duration(milliseconds: 1000),
|
||||
@ -210,7 +217,7 @@ final GoRouter appRouter = GoRouter(
|
||||
|
||||
return SlideTransition(
|
||||
position: Tween<Offset>(
|
||||
begin: const Offset(0, 1), // slide from bottom
|
||||
begin: const Offset(0, 1), // slide from bottom
|
||||
end: Offset.zero,
|
||||
).animate(curved),
|
||||
child: child,
|
||||
|
||||
@ -10,6 +10,7 @@ class AppRoutes {
|
||||
static const staff = '/staff/:id';
|
||||
static const String salesExecutiveLst = '/salesExecutiveLst';
|
||||
static const salesExecutive = '/salesExecutive/:id';
|
||||
static const String posLst = '/posLst';
|
||||
static const String enquiryLst = '/enquiryLst';
|
||||
static const String enquiryForStaff = '/enquiryForStaff';
|
||||
static const String tabEnquiry = '/tabEnquiry';
|
||||
|
||||
@ -307,6 +307,8 @@ class ApiService {
|
||||
// return;
|
||||
// }
|
||||
final url = Uri.parse('https://venbait.in/nhance/partner/dev/$path');
|
||||
// final url = Uri.parse('${Env.apiUrl}$path');
|
||||
// final url = Uri.parse('${Env.apiUrl}$path');
|
||||
print('getPdfDownload 2 - $url');
|
||||
await _initializeToken();
|
||||
|
||||
@ -387,6 +389,183 @@ class ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> generateChartExcel(
|
||||
// BuildContext context,
|
||||
String path,
|
||||
String id,
|
||||
String month,
|
||||
dynamic managerId,
|
||||
) async {
|
||||
print('getPdfDownload 1 - $path');
|
||||
|
||||
dynamic pathVal;
|
||||
if (path == 'Insurer') {
|
||||
pathVal =
|
||||
'dashboard/downloadInsurerPoliciesExcel?manager_id=$managerId&month=$month&insurer_id=$id';
|
||||
} else if (path == 'Broker') {
|
||||
pathVal =
|
||||
'dashboard/downloadBrokerPoliciesExcel?manager_id=$managerId&month=$month&broker_id=$id';
|
||||
} else if (path == 'Product') {
|
||||
pathVal =
|
||||
'dashboard/downloadProductPoliciesExcel?manager_id=$managerId&month=$month&vehicle_type=$id';
|
||||
} else if (path == 'PerformingTop50') {
|
||||
pathVal =
|
||||
'dashboard/downloadAgentMonthlyPoliciesExcel?manager_id=$managerId&agent_id=$id';
|
||||
} else if (path == 'NonPerformingBelow50K') {
|
||||
pathVal = 'dashboard/downloadLowPremiumAgentExcel?manager_id=$managerId';
|
||||
} else {
|
||||
//NoBusiness
|
||||
pathVal =
|
||||
'dashboard/downloadAgentsWithoutPoliciesExcel?manager_id=$managerId';
|
||||
}
|
||||
|
||||
final url = Uri.parse('${Env.apiUrl}$pathVal');
|
||||
// final url = Uri.parse('https://venbait.in/nhance/partner/dev/$path');
|
||||
print('getPdfDownload 2 - $url');
|
||||
await _initializeToken();
|
||||
|
||||
if (_token == null) throw Exception('Token not found. Please log in.');
|
||||
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $_token',
|
||||
// 'App-Signature': Env.App_Signature,
|
||||
'app-signature': Env.App_Signature,
|
||||
};
|
||||
|
||||
final response = await _makeGethttpRequest(url, headers);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final contentType = response.headers['content-type'] ?? '';
|
||||
if (contentType.contains('application/json')) {
|
||||
final jsonResponse = jsonDecode(response.body);
|
||||
if (jsonResponse['code'] == 404 || jsonResponse['code'] == 500) {
|
||||
ToastHelper.show('File Not Found', Colors.red);
|
||||
} else {
|
||||
ToastHelper.show('No File Found', Colors.red);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
final blob = html.Blob([response.bodyBytes]);
|
||||
final blobUrl = html.Url.createObjectUrlFromBlob(blob);
|
||||
print('getPdfDownload $blobUrl');
|
||||
final contentDisp = response.headers['content-disposition'];
|
||||
print('getPdfDownloadcontentDisp $contentDisp');
|
||||
|
||||
String fileName = extractFileName(contentDisp, path.split('/').last);
|
||||
print('Resolved fileName: $fileName');
|
||||
final anchor = html.AnchorElement(href: blobUrl)
|
||||
..setAttribute('download', fileName)
|
||||
..click();
|
||||
|
||||
html.Url.revokeObjectUrl(blobUrl);
|
||||
}
|
||||
} else if (response.statusCode == 404) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('File not found.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: const Text('OK'),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else if (response.statusCode == 403) {
|
||||
await clearLocalStorageAndRedirect();
|
||||
} else if (response.statusCode == 500) {
|
||||
ToastHelper.show('No File Found', Colors.red);
|
||||
} else if (response.statusCode == 302) {
|
||||
print('getPdfDownload 3-PP-302');
|
||||
ToastHelper.show('No File Found', Colors.red);
|
||||
} else {
|
||||
ToastHelper.show('No File Found', Colors.red);
|
||||
throw Exception('Failed to download file');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> generatePerformanceDashboardExcel(
|
||||
// BuildContext context,
|
||||
String path,
|
||||
String id,
|
||||
String salesId,
|
||||
String month,
|
||||
dynamic managerId,
|
||||
) async {
|
||||
print('getPdfDownload 1 - $path');
|
||||
|
||||
dynamic pathVal;
|
||||
|
||||
pathVal =
|
||||
'dashboard/downloadStaffAndProductPoliciesExcel?manager_id=$managerId&month=$month&sales_executive_id=$salesId&vehicle_type=$id';
|
||||
|
||||
final url = Uri.parse('${Env.apiUrl}$pathVal');
|
||||
// final url = Uri.parse('https://venbait.in/nhance/partner/dev/$path');
|
||||
print('getPdfDownload 2 - $url');
|
||||
await _initializeToken();
|
||||
|
||||
if (_token == null) throw Exception('Token not found. Please log in.');
|
||||
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $_token',
|
||||
// 'App-Signature': Env.App_Signature,
|
||||
'app-signature': Env.App_Signature,
|
||||
};
|
||||
|
||||
final response = await _makeGethttpRequest(url, headers);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final contentType = response.headers['content-type'] ?? '';
|
||||
if (contentType.contains('application/json')) {
|
||||
final jsonResponse = jsonDecode(response.body);
|
||||
if (jsonResponse['code'] == 404 || jsonResponse['code'] == 500) {
|
||||
ToastHelper.show('File Not Found', Colors.red);
|
||||
} else {
|
||||
ToastHelper.show('No File Found', Colors.red);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
final blob = html.Blob([response.bodyBytes]);
|
||||
final blobUrl = html.Url.createObjectUrlFromBlob(blob);
|
||||
print('getPdfDownload $blobUrl');
|
||||
final contentDisp = response.headers['content-disposition'];
|
||||
print('getPdfDownloadcontentDisp $contentDisp');
|
||||
|
||||
String fileName = extractFileName(contentDisp, path.split('/').last);
|
||||
print('Resolved fileName: $fileName');
|
||||
final anchor = html.AnchorElement(href: blobUrl)
|
||||
..setAttribute('download', fileName)
|
||||
..click();
|
||||
|
||||
html.Url.revokeObjectUrl(blobUrl);
|
||||
}
|
||||
} else if (response.statusCode == 404) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('File not found.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: const Text('OK'),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else if (response.statusCode == 403) {
|
||||
await clearLocalStorageAndRedirect();
|
||||
} else if (response.statusCode == 500) {
|
||||
ToastHelper.show('No File Found', Colors.red);
|
||||
} else if (response.statusCode == 302) {
|
||||
print('getPdfDownload 3-PP-302');
|
||||
ToastHelper.show('No File Found', Colors.red);
|
||||
} else {
|
||||
ToastHelper.show('No File Found', Colors.red);
|
||||
throw Exception('Failed to download file');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> downloadFile({
|
||||
required String? apiUrl,
|
||||
required PlatformFile? localFile,
|
||||
@ -754,7 +933,9 @@ class ApiService {
|
||||
} else if (role == 'Accounts') {
|
||||
print('manager');
|
||||
// url = Uri.parse('${Env.apiUrl}staff/staffList');
|
||||
url = Uri.parse('${Env.apiUrl}staff/staffList?manager_id=${managerId}');
|
||||
url = Uri.parse(
|
||||
'${Env.apiUrl}salesExecutive/executiveList?manager_id=${managerId}',
|
||||
);
|
||||
} else {
|
||||
print('handler');
|
||||
url = Uri.parse(
|
||||
@ -786,6 +967,36 @@ class ApiService {
|
||||
return response;
|
||||
}
|
||||
|
||||
// ----------------------------------- POS -------------------------------------------------
|
||||
Future<Map<String, dynamic>> fetchPosList(int managerId, val) async {
|
||||
// print(_token);
|
||||
|
||||
print('dropDown - $managerId');
|
||||
if (_token == null) {
|
||||
await _initializeToken();
|
||||
}
|
||||
|
||||
dynamic url;
|
||||
if (val == 'dropDown') {
|
||||
print('dropDown');
|
||||
url = Uri.parse(
|
||||
'${Env.apiUrl}master/getAllPOS?is_active=1&manager_id=${managerId}',
|
||||
);
|
||||
} else {
|
||||
print('List');
|
||||
url = Uri.parse(
|
||||
'${Env.apiUrl}master/getAllPOS?is_active=1&manager_id=${managerId}',
|
||||
);
|
||||
}
|
||||
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $_token' ?? '',
|
||||
'app-signature': Env.App_Signature,
|
||||
};
|
||||
final response = await _makeGetRequest(url, headers);
|
||||
return response;
|
||||
}
|
||||
|
||||
// ----------------------------------- ENQUIRY -------------------------------------------------
|
||||
|
||||
Future<Map<String, dynamic>> fetchEnquiryList(
|
||||
@ -1504,14 +1715,19 @@ class ApiService {
|
||||
|
||||
// --------------------------------- PayOut Module----------------------------------------------
|
||||
Future<Map<String, dynamic>> getCommissionRateList(data) async {
|
||||
print("getCommissionRateList------- $data}");
|
||||
final url = Uri.parse('${Env.apiUrl}/invoice/commission-rate-list');
|
||||
|
||||
print("getCommissionRateList 1");
|
||||
// final token = await getToken(); // Fetch token
|
||||
|
||||
if (_token == null) {
|
||||
throw Exception('Token not found. Please log in.');
|
||||
}
|
||||
// if (_token == null) {
|
||||
// throw Exception('Token not found. Please log in.');
|
||||
// }
|
||||
|
||||
if (_token == null) {
|
||||
await _initializeToken();
|
||||
}
|
||||
print("getCommissionRateList 2");
|
||||
print("data------- $data}");
|
||||
|
||||
final headers = {
|
||||
@ -1526,7 +1742,7 @@ class ApiService {
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> getCreateOrUpdate(data) async {
|
||||
final url = Uri.parse('${Env.apiUrl}/invoice/create-or-update');
|
||||
final url = Uri.parse('${Env.apiUrl}invoice/create-or-update');
|
||||
|
||||
// final token = await getToken(); // Fetch token
|
||||
|
||||
@ -1666,4 +1882,50 @@ class ApiService {
|
||||
final response = await _makePostRequestJson(url, data, headers);
|
||||
return response;
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> calculateCommissionRequest(data) async {
|
||||
final url = Uri.parse('${Env.apiUrl}policy/calculateCommissionRequest');
|
||||
|
||||
// final token = await getToken(); // Fetch token
|
||||
|
||||
if (_token == null) {
|
||||
throw Exception('Token not found. Please log in.');
|
||||
}
|
||||
|
||||
print("data------- $data}");
|
||||
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $_token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': Env.App_Signature,
|
||||
// 'app-signature': 'nhance-partner-2025-signature-35468846JRhH551HK',
|
||||
};
|
||||
|
||||
final response = await _makePostRequestJson(url, data, headers);
|
||||
return response;
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> fetchPolicyMasterDropDown(String val) async {
|
||||
// print(_token);
|
||||
if (_token == null) {
|
||||
await _initializeToken();
|
||||
}
|
||||
|
||||
print('VAl - $val');
|
||||
|
||||
dynamic url;
|
||||
|
||||
if (val == 'fuelType') {
|
||||
url = Uri.parse('${Env.apiUrl}policy/fuelTypeMaster');
|
||||
} else if (val == 'vehicleType') {
|
||||
url = Uri.parse('${Env.apiUrl}policy/vehicleTypeMaster');
|
||||
}
|
||||
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $_token' ?? '',
|
||||
'app-signature': Env.App_Signature,
|
||||
};
|
||||
final response = await _makeGetRequest(url, headers);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,8 +67,8 @@ class _AppHeaderState extends ConsumerState<AppHeader> {
|
||||
} else if (currentRoute.contains('broker') ||
|
||||
currentRoute.contains('payment')) {
|
||||
_activeMenu = 'Masters';
|
||||
} else if (currentRoute.contains('invoice')) {
|
||||
_activeMenu = 'Pay Out';
|
||||
} else if (currentRoute.contains('payout')) {
|
||||
_activeMenu = 'Invoice';
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -155,6 +155,15 @@ class _AppHeaderState extends ConsumerState<AppHeader> {
|
||||
context.go(AppRoutes.salesExecutiveLst);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
_buildPopupItem(
|
||||
label: "POS",
|
||||
onTap: () {
|
||||
_hidePopup();
|
||||
setState(() => _activeMenu = 'User');
|
||||
context.go(AppRoutes.posLst);
|
||||
},
|
||||
),
|
||||
],
|
||||
if (key == 'Reports') ...[
|
||||
if (role == 'manager') ...[
|
||||
@ -330,12 +339,12 @@ class _AppHeaderState extends ConsumerState<AppHeader> {
|
||||
// Pay Out button for Accounts
|
||||
if (role == 'Accounts') ...[
|
||||
_buildMenuItem(
|
||||
isActive: _activeMenu == 'Pay Out',
|
||||
isActive: _activeMenu == 'Invoice',
|
||||
icon: Icons.checklist_outlined,
|
||||
label: "Pay Out",
|
||||
label: "Invoice",
|
||||
onTap: () async {
|
||||
_hidePopup();
|
||||
setState(() => _activeMenu = 'Pay Out');
|
||||
setState(() => _activeMenu = 'Invoice');
|
||||
await _clearDashboardFilters();
|
||||
context.go(AppRoutes.invoiceList);
|
||||
},
|
||||
|
||||
@ -12,6 +12,7 @@ import 'package:http/http.dart' as http;
|
||||
import 'package:nhance_partner/core/routing/routes.dart';
|
||||
import 'package:nhance_partner/data/utils/toastNotification.dart';
|
||||
import 'package:nhance_partner/presentation/themes/indicators/text_field_theme.dart';
|
||||
import 'package:nhance_partner/presentation/themes/indicators/text_field_theme_inline_editor.dart';
|
||||
|
||||
import '../../../../core/config/env.dart';
|
||||
import '../../../../core/services/api_service.dart';
|
||||
@ -69,7 +70,11 @@ class BrokerState extends ConsumerState<Broker> {
|
||||
dynamic managerId;
|
||||
|
||||
Map<String, dynamic> dataDetails() {
|
||||
final data = {"name": controllers["name"]?.text, "is_active": isActive};
|
||||
final data = {
|
||||
"name": controllers["name"]?.text,
|
||||
"short_name": controllers["code"]?.text,
|
||||
"is_active": isActive,
|
||||
};
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -108,12 +113,16 @@ class BrokerState extends ConsumerState<Broker> {
|
||||
setState(() {
|
||||
selectedId = id;
|
||||
controllers['name']?.text = data['name'] ?? '';
|
||||
controllers['code']?.text = data['short_name'] ?? '';
|
||||
controllers["is_active"]?.text = data['is_active'].toString();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> handleSave() async {
|
||||
// if (controllers['name'] != null && controllers['name'] != '') {
|
||||
// return;
|
||||
// }
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
setState(() {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
@ -185,17 +194,12 @@ class BrokerState extends ConsumerState<Broker> {
|
||||
print("Broker submitted successfully!");
|
||||
print("Response: ${response.body}");
|
||||
|
||||
if(responseBody['status'] == 200){
|
||||
if (responseBody['status'] == 200) {
|
||||
refresh();
|
||||
isUpdating
|
||||
? ToastHelper.showSuccessToast(
|
||||
context,message
|
||||
)
|
||||
: ToastHelper.showSuccessToast(
|
||||
context,message,
|
||||
);
|
||||
? ToastHelper.showSuccessToast(context, message)
|
||||
: ToastHelper.showSuccessToast(context, message);
|
||||
} else {
|
||||
|
||||
print("Failed to submit plan. Status: ${response.statusCode}");
|
||||
print("Error: ${response.body}");
|
||||
|
||||
@ -281,7 +285,9 @@ class BrokerState extends ConsumerState<Broker> {
|
||||
Widget buildFormFields() {
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: Column(children: [buildName()]),
|
||||
child: Row(
|
||||
children: [buildName(), SizedBox(width: 10), buildShortName()],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -291,13 +297,39 @@ class BrokerState extends ConsumerState<Broker> {
|
||||
children: [
|
||||
Text("Broker *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
ThemedFormField(
|
||||
controller: controllers['name']!,
|
||||
validator: (value) => Validators.requiredField(value, "name"),
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.15,
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
highlightColor: Color(0xFF50A398),
|
||||
txtheight: 30,
|
||||
SizedBox(
|
||||
child: ThemedFormInlineField(
|
||||
controller: controllers['name']!,
|
||||
validator: (value) => Validators.requiredField(value, "name"),
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.15,
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
highlightColor: Color(0xFF50A398),
|
||||
// txtheight: 30,
|
||||
isdense: true,
|
||||
errFieldHgt: 0,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildShortName() {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Broker Code *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(
|
||||
child: ThemedFormInlineField(
|
||||
controller: controllers['code']!,
|
||||
validator: (value) => Validators.requiredField(value, "code"),
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.15,
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
highlightColor: Color(0xFF50A398),
|
||||
// txtheight: 30,
|
||||
isdense: true,
|
||||
errFieldHgt: 0,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@ -283,9 +283,13 @@ class BrokerListState extends ConsumerState<BrokerList> {
|
||||
child: Text('S.No.', style: _headerStyle),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
flex: 1,
|
||||
child: Text('Broker', style: _headerStyle),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text('Broker Code', style: _headerStyle),
|
||||
),
|
||||
|
||||
Expanded(
|
||||
flex: 1,
|
||||
@ -383,7 +387,11 @@ class BrokerListState extends ConsumerState<BrokerList> {
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(flex: 1, child: Text('$sno' ?? '-', style: _dataBold)),
|
||||
Expanded(flex: 2, child: Text(item['name'] ?? '-', style: _dataBold)),
|
||||
Expanded(flex: 1, child: Text(item['name'] ?? '-', style: _dataBold)),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(item['short_name'] ?? '-', style: _dataBold),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Row(
|
||||
@ -466,17 +474,16 @@ class BrokerListState extends ConsumerState<BrokerList> {
|
||||
);
|
||||
}
|
||||
|
||||
static final _dataBold = GoogleFonts.inter(
|
||||
fontSize: 11.5,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Color(0xFF000000),
|
||||
);
|
||||
|
||||
static final _dataSub = GoogleFonts.inter(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w300,
|
||||
color: Color(0xFF585757),
|
||||
);
|
||||
static final _dataBold = GoogleFonts.inter(
|
||||
fontSize: 11.5,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Color(0xFF000000),
|
||||
);
|
||||
|
||||
static final _headerStyle = GoogleFonts.poppins(
|
||||
fontSize: 11.2,
|
||||
|
||||
@ -114,6 +114,12 @@ class PaymentState extends ConsumerState<Payment> {
|
||||
}
|
||||
|
||||
Future<void> handleSave() async {
|
||||
if (controllers['value'] == null ||
|
||||
controllers['value']!.text.trim().isEmpty) {
|
||||
ToastHelper.showWarningToast(context, "Payment Mode is required");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
setState(() {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
@ -194,38 +200,33 @@ class PaymentState extends ConsumerState<Payment> {
|
||||
print("Response: ${response.body}");
|
||||
print(message);
|
||||
|
||||
if(responseBody['status'] == 200){
|
||||
refresh();
|
||||
isUpdating
|
||||
? ToastHelper.showSuccessToast(
|
||||
context,message,
|
||||
)
|
||||
: ToastHelper.showSuccessToast(
|
||||
context,message,
|
||||
);
|
||||
} else {
|
||||
print("Failed to submit plan. Status: ${response.statusCode}");
|
||||
print("Error: ${response.body}");
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text("Payment Creation Failed"),
|
||||
content: Text(message),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text("OK"),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
if (responseBody['status'] == 200) {
|
||||
refresh();
|
||||
isUpdating
|
||||
? ToastHelper.showSuccessToast(context, message)
|
||||
: ToastHelper.showSuccessToast(context, message);
|
||||
} else {
|
||||
print("Failed to submit plan. Status: ${response.statusCode}");
|
||||
print("Error: ${response.body}");
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text("Payment Creation Failed"),
|
||||
content: Text(message),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text("OK"),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
} else if (response.statusCode == 403) {
|
||||
await apiService.clearLocalStorageAndRedirect();
|
||||
}
|
||||
@ -302,11 +303,13 @@ class PaymentState extends ConsumerState<Payment> {
|
||||
SizedBox(width: 10),
|
||||
ThemedFormField(
|
||||
controller: controllers['value']!,
|
||||
validator: (value) => Validators.requiredField(value, "value"),
|
||||
// validator: (value) => Validators.requiredField(value, "value"),
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.15,
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
highlightColor: Color(0xFF50A398),
|
||||
txtheight: 30,
|
||||
isdense: true,
|
||||
errFieldFont: 0,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@ -35,7 +35,9 @@ import 'package:universal_html/html.dart' as html;
|
||||
|
||||
class Agent extends ConsumerStatefulWidget {
|
||||
final String? id;
|
||||
const Agent({super.key, this.id});
|
||||
final void Function(String value) onSubmit;
|
||||
const Agent({super.key, this.id, required this.onSubmit});
|
||||
|
||||
@override
|
||||
ConsumerState<Agent> createState() => AgentState();
|
||||
}
|
||||
@ -43,7 +45,14 @@ class Agent extends ConsumerStatefulWidget {
|
||||
class AgentState extends ConsumerState<Agent> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
late ApiService apiService;
|
||||
List<String> tabHeader = ['name', 'email', 'mobile', 'code', 'address'];
|
||||
List<String> tabHeader = [
|
||||
'name',
|
||||
'email',
|
||||
'mobile',
|
||||
'code',
|
||||
'address',
|
||||
'retenRate',
|
||||
];
|
||||
late String isActive = "1";
|
||||
// html.File? docUploadedFile;
|
||||
// PlatformFile? passportFile;
|
||||
@ -73,6 +82,7 @@ class AgentState extends ConsumerState<Agent> {
|
||||
"mobile": controllers["mobile"]?.text,
|
||||
"address": controllers["address"]?.text,
|
||||
"agent_code": controllers["code"]?.text,
|
||||
"retention_rate": controllers["retenRate"]?.text,
|
||||
'sales_executive_id': selectedSalesExectv,
|
||||
"is_active": isActive,
|
||||
"manager_id": managerId,
|
||||
@ -85,6 +95,8 @@ class AgentState extends ConsumerState<Agent> {
|
||||
super.initState();
|
||||
apiService = ApiService();
|
||||
|
||||
print('AGID - ${widget.id}');
|
||||
|
||||
for (String field in tabHeader) {
|
||||
controllers[field] = TextEditingController();
|
||||
}
|
||||
@ -156,8 +168,10 @@ class AgentState extends ConsumerState<Agent> {
|
||||
controllers['mobile']?.text = data['mobile'] ?? '';
|
||||
controllers['code']?.text = data['agent_code'] ?? '';
|
||||
controllers['address']?.text = data['address'] ?? '';
|
||||
controllers['retenRate']?.text = data['retention_rate'] ?? '';
|
||||
isActive = data["is_active"];
|
||||
selectedSalesExectv = data['sales_executive_id'] ?? '';
|
||||
print('selectedSalesExectv - $selectedSalesExectv');
|
||||
|
||||
String? apiDocPath = data["certificate_file_name"];
|
||||
if (apiDocPath != null && apiDocPath.isNotEmpty) {
|
||||
@ -182,7 +196,7 @@ class AgentState extends ConsumerState<Agent> {
|
||||
final email = controllers['email']!.text.trim();
|
||||
final phone = controllers['mobile']!.text.trim();
|
||||
|
||||
// 🔴 Conditional validation: at least one required
|
||||
// Conditional validation: at least one required
|
||||
if (email.isEmpty && phone.isEmpty) {
|
||||
ToastHelper.showSuccessToast(
|
||||
context,
|
||||
@ -317,7 +331,11 @@ class AgentState extends ConsumerState<Agent> {
|
||||
context,
|
||||
'Partner Created Successfully',
|
||||
);
|
||||
context.go(AppRoutes.agentLst);
|
||||
|
||||
Navigator.of(context).pop();
|
||||
|
||||
widget.onSubmit("success");
|
||||
// context.go(AppRoutes.agentLst);
|
||||
} else if (response.statusCode == 403) {
|
||||
await apiService.clearLocalStorageAndRedirect();
|
||||
} else {
|
||||
@ -395,11 +413,12 @@ class AgentState extends ConsumerState<Agent> {
|
||||
Widget build(BuildContext context) {
|
||||
// managerId = ref.watch(managerIdProvider);
|
||||
// userId = ref.watch(userProvider);
|
||||
return MainLayout(
|
||||
title: "Partner",
|
||||
body: Container(
|
||||
return AlertDialog(
|
||||
backgroundColor: Colors.white,
|
||||
content: Container(
|
||||
// color: Colors.yellow.shade50,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
width: MediaQuery.of(context).size.width * 0.62,
|
||||
height: MediaQuery.of(context).size.height * 0.7,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
@ -407,7 +426,7 @@ class AgentState extends ConsumerState<Agent> {
|
||||
Container(
|
||||
// height: 30,
|
||||
// color: Colors.red.shade50,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
width: MediaQuery.of(context).size.width * 0.8,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
context.go(AppRoutes.agentLst);
|
||||
@ -416,24 +435,24 @@ class AgentState extends ConsumerState<Agent> {
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Tooltip(
|
||||
message: 'Back',
|
||||
child: IconButton(
|
||||
icon: const Icon(
|
||||
Icons.arrow_left_sharp,
|
||||
size: 25,
|
||||
color: Color(0xFF425B5B),
|
||||
),
|
||||
onPressed: () {
|
||||
context.go(AppRoutes.agentLst);
|
||||
},
|
||||
splashRadius: 18,
|
||||
hoverColor: Colors.black12,
|
||||
padding: const EdgeInsets.all(4),
|
||||
constraints: const BoxConstraints(),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5), // spacing between icon and text
|
||||
// Tooltip(
|
||||
// message: 'Back',
|
||||
// child: IconButton(
|
||||
// icon: const Icon(
|
||||
// Icons.arrow_left_sharp,
|
||||
// size: 25,
|
||||
// color: Color(0xFF425B5B),
|
||||
// ),
|
||||
// onPressed: () {
|
||||
// context.go(AppRoutes.agentLst);
|
||||
// },
|
||||
// splashRadius: 18,
|
||||
// hoverColor: Colors.black12,
|
||||
// padding: const EdgeInsets.all(4),
|
||||
// constraints: const BoxConstraints(),
|
||||
// ),
|
||||
// ),
|
||||
const SizedBox(width: 15), // spacing between icon and text
|
||||
Text(
|
||||
"Partner",
|
||||
style: GoogleFonts.poppins(
|
||||
@ -441,16 +460,32 @@ class AgentState extends ConsumerState<Agent> {
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF1F1F1),
|
||||
borderRadius: BorderRadius.circular(5.0),
|
||||
),
|
||||
child: Tooltip(
|
||||
message: 'Close',
|
||||
child: const Icon(Icons.close, size: 18),
|
||||
),
|
||||
),
|
||||
),
|
||||
// const SizedBox(width: 15),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
// SizedBox(height: 10),
|
||||
Expanded(
|
||||
child: Container(
|
||||
// color: Colors.green,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
margin: EdgeInsets.all(8.0),
|
||||
// width: MediaQuery.of(context).size.width,
|
||||
// margin: EdgeInsets.all(8.0),
|
||||
padding: EdgeInsets.symmetric(horizontal: 14.0, vertical: 20.0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
@ -459,7 +494,7 @@ class AgentState extends ConsumerState<Agent> {
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(children: [Expanded(child: buildFormFields())]),
|
||||
Row(children: [buildFormFields()]),
|
||||
Spacer(),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
@ -507,39 +542,42 @@ class AgentState extends ConsumerState<Agent> {
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: buildName()),
|
||||
buildName(),
|
||||
SizedBox(width: 25),
|
||||
Expanded(child: buildEmail()),
|
||||
buildEmail(),
|
||||
SizedBox(width: 25),
|
||||
buildPhNumber(),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: buildPhNumber()),
|
||||
buildId(),
|
||||
SizedBox(width: 25),
|
||||
Expanded(child: buildId()),
|
||||
buildSalesExecutive(context),
|
||||
SizedBox(width: 25),
|
||||
buildRetentionRate(context),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(child: buildSalesExecutive(context)),
|
||||
buildAddress(),
|
||||
SizedBox(width: 25),
|
||||
Expanded(child: buildAddress()),
|
||||
buildUploadDocument(),
|
||||
SizedBox(width: 25),
|
||||
|
||||
// Expanded(child: SizedBox.shrink()),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: buildUploadDocument()),
|
||||
SizedBox(width: 25),
|
||||
Expanded(child: SizedBox.shrink()),
|
||||
],
|
||||
),
|
||||
// Row(
|
||||
// Column(
|
||||
// children: [
|
||||
// Expanded(child: buildIncentiveFile()),
|
||||
// SizedBox(width: 25),
|
||||
@ -552,28 +590,29 @@ class AgentState extends ConsumerState<Agent> {
|
||||
}
|
||||
|
||||
Widget buildName() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text("Full Name *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
ThemedFormField(
|
||||
controller: controllers['name']!,
|
||||
validator: (value) => Validators.requiredField(value, "name"),
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
highlightColor: Color(0xFF50A398),
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildEmail() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Email *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
ThemedFormField(
|
||||
controller: controllers['email']!,
|
||||
validator: (value) {
|
||||
@ -591,18 +630,18 @@ class AgentState extends ConsumerState<Agent> {
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_@.]')),
|
||||
],
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildPhNumber() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Phone Number *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
ThemedFormField(
|
||||
controller: controllers['mobile']!,
|
||||
validator: (value) {
|
||||
@ -621,18 +660,18 @@ class AgentState extends ConsumerState<Agent> {
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
|
||||
],
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildId() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Partner Id *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
ThemedFormField(
|
||||
controller: controllers['code']!,
|
||||
inputFormatters: [
|
||||
@ -641,23 +680,55 @@ class AgentState extends ConsumerState<Agent> {
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
highlightColor: Color(0xFF50A398),
|
||||
validator: (value) => Validators.requiredField(value, "id"),
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildRetentionRate(context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Retention Rate*", style: _textStyle),
|
||||
SizedBox(height: 10),
|
||||
ThemedFormField(
|
||||
controller: controllers['retenRate']!,
|
||||
inputFormatters: [
|
||||
TextInputFormatter.withFunction((oldValue, newValue) {
|
||||
if (newValue.text.isEmpty) return newValue;
|
||||
|
||||
final value = double.tryParse(newValue.text);
|
||||
if (value == null) return oldValue;
|
||||
|
||||
// Allow only values <= 10
|
||||
if (value <= 10) {
|
||||
return newValue;
|
||||
}
|
||||
return oldValue;
|
||||
}),
|
||||
],
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
highlightColor: Color(0xFF50A398),
|
||||
validator: (value) => Validators.requiredField(value, "id"),
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildAddress() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Address", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
ThemedFormField(
|
||||
controller: controllers['address']!,
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
highlightColor: Color(0xFF50A398),
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[ a-zA-Z0-9_#/.]')),
|
||||
],
|
||||
@ -669,17 +740,20 @@ class AgentState extends ConsumerState<Agent> {
|
||||
Widget buildSalesExecutive(BuildContext context) {
|
||||
Map<String, dynamic>? selectedroleVal = filteredSalesExecutiveData
|
||||
.firstWhere(
|
||||
(item) => item['id'].toString() == selectedSalesExectv,
|
||||
(item) => item['id'] == selectedSalesExectv,
|
||||
orElse: () => {},
|
||||
);
|
||||
|
||||
final isReadOnly = widget.id != null;
|
||||
print('selectedroleVal - $selectedroleVal');
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
final isReadOnly = false;
|
||||
// final isReadOnly = widget.id != null;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Sales Executive *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
// color: Colors.white,
|
||||
@ -687,7 +761,7 @@ class AgentState extends ConsumerState<Agent> {
|
||||
),
|
||||
width: ResponsiveLayout.isMobile(context)
|
||||
? null
|
||||
: MediaQuery.of(context).size.width * 0.26,
|
||||
: MediaQuery.of(context).size.width * 0.18,
|
||||
// height: 40,
|
||||
child: AbsorbPointer(
|
||||
absorbing: isReadOnly,
|
||||
@ -815,11 +889,11 @@ class AgentState extends ConsumerState<Agent> {
|
||||
}
|
||||
|
||||
Widget buildUploadDocument() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Upload Certificate", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
@ -827,7 +901,8 @@ class AgentState extends ConsumerState<Agent> {
|
||||
children: [
|
||||
ThemedUploadField(
|
||||
hintText: selectedFileNames ?? "Upload Document",
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
txtheight: 45,
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
// highlightColor: Color(0xFF50A398),
|
||||
onFileSelected: (fileName, file) {
|
||||
@ -842,7 +917,7 @@ class AgentState extends ConsumerState<Agent> {
|
||||
if (docUploadedFile != null || passportFileUrlFromApi != null)
|
||||
Container(
|
||||
// color: Colors.white,
|
||||
child: Row(
|
||||
child: Column(
|
||||
children: [
|
||||
// IconButton(
|
||||
// onPressed: () {
|
||||
@ -873,7 +948,7 @@ class AgentState extends ConsumerState<Agent> {
|
||||
// color: Color(0xFF425B5B),
|
||||
// color: Colors.green.shade300,
|
||||
),
|
||||
child: Row(
|
||||
child: Column(
|
||||
children: const [
|
||||
Text(
|
||||
"Download",
|
||||
@ -901,7 +976,7 @@ class AgentState extends ConsumerState<Agent> {
|
||||
// children: [
|
||||
// ThemedUploadField(
|
||||
// hintText: selectedFileNames ?? "Upload Document",
|
||||
// txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
// txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
//
|
||||
// onFileSelected: (fileName, file) {
|
||||
// // print("File picked: ${fileName}");
|
||||
@ -920,7 +995,7 @@ class AgentState extends ConsumerState<Agent> {
|
||||
// // Centers the text
|
||||
// Container(
|
||||
// color: Colors.white,
|
||||
// child: Row(
|
||||
// child: Column(
|
||||
// mainAxisAlignment: MainAxisAlignment.end,
|
||||
// crossAxisAlignment: CrossAxisAlignment.end,
|
||||
// children: [
|
||||
@ -1009,7 +1084,7 @@ class AgentState extends ConsumerState<Agent> {
|
||||
// borderRadius: BorderRadius.circular(5),
|
||||
// color: Colors.green.shade300,
|
||||
// ),
|
||||
// child: Row(
|
||||
// child: Column(
|
||||
// mainAxisAlignment: MainAxisAlignment.end,
|
||||
// crossAxisAlignment: CrossAxisAlignment.end,
|
||||
// children: [
|
||||
|
||||
@ -15,6 +15,7 @@ import '../../../themes/indicators/filter_btn.dart';
|
||||
import '../../../themes/indicators/search_field_theme.dart';
|
||||
import '../../../themes/indicators/text_field_theme.dart';
|
||||
import '../../../widgets/custom_action_popup.dart';
|
||||
import 'agent.dart';
|
||||
import 'agentIncentiveFile.dart';
|
||||
|
||||
class AgentList extends ConsumerStatefulWidget {
|
||||
@ -28,12 +29,14 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
int itemsPerPage = 10;
|
||||
late ApiService apiService;
|
||||
dynamic managerId;
|
||||
dynamic selected_id;
|
||||
// List<Map<String, dynamic>> dataVal = [];
|
||||
List<Map<String, dynamic>> getAgentData = [];
|
||||
List<Map<String, dynamic>> originalData = [];
|
||||
List<Map<String, dynamic>> filteredData = [];
|
||||
bool isLoading = false;
|
||||
dynamic sortedData;
|
||||
dynamic managerID;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -41,13 +44,19 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
// getAgentList();
|
||||
|
||||
Future.microtask(() {
|
||||
final id = ref.read(managerIdProvider);
|
||||
if (id != null) {
|
||||
getAgentList(id);
|
||||
managerID = ref.read(managerIdProvider);
|
||||
if (managerID != null) {
|
||||
getAgentList(managerID);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void refresh() {
|
||||
if (managerID != null) {
|
||||
getAgentList(managerID);
|
||||
}
|
||||
}
|
||||
|
||||
// @override
|
||||
// void didChangeDependencies() {
|
||||
// super.didChangeDependencies();
|
||||
@ -162,6 +171,20 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
];
|
||||
}
|
||||
|
||||
Future<void> showAgent({required String id}) {
|
||||
print('showAgent : $id');
|
||||
return showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => Agent(
|
||||
id: id,
|
||||
onSubmit: (value) {
|
||||
debugPrint("New Claims: $value");
|
||||
refresh();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
managerId = ref.watch(managerIdProvider);
|
||||
@ -301,6 +324,7 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
'Email',
|
||||
'Phone Number',
|
||||
'Id',
|
||||
'Retention Rate',
|
||||
'Address',
|
||||
'Status',
|
||||
],
|
||||
@ -310,6 +334,7 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
"email",
|
||||
"mobile",
|
||||
"agent_code",
|
||||
"retention_rate",
|
||||
"address",
|
||||
"is_active",
|
||||
],
|
||||
@ -318,7 +343,8 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
SizedBox(width: 10),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
context.go('/agent/create');
|
||||
// context.go('/agent/create');
|
||||
showAgent(id: 'Create');
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5.0),
|
||||
@ -391,6 +417,13 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
flex: 1,
|
||||
child: Text('Id', style: _headerStyle),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
'Retention Rate ',
|
||||
style: _headerStyle,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text('Address', style: _headerStyle),
|
||||
@ -511,6 +544,10 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
flex: 1,
|
||||
child: Text(item['agent_code'] ?? '-', style: _dataBold),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(item['retention_rate'] ?? '-', style: _dataBold),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
@ -567,8 +604,10 @@ class AgentListState extends ConsumerState<AgentList> {
|
||||
),
|
||||
onPressed: () {
|
||||
print('EDITStaff - ${item['id']}');
|
||||
dynamic id = item['id'];
|
||||
context.go('/agent/$id');
|
||||
selected_id = item['id'];
|
||||
|
||||
showAgent(id: selected_id);
|
||||
// context.go('/agent/$selected_id');
|
||||
},
|
||||
splashRadius: 28,
|
||||
hoverColor: Colors.black12,
|
||||
|
||||
569
lib/presentation/screens/UserManagement/POS/pos_list.dart
Normal file
569
lib/presentation/screens/UserManagement/POS/pos_list.dart
Normal file
@ -0,0 +1,569 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
|
||||
|
||||
import '../../../../core/routing/routes.dart';
|
||||
import '../../../../core/services/api_service.dart';
|
||||
import '../../../../data/utils/Pagination.dart';
|
||||
import '../../../layouts/main_layout.dart';
|
||||
import '../../../layouts/responsive_layout.dart';
|
||||
import '../../../providers/manager_provider.dart';
|
||||
import '../../../themes/indicators/export_btn.dart';
|
||||
import '../../../themes/indicators/filter_btn.dart';
|
||||
import '../../../themes/indicators/search_field_theme.dart';
|
||||
import '../../../themes/indicators/text_field_theme.dart';
|
||||
import '../../../widgets/custom_action_popup.dart';
|
||||
|
||||
class PosList extends ConsumerStatefulWidget {
|
||||
const PosList({super.key});
|
||||
@override
|
||||
ConsumerState<PosList> createState() => PosListState();
|
||||
}
|
||||
|
||||
class PosListState extends ConsumerState<PosList> {
|
||||
int currentPage = 1;
|
||||
int itemsPerPage = 10;
|
||||
late ApiService apiService;
|
||||
dynamic managerId;
|
||||
dynamic role;
|
||||
dynamic prefid;
|
||||
// List<Map<String, dynamic>> dataVal = [];
|
||||
List<Map<String, dynamic>> getStaffData = [];
|
||||
List<Map<String, dynamic>> originalData = [];
|
||||
List<Map<String, dynamic>> filteredData = [];
|
||||
bool isLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
apiService = ApiService();
|
||||
|
||||
Future.microtask(() {
|
||||
final data1 = ref.read(managerIdProvider);
|
||||
|
||||
prefid = data1;
|
||||
// role = ref.read(userRoleProvider);
|
||||
// print("E43 => mId: $prefid");
|
||||
// print("roleSTAFFLIST: $role");
|
||||
if (prefid != null) {
|
||||
getPosList(prefid);
|
||||
}
|
||||
});
|
||||
// getPosList();
|
||||
}
|
||||
//
|
||||
// @override
|
||||
// void didChangeDependencies() {
|
||||
// super.didChangeDependencies();
|
||||
// final id = ref.watch(managerIdProvider);
|
||||
// if (id != null) {
|
||||
// getPosList(id);
|
||||
// }
|
||||
// }
|
||||
|
||||
List<dynamic> get _paginatedData {
|
||||
// Sort descending by id first
|
||||
final sortedData = [...filteredData]
|
||||
..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
|
||||
|
||||
if (sortedData.isEmpty) return [];
|
||||
|
||||
// Ensure currentPage is valid
|
||||
final maxPage = (sortedData.length / itemsPerPage).ceil();
|
||||
final safePage = currentPage.clamp(1, maxPage);
|
||||
|
||||
final startIndex = (safePage - 1) * itemsPerPage;
|
||||
final endIndex = (startIndex + itemsPerPage).clamp(0, sortedData.length);
|
||||
|
||||
return sortedData.sublist(startIndex, endIndex);
|
||||
}
|
||||
|
||||
// void filterData(String query) {
|
||||
// print("FilterDAta - $query");
|
||||
// setState(() {
|
||||
// filteredData = getStaffData.where((item) {
|
||||
// final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive";
|
||||
//
|
||||
// return (item['name'] ?? '-').toLowerCase().contains(
|
||||
// query.toLowerCase(),
|
||||
// ) ||
|
||||
// (item['email'] ?? '-').toLowerCase().contains(
|
||||
// query.toLowerCase(),
|
||||
// ) ||
|
||||
// (item['mobile'] ?? '-').toLowerCase().contains(
|
||||
// query.toLowerCase(),
|
||||
// ) ||
|
||||
// (item['address'] ?? '-').toLowerCase().contains(
|
||||
// query.toLowerCase(),
|
||||
// ) ||
|
||||
// (item['emp_id'] ?? item['agent_code'] ?? '-')
|
||||
// .toLowerCase()
|
||||
// .contains(query.toLowerCase()) ||
|
||||
// isActiveStatus.contains(query.toLowerCase());
|
||||
// }).toList();
|
||||
// });
|
||||
// }
|
||||
|
||||
void filterData(String query) {
|
||||
setState(() {
|
||||
final q = query.toLowerCase();
|
||||
|
||||
if (q.isEmpty) {
|
||||
filteredData = getStaffData;
|
||||
return;
|
||||
}
|
||||
|
||||
filteredData = getStaffData.where((item) {
|
||||
final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive";
|
||||
|
||||
return (item['name'] ?? '').toString().toLowerCase().contains(q) ||
|
||||
(item['email'] ?? '').toString().toLowerCase().contains(q) ||
|
||||
(item['mobile'] ?? '').toString().toLowerCase().contains(q) ||
|
||||
(item['address'] ?? '').toString().toLowerCase().contains(q) ||
|
||||
(item['emp_id'] ?? item['agent_code'] ?? '')
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.contains(q) ||
|
||||
isActiveStatus.contains(q);
|
||||
}).toList();
|
||||
});
|
||||
}
|
||||
|
||||
final TextEditingController _searchStaffController = TextEditingController();
|
||||
|
||||
Future<void> getPosList(int id) async {
|
||||
print('E104 => Fns called => $id');
|
||||
|
||||
final val = 'list';
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
|
||||
try {
|
||||
final response = await apiService.fetchPosList(id, val);
|
||||
|
||||
if (response['status'] == 200) {
|
||||
print('E113 => getStaffListData => ${response['data']}');
|
||||
setState(() {
|
||||
getStaffData = List<Map<String, dynamic>>.from(response['data']);
|
||||
originalData = getStaffData;
|
||||
filteredData = List.from(originalData);
|
||||
// print('originalData - $getClaimPolicies');
|
||||
});
|
||||
} else {
|
||||
getStaffData = [];
|
||||
originalData = [];
|
||||
}
|
||||
} catch (e) {
|
||||
print('Exception occurred: $e');
|
||||
} finally {
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
List<Widget> _buildPopupMenuActions(BuildContext context, dynamic data) {
|
||||
return [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
print('EDITStaff - ${data['id']}');
|
||||
dynamic id = data['id'];
|
||||
context.go('/pos/$id');
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Icons.edit_sharp, color: Color(0xFF319718), size: 18),
|
||||
SizedBox(width: 10),
|
||||
Text('Edit'),
|
||||
],
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
managerId = ref.watch(managerIdProvider);
|
||||
|
||||
return MainLayout(
|
||||
title: "Pos",
|
||||
body: Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
// color: Colors.green,
|
||||
// color: Colors.green.shade50,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
// margin: EdgeInsets.all(10.0),
|
||||
decoration: BoxDecoration(
|
||||
// color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(15.0),
|
||||
),
|
||||
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
// height: 40,
|
||||
// color: Colors.pink,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'POS',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
ThemedSearchField(
|
||||
hintText: 'Search',
|
||||
// backgroundColor: Color(0xFFF6F8F8),
|
||||
backgroundColor: Color(0xFFFFFFFF),
|
||||
txtHeight: 30,
|
||||
onChanged: filterData,
|
||||
controller: _searchStaffController,
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.15,
|
||||
),
|
||||
|
||||
SizedBox(width: 10),
|
||||
ExportBtn(
|
||||
sheetName: "POS",
|
||||
fileName: "pos_list",
|
||||
txt: !ResponsiveLayout.isMobile(context)
|
||||
? true
|
||||
: false,
|
||||
data: filteredData,
|
||||
displayHeaders: [
|
||||
'S.No.',
|
||||
'Pos Name',
|
||||
'Code',
|
||||
'Email',
|
||||
'Mobile',
|
||||
'Bank',
|
||||
'Aadhar',
|
||||
'PAN',
|
||||
],
|
||||
keys: [
|
||||
"sno", // handled internally as i + 1
|
||||
"name",
|
||||
"pos_code",
|
||||
"email",
|
||||
"mobile",
|
||||
"bank_name",
|
||||
"aadhar",
|
||||
"pan",
|
||||
// "is_active",
|
||||
],
|
||||
),
|
||||
|
||||
// SizedBox(width: 10),
|
||||
// InkWell(
|
||||
// onTap: () {
|
||||
// context.go('/pos/create');
|
||||
// },
|
||||
// child: Container(
|
||||
// padding: EdgeInsets.all(4.8),
|
||||
// decoration: BoxDecoration(
|
||||
// color: const Color(0xFF2E7D6E),
|
||||
// borderRadius: BorderRadius.circular(8.0),
|
||||
// ),
|
||||
// child: Row(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// Tooltip(
|
||||
// message: 'Create Pos',
|
||||
// child: Icon(
|
||||
// Icons.add,
|
||||
// color: Colors.white,
|
||||
// size: 18,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xFFF1F5F9),
|
||||
|
||||
// color: Color(0xFFEDF6F5),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10,
|
||||
horizontal: 16,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text('S.No.', style: _headerStyle),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text('Name', style: _headerStyle),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text('Code', style: _headerStyle),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text('Email', style: _headerStyle),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text('Mobile', style: _headerStyle),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text('Bank', style: _headerStyle),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text('Aadhar', style: _headerStyle),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text('PAN', style: _headerStyle),
|
||||
),
|
||||
|
||||
// Expanded(
|
||||
// flex: 1,
|
||||
// child: Text('Status', style: _headerStyle),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(child: _buildDataTable(context)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Container(
|
||||
// height: 20,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
// color: Colors.green.shade50,
|
||||
child: PaginationControls(
|
||||
currentPage: currentPage,
|
||||
itemsPerPage: itemsPerPage,
|
||||
// totalItems: dataVal.length,
|
||||
totalItems: filteredData.length,
|
||||
// activeColor: layoutColor, // your theme color
|
||||
onPageChanged: (page) {
|
||||
setState(() {
|
||||
currentPage = page;
|
||||
});
|
||||
},
|
||||
onItemsPerPageChanged: (items) {
|
||||
setState(() {
|
||||
itemsPerPage = items;
|
||||
currentPage = 1;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDataTable(BuildContext context) {
|
||||
if (filteredData.isEmpty) {
|
||||
return const SizedBox(
|
||||
height: 50,
|
||||
child: Center(child: Text('No available data')),
|
||||
);
|
||||
}
|
||||
|
||||
final sortedData = [..._paginatedData];
|
||||
|
||||
return ListView.builder(
|
||||
// itemCount: filteredData.length + 1, // +1 for header, +1 for pagination
|
||||
itemCount: sortedData.length + 1, // +1 for header, +1 for pagination
|
||||
itemBuilder: (context, index) {
|
||||
if (index == 0) return _buildHeader();
|
||||
// if (index == dataVal.length + 1)
|
||||
// return _buildPagination(context);
|
||||
final startIndex = ((currentPage - 1) * itemsPerPage);
|
||||
// final item = filteredData[index - 1];
|
||||
final item = sortedData[index - 1];
|
||||
final sno = startIndex + index;
|
||||
return _buildDataRow(item, sno);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHeader() {
|
||||
return SizedBox.shrink();
|
||||
}
|
||||
|
||||
Widget _buildDataRow(Map<String, dynamic> item, sno) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
|
||||
// margin: const EdgeInsets.only(top: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
// color: Color(0xFFE0F7F9),
|
||||
border: const Border(
|
||||
bottom: BorderSide(color: Colors.blueGrey, width: 0.15),
|
||||
),
|
||||
// borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(flex: 1, child: Text('$sno' ?? '-', style: _dataBold)),
|
||||
Expanded(flex: 2, child: Text(item['name'] ?? '-', style: _dataBold)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(item['pos_code'] ?? '-', style: _dataBold),
|
||||
),
|
||||
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(item['email'] ?? '-', style: _dataBold),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(item['mobile'] ?? '-', style: _dataBold),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(item['bank_name'] ?? '-', style: _dataBold),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(item['aadhar'] ?? '-', style: _dataBold),
|
||||
),
|
||||
Expanded(flex: 2, child: Text(item['pan'] ?? '-', style: _dataBold)),
|
||||
|
||||
// Expanded(
|
||||
// flex: 1,
|
||||
// child: Row(
|
||||
// children: [
|
||||
// Container(
|
||||
// // color: Colors.yellow.shade50,
|
||||
// child: Transform.scale(
|
||||
// scale: 0.4, // reduce size (0.7–0.9 works well)
|
||||
// child: Switch(
|
||||
// value: item['is_active'] == "1",
|
||||
// onChanged: (val) {
|
||||
// setState(() {
|
||||
// item['is_active'] = val ? "1" : "0";
|
||||
// });
|
||||
// final response = apiService.updateStatus(
|
||||
// item['id'],
|
||||
// val ? "0" : "1",
|
||||
// 'pos',
|
||||
// );
|
||||
// print("Response - $response");
|
||||
// },
|
||||
// activeColor: Color(0xFF2E7D6E), // thumb when active
|
||||
// activeTrackColor: Color(0xFFDCFCE7), // track when active
|
||||
// // activeColor: Color(0xFF425B5B), // thumb when active
|
||||
// // activeTrackColor: Color(0xFFB2D8D3), // track when active
|
||||
// inactiveThumbColor:
|
||||
// Colors.grey.shade400, // thumb when inactive
|
||||
// inactiveTrackColor:
|
||||
// Colors.grey.shade300, // track when inactive
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
//
|
||||
// Expanded(
|
||||
// flex: 1,
|
||||
// child: item['is_active'] == "1"
|
||||
// ? Row(
|
||||
// children: [
|
||||
// // GestureDetector(
|
||||
// // onTap: () {
|
||||
// // // Navigator.pop(context);
|
||||
// // print('EDITStaff - ${item['id']}');
|
||||
// // dynamic id = item['id'];
|
||||
// // context.go('/pos/$id');
|
||||
// // },
|
||||
// // child: Image.asset(
|
||||
// // "assets/miscellaneous/Edit.png",
|
||||
// // height: 15,
|
||||
// // width: 15,
|
||||
// // ),
|
||||
// // ),
|
||||
// Tooltip(
|
||||
// message: 'Edit',
|
||||
// child: IconButton(
|
||||
// icon: Image.asset(
|
||||
// "assets/miscellaneous/Edit.png",
|
||||
// height: 12,
|
||||
// width: 15,
|
||||
// ),
|
||||
// onPressed: () {
|
||||
// print('EDITStaff - ${item['id']}');
|
||||
// dynamic id = item['id'];
|
||||
// context.go('/pos/$id');
|
||||
// },
|
||||
// splashRadius: 28,
|
||||
// hoverColor: Colors.black12,
|
||||
// padding: const EdgeInsets.all(8),
|
||||
// constraints: const BoxConstraints(),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
// : Row(
|
||||
// children: [
|
||||
// Image.asset(
|
||||
// "assets/miscellaneous/Edit_muted.png",
|
||||
// height: 12,
|
||||
// width: 15,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static final _dataBold = GoogleFonts.inter(
|
||||
fontSize: 12,
|
||||
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Color(0xFF000000),
|
||||
);
|
||||
|
||||
static final _dataSub = GoogleFonts.inter(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w300,
|
||||
color: Color(0xFF585757),
|
||||
);
|
||||
|
||||
static final _headerStyle = GoogleFonts.poppins(
|
||||
fontSize: 11.2,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF1E293B),
|
||||
);
|
||||
}
|
||||
@ -240,7 +240,10 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
|
||||
),
|
||||
const SizedBox(height: 26),
|
||||
if (profileData?['mobile'] != null ||
|
||||
profileData?['mobile'] != '') ...[
|
||||
profileData!['mobile']
|
||||
.toString()
|
||||
.trim()
|
||||
.isNotEmpty) ...[
|
||||
Row(
|
||||
children: [
|
||||
const Icon(
|
||||
@ -258,7 +261,10 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
if (profileData?['email'] != null ||
|
||||
profileData?['email'] != '') ...[
|
||||
profileData!['email']
|
||||
.toString()
|
||||
.trim()
|
||||
.isNotEmpty) ...[
|
||||
Row(
|
||||
children: [
|
||||
const Icon(
|
||||
@ -276,8 +282,11 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
|
||||
if (profileData?['address'] != null ||
|
||||
profileData?['address'] != '') ...[
|
||||
if (profileData?['address'] != null &&
|
||||
profileData!['address']
|
||||
.toString()
|
||||
.trim()
|
||||
.isNotEmpty) ...[
|
||||
if ((roleId != 1) &&
|
||||
(roleId != 2) &&
|
||||
(roleId != 3)) ...[
|
||||
@ -304,9 +313,7 @@ class ProfilePopUpState extends ConsumerState<ProfilePopUp> {
|
||||
],
|
||||
],
|
||||
|
||||
if ((roleId != 1) &&
|
||||
(roleId != 2) &&
|
||||
(roleId != 3)) ...[
|
||||
if ((roleId == 5)) ...[
|
||||
// Staff, Handler doesn't have this part Only Manager and agent have
|
||||
Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
|
||||
@ -27,7 +27,8 @@ import '../../../themes/indicators/input_field_decoration.dart';
|
||||
|
||||
class SalesExecutive extends ConsumerStatefulWidget {
|
||||
final String? id;
|
||||
const SalesExecutive({super.key, this.id});
|
||||
final void Function(String value) onSubmit;
|
||||
const SalesExecutive({super.key, this.id, required this.onSubmit});
|
||||
@override
|
||||
ConsumerState<SalesExecutive> createState() => SalesExecutiveState();
|
||||
}
|
||||
@ -75,7 +76,7 @@ class SalesExecutiveState extends ConsumerState<SalesExecutive> {
|
||||
// "emp_id": controllers["code"]?.text,
|
||||
"is_active": isActive,
|
||||
// "handler_id": selectedHandler,
|
||||
"manager_id": userId,
|
||||
"manager_id": managerId,
|
||||
};
|
||||
return data;
|
||||
}
|
||||
@ -204,7 +205,9 @@ class SalesExecutiveState extends ConsumerState<SalesExecutive> {
|
||||
context,
|
||||
'SalesExecutive Created Successfully',
|
||||
);
|
||||
context.go(AppRoutes.salesExecutiveLst);
|
||||
Navigator.of(context).pop();
|
||||
widget.onSubmit("success");
|
||||
// context.go(AppRoutes.salesExecutiveLst);
|
||||
} else if (response.statusCode == 403) {
|
||||
await apiService.clearLocalStorageAndRedirect();
|
||||
} else {
|
||||
@ -310,11 +313,12 @@ class SalesExecutiveState extends ConsumerState<SalesExecutive> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MainLayout(
|
||||
title: "SalesExecutive",
|
||||
body: Container(
|
||||
return AlertDialog(
|
||||
backgroundColor: Colors.white,
|
||||
content: Container(
|
||||
// color: Colors.yellow.shade50,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
width: MediaQuery.of(context).size.width * 0.42,
|
||||
height: MediaQuery.of(context).size.height * 0.55,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
@ -331,23 +335,23 @@ class SalesExecutiveState extends ConsumerState<SalesExecutive> {
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Tooltip(
|
||||
message: 'Back',
|
||||
child: IconButton(
|
||||
icon: const Icon(
|
||||
Icons.arrow_left_sharp,
|
||||
size: 25,
|
||||
color: Color(0xFF425B5B),
|
||||
),
|
||||
onPressed: () {
|
||||
context.go(AppRoutes.salesExecutiveLst);
|
||||
},
|
||||
splashRadius: 28,
|
||||
hoverColor: Colors.black12,
|
||||
padding: const EdgeInsets.all(8),
|
||||
constraints: const BoxConstraints(),
|
||||
),
|
||||
),
|
||||
// Tooltip(
|
||||
// message: 'Back',
|
||||
// child: IconButton(
|
||||
// icon: const Icon(
|
||||
// Icons.arrow_left_sharp,
|
||||
// size: 25,
|
||||
// color: Color(0xFF425B5B),
|
||||
// ),
|
||||
// onPressed: () {
|
||||
// context.go(AppRoutes.salesExecutiveLst);
|
||||
// },
|
||||
// splashRadius: 28,
|
||||
// hoverColor: Colors.black12,
|
||||
// padding: const EdgeInsets.all(8),
|
||||
// constraints: const BoxConstraints(),
|
||||
// ),
|
||||
// ),
|
||||
const SizedBox(width: 5), // spacing between icon and text
|
||||
Text(
|
||||
"Sales Executive",
|
||||
@ -356,6 +360,21 @@ class SalesExecutiveState extends ConsumerState<SalesExecutive> {
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF1F1F1),
|
||||
borderRadius: BorderRadius.circular(5.0),
|
||||
),
|
||||
child: Tooltip(
|
||||
message: 'Close',
|
||||
child: const Icon(Icons.close, size: 18),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -405,7 +424,7 @@ class SalesExecutiveState extends ConsumerState<SalesExecutive> {
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 30),
|
||||
// SizedBox(height: 30),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -422,51 +441,40 @@ class SalesExecutiveState extends ConsumerState<SalesExecutive> {
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: buildName()),
|
||||
SizedBox(width: 25),
|
||||
Expanded(child: buildEmail()),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: buildPhNumber()),
|
||||
SizedBox(width: 25),
|
||||
Expanded(child: buildAddress()),
|
||||
],
|
||||
),
|
||||
Row(children: [buildName(), SizedBox(width: 25), buildEmail()]),
|
||||
SizedBox(height: 20),
|
||||
Row(children: [buildPhNumber(), SizedBox(width: 25), buildAddress()]),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildName() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Name *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
ThemedFormField(
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
highlightColor: Color(0xFF50A398),
|
||||
controller: controllers['name']!,
|
||||
validator: (value) => Validators.requiredField(value, "name"),
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildEmail() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Email *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
ThemedFormField(
|
||||
controller: controllers['email']!,
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
@ -485,18 +493,18 @@ class SalesExecutiveState extends ConsumerState<SalesExecutive> {
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_@.]')),
|
||||
],
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildPhNumber() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Phone Number *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
ThemedFormField(
|
||||
controller: controllers['mobile']!,
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
@ -516,18 +524,18 @@ class SalesExecutiveState extends ConsumerState<SalesExecutive> {
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
|
||||
],
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildAddress() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Address", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
ThemedFormField(
|
||||
controller: controllers['address']!,
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
@ -535,15 +543,15 @@ class SalesExecutiveState extends ConsumerState<SalesExecutive> {
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[ a-zA-Z0-9_#/.]')),
|
||||
],
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildId() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("SalesExecutive Id ", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
@ -552,7 +560,7 @@ class SalesExecutiveState extends ConsumerState<SalesExecutive> {
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
highlightColor: Color(0xFF50A398),
|
||||
// validator: (value) => Validators.requiredField(value, "id"),
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
),
|
||||
],
|
||||
);
|
||||
@ -567,7 +575,7 @@ class SalesExecutiveState extends ConsumerState<SalesExecutive> {
|
||||
// ThemedFormField(
|
||||
// controller: controllers['address']!,
|
||||
//
|
||||
// txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
// txtwidth: MediaQuery.of(context).size.width *0.18,
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
@ -590,8 +598,8 @@ class SalesExecutiveState extends ConsumerState<SalesExecutive> {
|
||||
|
||||
final isReadOnly = widget.id != null;
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Role *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
@ -602,7 +610,7 @@ class SalesExecutiveState extends ConsumerState<SalesExecutive> {
|
||||
),
|
||||
width: ResponsiveLayout.isMobile(context)
|
||||
? null
|
||||
: MediaQuery.of(context).size.width * 0.26,
|
||||
: MediaQuery.of(context).size.width * 0.18,
|
||||
// height: 40,
|
||||
child: AbsorbPointer(
|
||||
absorbing: isReadOnly,
|
||||
@ -727,8 +735,8 @@ class SalesExecutiveState extends ConsumerState<SalesExecutive> {
|
||||
// final isReadOnly = widget.id != null;
|
||||
final isReadOnly = false;
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Handler Name *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
@ -739,7 +747,7 @@ class SalesExecutiveState extends ConsumerState<SalesExecutive> {
|
||||
),
|
||||
width: ResponsiveLayout.isMobile(context)
|
||||
? null
|
||||
: MediaQuery.of(context).size.width * 0.26,
|
||||
: MediaQuery.of(context).size.width * 0.18,
|
||||
// height: 40,
|
||||
child: AbsorbPointer(
|
||||
absorbing: isReadOnly,
|
||||
|
||||
@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
|
||||
import 'package:nhance_partner/presentation/screens/UserManagement/SalesExecutive/salesExecutive.dart';
|
||||
|
||||
import '../../../../core/routing/routes.dart';
|
||||
import '../../../../core/services/api_service.dart';
|
||||
@ -56,6 +57,12 @@ class SalesExecutiveListState extends ConsumerState<SalesExecutiveList> {
|
||||
// getSalesExecutiveList();
|
||||
}
|
||||
|
||||
void refresh() {
|
||||
if (prefid != null && role != null) {
|
||||
getSalesExecutiveList(prefid, role);
|
||||
}
|
||||
}
|
||||
|
||||
List<dynamic> get _paginatedData {
|
||||
// Sort descending by id first
|
||||
final sortedData = [...filteredData]
|
||||
@ -131,6 +138,20 @@ class SalesExecutiveListState extends ConsumerState<SalesExecutiveList> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> showSalesExecutive({required String id}) {
|
||||
print('showSalesEXEC : $id');
|
||||
return showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => SalesExecutive(
|
||||
id: id,
|
||||
onSubmit: (value) {
|
||||
debugPrint("New onSubmit: $value");
|
||||
refresh();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
managerId = ref.watch(managerIdProvider);
|
||||
@ -170,7 +191,7 @@ class SalesExecutiveListState extends ConsumerState<SalesExecutiveList> {
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Sales Executive List',
|
||||
'Sales Executive',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
@ -216,7 +237,8 @@ class SalesExecutiveListState extends ConsumerState<SalesExecutiveList> {
|
||||
SizedBox(width: 10),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
context.go('/salesExecutive/create');
|
||||
showSalesExecutive(id: 'create');
|
||||
// context.go('/salesExecutive/create');
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(4.8),
|
||||
@ -427,7 +449,9 @@ class SalesExecutiveListState extends ConsumerState<SalesExecutiveList> {
|
||||
onPressed: () {
|
||||
print('EDITStaff - ${item['id']}');
|
||||
dynamic id = item['id'];
|
||||
context.go('/salesExecutive/$id');
|
||||
// context.go('/salesExecutive/$id');
|
||||
|
||||
showSalesExecutive(id: id);
|
||||
},
|
||||
splashRadius: 28,
|
||||
hoverColor: Colors.black12,
|
||||
|
||||
@ -27,7 +27,8 @@ import '../../../themes/indicators/input_field_decoration.dart';
|
||||
|
||||
class Staff extends ConsumerStatefulWidget {
|
||||
final String? id;
|
||||
const Staff({super.key, this.id});
|
||||
final void Function(String value) onSubmit;
|
||||
const Staff({super.key, this.id, required this.onSubmit});
|
||||
@override
|
||||
ConsumerState<Staff> createState() => StaffState();
|
||||
}
|
||||
@ -56,8 +57,8 @@ class StaffState extends ConsumerState<Staff> {
|
||||
List<Map<String, dynamic>> filteredRolesData = [];
|
||||
List<Map<String, dynamic>> getRolesData = [];
|
||||
|
||||
List<dynamic>? selectedHandlerIds = [];
|
||||
String? selectedHandler;
|
||||
List<dynamic>? selectedHandlerIds = [];
|
||||
List<Map<String, dynamic>> filteredHandlersData = [];
|
||||
List<Map<String, dynamic>> getHandlersData = [];
|
||||
|
||||
@ -109,7 +110,7 @@ class StaffState extends ConsumerState<Staff> {
|
||||
}
|
||||
|
||||
void updateData() async {
|
||||
if (widget.id != null && widget.id != 'create') {
|
||||
if (widget.id != null && widget.id != 'Create') {
|
||||
dynamic response = await apiService.findSingleStaffData(widget.id!);
|
||||
final data = response['data'];
|
||||
print("updateData - ${response['data']}");
|
||||
@ -184,7 +185,7 @@ class StaffState extends ConsumerState<Staff> {
|
||||
}
|
||||
|
||||
Future<void> createUserData(data) async {
|
||||
final bool isUpdating = widget.id != null && widget.id != 'create';
|
||||
final bool isUpdating = widget.id != null && widget.id != 'Create';
|
||||
final String? id = isUpdating ? widget.id : null;
|
||||
final String apiUrldata;
|
||||
// apiUrldata = isUpdating
|
||||
@ -234,7 +235,10 @@ class StaffState extends ConsumerState<Staff> {
|
||||
context,
|
||||
'Staff Created Successfully',
|
||||
);
|
||||
context.go(AppRoutes.staffLst);
|
||||
|
||||
Navigator.of(context).pop();
|
||||
widget.onSubmit("success");
|
||||
// context.go(AppRoutes.staffLst);
|
||||
} else if (response.statusCode == 403) {
|
||||
await apiService.clearLocalStorageAndRedirect();
|
||||
} else {
|
||||
@ -340,11 +344,12 @@ class StaffState extends ConsumerState<Staff> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MainLayout(
|
||||
title: "Staff",
|
||||
body: Container(
|
||||
return AlertDialog(
|
||||
backgroundColor: Colors.white,
|
||||
content: Container(
|
||||
// color: Colors.yellow.shade50,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
width: MediaQuery.of(context).size.width * 0.62,
|
||||
height: MediaQuery.of(context).size.height * 0.65,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
@ -361,23 +366,23 @@ class StaffState extends ConsumerState<Staff> {
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Tooltip(
|
||||
message: 'Back',
|
||||
child: IconButton(
|
||||
icon: const Icon(
|
||||
Icons.arrow_left_sharp,
|
||||
size: 25,
|
||||
color: Color(0xFF425B5B),
|
||||
),
|
||||
onPressed: () {
|
||||
context.go(AppRoutes.staffLst);
|
||||
},
|
||||
splashRadius: 28,
|
||||
hoverColor: Colors.black12,
|
||||
padding: const EdgeInsets.all(8),
|
||||
constraints: const BoxConstraints(),
|
||||
),
|
||||
),
|
||||
// Tooltip(
|
||||
// message: 'Back',
|
||||
// child: IconButton(
|
||||
// icon: const Icon(
|
||||
// Icons.arrow_left_sharp,
|
||||
// size: 25,
|
||||
// color: Color(0xFF425B5B),
|
||||
// ),
|
||||
// onPressed: () {
|
||||
// context.go(AppRoutes.staffLst);
|
||||
// },
|
||||
// splashRadius: 28,
|
||||
// hoverColor: Colors.black12,
|
||||
// padding: const EdgeInsets.all(8),
|
||||
// constraints: const BoxConstraints(),
|
||||
// ),
|
||||
// ),
|
||||
const SizedBox(width: 5), // spacing between icon and text
|
||||
Text(
|
||||
"Staff",
|
||||
@ -386,6 +391,21 @@ class StaffState extends ConsumerState<Staff> {
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF1F1F1),
|
||||
borderRadius: BorderRadius.circular(5.0),
|
||||
),
|
||||
child: Tooltip(
|
||||
message: 'Close',
|
||||
child: const Icon(Icons.close, size: 18),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -455,30 +475,30 @@ class StaffState extends ConsumerState<Staff> {
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: buildName()),
|
||||
buildName(),
|
||||
SizedBox(width: 25),
|
||||
Expanded(child: buildEmail()),
|
||||
buildEmail(),
|
||||
SizedBox(width: 25),
|
||||
buildPhNumber(),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: buildPhNumber()),
|
||||
buildRole(context),
|
||||
SizedBox(width: 25),
|
||||
Expanded(child: buildRole(context)),
|
||||
if (showHandler) ...[
|
||||
Row(
|
||||
children: [
|
||||
buildHandler(context),
|
||||
SizedBox(width: 25),
|
||||
SizedBox.shrink(),
|
||||
],
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
|
||||
if (showHandler) ...[
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: buildHandler(context)),
|
||||
SizedBox(width: 25),
|
||||
Expanded(child: SizedBox.shrink()),
|
||||
],
|
||||
),
|
||||
],
|
||||
// Row(
|
||||
// children: [
|
||||
// Expanded(child: buildAddress()),
|
||||
@ -492,28 +512,28 @@ class StaffState extends ConsumerState<Staff> {
|
||||
}
|
||||
|
||||
Widget buildName() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Full Name *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
ThemedFormField(
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
highlightColor: Color(0xFF50A398),
|
||||
controller: controllers['name']!,
|
||||
validator: (value) => Validators.requiredField(value, "name"),
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildEmail() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Email *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
ThemedFormField(
|
||||
controller: controllers['email']!,
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
@ -532,18 +552,18 @@ class StaffState extends ConsumerState<Staff> {
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_@.]')),
|
||||
],
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildPhNumber() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Phone Number *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
ThemedFormField(
|
||||
controller: controllers['mobile']!,
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
@ -563,24 +583,24 @@ class StaffState extends ConsumerState<Staff> {
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
|
||||
],
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildId() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Staff Id ", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
ThemedFormField(
|
||||
controller: controllers['code']!,
|
||||
borderColor: Color(0xFFE2E8F0),
|
||||
highlightColor: Color(0xFF50A398),
|
||||
// validator: (value) => Validators.requiredField(value, "id"),
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
),
|
||||
],
|
||||
);
|
||||
@ -595,7 +615,7 @@ class StaffState extends ConsumerState<Staff> {
|
||||
// ThemedFormField(
|
||||
// controller: controllers['address']!,
|
||||
//
|
||||
// txtwidth: MediaQuery.of(context).size.width * 0.26,
|
||||
// txtwidth: MediaQuery.of(context).size.width * 0.18,
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
@ -616,13 +636,13 @@ class StaffState extends ConsumerState<Staff> {
|
||||
showHandler = false;
|
||||
}
|
||||
|
||||
final isReadOnly = widget.id != null;
|
||||
final isReadOnly = widget.id != null && widget.id != 'Create';
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Role *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
// color: Colors.white,
|
||||
@ -630,7 +650,7 @@ class StaffState extends ConsumerState<Staff> {
|
||||
),
|
||||
width: ResponsiveLayout.isMobile(context)
|
||||
? null
|
||||
: MediaQuery.of(context).size.width * 0.26,
|
||||
: MediaQuery.of(context).size.width * 0.18,
|
||||
// height: 40,
|
||||
child: AbsorbPointer(
|
||||
absorbing: isReadOnly,
|
||||
@ -719,13 +739,14 @@ class StaffState extends ConsumerState<Staff> {
|
||||
// constraints: BoxConstraints(),
|
||||
),
|
||||
|
||||
onChanged: widget.id != null
|
||||
onChanged: widget.id != null && widget.id != 'Create'
|
||||
? null
|
||||
: (val) {
|
||||
if (val != null) {
|
||||
print("Selected Role : ${val['role']}");
|
||||
print("Id: ${val['id']}");
|
||||
selectedRole = val['id'];
|
||||
print('selectedRole - ${val['role']}');
|
||||
if (val['role'] == 'Staff') {
|
||||
setState(() {
|
||||
showHandler = true;
|
||||
@ -736,6 +757,8 @@ class StaffState extends ConsumerState<Staff> {
|
||||
});
|
||||
}
|
||||
|
||||
print('showHandler - $showHandler');
|
||||
|
||||
// controllers['agentId']?.text = val['agent_code'];
|
||||
// agentId = agent['id'];
|
||||
}
|
||||
@ -755,11 +778,11 @@ class StaffState extends ConsumerState<Staff> {
|
||||
// final isReadOnly = widget.id != null;
|
||||
final isReadOnly = false;
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Handler Name *", style: _textStyle),
|
||||
SizedBox(width: 10),
|
||||
SizedBox(height: 10),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
// color: Colors.white,
|
||||
@ -767,7 +790,7 @@ class StaffState extends ConsumerState<Staff> {
|
||||
),
|
||||
width: ResponsiveLayout.isMobile(context)
|
||||
? null
|
||||
: MediaQuery.of(context).size.width * 0.26,
|
||||
: MediaQuery.of(context).size.width * 0.18,
|
||||
// height: 40,
|
||||
child: AbsorbPointer(
|
||||
absorbing: isReadOnly,
|
||||
|
||||
@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
|
||||
import 'package:nhance_partner/presentation/screens/UserManagement/Staff/staff.dart';
|
||||
|
||||
import '../../../../core/routing/routes.dart';
|
||||
import '../../../../core/services/api_service.dart';
|
||||
@ -56,6 +57,13 @@ class StaffListState extends ConsumerState<StaffList> {
|
||||
});
|
||||
// getStaffList();
|
||||
}
|
||||
|
||||
void refresh() {
|
||||
if (prefid != null && role != null) {
|
||||
getStaffList(prefid, role);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// @override
|
||||
// void didChangeDependencies() {
|
||||
@ -167,6 +175,20 @@ class StaffListState extends ConsumerState<StaffList> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> showStaff({required String id}) {
|
||||
print('showAgent : $id');
|
||||
return showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => Staff(
|
||||
id: id,
|
||||
onSubmit: (value) {
|
||||
debugPrint("New Claims: $value");
|
||||
refresh();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildPopupMenuActions(BuildContext context, dynamic data) {
|
||||
return [
|
||||
GestureDetector(
|
||||
@ -204,48 +226,6 @@ class StaffListState extends ConsumerState<StaffList> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
// Container(
|
||||
// // height: 30,
|
||||
// // color: Colors.red.shade50,
|
||||
// width: MediaQuery.of(context).size.width,
|
||||
// child: GestureDetector(
|
||||
// onTap: () {
|
||||
// context.go(AppRoutes.dashboard);
|
||||
// },
|
||||
// child: Row(
|
||||
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||
// mainAxisAlignment: MainAxisAlignment.start,
|
||||
// children: [
|
||||
// Text('Staff List', style: _headerStyle),
|
||||
// // Icon(
|
||||
// // Icons.arrow_left_sharp,
|
||||
// // size: 35,
|
||||
// // color: Color(0xFF425B5B),
|
||||
// // ),
|
||||
// // Tooltip(
|
||||
// // message: 'Back',
|
||||
// // child: IconButton(
|
||||
// // icon: const Icon(
|
||||
// // Icons.arrow_left_sharp,
|
||||
// // size: 25,
|
||||
// // color: Color(0xFF425B5B),
|
||||
// // ),
|
||||
// // onPressed: () {
|
||||
// // context.go(AppRoutes.dashboard);
|
||||
// // },
|
||||
// // splashRadius: 18,
|
||||
// // hoverColor: Colors.black12,
|
||||
// // padding: const EdgeInsets.all(4),
|
||||
// // constraints: const BoxConstraints(),
|
||||
// // ),
|
||||
// // ),
|
||||
// // const SizedBox(width: 15), // spacing between icon and text
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
//
|
||||
// SizedBox(height: 5),
|
||||
Expanded(
|
||||
child: Container(
|
||||
// color: Colors.green,
|
||||
@ -269,7 +249,7 @@ class StaffListState extends ConsumerState<StaffList> {
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Staff List',
|
||||
'Staff',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
@ -315,7 +295,9 @@ class StaffListState extends ConsumerState<StaffList> {
|
||||
SizedBox(width: 10),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
context.go('/staff/create');
|
||||
// context.go('/staff/create');
|
||||
|
||||
showStaff(id: 'Create');
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(4.8),
|
||||
@ -544,7 +526,9 @@ class StaffListState extends ConsumerState<StaffList> {
|
||||
onPressed: () {
|
||||
print('EDITStaff - ${item['id']}');
|
||||
dynamic id = item['id'];
|
||||
context.go('/staff/$id');
|
||||
|
||||
showStaff(id: id);
|
||||
// context.go('/staff/$id');
|
||||
},
|
||||
splashRadius: 28,
|
||||
hoverColor: Colors.black12,
|
||||
|
||||
@ -243,6 +243,12 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<String> buildBrokerShortNames() {
|
||||
return filteredBrokerWise.map<String>((item) {
|
||||
return item['broker_short_name']?.toString() ?? '';
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<BarData> buildProductBarData() {
|
||||
double parseDouble(dynamic value) {
|
||||
if (value == null) return 0.0;
|
||||
@ -291,8 +297,9 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Spacer(),
|
||||
Text('Hide and Show Charts : ', style: _styleSmall1),
|
||||
|
||||
Row(
|
||||
@ -355,19 +362,43 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
),
|
||||
],
|
||||
),
|
||||
Spacer(),
|
||||
legendWidget(),
|
||||
],
|
||||
),
|
||||
|
||||
Expanded(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
showInsurer ? Expanded(child: insurerContainer()) : SizedBox(),
|
||||
showBroker ? Expanded(child: brokerContainer()) : SizedBox(),
|
||||
showProduct ? Expanded(child: productContainer()) : SizedBox(),
|
||||
],
|
||||
(showInsurer || showBroker)
|
||||
? Expanded(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// if (showInsurer) Expanded(child: insurerContainer()),
|
||||
// if (showBroker) Expanded(child: brokerContainer()),
|
||||
showInsurer
|
||||
? Expanded(child: insurerContainer())
|
||||
: SizedBox(),
|
||||
showBroker
|
||||
? Expanded(child: brokerContainer())
|
||||
: SizedBox(),
|
||||
// showProduct ? Expanded(child: productContainer()) : SizedBox(),
|
||||
],
|
||||
),
|
||||
)
|
||||
: SizedBox(),
|
||||
if (showProduct) ...[
|
||||
SizedBox(height: 10),
|
||||
Expanded(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
showProduct
|
||||
? Expanded(child: productContainer())
|
||||
: SizedBox(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
] else ...[
|
||||
SizedBox.shrink(),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
@ -381,31 +412,18 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
return Card(
|
||||
margin: const EdgeInsets.only(right: 10),
|
||||
color: Colors.white,
|
||||
elevation: 1, // card shadow
|
||||
// color: Colors.amber.shade100,
|
||||
elevation: 0.01, // card shadow
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Insurer Wise', style: _chartHeader),
|
||||
Text(
|
||||
'(Previous / Current Month)',
|
||||
style: _chartHeader.copyWith(
|
||||
color: Colors.black87,
|
||||
fontSize: 8,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(child: Text('Insurer-Wise', style: _chartHeader)),
|
||||
|
||||
// buildInsurer(context),
|
||||
Text(
|
||||
@ -425,6 +443,7 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
SizedBox(height: 10),
|
||||
Expanded(
|
||||
child: Container(
|
||||
// color: Colors.amber.shade100,
|
||||
clipBehavior: Clip.none,
|
||||
// color: Colors.red.shade100,
|
||||
child: CustomBarChart(
|
||||
@ -433,7 +452,7 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
),
|
||||
),
|
||||
),
|
||||
legendWidget(),
|
||||
// legendWidget(),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -443,27 +462,23 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
Widget brokerContainer() {
|
||||
final chartBrokerData = buildBrokerBarData();
|
||||
final chartBrokerLabels = buildBrokerLabels();
|
||||
final chartBrokerShortName = buildBrokerShortNames();
|
||||
print('chartBrokerData - $chartBrokerData');
|
||||
print('chartBrokerLabels - $chartBrokerLabels');
|
||||
return Card(
|
||||
margin: const EdgeInsets.only(right: 10),
|
||||
color: Colors.white,
|
||||
elevation: 1, // card shadow
|
||||
elevation: 0.01, // card shadow
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Broker Wise (Previous / Current Month)',
|
||||
style: _chartHeader,
|
||||
),
|
||||
),
|
||||
Expanded(child: Text('Broker-Wise', style: _chartHeader)),
|
||||
|
||||
Text(
|
||||
isBrokerWisePolicy ? "Policies" : "Premium",
|
||||
@ -483,10 +498,14 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
Expanded(
|
||||
child: CustomBarChart(
|
||||
dataList: chartBrokerData,
|
||||
labels: chartBrokerLabels,
|
||||
labels: chartBrokerShortName,
|
||||
shortName: chartBrokerLabels,
|
||||
|
||||
// labels: chartBrokerLabels,
|
||||
// shortName: chartBrokerShortName,
|
||||
),
|
||||
),
|
||||
legendWidget(),
|
||||
// legendWidget(),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -501,22 +520,17 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
return Card(
|
||||
margin: const EdgeInsets.only(right: 10),
|
||||
color: Colors.white,
|
||||
elevation: 1, // card shadow
|
||||
elevation: 0.01, // card shadow
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Product Wise (Previous / Current Month)',
|
||||
style: _chartHeader,
|
||||
),
|
||||
),
|
||||
Expanded(child: Text('Product-Wise', style: _chartHeader)),
|
||||
Text(
|
||||
isProductWisePolicy ? "Policies" : "Premium",
|
||||
style: _styleSmall1,
|
||||
@ -538,7 +552,7 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
|
||||
labels: chartProductLabels,
|
||||
),
|
||||
),
|
||||
legendWidget(),
|
||||
// legendWidget(),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@ -372,6 +372,8 @@ class _DashboardState extends ConsumerState<PartnerDashboard> {
|
||||
: agentsPerformanceListPremium,
|
||||
isPerfomingAgntPolicy:
|
||||
isPerfomingAgntPolicy,
|
||||
apiService: apiService,
|
||||
managerId: managerId,
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -437,6 +439,8 @@ class _DashboardState extends ConsumerState<PartnerDashboard> {
|
||||
: nonAgentsPerformanceListPremium,
|
||||
isPerfomingAgntPolicy:
|
||||
isNonPerfomingAgntPolicy,
|
||||
apiService: apiService,
|
||||
managerId: managerId,
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -459,12 +463,16 @@ class Performance extends StatefulWidget {
|
||||
final String title;
|
||||
final List<Map<String, dynamic>> data;
|
||||
final bool isPerfomingAgntPolicy;
|
||||
late ApiService apiService;
|
||||
dynamic managerId;
|
||||
|
||||
Performance({
|
||||
Key? key,
|
||||
required this.title,
|
||||
required this.data,
|
||||
required this.isPerfomingAgntPolicy,
|
||||
required this.apiService,
|
||||
required this.managerId,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@ -504,7 +512,7 @@ class _PerformanceState extends State<Performance> {
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
"S.no.",
|
||||
"S.No.",
|
||||
textAlign: TextAlign.left,
|
||||
style: _headerStyle,
|
||||
),
|
||||
@ -521,7 +529,7 @@ class _PerformanceState extends State<Performance> {
|
||||
flex: 1,
|
||||
child: Text(
|
||||
"Partner Code",
|
||||
textAlign: TextAlign.center,
|
||||
textAlign: TextAlign.left,
|
||||
style: _headerStyle,
|
||||
),
|
||||
),
|
||||
@ -610,34 +618,45 @@ class _PerformanceState extends State<Performance> {
|
||||
flex: 1,
|
||||
child: Text(
|
||||
row['total_premium_amount'] ?? "",
|
||||
textAlign: TextAlign.center,
|
||||
textAlign: TextAlign.right,
|
||||
style: _tableDataStyle,
|
||||
),
|
||||
),
|
||||
],
|
||||
// (widget.title == 'Performing Partner')
|
||||
// ? Expanded(
|
||||
// flex: 1,
|
||||
// child: Text(
|
||||
// isPerfomingAgntPolicy
|
||||
// ? (row['policy_count']?.toString() ?? "0")
|
||||
// : (row['total_premium_amount']
|
||||
// ?.toString() ??
|
||||
// "0"),
|
||||
// textAlign: TextAlign.center,
|
||||
// style: GoogleFonts.inter(
|
||||
// fontSize: 11,
|
||||
// fontWeight: FontWeight.w500,
|
||||
// // color: isPerfomingAgntPolicy
|
||||
// // ? Colors.black
|
||||
// // : (row['status']?.toString().toLowerCase() ==
|
||||
// // "active"
|
||||
// // ? Colors.green
|
||||
// // : Colors.red),
|
||||
// ),
|
||||
// ),
|
||||
// )
|
||||
// : SizedBox(),
|
||||
SizedBox(width: 10),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
final path1 = 'PerformingTop50';
|
||||
final path2 = widget.isPerfomingAgntPolicy
|
||||
? "NoBusiness"
|
||||
: "NonPerformingBelow50K";
|
||||
final path = (widget.title == 'Performing Partner')
|
||||
? path1
|
||||
: path2;
|
||||
|
||||
final id =
|
||||
((widget.title == 'Performing Partner') &&
|
||||
(row['agent_id'] != null))
|
||||
? row['agent_id']
|
||||
: '';
|
||||
final month = 'current';
|
||||
|
||||
await widget.apiService.generateChartExcel(
|
||||
path,
|
||||
id,
|
||||
month,
|
||||
widget.managerId,
|
||||
);
|
||||
},
|
||||
child: Tooltip(
|
||||
message: 'Click To Download Excel',
|
||||
child: Icon(
|
||||
Icons.download,
|
||||
size: 14,
|
||||
color: Colors.green.shade300,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@ -48,6 +48,7 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
|
||||
[]; // 👈 Add this at the top with other state variables
|
||||
Map<String, Color> vehicleColors = {};
|
||||
List<String> staffLabels = [];
|
||||
List<String> staffLabelsId = [];
|
||||
// List<List<List<dynamic>>> staffChartData = [];
|
||||
List<List<List<dynamic>>> staffChartData = [];
|
||||
|
||||
@ -170,6 +171,7 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
|
||||
print('Dynamic Vehicle Colors: $dynamicVehicleColors');
|
||||
|
||||
List<String> newLabels = [];
|
||||
List<String> newLabelsId = [];
|
||||
List<List<List<dynamic>>> newChartData = [];
|
||||
List<List<String>> vehicleNames = [];
|
||||
double newMax = 0.0;
|
||||
@ -188,6 +190,9 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
|
||||
'';
|
||||
newLabels.add(name);
|
||||
|
||||
final id = (staff['sales_executive_id'])?.toString() ?? '';
|
||||
newLabelsId.add(id);
|
||||
|
||||
final products = (staff['products_list'] ?? []) as List<dynamic>;
|
||||
|
||||
List<List<dynamic>> currentRod = [];
|
||||
@ -232,6 +237,7 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
|
||||
filteredStaffWise = List<Map<String, dynamic>>.from(originalStaffWise);
|
||||
|
||||
staffLabels = newLabels;
|
||||
staffLabelsId = newLabelsId;
|
||||
staffChartData = newChartData;
|
||||
staffVehicleTypeNames = vehicleNames;
|
||||
vehicleColors = dynamicVehicleColors; // Save for legend
|
||||
@ -274,79 +280,6 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
|
||||
}).toList();
|
||||
}
|
||||
|
||||
// In insurerContainer() you are passing staffLabels (which we now populate).
|
||||
// Also set the chart maxY to some headroom:
|
||||
// CustomStackedBarChart(..., maxY: (maxPremium * 1.1).ceilToDouble(), ...)
|
||||
|
||||
List<BarData> buildStaffBarData() {
|
||||
double parseDouble(dynamic value) {
|
||||
if (value == null) return 0.0;
|
||||
if (value is num) return value.toDouble();
|
||||
if (value is String) return double.tryParse(value) ?? 0.0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return filteredStaffWise.map((item) {
|
||||
print('policies_current - ${item['total_policies_current_month']}');
|
||||
print('policies_PREV - ${item['total_policies_pre_month']}');
|
||||
|
||||
print('premium_current - ${item['total_premium_current_month']}');
|
||||
print('premium_PREV - ${item['total_premium_pre_month']}');
|
||||
return BarData(
|
||||
Colors.blue,
|
||||
isInsureWisePolicy
|
||||
? parseDouble(item['total_policies_current_month'])
|
||||
: parseDouble(item['total_premium_current_month']),
|
||||
isInsureWisePolicy
|
||||
? parseDouble(item['total_policies_pre_month'])
|
||||
: parseDouble(item['total_premium_pre_month']),
|
||||
item['vehicle_type'] != null ? item['vehicle_type'] : 0,
|
||||
'Productivity',
|
||||
5,
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<BarData> buildProductBarData() {
|
||||
double parseDouble(dynamic value) {
|
||||
if (value == null) return 0.0;
|
||||
if (value is num) return value.toDouble();
|
||||
if (value is String) return double.tryParse(value) ?? 0.0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return filteredProductWise.map((item) {
|
||||
print('policies_current - ${item['total_policies_current_month']}');
|
||||
print('policies_PREV - ${item['total_policies_pre_month']}');
|
||||
|
||||
print('premium_current - ${item['total_premium_current_month']}');
|
||||
print('premium_PREV - ${item['total_premium_pre_month']}');
|
||||
return BarData(
|
||||
Colors.blue,
|
||||
isProductWisePolicy
|
||||
? parseDouble(item['total_policies_current_month'])
|
||||
: parseDouble(item['total_premium_current_month']),
|
||||
isProductWisePolicy
|
||||
? parseDouble(item['total_policies_pre_month'])
|
||||
: parseDouble(item['total_premium_pre_month']),
|
||||
item['vehicle_type'],
|
||||
'Productivity',
|
||||
10,
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<String> buildProductLabels() {
|
||||
return filteredProductWise.map<String>((item) {
|
||||
final name = item['vehicle_type'];
|
||||
if (name != null && name.toString().trim().isNotEmpty) {
|
||||
return name.toString();
|
||||
} else {
|
||||
return item['vehicle_type']?.toString() ?? '';
|
||||
}
|
||||
}).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
@ -417,9 +350,6 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
|
||||
}
|
||||
|
||||
Widget insurerContainer() {
|
||||
final chartStaffData = buildStaffBarData();
|
||||
final chartStaffLabels = buildStaffLabels();
|
||||
|
||||
return Card(
|
||||
margin: const EdgeInsets.only(right: 10),
|
||||
color: Colors.white,
|
||||
@ -447,6 +377,10 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
|
||||
Transform.scale(
|
||||
scale: 0.5,
|
||||
child: Switch(
|
||||
activeColor: Colors.teal,
|
||||
activeTrackColor: Colors.grey.shade200,
|
||||
inactiveThumbColor: Colors.orange,
|
||||
inactiveTrackColor: Colors.white,
|
||||
value: isInsureWisePolicy,
|
||||
onChanged: (val) {
|
||||
setState(() {
|
||||
@ -463,6 +397,7 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
|
||||
Expanded(
|
||||
child: CustomStackedBarChart(
|
||||
labels: staffLabels,
|
||||
labelsId: staffLabelsId,
|
||||
// maxY: (maxPremium * 1.1).ceilToDouble(),
|
||||
maxY: _getSmartMaxValue(),
|
||||
initialRotation: 1,
|
||||
@ -479,55 +414,6 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
|
||||
);
|
||||
}
|
||||
|
||||
// Widget productContainer() {
|
||||
// final chartProductData = buildProductBarData();
|
||||
// final chartProductLabels = buildProductLabels();
|
||||
// print('chartProductData - $chartProductData');
|
||||
// print('chartProductLabels - $chartProductLabels');
|
||||
// return Container(
|
||||
// padding: EdgeInsets.all(10),
|
||||
// margin: EdgeInsets.only(right: 20),
|
||||
// decoration: BoxDecoration(
|
||||
// color: Colors.white,
|
||||
// borderRadius: BorderRadius.circular(10),
|
||||
// ),
|
||||
// child: Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// Row(
|
||||
// children: [
|
||||
// Expanded(
|
||||
// child: Text(
|
||||
// 'Sales Executive Product Wise (Previous / Current Month)',
|
||||
// style: _chartHeader,
|
||||
// ),
|
||||
// ),
|
||||
// Text(
|
||||
// isProductWisePolicy ? "Policies" : "Premium",
|
||||
// style: _styleSmall1,
|
||||
// ),
|
||||
// Transform.scale(
|
||||
// scale: 0.5,
|
||||
// child: Switch(
|
||||
// value: isProductWisePolicy,
|
||||
// onChanged: (val) => setState(() => isProductWisePolicy = val),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// SizedBox(height: 10),
|
||||
// Expanded(
|
||||
// child: CustomBarChart(
|
||||
// dataList: chartProductData,
|
||||
// labels: chartProductLabels,
|
||||
// ),
|
||||
// ),
|
||||
// legendWidget(),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
Widget legendWidget() {
|
||||
return Wrap(
|
||||
spacing: 8,
|
||||
|
||||
@ -344,7 +344,8 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
|
||||
if (userRole == 'staff') {
|
||||
context.go(AppRoutes.enquiryForStaff);
|
||||
} else if (userRole == 'Accounts') {
|
||||
context.go(AppRoutes.payout);
|
||||
// context.go(AppRoutes.payout);
|
||||
context.go(AppRoutes.invoiceList);
|
||||
} else {
|
||||
context.go(AppRoutes.dashboard);
|
||||
}
|
||||
|
||||
806
lib/presentation/screens/payout/custom_dateRange.dart
Normal file
806
lib/presentation/screens/payout/custom_dateRange.dart
Normal file
@ -0,0 +1,806 @@
|
||||
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 DateFilterRowPayout extends ConsumerStatefulWidget {
|
||||
final TextEditingController startController;
|
||||
final String? selectedBroker;
|
||||
final List<dynamic>? selectedParnter;
|
||||
final String? selectedStaffId;
|
||||
final TextEditingController endController;
|
||||
final ValueChanged<String?>? onBrokerChanged;
|
||||
final ValueChanged<List<String>>? onPartnerChanges;
|
||||
final String? dataFrom;
|
||||
final VoidCallback onFilter;
|
||||
final VoidCallback onRefresh;
|
||||
final GlobalKey<FormState> formKey;
|
||||
final bool isMobile;
|
||||
final role;
|
||||
final id;
|
||||
|
||||
const DateFilterRowPayout({
|
||||
super.key,
|
||||
required this.startController,
|
||||
required this.endController,
|
||||
required this.onFilter,
|
||||
required this.onRefresh,
|
||||
this.onBrokerChanged,
|
||||
this.onPartnerChanges,
|
||||
required this.selectedStaffId,
|
||||
required this.selectedParnter,
|
||||
this.selectedBroker,
|
||||
required this.formKey,
|
||||
required this.role,
|
||||
required this.id,
|
||||
this.isMobile = false,
|
||||
this.dataFrom,
|
||||
});
|
||||
|
||||
@override
|
||||
ConsumerState<DateFilterRowPayout> createState() => _DateFilterRowState();
|
||||
}
|
||||
|
||||
class _DateFilterRowState extends ConsumerState<DateFilterRowPayout> {
|
||||
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKey =
|
||||
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
||||
|
||||
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKeyBroker =
|
||||
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
||||
|
||||
final GlobalKey<DropdownSearchState<Map<String, dynamic>>>
|
||||
dropDownKeyPartner = GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
||||
|
||||
late ApiService apiService;
|
||||
List<dynamic>? selectedPartnerIds = [];
|
||||
List<Map<String, dynamic>> getPartnerData = [];
|
||||
List<Map<String, dynamic>> filteredPartnerData = [];
|
||||
|
||||
List<Map<String, dynamic>> getBrokerData = [];
|
||||
List<Map<String, dynamic>> filteredBrokerData = [];
|
||||
|
||||
String? selectedStaff;
|
||||
String? selectedBroker;
|
||||
String? selectedPartner;
|
||||
String? selectedStaffName;
|
||||
dynamic role;
|
||||
dynamic managerId;
|
||||
|
||||
bool isLoading = false;
|
||||
bool isLoadingBroker = false;
|
||||
bool isLoadingAgentList = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
apiService = ApiService();
|
||||
|
||||
Future.microtask(() {
|
||||
managerId = ref.watch(managerIdProvider);
|
||||
final userID = ref.watch(userIdProvider);
|
||||
role = ref.watch(userRoleProvider);
|
||||
print("managerId - $managerId");
|
||||
if (userID != null && role != null) {
|
||||
print('hansles');
|
||||
getPartnerDetails(userID);
|
||||
}
|
||||
|
||||
if (managerId != null) {
|
||||
print('managerId - $managerId');
|
||||
getAgentList(managerId);
|
||||
}
|
||||
});
|
||||
|
||||
getBroker();
|
||||
}
|
||||
|
||||
Future<void> getBroker() async {
|
||||
print('getBroker called');
|
||||
setState(() {
|
||||
isLoadingBroker = true;
|
||||
});
|
||||
|
||||
try {
|
||||
final response = await apiService.fetchMasterDropDown('Broker');
|
||||
|
||||
if (response['status'] == 200) {
|
||||
print('getBroker - ${response['data']}');
|
||||
setState(() {
|
||||
getBrokerData = List<Map<String, dynamic>>.from(response['data']);
|
||||
print('API Data - $getBrokerData');
|
||||
|
||||
filteredBrokerData = List.from(getBrokerData);
|
||||
print('originalData - $filteredBrokerData');
|
||||
});
|
||||
} else {
|
||||
getBrokerData = [];
|
||||
filteredBrokerData = [];
|
||||
}
|
||||
} catch (e) {
|
||||
print('Exception occurred: $e');
|
||||
} finally {
|
||||
setState(() {
|
||||
isLoadingBroker = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getAgentList(id) async {
|
||||
print('getAgentListData called');
|
||||
setState(() {
|
||||
isLoadingAgentList = true;
|
||||
});
|
||||
|
||||
try {
|
||||
final response = await apiService.fetchAgentNameDropDown(id);
|
||||
print('getAgentListData called response');
|
||||
print('get Agent- ${response['data']}');
|
||||
if (response['status'] == 'success') {
|
||||
print('get Agent- ${response['data']}');
|
||||
setState(() {
|
||||
getPartnerData = List<Map<String, dynamic>>.from(response['data']);
|
||||
print('API Data - $getPartnerData');
|
||||
|
||||
filteredPartnerData = List.from(getPartnerData);
|
||||
print('originalAgentData - $filteredPartnerData');
|
||||
});
|
||||
} else {
|
||||
getPartnerData = [];
|
||||
filteredPartnerData = [];
|
||||
}
|
||||
} catch (e) {
|
||||
print('Exception occurred: $e');
|
||||
} finally {
|
||||
setState(() {
|
||||
isLoadingAgentList = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getPartnerDetails(int id) async {
|
||||
print('getPartnerDetails called By handler');
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
|
||||
try {
|
||||
// final response = await apiService.fetchStaffUserList(id, role);
|
||||
final response = await apiService.fetchStaffListForEnquiryAssignDropDown(
|
||||
managerId,
|
||||
id,
|
||||
role,
|
||||
);
|
||||
if (response['status'] == 'success') {
|
||||
print('getStaffDetails - ${response['data']}');
|
||||
setState(() {
|
||||
getPartnerData = List<Map<String, dynamic>>.from(response['data']);
|
||||
print('API Data - $getPartnerData');
|
||||
|
||||
filteredPartnerData = List.from(getPartnerData);
|
||||
print('originalData - $filteredPartnerData');
|
||||
});
|
||||
} else {
|
||||
getPartnerData = [];
|
||||
filteredPartnerData = [];
|
||||
}
|
||||
} catch (e) {
|
||||
print('Exception occurred: $e');
|
||||
} finally {
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final spacing = 5.0;
|
||||
|
||||
List<Widget> getRowChildren(bool isMobile, double spacing) {
|
||||
final dateFields = [
|
||||
buildStartDate(context),
|
||||
SizedBox(width: spacing),
|
||||
buildEndDate(context),
|
||||
SizedBox(width: spacing),
|
||||
buildBroker(context),
|
||||
SizedBox(width: spacing),
|
||||
buildPartner(context),
|
||||
SizedBox(width: spacing),
|
||||
];
|
||||
|
||||
final buttons = [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 0.0),
|
||||
// child: GestureDetector(
|
||||
// onTap: () {
|
||||
// if (formKey.currentState!.validate()) onFilter();
|
||||
// },
|
||||
// child: Icon(Icons.filter_alt_outlined),
|
||||
// ),
|
||||
child: Tooltip(
|
||||
message: 'Filter',
|
||||
child: IconButton(
|
||||
icon: const Icon(
|
||||
Icons.search_rounded,
|
||||
size: 18,
|
||||
color: const Color(0xFF94A3B8),
|
||||
),
|
||||
|
||||
onPressed: () {
|
||||
if (widget.formKey.currentState!.validate()) {
|
||||
widget.onFilter();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(0.0),
|
||||
// child: GestureDetector(onTap: onRefresh, child: Icon(Icons.refresh)),
|
||||
child: Tooltip(
|
||||
message: 'Refresh',
|
||||
child: IconButton(
|
||||
onPressed: widget.onRefresh,
|
||||
icon: const Icon(
|
||||
Icons.refresh,
|
||||
size: 18,
|
||||
color: const Color(0xFF94A3B8),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
if (isMobile) {
|
||||
// For mobile: buttons below fields
|
||||
return [
|
||||
...dateFields,
|
||||
SizedBox(height: 10),
|
||||
Row(mainAxisAlignment: MainAxisAlignment.end, children: buttons),
|
||||
];
|
||||
} else {
|
||||
// For desktop: buttons inline with fields
|
||||
return [...dateFields, Spacer(), ...buttons];
|
||||
}
|
||||
}
|
||||
|
||||
return Form(
|
||||
key: widget.formKey,
|
||||
child: widget.isMobile
|
||||
? Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
||||
children: getRowChildren(widget.isMobile, spacing),
|
||||
)
|
||||
: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
|
||||
children: getRowChildren(widget.isMobile, spacing),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildStartDate(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Start Date', style: _textStyle),
|
||||
SizedBox(height: 5),
|
||||
SizedBox(
|
||||
height: 35,
|
||||
child: ThemedDateField(
|
||||
hintText: "Select Date",
|
||||
txtwidth: ResponsiveLayout.isMobile(context)
|
||||
? null
|
||||
: MediaQuery.of(context).size.width * 0.15,
|
||||
// txtheight: 50,
|
||||
// backgroundColor: const Color(0xFFECECEC),
|
||||
// validator: (value) => Validators.requiredField(value, "date"),
|
||||
controller: widget.startController,
|
||||
onDateSelected: (date) {
|
||||
print("Picked Date: $date");
|
||||
widget.startController.text = DateFormat(
|
||||
'dd-MM-yyyy',
|
||||
).format(date);
|
||||
// controllers['date']?.text = date as String;
|
||||
Future.microtask(() => widget.onFilter());
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildEndDate(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('End Date', style: _textStyle),
|
||||
SizedBox(height: 5),
|
||||
SizedBox(
|
||||
height: 35,
|
||||
child: ThemedDateField(
|
||||
hintText: "Select Date",
|
||||
txtwidth: ResponsiveLayout.isMobile(context)
|
||||
? null
|
||||
: MediaQuery.of(context).size.width * 0.15,
|
||||
// txtheight: 50,
|
||||
// backgroundColor: const Color(0xFFECECEC),
|
||||
validator: (value) {
|
||||
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)) {
|
||||
return "End Date cannot be earlier than Start Date";
|
||||
}
|
||||
}
|
||||
return null; // ✅ no error
|
||||
},
|
||||
controller: widget.endController,
|
||||
lastDate: DateTime.now(),
|
||||
onDateSelected: (date) {
|
||||
print("Picked Date: $date");
|
||||
widget.endController.text = DateFormat('dd-MM-yyyy').format(date);
|
||||
Future.microtask(() => widget.onFilter());
|
||||
// controllers['date']?.text = date as String;
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildBroker(BuildContext context) {
|
||||
Map<String, dynamic>? selectedBrokers = filteredBrokerData.firstWhere(
|
||||
(item) => item['id'].toString() == widget.selectedBroker,
|
||||
orElse: () => {},
|
||||
);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Broker', style: _textStyle),
|
||||
SizedBox(height: 5),
|
||||
SizedBox(
|
||||
height: 35,
|
||||
width: MediaQuery.of(context).size.width * 0.15,
|
||||
child: DropdownSearch<Map<String, dynamic>>(
|
||||
key: dropDownKeyBroker,
|
||||
selectedItem: selectedBrokers.isNotEmpty ? selectedBrokers : null,
|
||||
items: (filter, infiniteScrollProps) {
|
||||
return filteredBrokerData;
|
||||
},
|
||||
|
||||
itemAsString: (val) => val['name'].toString(), // what to show
|
||||
compareFn: (item, selectedItem) =>
|
||||
item['id'] == selectedItem['id'], // ✅ compare by id
|
||||
// validator: (val) {
|
||||
// if (val == null) {
|
||||
// return "Required"; // ✅ error message
|
||||
// }
|
||||
// return null;
|
||||
// },
|
||||
suffixProps: DropdownSuffixProps(
|
||||
// make sure the dropdown button is visible
|
||||
dropdownButtonProps: DropdownButtonProps(
|
||||
isVisible: true,
|
||||
padding: EdgeInsets.zero, // remove default padding
|
||||
constraints: const BoxConstraints(
|
||||
// shrink icon tap area
|
||||
minWidth: 12,
|
||||
minHeight: 12,
|
||||
),
|
||||
iconSize: 15, // smaller icon
|
||||
// icon: const Icon(Icons.arrow_drop_down),
|
||||
),
|
||||
),
|
||||
dropdownBuilder: (context, selectedItem) => Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
selectedItem != null ? selectedItem['name'].toString() : "",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11,
|
||||
color: Colors.black,
|
||||
// color: Color(0XFF6366F1),
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
),
|
||||
),
|
||||
decoratorProps: DropDownDecoratorProps(
|
||||
decoration:
|
||||
AppInputDecorations.dropdownDecoration(
|
||||
label: "Broker",
|
||||
).copyWith(
|
||||
filled: true,
|
||||
fillColor:
|
||||
Colors.white, // 👈 makes the dropdown input white
|
||||
isDense: true,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
borderSide: const BorderSide(
|
||||
color: Color(0xFFE2E8F0),
|
||||
width: 0.1,
|
||||
),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
borderSide: const BorderSide(
|
||||
color: Color(0xFFE2E8F0),
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 6,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
popupProps: PopupProps.menu(
|
||||
fit: FlexFit.loose,
|
||||
constraints: BoxConstraints(maxHeight: 250),
|
||||
menuProps: MenuProps(
|
||||
backgroundColor:
|
||||
Colors.white, // 👈 sets dropdown background to white
|
||||
),
|
||||
showSearchBox: true,
|
||||
searchFieldProps: TextFieldProps(
|
||||
autofocus: true,
|
||||
style: GoogleFonts.inter(fontSize: 11, color: Colors.black),
|
||||
decoration: InputDecoration(
|
||||
contentPadding: EdgeInsets.all(1),
|
||||
filled: true,
|
||||
fillColor: Colors.white,
|
||||
hintText: "Search Broker...",
|
||||
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) {
|
||||
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: 12, color: Colors.black),
|
||||
),
|
||||
);
|
||||
},
|
||||
// constraints: BoxConstraints(),
|
||||
),
|
||||
|
||||
onChanged: (val) {
|
||||
if (val != null) {
|
||||
print("Selected Broker : ${val['name']}");
|
||||
print("Id: ${val['id']}");
|
||||
// selectedBroker = val['id'];
|
||||
widget.onBrokerChanged?.call(val['id'].toString());
|
||||
// widget.onBrokerChanged?.call(val['id']);
|
||||
// controllers['agentId']?.text = val['agent_code'];
|
||||
// agentId = agent['id'];
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildPartner(BuildContext context) {
|
||||
final isReadOnly = false;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Referer", style: _textStyle),
|
||||
SizedBox(height: 5),
|
||||
SizedBox(
|
||||
height: 35,
|
||||
width: MediaQuery.of(context).size.width * 0.42,
|
||||
child: DropdownSearch<Map<String, dynamic>>.multiSelection(
|
||||
key: dropDownKeyPartner,
|
||||
|
||||
// selectedItem: selectedHandlered.isNotEmpty
|
||||
// ? selectedHandlered
|
||||
// : null,
|
||||
selectedItems: filteredPartnerData
|
||||
.where(
|
||||
(item) => (selectedPartnerIds ?? []).contains(item['id']),
|
||||
)
|
||||
.toList(),
|
||||
items: (filter, infiniteScrollProps) {
|
||||
return filteredPartnerData;
|
||||
},
|
||||
|
||||
itemAsString: (val) => val['name'].toString(), // what to show
|
||||
compareFn: (item, selectedItem) =>
|
||||
item['id'] == selectedItem['id'], // ✅ compare by id
|
||||
// validator: (val) {
|
||||
// if (val == null) {
|
||||
// return "Required"; // ✅ error message
|
||||
// }
|
||||
// return null;
|
||||
// },
|
||||
validator: (val) {
|
||||
if (val == null || val.isEmpty) {
|
||||
return "Required";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
decoratorProps: DropDownDecoratorProps(
|
||||
decoration:
|
||||
AppInputDecorations.dropdownDecoration(
|
||||
label: "Select Partner",
|
||||
).copyWith(
|
||||
hintStyle: GoogleFonts.inter(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
),
|
||||
filled: true,
|
||||
fillColor:
|
||||
Colors.white, // 👈 makes the dropdown input white
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Color(0xFFE2E8F0),
|
||||
// color: Colors.white,
|
||||
), // 👈 Normal border
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Color(0xFFE2E8F0),
|
||||
// color: Colors.white,
|
||||
width: 1.5,
|
||||
), // 👈 Focused border
|
||||
),
|
||||
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 6,
|
||||
),
|
||||
),
|
||||
),
|
||||
popupProps: PopupPropsMultiSelection.menu(
|
||||
fit: FlexFit.loose,
|
||||
constraints: BoxConstraints(maxHeight: 250),
|
||||
showSearchBox: true,
|
||||
menuProps: MenuProps(backgroundColor: Colors.white),
|
||||
|
||||
searchFieldProps: TextFieldProps(
|
||||
autofocus: true,
|
||||
decoration: InputDecoration(
|
||||
filled: true,
|
||||
fillColor: Colors.white,
|
||||
hintText: "Search Partner...",
|
||||
hintStyle: GoogleFonts.inter(
|
||||
fontSize: 11,
|
||||
color: Colors.black,
|
||||
),
|
||||
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.white),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
// color: Colors.blue,
|
||||
color: Color(0xFFEDF6F5),
|
||||
width: 1.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
itemBuilder: (context, item, isDisabled, isSelected) {
|
||||
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: 12, color: Colors.black),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
onChanged: (List<Map<String, dynamic>> selectedVals) {
|
||||
// selectedPartnerIds = selectedVals
|
||||
// .map((v) => v['id'].toString())
|
||||
// .toList();
|
||||
final ids = selectedVals.map((v) => v['id'].toString()).toList();
|
||||
print("Selected PArnter IDs: $selectedPartnerIds");
|
||||
widget.onPartnerChanges?.call(ids);
|
||||
// widget.onPartnerChanges!(v['id']);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildSelectStaffMem(BuildContext context) {
|
||||
Map<String, dynamic>? selectedVehicle;
|
||||
if (widget.selectedStaffId == null) {
|
||||
selectedVehicle = null;
|
||||
} else if (widget.selectedStaffId != null) {
|
||||
selectedVehicle = filteredPartnerData.firstWhere(
|
||||
(item) => item['id'] == widget.selectedStaffId,
|
||||
orElse: () => {}, // empty map
|
||||
);
|
||||
if (selectedVehicle.isEmpty) selectedVehicle = null;
|
||||
} else if (selectedStaff != null) {
|
||||
selectedVehicle = filteredPartnerData.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),
|
||||
SizedBox(
|
||||
height: 35,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5.0),
|
||||
border: Border.all(color: Color(0xFFE2E8F0)),
|
||||
// color: Colors.black,
|
||||
),
|
||||
|
||||
width: ResponsiveLayout.isMobile(context)
|
||||
? null
|
||||
: MediaQuery.of(context).size.width * 0.13,
|
||||
// height: 45,
|
||||
child: DropdownSearch<Map<String, dynamic>>(
|
||||
// key: dropDownKey,
|
||||
key: ValueKey(selectedStaff),
|
||||
// selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null,
|
||||
selectedItem: selectedVehicle,
|
||||
|
||||
items: (filter, infiniteScrollProps) {
|
||||
return filteredPartnerData;
|
||||
},
|
||||
|
||||
itemAsString: (val) => val['name'].toString(),
|
||||
compareFn: (item, selectedItem) =>
|
||||
item['id'] == selectedItem['id'], // ✅ compare by id
|
||||
dropdownBuilder: (context, selectedItem) => Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
selectedItem != null ? selectedItem['name'].toString() : "",
|
||||
style: GoogleFonts.poppins(fontSize: 11, color: Colors.black),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
),
|
||||
),
|
||||
decoratorProps: DropDownDecoratorProps(
|
||||
decoration:
|
||||
AppInputDecorations.dropdownDecoration(
|
||||
label: "Select Staff ",
|
||||
).copyWith(
|
||||
filled: true,
|
||||
fillColor:
|
||||
Colors.white, // 👈 makes the dropdown input white
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 1, // 👈 adjust this to make the field shorter
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
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) {
|
||||
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'];
|
||||
widget.onBrokerChanged!(val['id']);
|
||||
// if (widget.onFilterStaff != null)
|
||||
// widget.onFilterStaff!(val['id']);
|
||||
|
||||
// Future.microtask(() => widget.onFilter());
|
||||
// controllers['agentId']?.text = val['agent_code'];
|
||||
// agentId = agent['id'];
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
static final _textStyle = GoogleFonts.poppins(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
}
|
||||
@ -177,13 +177,16 @@ class _InvoiceListState extends ConsumerState<InvoiceList> {
|
||||
(item['invoice_no'] ?? '-').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
(item['invoice_amount'] ?? '-').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
(item['invoice_amount_indian_format'] ?? '-')
|
||||
.toLowerCase()
|
||||
.contains(query.toLowerCase()) ||
|
||||
(item['broker_name'] ?? '-').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
(item['agent_name'] ?? '-').toLowerCase().contains(
|
||||
(item['pos_name'] ?? '-').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
) ||
|
||||
(item['payout_status'] ?? '-').toLowerCase().contains(
|
||||
query.toLowerCase(),
|
||||
)
|
||||
// ||
|
||||
@ -195,7 +198,7 @@ class _InvoiceListState extends ConsumerState<InvoiceList> {
|
||||
|
||||
final TextEditingController _searchStaffController = TextEditingController();
|
||||
|
||||
String _formatDate(String rawDate) {
|
||||
String _formatDateTime(String rawDate) {
|
||||
try {
|
||||
final dateTime = DateTime.parse(rawDate);
|
||||
return DateFormat('dd-MM-yyyy HH:mm').format(dateTime); // 24-hour format
|
||||
@ -204,61 +207,69 @@ class _InvoiceListState extends ConsumerState<InvoiceList> {
|
||||
}
|
||||
}
|
||||
|
||||
String _formatDate(String rawDate) {
|
||||
try {
|
||||
final dateTime = DateTime.parse(rawDate);
|
||||
return DateFormat('dd-MM-yyyy').format(dateTime); // 24-hour format
|
||||
} catch (e) {
|
||||
return rawDate; // fallback if parsing fails
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MainLayout(
|
||||
title: "Pay Out",
|
||||
body: Container(
|
||||
height: 30,
|
||||
// height: 30,
|
||||
// color: Colors.yellow.shade50,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
height: 30,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
context.go(AppRoutes.dashboard);
|
||||
},
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
// Tooltip(
|
||||
// message: 'Back',
|
||||
// child: IconButton(
|
||||
// icon: const Icon(
|
||||
// Icons.arrow_left_sharp,
|
||||
// size: 25,
|
||||
// color: Color(0xFF425B5B),
|
||||
// ),
|
||||
// onPressed: () {
|
||||
// context.go(AppRoutes.dashboard);
|
||||
// },
|
||||
// splashRadius: 18,
|
||||
// hoverColor: Colors.black12,
|
||||
// padding: const EdgeInsets.all(4),
|
||||
// constraints: const BoxConstraints(),
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(width: 5), // spacing between icon and text
|
||||
Text(
|
||||
"Invoice",
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(height: 5),
|
||||
|
||||
// Container(
|
||||
// height: 30,
|
||||
// width: MediaQuery.of(context).size.width,
|
||||
// child: GestureDetector(
|
||||
// onTap: () {
|
||||
// context.go(AppRoutes.dashboard);
|
||||
// },
|
||||
// child: Row(
|
||||
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||
// mainAxisAlignment: MainAxisAlignment.start,
|
||||
// children: [
|
||||
// // Tooltip(
|
||||
// // message: 'Back',
|
||||
// // child: IconButton(
|
||||
// // icon: const Icon(
|
||||
// // Icons.arrow_left_sharp,
|
||||
// // size: 25,
|
||||
// // color: Color(0xFF425B5B),
|
||||
// // ),
|
||||
// // onPressed: () {
|
||||
// // context.go(AppRoutes.dashboard);
|
||||
// // },
|
||||
// // splashRadius: 18,
|
||||
// // hoverColor: Colors.black12,
|
||||
// // padding: const EdgeInsets.all(4),
|
||||
// // constraints: const BoxConstraints(),
|
||||
// // ),
|
||||
// // ),
|
||||
// // const SizedBox(width: 5), // spacing between icon and text
|
||||
// Text(
|
||||
// "Invoice",
|
||||
// style: GoogleFonts.inter(
|
||||
// fontSize: 14,
|
||||
// fontWeight: FontWeight.w500,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
//
|
||||
// SizedBox(height: 5),
|
||||
Expanded(
|
||||
child: Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
@ -306,71 +317,15 @@ class _InvoiceListState extends ConsumerState<InvoiceList> {
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
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: () {
|
||||
// // call your filter logic
|
||||
// filterDateRange();
|
||||
// },
|
||||
// onRefresh: () {
|
||||
// // call your refresh logic
|
||||
// refrshfilterDateRange();
|
||||
// },
|
||||
// ),
|
||||
//
|
||||
// // Form(
|
||||
// // key: _formKey,
|
||||
// // child: Row(
|
||||
// // mainAxisAlignment: MainAxisAlignment.start,
|
||||
// // crossAxisAlignment: CrossAxisAlignment.end,
|
||||
// // children: [
|
||||
// // buildStartDate(context),
|
||||
// // SizedBox(width: 10),
|
||||
// // buildEndDate(context),
|
||||
// // SizedBox(width: 10),
|
||||
// //
|
||||
// // Padding(
|
||||
// // padding: const EdgeInsets.symmetric(
|
||||
// // vertical: 8.0,
|
||||
// // ),
|
||||
// // child: GestureDetector(
|
||||
// // // onTap: filterDateRange,
|
||||
// // onTap: () {
|
||||
// // if (_formKey.currentState!.validate()) {
|
||||
// // filterDateRange(); // only runs if valid
|
||||
// // }
|
||||
// // },
|
||||
// // child: Icon(Icons.filter_alt_outlined),
|
||||
// // ),
|
||||
// // ),
|
||||
// //
|
||||
// // Padding(
|
||||
// // padding: const EdgeInsets.all(8.0),
|
||||
// // child: GestureDetector(
|
||||
// // onTap: refrshfilterDateRange,
|
||||
// // child: Icon(Icons.refresh),
|
||||
// // ),
|
||||
// // ),
|
||||
// // ],
|
||||
// // ),
|
||||
// // ),
|
||||
// Spacer(),
|
||||
// ],
|
||||
Text(
|
||||
"Invoice",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
|
||||
Spacer(),
|
||||
ThemedSearchField(
|
||||
hintText: 'Search',
|
||||
// backgroundColor: Color(0xFFF6F8F8),
|
||||
@ -383,24 +338,13 @@ class _InvoiceListState extends ConsumerState<InvoiceList> {
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Tooltip(
|
||||
message: 'Export File',
|
||||
message: 'Raise Invoice',
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
context.go(AppRoutes.payout);
|
||||
},
|
||||
// onTap: () {
|
||||
// print('TAV ExcelExporter');
|
||||
//
|
||||
// ExcelExporter.exportToExcel(
|
||||
// sheetName: sheetName,
|
||||
// data: data,
|
||||
// headers: headers,
|
||||
// fileName: fileName,
|
||||
// keys: keys!,
|
||||
// );
|
||||
// },
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF2E7D6E),
|
||||
// color: const Color(0xFF425B5B),
|
||||
@ -414,7 +358,7 @@ class _InvoiceListState extends ConsumerState<InvoiceList> {
|
||||
// height: 25,
|
||||
// width: 25,
|
||||
// ),
|
||||
Icon(Icons.add, color: Colors.white, size: 25),
|
||||
Icon(Icons.add, color: Colors.white, size: 18),
|
||||
// Image.asset("assets/miscellaneous/export", height: 15, width: 15),
|
||||
],
|
||||
),
|
||||
@ -428,20 +372,22 @@ class _InvoiceListState extends ConsumerState<InvoiceList> {
|
||||
data: filteredData,
|
||||
txt: true,
|
||||
displayHeaders: [
|
||||
"Updated Date",
|
||||
"Invoice Date",
|
||||
"Invoice No",
|
||||
"Invoice Date",
|
||||
"Invoice Amount",
|
||||
"Broker Name",
|
||||
"Partner Name",
|
||||
"Broker ",
|
||||
"POS ",
|
||||
"Status ",
|
||||
"Updated Date",
|
||||
],
|
||||
keys: [
|
||||
"updated_at",
|
||||
"invoice_date",
|
||||
"invoice_no",
|
||||
"invoice_amount",
|
||||
"invoice_amount_indian_format",
|
||||
"broker_name",
|
||||
"agent_name",
|
||||
"pos_name",
|
||||
"payout_status",
|
||||
"updated_at",
|
||||
],
|
||||
),
|
||||
],
|
||||
@ -450,34 +396,32 @@ class _InvoiceListState extends ConsumerState<InvoiceList> {
|
||||
SizedBox(height: 5),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xFFEDF6F5),
|
||||
color: Color(0xFFF1F5F9),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
|
||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(flex: 3, child: Text('Invoice No', style: _headerStyle)),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
flex: 2,
|
||||
child: Text('Invoice Date', style: _headerStyle),
|
||||
),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
flex: 2,
|
||||
child: Text('Invoice Amount', style: _headerStyle),
|
||||
),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
flex: 2,
|
||||
child: Text('Broker Name', style: _headerStyle),
|
||||
),
|
||||
Expanded(flex: 2, child: Text('POS Name', style: _headerStyle)),
|
||||
Expanded(flex: 2, child: Text('Status', style: _headerStyle)),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text('Partner Name', style: _headerStyle),
|
||||
),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
flex: 2,
|
||||
child: Text('Updated Date', style: _headerStyle),
|
||||
),
|
||||
Expanded(flex: 3, child: Text('Action', style: _headerStyle)),
|
||||
Expanded(flex: 2, child: Text('Action', style: _headerStyle)),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -516,7 +460,7 @@ class _InvoiceListState extends ConsumerState<InvoiceList> {
|
||||
|
||||
Widget _buildDataRow(Map<String, dynamic> item, sno) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 16),
|
||||
// margin: const EdgeInsets.only(top: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
@ -533,40 +477,62 @@ class _InvoiceListState extends ConsumerState<InvoiceList> {
|
||||
child: Text(item['invoice_no'] ?? '-', style: _dataBold),
|
||||
),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(item['invoice_date'] ?? '-', style: _dataBold),
|
||||
flex: 2,
|
||||
child: Text(
|
||||
item['invoice_date'] != null
|
||||
? _formatDate(item['invoice_date'])
|
||||
: '-',
|
||||
style: _dataBold,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
flex: 2,
|
||||
child: Text(
|
||||
item['invoice_amount'] ?? '-',
|
||||
item['invoice_amount_indian_format'] ?? '-',
|
||||
style: _dataBold,
|
||||
softWrap: true,
|
||||
maxLines: 3,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
flex: 2,
|
||||
child: Text(
|
||||
item['broker_name'] ?? '-',
|
||||
item['broker_name'] != null ? item['broker_name'] : '-',
|
||||
style: _dataBold,
|
||||
softWrap: true,
|
||||
maxLines: 3,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
flex: 2,
|
||||
child: Text(
|
||||
item['agent_name'] ?? '-',
|
||||
item['pos_name'] != null ? item['pos_name'] : '-',
|
||||
style: _dataBold,
|
||||
softWrap: true,
|
||||
maxLines: 3,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
flex: 2,
|
||||
child: Text(
|
||||
_formatDate(item['updated_at']) ?? '-',
|
||||
// item['payout_status'] != null ? item['payout_status'] : '-',
|
||||
item['payout_status'] == '1'
|
||||
? 'Pending'
|
||||
: item['payout_status'] != null
|
||||
? 'Completed'
|
||||
: '-',
|
||||
style: _dataBold,
|
||||
softWrap: true,
|
||||
maxLines: 3,
|
||||
),
|
||||
),
|
||||
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
item['updated_at'] != null
|
||||
? _formatDateTime(item['updated_at'])
|
||||
: '-',
|
||||
style: _dataBold,
|
||||
softWrap: true,
|
||||
maxLines: 3,
|
||||
@ -577,27 +543,38 @@ class _InvoiceListState extends ConsumerState<InvoiceList> {
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
// EDIT ICON
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit, color: Colors.blue, size: 20),
|
||||
icon: const Icon(
|
||||
Icons.remove_red_eye_outlined,
|
||||
color: Colors.blue,
|
||||
size: 18,
|
||||
),
|
||||
onPressed: () {
|
||||
// TODO: handle edit
|
||||
context.go(AppRoutes.payout, extra: item);
|
||||
print("Edit clicked for ${item['invoice_no']}");
|
||||
},
|
||||
splashRadius: 18,
|
||||
hoverColor: Colors.black12,
|
||||
padding: const EdgeInsets.all(8),
|
||||
constraints: const BoxConstraints(),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
|
||||
// DELETE ICON
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete, color: Colors.red, size: 20),
|
||||
icon: const Icon(Icons.delete, color: Colors.red, size: 18),
|
||||
onPressed: () {
|
||||
// TODO: handle delete
|
||||
deleteInvoice(item['id']);
|
||||
print("Delete clicked for ${item['invoice_no']}");
|
||||
},
|
||||
splashRadius: 18,
|
||||
hoverColor: Colors.black12,
|
||||
padding: const EdgeInsets.all(8),
|
||||
constraints: const BoxConstraints(),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -608,14 +585,14 @@ class _InvoiceListState extends ConsumerState<InvoiceList> {
|
||||
}
|
||||
|
||||
static final _dataBold = GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
|
||||
fontSize: 11.5,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Color(0xFF000000),
|
||||
);
|
||||
|
||||
static final _headerStyle = GoogleFonts.inter(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
static final _headerStyle = GoogleFonts.poppins(
|
||||
fontSize: 11.2,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF1E293B),
|
||||
);
|
||||
}
|
||||
|
||||
1070
lib/presentation/screens/payout/payout_old.dart
Normal file
1070
lib/presentation/screens/payout/payout_old.dart
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -371,46 +371,62 @@ class _SubRowWidgetState extends ConsumerState<SubRowWidget> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
buildSelectStaffMem(context),
|
||||
buildAgentName(context, fromHeader: false),
|
||||
buildInsurer(context),
|
||||
buildBroker(context),
|
||||
buildInsuredName(context),
|
||||
buildVehicleNumber(context),
|
||||
buildEmail(context),
|
||||
buildPhNumber(context),
|
||||
buildRemarks(context),
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
buildSelectStaffMem(context),
|
||||
buildAgentName(context, fromHeader: false),
|
||||
buildInsurer(context),
|
||||
buildBroker(context),
|
||||
buildInsuredName(context),
|
||||
buildVehicleNumber(context),
|
||||
buildEmail(context),
|
||||
buildPhNumber(context),
|
||||
buildRemarks(context),
|
||||
|
||||
IconButton(
|
||||
tooltip: 'Save',
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(minWidth: 24, minHeight: 24),
|
||||
icon: const Icon(
|
||||
Icons.check,
|
||||
color: Colors.green,
|
||||
size: 28, // smaller icon
|
||||
),
|
||||
splashRadius: 14, //
|
||||
onPressed: () => widget.onSave(widget.selectId),
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
|
||||
IconButton(
|
||||
tooltip: 'Close',
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(minWidth: 24, minHeight: 24),
|
||||
icon: const Icon(
|
||||
Icons.close,
|
||||
color: Colors.indigo,
|
||||
size: 28, // smaller icon
|
||||
children: [
|
||||
IconButton(
|
||||
tooltip: 'Save',
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(minWidth: 14, minHeight: 24),
|
||||
icon: const Icon(
|
||||
Icons.check,
|
||||
color: Colors.green,
|
||||
size: 20, // smaller icon
|
||||
),
|
||||
splashRadius: 14, //
|
||||
onPressed: () {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
|
||||
widget.onSave(widget.selectId);
|
||||
},
|
||||
),
|
||||
|
||||
IconButton(
|
||||
tooltip: 'Close',
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(minWidth: 14, minHeight: 24),
|
||||
icon: const Icon(
|
||||
Icons.close,
|
||||
color: Colors.indigo,
|
||||
size: 20, // smaller icon
|
||||
),
|
||||
splashRadius: 14, //
|
||||
onPressed: widget.onClose,
|
||||
),
|
||||
],
|
||||
),
|
||||
splashRadius: 14, //
|
||||
onPressed: widget.onClose,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -446,12 +462,12 @@ class _SubRowWidgetState extends ConsumerState<SubRowWidget> {
|
||||
itemAsString: (val) => val['name'].toString(), // what to show
|
||||
compareFn: (item, selectedItem) =>
|
||||
item['id'] == selectedItem['id'], // ✅ compare by id
|
||||
validator: (val) {
|
||||
if (val == null) {
|
||||
return "Required"; // ✅ error message
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// validator: (val) {
|
||||
// if (val == null) {
|
||||
// return "Required"; // ✅ error message
|
||||
// }
|
||||
// return null;
|
||||
// },
|
||||
suffixProps: DropdownSuffixProps(
|
||||
// make sure the dropdown button is visible
|
||||
dropdownButtonProps: DropdownButtonProps(
|
||||
@ -608,6 +624,10 @@ class _SubRowWidgetState extends ConsumerState<SubRowWidget> {
|
||||
hintText: 'Vehicle Number',
|
||||
borderColor: Color(0XFF6366F1),
|
||||
textColr: Color(0XFF6366F1),
|
||||
enableBorderWidth: 0.5,
|
||||
bordedRad: 5,
|
||||
errFieldHgt: 10,
|
||||
errFieldFont: 0,
|
||||
isdense: true,
|
||||
inputFormatters: [
|
||||
UpperCaseTextFormatter(), // 👈 custom formatter for uppercase
|
||||
@ -662,7 +682,7 @@ class _SubRowWidgetState extends ConsumerState<SubRowWidget> {
|
||||
// errorText: fieldErrors['name'],
|
||||
borderColor: Color(0XFF6366F1),
|
||||
isdense: true,
|
||||
validator: (value) => Validators.requiredField(value, "name"),
|
||||
// validator: (value) => Validators.requiredField(value, "name"),
|
||||
widthNone: true,
|
||||
),
|
||||
),
|
||||
@ -678,11 +698,15 @@ class _SubRowWidgetState extends ConsumerState<SubRowWidget> {
|
||||
SizedBox(height: 5),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.1,
|
||||
child: ThemedFormInlineField(
|
||||
child: ThemedFormField(
|
||||
controller: widget.controllers['email']!,
|
||||
borderColor: Color(0XFF6366F1),
|
||||
textColr: Color(0XFF6366F1),
|
||||
hintText: 'Email',
|
||||
bordedRad: 5,
|
||||
enableBorderWidth: 0.5,
|
||||
// errFieldHgt: 10,
|
||||
// errFieldFont: 0,
|
||||
isdense: true,
|
||||
validator: (value) => Validators.nonReqemail(value, "email"),
|
||||
inputFormatters: [
|
||||
@ -705,15 +729,17 @@ class _SubRowWidgetState extends ConsumerState<SubRowWidget> {
|
||||
SizedBox(height: 5),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.1,
|
||||
child: ThemedFormInlineField(
|
||||
child: ThemedFormField(
|
||||
controller: widget.controllers['mobile']!,
|
||||
borderColor: Color(0XFF6366F1),
|
||||
textColr: Color(0XFF6366F1),
|
||||
hintText: 'Mobile',
|
||||
enableBorderWidth: 0.5,
|
||||
bordedRad: 5,
|
||||
isdense: true,
|
||||
validator: (value) => Validators.nonReqphone(value, "phone"),
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[ 0-9]')),
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
|
||||
],
|
||||
txtwidth: ResponsiveLayout.isMobile(context)
|
||||
? null
|
||||
@ -737,6 +763,7 @@ class _SubRowWidgetState extends ConsumerState<SubRowWidget> {
|
||||
controller: widget.controllers['remarks']!,
|
||||
borderColor: Color(0XFF6366F1),
|
||||
textColr: Color(0XFF6366F1),
|
||||
bordedRad: 5,
|
||||
verticalPad: 10,
|
||||
horizonalPad: 10,
|
||||
isdense: true,
|
||||
@ -785,12 +812,12 @@ class _SubRowWidgetState extends ConsumerState<SubRowWidget> {
|
||||
itemAsString: (val) => val['name'].toString(),
|
||||
compareFn: (item, selectedItem) =>
|
||||
item['id'] == selectedItem['id'], // ✅ compare by id
|
||||
validator: (val) {
|
||||
if (val == null) {
|
||||
return "Required"; // ✅ error message
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// validator: (val) {
|
||||
// if (val == null) {
|
||||
// return "Required"; // ✅ error message
|
||||
// }
|
||||
// return null;
|
||||
// },
|
||||
suffixProps: DropdownSuffixProps(
|
||||
// make sure the dropdown button is visible
|
||||
dropdownButtonProps: DropdownButtonProps(
|
||||
@ -963,12 +990,12 @@ class _SubRowWidgetState extends ConsumerState<SubRowWidget> {
|
||||
itemAsString: (val) => val['short_name'].toString(), // what to show
|
||||
compareFn: (item, selectedItem) =>
|
||||
item['id'] == selectedItem['id'], // ✅ compare by id
|
||||
validator: (val) {
|
||||
if (val == null) {
|
||||
return "Required"; // ✅ error message
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// validator: (val) {
|
||||
// if (val == null) {
|
||||
// return "Required"; // ✅ error message
|
||||
// }
|
||||
// return null;
|
||||
// },
|
||||
suffixProps: DropdownSuffixProps(
|
||||
// make sure the dropdown button is visible
|
||||
dropdownButtonProps: DropdownButtonProps(
|
||||
@ -1117,12 +1144,12 @@ class _SubRowWidgetState extends ConsumerState<SubRowWidget> {
|
||||
itemAsString: (val) => val['name'].toString(), // what to show
|
||||
compareFn: (item, selectedItem) =>
|
||||
item['id'] == selectedItem['id'], // ✅ compare by id
|
||||
validator: (val) {
|
||||
if (val == null) {
|
||||
return "Required"; // ✅ error message
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// validator: (val) {
|
||||
// if (val == null) {
|
||||
// return "Required"; // ✅ error message
|
||||
// }
|
||||
// return null;
|
||||
// },
|
||||
suffixProps: DropdownSuffixProps(
|
||||
// make sure the dropdown button is visible
|
||||
dropdownButtonProps: DropdownButtonProps(
|
||||
|
||||
@ -52,12 +52,14 @@ class EnquiryListStaffInline extends ConsumerStatefulWidget {
|
||||
class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
|
||||
int currentPage = 1;
|
||||
int itemsPerPage = 10;
|
||||
// int itemsPerPage = 5;
|
||||
|
||||
int completedCurrentPage = 1;
|
||||
// int completedItemsPerPage = 5;
|
||||
int completedItemsPerPage = 50;
|
||||
int totalCompletedPages = 1;
|
||||
List<int> itemsPerPageOptions = [25, 50, 100, 200];
|
||||
|
||||
Timer? _debounce;
|
||||
late ApiService apiService;
|
||||
dynamic userId;
|
||||
dynamic idPrimary;
|
||||
@ -389,21 +391,80 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
|
||||
}
|
||||
|
||||
// Add this getter method to calculate paginated completed data
|
||||
// List<Map<String, dynamic>> get paginatedCompletedData {
|
||||
// if (completedData.isEmpty) return [];
|
||||
//
|
||||
// // Calculate total pages
|
||||
// totalCompletedPages = (completedData.length / completedItemsPerPage).ceil();
|
||||
//
|
||||
// // Calculate start and end indices
|
||||
// final startIndex = (completedCurrentPage - 1) * completedItemsPerPage;
|
||||
// final endIndex = (startIndex + completedItemsPerPage).clamp(
|
||||
// 0,
|
||||
// completedData.length,
|
||||
// );
|
||||
//
|
||||
// // Return paginated subset
|
||||
// return completedData.sublist(startIndex, endIndex);
|
||||
// }
|
||||
|
||||
List<Map<String, dynamic>> get paginatedCompletedData1 {
|
||||
// If search is active (filteredData is different from completedData), use filteredData
|
||||
// Otherwise use completedData
|
||||
final dataToUse = filteredData;
|
||||
|
||||
print("paginatedCompletedData - $dataToUse");
|
||||
|
||||
if (dataToUse.isEmpty) return [];
|
||||
|
||||
// For completed tab only
|
||||
if (selectedIndex == 1) {
|
||||
// Calculate total pages based on current data
|
||||
totalCompletedPages = (dataToUse.length / completedItemsPerPage).ceil();
|
||||
if (totalCompletedPages == 0) totalCompletedPages = 1;
|
||||
|
||||
// Calculate start and end indices
|
||||
final startIndex = (completedCurrentPage - 1) * completedItemsPerPage;
|
||||
final endIndex = (startIndex + completedItemsPerPage).clamp(
|
||||
0,
|
||||
dataToUse.length,
|
||||
);
|
||||
|
||||
// Return paginated subset
|
||||
return dataToUse.sublist(startIndex, endIndex);
|
||||
}
|
||||
|
||||
return dataToUse;
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> get paginatedCompletedData {
|
||||
if (completedData.isEmpty) return [];
|
||||
final dataToUse = filteredData;
|
||||
|
||||
// Calculate total pages
|
||||
totalCompletedPages = (completedData.length / completedItemsPerPage).ceil();
|
||||
if (dataToUse.isEmpty) return [];
|
||||
|
||||
// Calculate start and end indices
|
||||
final startIndex = (completedCurrentPage - 1) * completedItemsPerPage;
|
||||
final endIndex = (startIndex + completedItemsPerPage).clamp(
|
||||
0,
|
||||
completedData.length,
|
||||
);
|
||||
if (selectedIndex == 1) {
|
||||
totalCompletedPages = (dataToUse.length / completedItemsPerPage)
|
||||
.ceil()
|
||||
.clamp(1, double.infinity)
|
||||
.toInt();
|
||||
|
||||
// Return paginated subset
|
||||
return completedData.sublist(startIndex, endIndex);
|
||||
final startIndex = (completedCurrentPage - 1) * completedItemsPerPage;
|
||||
|
||||
// 🚨 Guard: page out of range after search
|
||||
if (startIndex >= dataToUse.length) {
|
||||
completedCurrentPage = 1;
|
||||
return dataToUse.take(completedItemsPerPage).toList();
|
||||
}
|
||||
|
||||
final endIndex = (startIndex + completedItemsPerPage).clamp(
|
||||
0,
|
||||
dataToUse.length,
|
||||
);
|
||||
|
||||
return dataToUse.sublist(startIndex, endIndex);
|
||||
}
|
||||
|
||||
return dataToUse;
|
||||
}
|
||||
|
||||
Future<void> autoRefrshfilterDateRange() async {
|
||||
@ -647,6 +708,10 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
|
||||
? List.from(inProgressData)
|
||||
: List.from(completedData);
|
||||
|
||||
if (SelectedStatus == 'Completed') {
|
||||
selectedIndex = 1;
|
||||
}
|
||||
|
||||
print('filteredData count: ${filteredData.length}');
|
||||
print('inProgressData count: ${inProgressData.length}');
|
||||
print('completedData count: ${completedData.length}');
|
||||
@ -671,7 +736,180 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
|
||||
}
|
||||
}
|
||||
|
||||
String safeString(dynamic value) {
|
||||
if (value == null) return '';
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
void filterData(String query) {
|
||||
_debounce?.cancel();
|
||||
_debounce = Timer(const Duration(milliseconds: 300), () {
|
||||
_applyFilter(query);
|
||||
});
|
||||
}
|
||||
|
||||
void _applyFilter(String query) {
|
||||
print("FilterData - $query");
|
||||
|
||||
setState(() {
|
||||
final sourceList = (selectedIndex == 0) ? inProgressData : completedData;
|
||||
|
||||
final q = query.trim().toLowerCase();
|
||||
|
||||
completedCurrentPage = 1;
|
||||
|
||||
if (q.length < 2) {
|
||||
filteredData = List.from(sourceList);
|
||||
return;
|
||||
}
|
||||
|
||||
filteredData = sourceList.where((item) {
|
||||
return safeString(item['agent_name']).toLowerCase().contains(q) ||
|
||||
safeString(item['agent_code']).toLowerCase().contains(q) ||
|
||||
safeString(item['reg_no']).toLowerCase().contains(q) ||
|
||||
safeString(item['insured_name']).toLowerCase().contains(q) ||
|
||||
safeString(item['policy_number']).toLowerCase().contains(q) ||
|
||||
safeString(item['broker_name']).toLowerCase().contains(q) ||
|
||||
safeString(item['insurer_name']).toLowerCase().contains(q) ||
|
||||
safeString(item['insurer_short_name']).toLowerCase().contains(q) ||
|
||||
safeString(item['enquiry_status']).toLowerCase().contains(q) ||
|
||||
safeString(item['assigned_to_name']).toLowerCase().contains(q) ||
|
||||
safeString(item['status']).toLowerCase().contains(q) ||
|
||||
safeString(item['payment_mode']).toLowerCase().contains(q) ||
|
||||
safeString(item['premium_amount']).toLowerCase().contains(q) ||
|
||||
safeString(
|
||||
_formatDate(item['created_on']),
|
||||
).toLowerCase().contains(q) ||
|
||||
safeString(
|
||||
_formatDate(item['updated_on']),
|
||||
).toLowerCase().contains(q);
|
||||
}).toList();
|
||||
|
||||
print("FilterData2 - ${filteredData.length}");
|
||||
});
|
||||
}
|
||||
|
||||
// void _applyFilter(String query) {
|
||||
// print("FilterData - $query");
|
||||
// setState(() {
|
||||
// // ALWAYS search from the FULL source list, not current filtered results
|
||||
// final sourceList = (selectedIndex == 0) ? inProgressData : completedData;
|
||||
//
|
||||
// final q = query.trim().toLowerCase();
|
||||
//
|
||||
// if (q.length < 2) {
|
||||
// filteredData = List.from(sourceList);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (query.isEmpty) {
|
||||
// // If search is empty, show all data for current tab
|
||||
// filteredData = List.from(sourceList);
|
||||
//
|
||||
// print("FilterData1 - $filteredData");
|
||||
// } else {
|
||||
// // Search within ALL data from the current tab's source
|
||||
// filteredData = sourceList.where((item) {
|
||||
// final searchLower = query.toLowerCase();
|
||||
//
|
||||
// return safeString(
|
||||
// item['agent_name'],
|
||||
// ).toLowerCase().contains(searchLower) ||
|
||||
// safeString(
|
||||
// item['agent_code'],
|
||||
// ).toLowerCase().contains(searchLower) ||
|
||||
// safeString(item['reg_no']).toLowerCase().contains(searchLower) ||
|
||||
// safeString(
|
||||
// item['insurer_name'],
|
||||
// ).toLowerCase().contains(searchLower) ||
|
||||
// safeString(
|
||||
// item['enquiry_status'],
|
||||
// ).toLowerCase().contains(searchLower) ||
|
||||
// safeString(
|
||||
// item['assigned_to_name'],
|
||||
// ).toLowerCase().contains(searchLower) ||
|
||||
// safeString(
|
||||
// item['insured_name'],
|
||||
// ).toLowerCase().contains(searchLower) ||
|
||||
// safeString(
|
||||
// item['insurer_short_name'],
|
||||
// ).toLowerCase().contains(searchLower) ||
|
||||
// safeString(
|
||||
// item['premium_amount']?.toString(),
|
||||
// ).contains(searchLower) ||
|
||||
// safeString(
|
||||
// item['payment_mode'],
|
||||
// ).toLowerCase().contains(searchLower) ||
|
||||
// safeString(
|
||||
// item['broker_name'],
|
||||
// ).toLowerCase().contains(searchLower) ||
|
||||
// safeString(
|
||||
// _formatDate(item['created_on']),
|
||||
// ).toLowerCase().contains(q) ||
|
||||
// safeString(
|
||||
// _formatDate(item['updated_on']),
|
||||
// ).toLowerCase().contains(q) ||
|
||||
// safeString(
|
||||
// item['policy_number'],
|
||||
// ).toLowerCase().contains(searchLower) ||
|
||||
// safeString(item['status']).toLowerCase().contains(searchLower);
|
||||
//
|
||||
// // return safeString(
|
||||
// // item['agent_name'] ?? '-',
|
||||
// // ).toLowerCase().contains(searchLower) ||
|
||||
// // safeString(
|
||||
// // item['agent_code'] ?? '-',
|
||||
// // ).toLowerCase().contains(searchLower) ||
|
||||
// // safeString(
|
||||
// // item['reg_no'] ?? '-',
|
||||
// // ).toLowerCase().contains(searchLower) ||
|
||||
// // safeString(
|
||||
// // item['insurer_name'] ?? '-',
|
||||
// // ).toLowerCase().contains(searchLower) ||
|
||||
// // safeString(
|
||||
// // item['enquiry_status'] ?? '-',
|
||||
// // ).toLowerCase().contains(searchLower) ||
|
||||
// // safeString(
|
||||
// // item['assigned_to_name'] ?? '-',
|
||||
// // ).toLowerCase().contains(searchLower) ||
|
||||
// // safeString(
|
||||
// // item['insured_name'] ?? '-',
|
||||
// // ).toLowerCase().contains(searchLower) ||
|
||||
// // safeString(
|
||||
// // item['insurer_short_name'] ?? '-',
|
||||
// // ).toLowerCase().contains(searchLower) ||
|
||||
// // safeString(
|
||||
// // item['premium_amount'] ?? '-',
|
||||
// // ).toString().toLowerCase().contains(searchLower) ||
|
||||
// // safeString(
|
||||
// // item['payment_mode'] ?? '-',
|
||||
// // ).toLowerCase().contains(searchLower) ||
|
||||
// // safeString(
|
||||
// // item['broker_name'] ?? '-',
|
||||
// // ).toLowerCase().contains(searchLower) ||
|
||||
// // safeString(
|
||||
// // _formatDate(item['created_on']),
|
||||
// // ).toLowerCase().contains(searchLower) ||
|
||||
// // safeString(
|
||||
// // _formatDate(item['updated_on']),
|
||||
// // ).toLowerCase().contains(searchLower) ||
|
||||
// // safeString(
|
||||
// // item['policy_number'] ?? '-',
|
||||
// // ).toLowerCase().contains(searchLower) ||
|
||||
// // safeString(
|
||||
// // item['status'] ?? '-',
|
||||
// // ).toLowerCase().contains(searchLower);
|
||||
// }).toList();
|
||||
// print("FilterData2 - $filteredData");
|
||||
// // Reset to page 1 when searching in completed tab
|
||||
// if (selectedIndex == 1) {
|
||||
// completedCurrentPage = 1;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
void filterData1(String query) {
|
||||
print("FilterData - $query");
|
||||
setState(() {
|
||||
// Get the correct source list based on selected tab
|
||||
@ -730,6 +968,10 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
if (selectedIndex == 1) {
|
||||
completedCurrentPage = 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -1537,6 +1779,17 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
MouseRegion(
|
||||
onEnter: (_) {
|
||||
setState(() {
|
||||
isActionable = true;
|
||||
});
|
||||
},
|
||||
onExit: (_) {
|
||||
setState(() {
|
||||
// isActionable = false;
|
||||
isActionable = _searchStaffController.text.isNotEmpty;
|
||||
});
|
||||
},
|
||||
child: ThemedSearchField(
|
||||
hintText: 'Search',
|
||||
backgroundColor: Color(0xFFFFFFFF),
|
||||
@ -1614,49 +1867,13 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
|
||||
'Assigned': 'Assigned',
|
||||
'In progress': 'In Progress',
|
||||
};
|
||||
|
||||
List<Map<String, dynamic>> get filteredDataByTab1 {
|
||||
if (selectedIndex == 0) {
|
||||
// Progress enquiries
|
||||
final sortedData = [...inProgressData]
|
||||
..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
|
||||
|
||||
// final sortedData = [...filteredData]
|
||||
// ..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
|
||||
|
||||
if (sortedData.isEmpty) return [];
|
||||
return sortedData.where((e) {
|
||||
return [
|
||||
"To be assigned",
|
||||
"Assigned",
|
||||
"In progress",
|
||||
].contains(e['enquiry_status']);
|
||||
}).toList();
|
||||
} else {
|
||||
// final sortedData = [...filteredData]
|
||||
// ..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
|
||||
|
||||
final sortedData = [...completedData]
|
||||
..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
|
||||
|
||||
if (sortedData.isEmpty) return [];
|
||||
// Completed enquiries
|
||||
return paginatedCompletedData;
|
||||
// return sortedData.where((e) {
|
||||
// return e['enquiry_status'] == "Completed";
|
||||
// }).toList();
|
||||
}
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> get filteredDataByTab {
|
||||
// Use filteredData instead of the raw source lists
|
||||
final sortedData = [...filteredData]
|
||||
..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
|
||||
|
||||
if (sortedData.isEmpty) return [];
|
||||
|
||||
if (selectedIndex == 0) {
|
||||
// Progress enquiries - return filtered in-progress items
|
||||
return sortedData.where((e) {
|
||||
return [
|
||||
"To be assigned",
|
||||
@ -1664,26 +1881,10 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
|
||||
"In progress",
|
||||
].contains(e['enquiry_status']);
|
||||
}).toList();
|
||||
} else {
|
||||
// Completed enquiries - apply pagination to filtered completed items
|
||||
final completedFiltered = sortedData.where((e) {
|
||||
return e['enquiry_status'] == "Completed";
|
||||
}).toList();
|
||||
|
||||
// Update total pages based on filtered results
|
||||
totalCompletedPages = (completedFiltered.length / completedItemsPerPage)
|
||||
.ceil();
|
||||
if (totalCompletedPages == 0) totalCompletedPages = 1;
|
||||
|
||||
// Apply pagination
|
||||
final startIndex = (completedCurrentPage - 1) * completedItemsPerPage;
|
||||
final endIndex = (startIndex + completedItemsPerPage).clamp(
|
||||
0,
|
||||
completedFiltered.length,
|
||||
);
|
||||
|
||||
return completedFiltered.sublist(startIndex, endIndex);
|
||||
}
|
||||
|
||||
// Completed tab → ALWAYS paginate
|
||||
return paginatedCompletedData;
|
||||
}
|
||||
|
||||
// Add group enquiries by status
|
||||
@ -2647,7 +2848,12 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
|
||||
: '-',
|
||||
style: _dataBold,
|
||||
),
|
||||
Text(_formatDate(item['updated_on']), style: _dataBoldthm4),
|
||||
Text(
|
||||
item['updated_on'] != null
|
||||
? _formatDate(item['updated_on'])
|
||||
: '-',
|
||||
style: _dataBoldthm4,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -2828,10 +3034,15 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
|
||||
setState(() {
|
||||
print('TAPPED TAB');
|
||||
selectedIndex = index;
|
||||
|
||||
filteredData = (index == 0) ? inProgressData : completedData;
|
||||
if (index == 1) {
|
||||
completedCurrentPage = 1;
|
||||
// final newValue = false;
|
||||
// isActionable = newValue;
|
||||
}
|
||||
|
||||
_searchStaffController.clear();
|
||||
});
|
||||
},
|
||||
child: AnimatedContainer(
|
||||
@ -3079,6 +3290,129 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
|
||||
if (selectedIndex != 1 || completedData.length <= 25) {
|
||||
return SizedBox.shrink();
|
||||
}
|
||||
// if (selectedIndex != 1 || completedData.length <= 25) {
|
||||
// return SizedBox.shrink();
|
||||
// }
|
||||
|
||||
// Calculate display values based on filteredData
|
||||
final totalItems = filteredData.length;
|
||||
final startItem = ((completedCurrentPage - 1) * completedItemsPerPage) + 1;
|
||||
final endItem = (completedCurrentPage * completedItemsPerPage).clamp(
|
||||
0,
|
||||
totalItems,
|
||||
);
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 2, horizontal: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
border: Border(top: BorderSide(color: Color(0xFFE2E8F0))),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
'Showing $startItem-$endItem of $totalItems', // ← Changed this
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 10,
|
||||
color: Color(0xFF64748B),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 16),
|
||||
// Items per page dropdown
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Color(0xFFE2E8F0)),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: DropdownButton<int>(
|
||||
value: completedItemsPerPage,
|
||||
underline: SizedBox(),
|
||||
isDense: true,
|
||||
items: itemsPerPageOptions.map((int value) {
|
||||
return DropdownMenuItem<int>(
|
||||
value: value,
|
||||
child: Text(
|
||||
'$value / page',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 10,
|
||||
color: Color(0xFF334155),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (int? newValue) {
|
||||
if (newValue != null) {
|
||||
setState(() {
|
||||
completedItemsPerPage = newValue;
|
||||
completedCurrentPage = 1;
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// Pagination buttons remain the same
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.first_page, size: 18),
|
||||
onPressed: completedCurrentPage > 1
|
||||
? () => setState(() => completedCurrentPage = 1)
|
||||
: null,
|
||||
color: completedCurrentPage > 1
|
||||
? Color(0xFF2E7D6E)
|
||||
: Colors.grey,
|
||||
tooltip: 'First page',
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.chevron_left, size: 18),
|
||||
onPressed: completedCurrentPage > 1
|
||||
? () => setState(() => completedCurrentPage--)
|
||||
: null,
|
||||
color: completedCurrentPage > 1
|
||||
? Color(0xFF2E7D6E)
|
||||
: Colors.grey,
|
||||
tooltip: 'Previous page',
|
||||
),
|
||||
..._buildPageNumbers(),
|
||||
IconButton(
|
||||
icon: Icon(Icons.chevron_right, size: 18),
|
||||
onPressed: completedCurrentPage < totalCompletedPages
|
||||
? () => setState(() => completedCurrentPage++)
|
||||
: null,
|
||||
color: completedCurrentPage < totalCompletedPages
|
||||
? Color(0xFF2E7D6E)
|
||||
: Colors.grey,
|
||||
tooltip: 'Next page',
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.last_page, size: 18),
|
||||
onPressed: completedCurrentPage < totalCompletedPages
|
||||
? () => setState(
|
||||
() => completedCurrentPage = totalCompletedPages,
|
||||
)
|
||||
: null,
|
||||
color: completedCurrentPage < totalCompletedPages
|
||||
? Color(0xFF2E7D6E)
|
||||
: Colors.grey,
|
||||
tooltip: 'Last page',
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPaginationControls1() {
|
||||
if (selectedIndex != 1 || completedData.length <= 25) {
|
||||
return SizedBox.shrink();
|
||||
}
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 2, horizontal: 16),
|
||||
@ -3093,7 +3427,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
'Showing ${((completedCurrentPage - 1) * completedItemsPerPage) + 1}-${(completedCurrentPage * completedItemsPerPage).clamp(0, completedData.length)} of ${completedData.length}',
|
||||
'Showing ${((completedCurrentPage - 1) * completedItemsPerPage) + 1}-${(completedCurrentPage * completedItemsPerPage).clamp(0, filteredData.length)} of ${filteredData.length}',
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 10,
|
||||
color: Color(0xFF64748B),
|
||||
|
||||
@ -423,6 +423,7 @@ class RaiseEnqFormState extends ConsumerState<RaiseEnqForm> {
|
||||
buildVehicleNumber(context),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
buildRefresh(context),
|
||||
SizedBox(width: 5),
|
||||
|
||||
@ -775,7 +775,7 @@ class policylistState extends ConsumerState<policylist> {
|
||||
context.push(AppRoutes.policyValidation, extra: item);
|
||||
},
|
||||
child: Container(
|
||||
width: 110, // ⭐ FIXED WIDTH → Equal in both states
|
||||
width: 80, // ⭐ FIXED WIDTH → Equal in both states
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 4,
|
||||
@ -787,8 +787,9 @@ class policylistState extends ConsumerState<policylist> {
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center, // ⭐ Center content
|
||||
MainAxisAlignment.spaceEvenly, // ⭐ Center content
|
||||
children: [
|
||||
Icon(
|
||||
item['is_data_accuracy_checked'] == '1'
|
||||
@ -797,12 +798,12 @@ class policylistState extends ConsumerState<policylist> {
|
||||
size: 12,
|
||||
color: Colors.white,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
const SizedBox(width: 1),
|
||||
Text(
|
||||
item['is_data_accuracy_checked'] == '1'
|
||||
? 'Verified'
|
||||
: 'Click to Verify',
|
||||
style: const TextStyle(
|
||||
: 'To Verify',
|
||||
style: GoogleFonts.poppins(
|
||||
color: Colors.white,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1355
lib/presentation/screens/staff/policy/policy_validation_old.dart
Normal file
1355
lib/presentation/screens/staff/policy/policy_validation_old.dart
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,18 @@
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter/cupertino.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 '../../../data/models/bar_data.dart';
|
||||
import '../../providers/manager_provider.dart';
|
||||
import 'appChartColors.dart';
|
||||
|
||||
class CustomBarChart extends StatefulWidget {
|
||||
class CustomBarChart extends ConsumerStatefulWidget {
|
||||
final List<BarData> dataList;
|
||||
final List<String> labels;
|
||||
final List<String>? shortName;
|
||||
final String title;
|
||||
final String? btnName;
|
||||
final double maxY;
|
||||
@ -17,6 +22,7 @@ class CustomBarChart extends StatefulWidget {
|
||||
super.key,
|
||||
required this.dataList,
|
||||
required this.labels,
|
||||
this.shortName,
|
||||
this.btnName,
|
||||
this.title = "Horizontal Bar Chart",
|
||||
this.maxY = 20,
|
||||
@ -26,23 +32,27 @@ class CustomBarChart extends StatefulWidget {
|
||||
final shadowColor = const Color(0xFFCCCCCC);
|
||||
|
||||
@override
|
||||
State<CustomBarChart> createState() => _CustomBarChartState();
|
||||
// State<CustomBarChart> createState() => _CustomBarChartState();
|
||||
ConsumerState<CustomBarChart> createState() => _CustomBarChartState();
|
||||
}
|
||||
|
||||
class _CustomBarChartState extends State<CustomBarChart> {
|
||||
class _CustomBarChartState extends ConsumerState<CustomBarChart> {
|
||||
int touchedGroupIndex = -1;
|
||||
late int rotationTurns;
|
||||
dynamic managerId;
|
||||
late ApiService apiService;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
apiService = ApiService();
|
||||
rotationTurns = widget.initialRotation;
|
||||
// Future.microtask(() {
|
||||
// managerId = ref.read(managerIdProvider);
|
||||
// });
|
||||
Future.microtask(() {
|
||||
managerId = ref.read(managerIdProvider);
|
||||
});
|
||||
}
|
||||
|
||||
final indianFormatter = NumberFormat('#,##,##0', 'en_IN');
|
||||
BarChartGroupData generateBarGroup(
|
||||
int x,
|
||||
Color color,
|
||||
@ -53,180 +63,267 @@ class _CustomBarChartState extends State<CustomBarChart> {
|
||||
return BarChartGroupData(
|
||||
x: x,
|
||||
groupVertically: false,
|
||||
|
||||
// showingTooltipIndicators: [0],
|
||||
// barsSpace: 30,
|
||||
barRods: [
|
||||
BarChartRodData(toY: value1, color: Colors.cyan.shade300, width: 4),
|
||||
BarChartRodData(toY: 0, color: Colors.transparent, width: 10),
|
||||
BarChartRodData(
|
||||
toY: value1,
|
||||
color: Colors.cyan.shade300,
|
||||
width: 20,
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
),
|
||||
// BarChartRodData(toY: 2, color: Colors.orange.shade300, width: 6),
|
||||
BarChartRodData(toY: value2, color: Colors.orange.shade300, width: 4),
|
||||
BarChartRodData(
|
||||
toY: value2,
|
||||
color: Colors.orange.shade300,
|
||||
width: 20,
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
),
|
||||
],
|
||||
showingTooltipIndicators: touchedGroupIndex == x ? [0] : [],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
// Widget build(BuildContext context) {
|
||||
// return AspectRatio(
|
||||
// aspectRatio: 1.4,
|
||||
//
|
||||
// );
|
||||
// }
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AspectRatio(
|
||||
aspectRatio: 1.4,
|
||||
child: BarChart(
|
||||
BarChartData(
|
||||
alignment: BarChartAlignment.spaceBetween,
|
||||
// verticalAxis: Axis.horizontal,
|
||||
rotationQuarterTurns: rotationTurns,
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return SizedBox(
|
||||
width: constraints.maxWidth,
|
||||
height: constraints.maxHeight,
|
||||
child: BarChart(
|
||||
BarChartData(
|
||||
// alignment: BarChartAlignment.spaceBetween,
|
||||
alignment: BarChartAlignment.start,
|
||||
// verticalAxis: Axis.horizontal,
|
||||
// rotationQuarterTurns: rotationTurns,
|
||||
barTouchData: BarTouchData(
|
||||
enabled: true,
|
||||
handleBuiltInTouches: true,
|
||||
touchTooltipData: BarTouchTooltipData(
|
||||
tooltipMargin: 6,
|
||||
tooltipRoundedRadius: 6,
|
||||
tooltipPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 6,
|
||||
),
|
||||
// ask fl_chart to fit tooltip inside available space
|
||||
fitInsideVertically:
|
||||
true, // if your fl_chart version supports it
|
||||
fitInsideHorizontally:
|
||||
true, // if your fl_chart version supports it
|
||||
getTooltipItem:
|
||||
(
|
||||
BarChartGroupData group,
|
||||
int groupIndex,
|
||||
BarChartRodData rod,
|
||||
int rodIndex,
|
||||
) {
|
||||
final textColor = rodIndex == 1
|
||||
? Colors.cyan.shade300
|
||||
: Colors.orange.shade300;
|
||||
final textStyle = TextStyle(
|
||||
color: textColor,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
);
|
||||
|
||||
barTouchData: BarTouchData(
|
||||
enabled: true,
|
||||
handleBuiltInTouches: true,
|
||||
touchTooltipData: BarTouchTooltipData(
|
||||
tooltipMargin: 6,
|
||||
tooltipRoundedRadius: 6,
|
||||
tooltipPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 6,
|
||||
),
|
||||
// ask fl_chart to fit tooltip inside available space
|
||||
fitInsideVertically: true, // if your fl_chart version supports it
|
||||
fitInsideHorizontally:
|
||||
true, // if your fl_chart version supports it
|
||||
getTooltipItem:
|
||||
(
|
||||
BarChartGroupData group,
|
||||
int groupIndex,
|
||||
BarChartRodData rod,
|
||||
int rodIndex,
|
||||
) {
|
||||
final textColor = rodIndex == 0
|
||||
? Colors.cyan.shade300
|
||||
: Colors.orange.shade300;
|
||||
final textStyle = TextStyle(
|
||||
color: textColor,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
final formattedValue = indianFormatter.format(
|
||||
rod.toY.round(),
|
||||
);
|
||||
|
||||
return BarTooltipItem(formattedValue, textStyle);
|
||||
// return BarTooltipItem('${rod.toY.round()}', textStyle);
|
||||
},
|
||||
),
|
||||
|
||||
touchCallback: (FlTouchEvent e, BarTouchResponse? r) async {
|
||||
// optional: change state to highlight tapped group
|
||||
if (r == null || r.spot == null) {
|
||||
setState(() => touchedGroupIndex = -1);
|
||||
return;
|
||||
}
|
||||
setState(
|
||||
() => touchedGroupIndex = r.spot!.touchedBarGroupIndex,
|
||||
);
|
||||
|
||||
final spot = r.spot!;
|
||||
final groupIndex = spot.touchedBarGroupIndex;
|
||||
final rodIndex = spot.touchedRodDataIndex;
|
||||
|
||||
final barData = widget.dataList[groupIndex];
|
||||
|
||||
final name = barData.chartName;
|
||||
final val = barData.id;
|
||||
final month = rodIndex == 1 ? 'current' : 'previous';
|
||||
print('name - $name');
|
||||
print('val - $val');
|
||||
print('month - $month');
|
||||
print('managerId - $managerId');
|
||||
if (e is FlTapUpEvent) {
|
||||
debugPrint(
|
||||
'Tapped value → ${rodIndex == 1 ? barData.value1 : barData.value2} -> ${barData.id}-'
|
||||
' ${rodIndex == 1 ? 'current' : 'previous'} -> ${barData.chartName}',
|
||||
);
|
||||
return BarTooltipItem('${rod.toY.round()}', textStyle);
|
||||
},
|
||||
),
|
||||
|
||||
touchCallback: (FlTouchEvent e, BarTouchResponse? r) {
|
||||
// optional: change state to highlight tapped group
|
||||
if (r == null || r.spot == null) {
|
||||
setState(() => touchedGroupIndex = -1);
|
||||
return;
|
||||
}
|
||||
setState(() => touchedGroupIndex = r.spot!.touchedBarGroupIndex);
|
||||
|
||||
final spot = r.spot!;
|
||||
final groupIndex = spot.touchedBarGroupIndex;
|
||||
final rodIndex = spot.touchedRodDataIndex;
|
||||
|
||||
final barData = widget.dataList[groupIndex];
|
||||
|
||||
if (e is FlTapUpEvent) {
|
||||
debugPrint(
|
||||
'Tapped value → ${rodIndex == 0 ? barData.value1 : barData.value2} -> ${barData.id}-'
|
||||
' ${rodIndex == 0 ? 'current' : 'previous'} -> ${barData.chartName}',
|
||||
);
|
||||
// await apiService.generateExcel()
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
borderData: FlBorderData(
|
||||
show: true,
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: AppColors.contentColorBlack,
|
||||
width: 0.1,
|
||||
),
|
||||
right: BorderSide(color: AppColors.contentColorBlack, width: 0.1),
|
||||
),
|
||||
),
|
||||
gridData: FlGridData(
|
||||
show: true,
|
||||
// drawVerticalLine: true,
|
||||
drawVerticalLine: false,
|
||||
getDrawingHorizontalLine: (value) => FlLine(
|
||||
// color: AppColors.gridLinesColor.withValues(alpha: 0.2),
|
||||
color: Colors.blueGrey.shade100,
|
||||
// color: Colors.black,
|
||||
// color: AppColors.borderColor,
|
||||
strokeWidth: 0.3,
|
||||
),
|
||||
),
|
||||
titlesData: FlTitlesData(
|
||||
bottomTitles: AxisTitles(
|
||||
axisNameWidget: widget.btnName != null
|
||||
? Text(widget.btnName!)
|
||||
: Text(''),
|
||||
axisNameSize: 10,
|
||||
sideTitles: SideTitles(
|
||||
reservedSize: 60,
|
||||
showTitles: true,
|
||||
getTitlesWidget: (value, meta) {
|
||||
final i = value.toInt();
|
||||
if (i >= widget.labels.length) return const SizedBox();
|
||||
return SideTitleWidget(
|
||||
meta: meta,
|
||||
child: Text(
|
||||
widget.labels[i],
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 9.5,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
textAlign: TextAlign.end,
|
||||
),
|
||||
);
|
||||
if (managerId != null) {
|
||||
print('managerId - $managerId');
|
||||
await apiService.generateChartExcel(
|
||||
name,
|
||||
val,
|
||||
month,
|
||||
managerId,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
rightTitles: AxisTitles(
|
||||
sideTitles: SideTitles(
|
||||
showTitles: true,
|
||||
getTitlesWidget: (value, meta) {
|
||||
return Transform.rotate(
|
||||
angle: -3,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 3.0),
|
||||
child: Text(
|
||||
value.toInt().toString(),
|
||||
textAlign: TextAlign.end,
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w400,
|
||||
borderData: FlBorderData(
|
||||
show: true,
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: AppColors.contentColorBlack,
|
||||
width: 0.1,
|
||||
),
|
||||
left: BorderSide(
|
||||
color: AppColors.contentColorBlack,
|
||||
width: 0.1,
|
||||
),
|
||||
),
|
||||
),
|
||||
gridData: FlGridData(
|
||||
show: true,
|
||||
// drawVerticalLine: true,
|
||||
drawVerticalLine: false,
|
||||
getDrawingHorizontalLine: (value) => FlLine(
|
||||
// color: AppColors.gridLinesColor.withValues(alpha: 0.2),
|
||||
color: Colors.blueGrey.shade100,
|
||||
// color: Colors.black,
|
||||
// color: AppColors.borderColor,
|
||||
strokeWidth: 0.3,
|
||||
),
|
||||
),
|
||||
titlesData: FlTitlesData(
|
||||
bottomTitles: AxisTitles(
|
||||
axisNameWidget: widget.btnName != null
|
||||
? Text(widget.btnName!)
|
||||
: Text(''),
|
||||
axisNameSize: 10,
|
||||
sideTitles: SideTitles(
|
||||
reservedSize: 30,
|
||||
showTitles: true,
|
||||
getTitlesWidget: (value, meta) {
|
||||
final i = value.toInt();
|
||||
if (i >= widget.labels.length) return const SizedBox();
|
||||
final hasShortName =
|
||||
widget.shortName != null &&
|
||||
widget.shortName!.length > i &&
|
||||
widget.shortName![i].trim().isNotEmpty;
|
||||
|
||||
return SideTitleWidget(
|
||||
meta: meta,
|
||||
child: hasShortName
|
||||
? Tooltip(
|
||||
message: widget.shortName![i],
|
||||
child: Text(
|
||||
widget.labels[i],
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 9.5,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
textAlign: TextAlign.end,
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
widget.labels[i],
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 9.5,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
textAlign: TextAlign.end,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
leftTitles: AxisTitles(
|
||||
sideTitles: SideTitles(
|
||||
showTitles: true,
|
||||
// interval: 10,
|
||||
getTitlesWidget: (value, meta) {
|
||||
// print("valuevalue - $value");
|
||||
|
||||
final text = value.toInt().toString();
|
||||
|
||||
final bool isLast = value == meta.max;
|
||||
// if (isLast) {
|
||||
// return const SizedBox.shrink(); // 👈 hide last label
|
||||
// }
|
||||
// print('value: $value');
|
||||
// print('text: $text');
|
||||
// print('length: ${text.length}');
|
||||
// print('isLast: $isLast');
|
||||
return Transform.rotate(
|
||||
// angle: -3,
|
||||
angle: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 3.0),
|
||||
child: Text(
|
||||
isLast ? '0' : value.toInt().toString(),
|
||||
textAlign: TextAlign.end,
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 9,
|
||||
color: isLast ? Colors.white : Colors.black,
|
||||
fontWeight: isLast
|
||||
? FontWeight.w100
|
||||
: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
reservedSize: 45,
|
||||
);
|
||||
},
|
||||
reservedSize: 45,
|
||||
),
|
||||
),
|
||||
rightTitles: const AxisTitles(),
|
||||
topTitles: const AxisTitles(),
|
||||
),
|
||||
),
|
||||
leftTitles: const AxisTitles(),
|
||||
topTitles: const AxisTitles(),
|
||||
),
|
||||
barGroups: widget.dataList.asMap().entries.map((e) {
|
||||
final index = e.key;
|
||||
final data = e.value;
|
||||
print('generateBarGroupBAR - $data');
|
||||
return generateBarGroup(
|
||||
index,
|
||||
data.color,
|
||||
data.value1,
|
||||
data.value2,
|
||||
data.shadowValue,
|
||||
);
|
||||
}).toList(),
|
||||
barGroups: widget.dataList.asMap().entries.map((e) {
|
||||
final index = e.key;
|
||||
final data = e.value;
|
||||
print('generateBarGroupBAR - $data');
|
||||
return generateBarGroup(
|
||||
index,
|
||||
data.color,
|
||||
data.value1,
|
||||
data.value2,
|
||||
data.shadowValue,
|
||||
);
|
||||
}).toList(),
|
||||
|
||||
// maxY: widget.maxY,
|
||||
maxY: (widget.dataList != null && widget.dataList!.isNotEmpty)
|
||||
? widget.dataList!
|
||||
.map((e) => e.value1 > e.value2 ? e.value1 : e.value2)
|
||||
.reduce((a, b) => a > b ? a : b) +
|
||||
15
|
||||
: 20,
|
||||
),
|
||||
),
|
||||
// maxY: widget.maxY,
|
||||
maxY: (widget.dataList != null && widget.dataList!.isNotEmpty)
|
||||
? widget.dataList!
|
||||
.map(
|
||||
(e) => e.value1 > e.value2 ? e.value1 : e.value2,
|
||||
)
|
||||
.reduce((a, b) => a > b ? a : b) +
|
||||
15
|
||||
: 20,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
// custom_stacked_bar_chart.dart
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
import '../../../core/services/api_service.dart';
|
||||
import '../../../data/models/bar_data.dart';
|
||||
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
@ -13,10 +15,12 @@ import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
import '../../providers/manager_provider.dart';
|
||||
import 'appChartColors.dart';
|
||||
|
||||
class CustomStackedBarChart extends StatefulWidget {
|
||||
class CustomStackedBarChart extends ConsumerStatefulWidget {
|
||||
final List<String> labels;
|
||||
final List<String> labelsId;
|
||||
final List<dynamic> dataList;
|
||||
final double maxY;
|
||||
final int initialRotation;
|
||||
@ -27,6 +31,7 @@ class CustomStackedBarChart extends StatefulWidget {
|
||||
const CustomStackedBarChart({
|
||||
super.key,
|
||||
required this.labels,
|
||||
required this.labelsId,
|
||||
required this.dataList,
|
||||
this.maxY = 100.0,
|
||||
this.initialRotation = 1,
|
||||
@ -36,16 +41,23 @@ class CustomStackedBarChart extends StatefulWidget {
|
||||
});
|
||||
|
||||
@override
|
||||
State<CustomStackedBarChart> createState() => _CustomStackedBarChartState();
|
||||
ConsumerState<CustomStackedBarChart> createState() =>
|
||||
_CustomStackedBarChartState();
|
||||
}
|
||||
|
||||
class _CustomStackedBarChartState extends State<CustomStackedBarChart> {
|
||||
class _CustomStackedBarChartState extends ConsumerState<CustomStackedBarChart> {
|
||||
late int rotationTurns;
|
||||
dynamic managerId;
|
||||
late ApiService apiService;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
apiService = ApiService();
|
||||
rotationTurns = widget.initialRotation;
|
||||
Future.microtask(() {
|
||||
managerId = ref.read(managerIdProvider);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@ -191,6 +203,37 @@ class _CustomStackedBarChartState extends State<CustomStackedBarChart> {
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
touchCallback: (event, response) async {
|
||||
if (response == null || response.spot == null) return;
|
||||
|
||||
// ✅ ONLY handle clicks
|
||||
if (event is! FlTapUpEvent) return;
|
||||
|
||||
final spot = response.spot!;
|
||||
final int groupIndex = spot.touchedBarGroupIndex;
|
||||
final int rodIndex = spot.touchedRodDataIndex;
|
||||
final int stackIndex = spot.touchedStackItemIndex!;
|
||||
|
||||
final label =
|
||||
widget.vehicleTypeNames?[groupIndex][stackIndex] ?? 'Unknown';
|
||||
final isCurrentMonth = rodIndex == 0;
|
||||
final monthLabel = isCurrentMonth ? 'Current' : 'Previous';
|
||||
final categoryLabel = widget.labels[groupIndex];
|
||||
final categoryLabelID = widget.labelsId[groupIndex];
|
||||
|
||||
debugPrint(
|
||||
'Clicked stack → $label -> $monthLabel ->$managerId ->$categoryLabel->$categoryLabelID',
|
||||
);
|
||||
|
||||
await apiService.generatePerformanceDashboardExcel(
|
||||
'StaffProduct',
|
||||
label,
|
||||
categoryLabelID,
|
||||
monthLabel,
|
||||
managerId,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
barGroups: widget.productsList.asMap().entries.map((entry) {
|
||||
|
||||
@ -34,6 +34,9 @@ class ThemedFormField extends HookWidget {
|
||||
this.horizonalPad,
|
||||
this.enableBorderWidth,
|
||||
this.textColr,
|
||||
|
||||
this.errFieldFont,
|
||||
this.errFieldHgt,
|
||||
});
|
||||
|
||||
final double? verticalPad;
|
||||
@ -53,6 +56,8 @@ class ThemedFormField extends HookWidget {
|
||||
final Color? borderColor;
|
||||
final Color? errorBorderColor;
|
||||
final Color? errorTextColor;
|
||||
final double? errFieldFont;
|
||||
final double? errFieldHgt;
|
||||
final double? txtwidth;
|
||||
final bool readOnly;
|
||||
final bool isdense;
|
||||
@ -91,7 +96,13 @@ class ThemedFormField extends HookWidget {
|
||||
);
|
||||
final inputDecoration = InputDecoration(
|
||||
isDense: isdense,
|
||||
errorStyle: TextStyle(color: Color(0xFFD83731)),
|
||||
|
||||
// errorStyle: TextStyle(color: Color(0xFFD83731)),
|
||||
// errorStyle: TextStyle(
|
||||
// color: Color(0xFFD83731),
|
||||
// fontSize: errFieldFont ?? 12,
|
||||
// height: errFieldHgt ?? 10,
|
||||
// ),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(
|
||||
@ -140,7 +151,7 @@ class ThemedFormField extends HookWidget {
|
||||
borderSide: BorderSide(color: borderColor ?? Color(0xFFFFFFFF)),
|
||||
)
|
||||
: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderRadius: BorderRadius.circular(bordedRad ?? 10),
|
||||
borderSide: BorderSide(
|
||||
color: highlightColor ?? borderColor ?? Color(0xFF50A398),
|
||||
width: 2,
|
||||
|
||||
@ -182,6 +182,7 @@ class ThemedFormInlineField extends HookWidget {
|
||||
suffixIcon: isObscurable ? obscureBtn : null,
|
||||
);
|
||||
return Container(
|
||||
width: txtwidth ?? MediaQuery.of(context).size.width,
|
||||
height: txtheight ?? null,
|
||||
child: DecoratedBox(
|
||||
decoration: boxDecoration,
|
||||
|
||||
@ -11,6 +11,8 @@ import '../../core/routing/routes.dart';
|
||||
import '../layouts/responsive_layout.dart';
|
||||
import '../providers/manager_provider.dart';
|
||||
import '../providers/userRoleProvider.dart';
|
||||
import '../screens/staff/Enquiry/Proposal_QuickCreation/Proposal_QuickCreation.dart';
|
||||
import '../themes/indicators/side_Drawer_Panel.dart';
|
||||
|
||||
class TopBar extends ConsumerStatefulWidget implements PreferredSizeWidget {
|
||||
final String title;
|
||||
@ -141,6 +143,32 @@ class _TopBarState extends ConsumerState<TopBar> {
|
||||
),
|
||||
],
|
||||
SizedBox(width: 10),
|
||||
if (role != 'Accounts') ...[
|
||||
// Proposal button
|
||||
Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: Colors.grey.shade200, width: 1),
|
||||
),
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
icon: const Icon(Icons.quora, color: Colors.black87, size: 20),
|
||||
onPressed: () {
|
||||
SideDrawerPanel.show(
|
||||
context: context,
|
||||
title: 'Quote Creation',
|
||||
child: CreateProposal_Quick(),
|
||||
);
|
||||
},
|
||||
tooltip: 'Quick Quote',
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(width: 12),
|
||||
],
|
||||
Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
|
||||
20
pubspec.lock
20
pubspec.lock
@ -700,26 +700,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
|
||||
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "11.0.2"
|
||||
version: "10.0.9"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
|
||||
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.10"
|
||||
version: "3.0.9"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_testing
|
||||
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
|
||||
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
version: "3.0.1"
|
||||
lints:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1297,10 +1297,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
|
||||
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.6"
|
||||
version: "0.7.4"
|
||||
toastification:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1417,10 +1417,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
|
||||
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.1.4"
|
||||
vm_service:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user