staff enq modification
This commit is contained in:
parent
857179ca65
commit
7b0e14c1ba
File diff suppressed because one or more lines are too long
@ -5,7 +5,7 @@ import 'package:nhance_partner/core/routing/routes.dart';
|
|||||||
import 'package:nhance_partner/presentation/screens/Enquiry/enquiryList.dart';
|
import 'package:nhance_partner/presentation/screens/Enquiry/enquiryList.dart';
|
||||||
import 'package:nhance_partner/presentation/screens/UserManagement/Profile/profile_web.dart';
|
import 'package:nhance_partner/presentation/screens/UserManagement/Profile/profile_web.dart';
|
||||||
import 'package:nhance_partner/presentation/screens/dashboard/dashboard.dart';
|
import 'package:nhance_partner/presentation/screens/dashboard/dashboard.dart';
|
||||||
import 'package:nhance_partner/presentation/screens/handler/enquiryList.dart';
|
|
||||||
import '../../data/services/auth_service.dart';
|
import '../../data/services/auth_service.dart';
|
||||||
import '../../presentation/providers/manager_provider.dart';
|
import '../../presentation/providers/manager_provider.dart';
|
||||||
import '../../presentation/screens/Enquiry/enquiry/tabs.dart';
|
import '../../presentation/screens/Enquiry/enquiry/tabs.dart';
|
||||||
@ -18,9 +18,12 @@ import '../../presentation/screens/UserManagement/Agent/agentList.dart';
|
|||||||
import '../../presentation/screens/UserManagement/Profile/profile_mobile.dart';
|
import '../../presentation/screens/UserManagement/Profile/profile_mobile.dart';
|
||||||
import '../../presentation/screens/UserManagement/Staff/staff.dart';
|
import '../../presentation/screens/UserManagement/Staff/staff.dart';
|
||||||
import '../../presentation/screens/UserManagement/Staff/staffList.dart';
|
import '../../presentation/screens/UserManagement/Staff/staffList.dart';
|
||||||
|
import '../../presentation/screens/handler/enquiryList.dart';
|
||||||
|
import '../../presentation/screens/handler/enquiryListOld.dart';
|
||||||
import '../../presentation/screens/home/home_screen.dart';
|
import '../../presentation/screens/home/home_screen.dart';
|
||||||
import '../../presentation/screens/login/login_screen.dart';
|
import '../../presentation/screens/login/login_screen.dart';
|
||||||
import '../../presentation/screens/splash/splash_screen.dart';
|
import '../../presentation/screens/splash/splash_screen.dart';
|
||||||
|
import '../../presentation/screens/staff/Enquiry/enquiry_inline_list.dart';
|
||||||
import '../../presentation/screens/staff/Enquiry/enquiry_list.dart';
|
import '../../presentation/screens/staff/Enquiry/enquiry_list.dart';
|
||||||
import '../../presentation/screens/staff/policy/policy.dart';
|
import '../../presentation/screens/staff/policy/policy.dart';
|
||||||
import '../../presentation/screens/staff/policy/policy_list.dart';
|
import '../../presentation/screens/staff/policy/policy_list.dart';
|
||||||
@ -157,11 +160,13 @@ final GoRouter appRouter = GoRouter(
|
|||||||
|
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: AppRoutes.enquiryForStaff,
|
path: AppRoutes.enquiryForStaff,
|
||||||
builder: (context, state) => const EnquiryStaff(),
|
builder: (context, state) => const EnquiryListStaffInline(),
|
||||||
|
// builder: (context, state) => const EnquiryStaff(),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: AppRoutes.enquiryHandlerLst,
|
path: AppRoutes.enquiryHandlerLst,
|
||||||
builder: (context, state) => const EnquiryHandler(),
|
// builder: (context, state) => const EnquiryHandler(),
|
||||||
|
builder: (context, state) => EnquiryListHandler(),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: AppRoutes.allStaffAttendance,
|
path: AppRoutes.allStaffAttendance,
|
||||||
|
|||||||
@ -596,13 +596,14 @@ class ApiService {
|
|||||||
|
|
||||||
final String query;
|
final String query;
|
||||||
|
|
||||||
if (role == 'manager' || role == 'handler') {
|
// if (role == 'manager' || role == 'handler') {
|
||||||
query = 'manager_id=$id';
|
// query = 'manager_id=$id';
|
||||||
}
|
|
||||||
// else if (role == 'handler') {
|
|
||||||
// query = 'handler_id=$id';
|
|
||||||
// }
|
// }
|
||||||
else if (role == 'staff') {
|
if (role == 'manager') {
|
||||||
|
query = 'manager_id=$id';
|
||||||
|
} else if (role == 'handler') {
|
||||||
|
query = 'handler_id=$id';
|
||||||
|
} else if (role == 'staff') {
|
||||||
query = 'staff_id=$id';
|
query = 'staff_id=$id';
|
||||||
} else {
|
} else {
|
||||||
query = 'agent_id=$id';
|
query = 'agent_id=$id';
|
||||||
@ -991,6 +992,8 @@ class ApiService {
|
|||||||
url = Uri.parse('${Env.apiUrl}master/getClaimMaster');
|
url = Uri.parse('${Env.apiUrl}master/getClaimMaster');
|
||||||
} else if (val == 'Endorsement') {
|
} else if (val == 'Endorsement') {
|
||||||
url = Uri.parse('${Env.apiUrl}master/getEndorsementMaster');
|
url = Uri.parse('${Env.apiUrl}master/getEndorsementMaster');
|
||||||
|
} else if (val == 'Broker') {
|
||||||
|
url = Uri.parse('${Env.apiUrl}master/getAllBrokers');
|
||||||
}
|
}
|
||||||
|
|
||||||
final headers = {
|
final headers = {
|
||||||
|
|||||||
@ -50,68 +50,73 @@ class PaginationControls extends StatelessWidget {
|
|||||||
final int totalPages = (totalItems / itemsPerPage).ceil();
|
final int totalPages = (totalItems / itemsPerPage).ceil();
|
||||||
final List<int> pages = _visiblePages(totalPages, currentPage);
|
final List<int> pages = _visiblePages(totalPages, currentPage);
|
||||||
|
|
||||||
return Row(
|
return Container(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
// color: Colors.yellow.shade100,
|
||||||
children: [
|
height: 30,
|
||||||
// Dropdown for rows per page
|
child: Row(
|
||||||
DropdownButton<int>(
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
value: itemsPerPage,
|
mainAxisSize: MainAxisSize.min,
|
||||||
items: [5, 10, 15, 20, 50].map((int value) {
|
children: [
|
||||||
return DropdownMenuItem<int>(
|
// Dropdown for rows per page
|
||||||
value: value,
|
DropdownButton<int>(
|
||||||
child: Text('$value', style: GoogleFonts.poppins(fontSize: 15)),
|
value: itemsPerPage,
|
||||||
);
|
items: [5, 10, 15, 20, 50].map((int value) {
|
||||||
}).toList(),
|
return DropdownMenuItem<int>(
|
||||||
onChanged: (newValue) {
|
value: value,
|
||||||
if (newValue != null) {
|
child: Text('$value', style: GoogleFonts.inter(fontSize: 12)),
|
||||||
onItemsPerPageChanged(newValue);
|
);
|
||||||
onPageChanged(1);
|
}).toList(),
|
||||||
}
|
onChanged: (newValue) {
|
||||||
},
|
if (newValue != null) {
|
||||||
),
|
onItemsPerPageChanged(newValue);
|
||||||
|
onPageChanged(1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
// Previous Button
|
// Previous Button
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: currentPage > 1
|
onPressed: currentPage > 1
|
||||||
? () => onPageChanged(currentPage - 1)
|
? () => onPageChanged(currentPage - 1)
|
||||||
: null,
|
: null,
|
||||||
icon: const Icon(Icons.chevron_left),
|
icon: const Icon(Icons.chevron_left, size: 18),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Page buttons with ellipsis
|
// Page buttons with ellipsis
|
||||||
for (final i in pages)
|
for (final i in pages)
|
||||||
if (i == -1)
|
if (i == -1)
|
||||||
const Padding(
|
const Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 4),
|
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||||
child: Text("..."),
|
child: Text("..."),
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
padding: const EdgeInsets.symmetric(horizontal: 2),
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: currentPage == i
|
backgroundColor: currentPage == i
|
||||||
? const Color(0xFFD4F8F3)
|
? const Color(0xFFD4F8F3)
|
||||||
: const Color(0xFFEDF6F5),
|
: const Color(0xFFEDF6F5),
|
||||||
foregroundColor: currentPage == i
|
foregroundColor: currentPage == i
|
||||||
? Colors.black
|
? Colors.black
|
||||||
: Colors.grey,
|
: Colors.grey,
|
||||||
minimumSize: const Size(36, 36),
|
minimumSize: const Size(26, 26),
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
|
),
|
||||||
|
onPressed: () => onPageChanged(i),
|
||||||
|
child: Text(i.toString()),
|
||||||
),
|
),
|
||||||
onPressed: () => onPageChanged(i),
|
|
||||||
child: Text(i.toString()),
|
|
||||||
),
|
),
|
||||||
),
|
|
||||||
|
|
||||||
// Next Button
|
// Next Button
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: currentPage < totalPages
|
onPressed: currentPage < totalPages
|
||||||
? () => onPageChanged(currentPage + 1)
|
? () => onPageChanged(currentPage + 1)
|
||||||
: null,
|
: null,
|
||||||
icon: const Icon(Icons.chevron_right),
|
icon: const Icon(Icons.chevron_right, size: 18),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,7 @@ class MainLayout extends ConsumerStatefulWidget {
|
|||||||
class MainLayoutState extends ConsumerState<MainLayout> {
|
class MainLayoutState extends ConsumerState<MainLayout> {
|
||||||
dynamic role;
|
dynamic role;
|
||||||
ApiService apiService = ApiService();
|
ApiService apiService = ApiService();
|
||||||
|
bool isDrawerOpen = true;
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -93,7 +93,12 @@ class MainLayoutState extends ConsumerState<MainLayout> {
|
|||||||
appBar: TopBar(
|
appBar: TopBar(
|
||||||
title: widget.title,
|
title: widget.title,
|
||||||
onMenuPressed: () {
|
onMenuPressed: () {
|
||||||
Scaffold.of(context).openDrawer();
|
// Scaffold.of(context).openDrawer();
|
||||||
|
// Scaffold.of(context).openDrawer();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
isDrawerOpen = !isDrawerOpen;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onLogout: () async {
|
onLogout: () async {
|
||||||
debugPrint("Logout tapped");
|
debugPrint("Logout tapped");
|
||||||
@ -118,7 +123,7 @@ class MainLayoutState extends ConsumerState<MainLayout> {
|
|||||||
items: [
|
items: [
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
enabled: false,
|
enabled: false,
|
||||||
child: SizedBox(width: 500, child: ProfilePopUp()),
|
child: SizedBox(width: 80, child: ProfilePopUp()),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -130,13 +135,17 @@ class MainLayoutState extends ConsumerState<MainLayout> {
|
|||||||
),
|
),
|
||||||
body: Row(
|
body: Row(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(
|
AnimatedContainer(
|
||||||
width: 100, // fixed width for drawer
|
duration: const Duration(milliseconds: 250),
|
||||||
child: DrawerMenu(),
|
width: isDrawerOpen ? 100 : 0, // 👈 adjust width
|
||||||
|
child: isDrawerOpen
|
||||||
|
? const DrawerMenu()
|
||||||
|
: const SizedBox.shrink(), // hides drawer
|
||||||
),
|
),
|
||||||
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.all(2.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: Column(children: [Expanded(child: widget.body)]),
|
child: Column(children: [Expanded(child: widget.body)]),
|
||||||
),
|
),
|
||||||
@ -144,6 +153,23 @@ class MainLayoutState extends ConsumerState<MainLayout> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// body: Row(
|
||||||
|
// children: [
|
||||||
|
// const SizedBox(
|
||||||
|
// width: 100, // fixed width for drawer
|
||||||
|
// child: DrawerMenu(),
|
||||||
|
// ),
|
||||||
|
// Expanded(
|
||||||
|
// child: Container(
|
||||||
|
// padding: EdgeInsets.all(2.0),
|
||||||
|
// color: Colors.white,
|
||||||
|
// child: Column(children: [Expanded(child: widget.body)]),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ final managerIdProvider = StateProvider<int?>((ref) => null);
|
|||||||
final userIdProvider = StateProvider<int?>((ref) => null);
|
final userIdProvider = StateProvider<int?>((ref) => null);
|
||||||
final enquiryIdProvider = StateProvider<String?>((ref) => null);
|
final enquiryIdProvider = StateProvider<String?>((ref) => null);
|
||||||
final navFromEnqStaffProvider = StateProvider<String?>((ref) => null);
|
final navFromEnqStaffProvider = StateProvider<String?>((ref) => null);
|
||||||
|
final enqBrokerNameProvider = StateProvider<String?>((ref) => null);
|
||||||
final staffIndiviualAttendanceIdProvider = StateProvider<String?>(
|
final staffIndiviualAttendanceIdProvider = StateProvider<String?>(
|
||||||
(ref) => null,
|
(ref) => null,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -86,12 +86,12 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
|
|||||||
String? selectedInsurer;
|
String? selectedInsurer;
|
||||||
String? selectedAgent;
|
String? selectedAgent;
|
||||||
|
|
||||||
Map<String, TextEditingController> controllers = {};
|
|
||||||
String? _token;
|
String? _token;
|
||||||
dynamic userId;
|
dynamic userId;
|
||||||
dynamic managerId;
|
dynamic managerId;
|
||||||
dynamic role;
|
dynamic role;
|
||||||
|
|
||||||
|
Map<String, TextEditingController> controllers = {};
|
||||||
List<Map<String, dynamic>> getVehicleTypeData = [];
|
List<Map<String, dynamic>> getVehicleTypeData = [];
|
||||||
List<Map<String, dynamic>> filteredVechicleData = [];
|
List<Map<String, dynamic>> filteredVechicleData = [];
|
||||||
|
|
||||||
@ -733,42 +733,6 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Widget buildResponsiveUploadField({
|
|
||||||
// required String label,
|
|
||||||
// required String? hintText,
|
|
||||||
// required void Function(String fileName, dynamic file) onFileSelected,
|
|
||||||
// })
|
|
||||||
// {
|
|
||||||
// final isMobile = ResponsiveLayout.isMobile(context);
|
|
||||||
//
|
|
||||||
// final uploadWidget = ThemedUploadField(
|
|
||||||
// hintText: hintText ?? "Upload Document",
|
|
||||||
// txtwidth: MediaQuery.of(context).size.width * 0.26,
|
|
||||||
// onFileSelected: onFileSelected,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// if (isMobile) {
|
|
||||||
// return Column(
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
// children: [
|
|
||||||
// Text(label, style: _textStyle),
|
|
||||||
// const SizedBox(height: 8),
|
|
||||||
// uploadWidget,
|
|
||||||
// const SizedBox(height: 16),
|
|
||||||
// ],
|
|
||||||
// );
|
|
||||||
// } else {
|
|
||||||
// return Row(
|
|
||||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
// children: [
|
|
||||||
// Expanded(child: Text(label, style: _textStyle)),
|
|
||||||
// const SizedBox(width: 10),
|
|
||||||
// uploadWidget,
|
|
||||||
// ],
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
Widget buildName(BuildContext context) {
|
Widget buildName(BuildContext context) {
|
||||||
return buildResponsiveField(
|
return buildResponsiveField(
|
||||||
label: "Insured Name *",
|
label: "Insured Name *",
|
||||||
|
|||||||
@ -677,7 +677,8 @@ class StaffState extends ConsumerState<Staff> {
|
|||||||
(item) => item['id'].toString() == selectedHandler,
|
(item) => item['id'].toString() == selectedHandler,
|
||||||
orElse: () => {},
|
orElse: () => {},
|
||||||
);
|
);
|
||||||
final isReadOnly = widget.id != null;
|
// final isReadOnly = widget.id != null;
|
||||||
|
final isReadOnly = false;
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
1375
lib/presentation/screens/handler/enquiryListOld.dart
Normal file
1375
lib/presentation/screens/handler/enquiryListOld.dart
Normal file
File diff suppressed because it is too large
Load Diff
155
lib/presentation/screens/handler/inline
Normal file
155
lib/presentation/screens/handler/inline
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class InlineEditableTable extends StatefulWidget {
|
||||||
|
const InlineEditableTable({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<InlineEditableTable> createState() => _InlineEditableTableState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _InlineEditableTableState extends State<InlineEditableTable> {
|
||||||
|
List<Map<String, dynamic>> rows = [
|
||||||
|
{"id": 1, "agent_name": "Ravi", "insurer_name": "ICICI"},
|
||||||
|
{"id": 2, "agent_name": "Priya", "insurer_name": "HDFC"},
|
||||||
|
];
|
||||||
|
|
||||||
|
Map<int, bool> isEditingRow = {};
|
||||||
|
Map<int, TextEditingController> agentControllers = {};
|
||||||
|
Map<int, TextEditingController> insurerControllers = {};
|
||||||
|
|
||||||
|
void _addRow() {
|
||||||
|
final newId = DateTime.now().millisecondsSinceEpoch;
|
||||||
|
setState(() {
|
||||||
|
rows.add({"id": newId, "agent_name": "", "insurer_name": ""});
|
||||||
|
isEditingRow[newId] = true;
|
||||||
|
agentControllers[newId] = TextEditingController();
|
||||||
|
insurerControllers[newId] = TextEditingController();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _editRow(int id) {
|
||||||
|
setState(() {
|
||||||
|
isEditingRow[id] = true;
|
||||||
|
agentControllers[id] = TextEditingController(
|
||||||
|
text: rows.firstWhere((row) => row["id"] == id)["agent_name"],
|
||||||
|
);
|
||||||
|
insurerControllers[id] = TextEditingController(
|
||||||
|
text: rows.firstWhere((row) => row["id"] == id)["insurer_name"],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _saveRow(int id) {
|
||||||
|
setState(() {
|
||||||
|
final index = rows.indexWhere((row) => row["id"] == id);
|
||||||
|
if (index != -1) {
|
||||||
|
rows[index]["agent_name"] = agentControllers[id]?.text ?? "";
|
||||||
|
rows[index]["insurer_name"] = insurerControllers[id]?.text ?? "";
|
||||||
|
}
|
||||||
|
isEditingRow[id] = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _deleteRow(int id) {
|
||||||
|
setState(() {
|
||||||
|
rows.removeWhere((row) => row["id"] == id);
|
||||||
|
isEditingRow.remove(id);
|
||||||
|
agentControllers.remove(id);
|
||||||
|
insurerControllers.remove(id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(title: const Text("Inline Editable Table")),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
child: ElevatedButton.icon(
|
||||||
|
onPressed: _addRow,
|
||||||
|
icon: const Icon(Icons.add),
|
||||||
|
label: const Text("Add Row"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Expanded(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.vertical,
|
||||||
|
child: DataTable(
|
||||||
|
columns: const [
|
||||||
|
DataColumn(label: Text("Agent Name")),
|
||||||
|
DataColumn(label: Text("Insurer Name")),
|
||||||
|
DataColumn(label: Text("Actions")),
|
||||||
|
],
|
||||||
|
rows: rows.map((row) {
|
||||||
|
final id = row["id"];
|
||||||
|
final isEditing = isEditingRow[id] ?? false;
|
||||||
|
return DataRow(
|
||||||
|
cells: [
|
||||||
|
DataCell(
|
||||||
|
isEditing
|
||||||
|
? TextField(
|
||||||
|
controller: agentControllers[id],
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
isDense: true,
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Text(row["agent_name"]),
|
||||||
|
),
|
||||||
|
DataCell(
|
||||||
|
isEditing
|
||||||
|
? TextField(
|
||||||
|
controller: insurerControllers[id],
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
isDense: true,
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Text(row["insurer_name"]),
|
||||||
|
),
|
||||||
|
DataCell(
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
if (isEditing)
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.save,
|
||||||
|
color: Colors.green,
|
||||||
|
),
|
||||||
|
onPressed: () => _saveRow(id),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.edit,
|
||||||
|
color: Colors.blue,
|
||||||
|
),
|
||||||
|
onPressed: () => _editRow(id),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.delete,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
onPressed: () => _deleteRow(id),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
515
lib/presentation/screens/handler/new
Normal file
515
lib/presentation/screens/handler/new
Normal file
@ -0,0 +1,515 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
|
||||||
|
import '../../../../core/config/env.dart';
|
||||||
|
import '../../../../core/services/api_service.dart';
|
||||||
|
import '../../../../data/services/auth_service.dart';
|
||||||
|
import '../../../../data/utils/toastNotification.dart';
|
||||||
|
import '../../layouts/responsive_layout.dart';
|
||||||
|
import '../../providers/manager_provider.dart';
|
||||||
|
|
||||||
|
class QuotationPopUpTab extends ConsumerStatefulWidget {
|
||||||
|
String? id;
|
||||||
|
final Future<void> Function()? onRefresh;
|
||||||
|
QuotationPopUpTab({super.key, this.id, this.onRefresh});
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<QuotationPopUpTab> createState() => QuotationTabState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class QuotationTabState extends ConsumerState<QuotationPopUpTab> {
|
||||||
|
late ApiService apiService;
|
||||||
|
|
||||||
|
bool isLoading = false;
|
||||||
|
bool blockKey = false;
|
||||||
|
|
||||||
|
String? _token;
|
||||||
|
dynamic userId;
|
||||||
|
dynamic managerId;
|
||||||
|
dynamic role;
|
||||||
|
|
||||||
|
List<Map<String, dynamic>> getQuotationData = [];
|
||||||
|
List<Map<String, dynamic>> originalData = [];
|
||||||
|
List<Map<String, dynamic>> filteredData = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
apiService = ApiService();
|
||||||
|
_initializeToken();
|
||||||
|
Future.microtask(() {
|
||||||
|
managerId = ref.watch(managerIdProvider);
|
||||||
|
userId = ref.watch(userIdProvider);
|
||||||
|
role = ref.watch(userRoleProvider);
|
||||||
|
getQuotationList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _initializeToken() async {
|
||||||
|
_token = await AuthService.getToken();
|
||||||
|
print("APISERTOKEN - $_token");
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh() {
|
||||||
|
getQuotationList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ✅ Instead of using `widget.data`, call the API directly
|
||||||
|
Future<void> getQuotationList() async {
|
||||||
|
print('Fetching quotation list from API...');
|
||||||
|
setState(() => isLoading = true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (widget.id == null) {
|
||||||
|
throw Exception('QuotationTab: ID is null');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example: adjust this endpoint based on your actual API
|
||||||
|
final response = await apiService.findEnqQuotePolicyView(widget.id);
|
||||||
|
|
||||||
|
// Extract quotation data safely
|
||||||
|
final quotations = (response["data"]?["quotations"] as List?) ?? [];
|
||||||
|
|
||||||
|
final data = quotations
|
||||||
|
.map((e) => Map<String, dynamic>.from(e as Map))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
getQuotationData = data;
|
||||||
|
filteredData = List.from(data);
|
||||||
|
blockKey = data.any((item) => item['status'] == 'Accepted');
|
||||||
|
});
|
||||||
|
|
||||||
|
print('Fetched quotation data: ${data.length}');
|
||||||
|
} catch (e, s) {
|
||||||
|
print('❌ Error fetching quotations: $e\n$s');
|
||||||
|
} finally {
|
||||||
|
setState(() => isLoading = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> handleAction(String action, String quotationId) async {
|
||||||
|
final String apiUrldata = '${Env.apiUrl}quotation/acceptOrRejectQuotation';
|
||||||
|
|
||||||
|
if (_token == null) {
|
||||||
|
throw Exception('Token not found. Please log in.');
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<String, dynamic> data = {
|
||||||
|
"id": quotationId,
|
||||||
|
"status": action,
|
||||||
|
"action_by": userId,
|
||||||
|
"action_user": role,
|
||||||
|
};
|
||||||
|
|
||||||
|
print("data------- $data");
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await http.post(
|
||||||
|
Uri.parse(apiUrldata),
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer $_token',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'app-signature': Env.App_Signature,
|
||||||
|
},
|
||||||
|
body: jsonEncode(data),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
print("Response: ${response.body}");
|
||||||
|
ToastHelper.showSuccessToast(context, 'Status Updated');
|
||||||
|
|
||||||
|
// Close popup
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
|
// Refresh parent
|
||||||
|
if (widget.onRefresh != null) {
|
||||||
|
await widget.onRefresh!();
|
||||||
|
}
|
||||||
|
} else if (response.statusCode == 403) {
|
||||||
|
await apiService.clearLocalStorageAndRedirect();
|
||||||
|
} else {
|
||||||
|
final responseBody = jsonDecode(response.body);
|
||||||
|
ToastHelper.showErrorToast(context, 'Status Updation Failed');
|
||||||
|
print("Failed to submit. Status: ${response.statusCode}");
|
||||||
|
print("Error: ${response.body}");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("Error submitting: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showQuotationPopup() {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return Dialog(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
width: ResponsiveLayout.isMobile(context)
|
||||||
|
? MediaQuery.of(context).size.width * 0.9
|
||||||
|
: MediaQuery.of(context).size.width * 0.5,
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'Quotation Details',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.close),
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Flexible(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
...filteredData
|
||||||
|
.map((item) => _buildQuotationCard(item))
|
||||||
|
.toList(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildQuotationCard(Map<String, dynamic> item) {
|
||||||
|
final bool isAccepted = item['status'] == 'Accepted';
|
||||||
|
final bool isRejected = item['status'] == 'Rejected';
|
||||||
|
final bool isPending = item['status'] == 'Pending';
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
margin: const EdgeInsets.only(bottom: 16),
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: isAccepted
|
||||||
|
? Colors.green.withOpacity(0.1)
|
||||||
|
: isRejected
|
||||||
|
? Colors.red.withOpacity(0.1)
|
||||||
|
: const Color(0xFFF6FEFD),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(
|
||||||
|
color: isAccepted
|
||||||
|
? Colors.green
|
||||||
|
: isRejected
|
||||||
|
? Colors.red
|
||||||
|
: const Color(0xffD9EBE8),
|
||||||
|
width: 1.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Header with status
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
item['insurer_name'] ?? '-',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 12,
|
||||||
|
vertical: 4,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: _getStatusColor(item['status']),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
item['status'] ?? '-',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
|
// Details
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: _buildDetailItem(
|
||||||
|
'IDV',
|
||||||
|
item['insured_declared_value']?.toString() ?? '-',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: _buildDetailItem(
|
||||||
|
'Premium',
|
||||||
|
item['premium_amount']?.toString() ?? '-',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
_buildDetailItem(
|
||||||
|
'Plan Type',
|
||||||
|
item['insurance_plan_type']?.toString() ?? '-',
|
||||||
|
),
|
||||||
|
|
||||||
|
// Action buttons (only if pending and no other quotation is accepted)
|
||||||
|
if (isPending && !blockKey) ...[
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => handleAction('Rejected', item['id']),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 24,
|
||||||
|
vertical: 12,
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.red.shade50,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'Reject',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.red,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => handleAction('Accepted', item['id']),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 24,
|
||||||
|
vertical: 12,
|
||||||
|
),
|
||||||
|
backgroundColor: const Color(0xFF425B5B),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'Accept',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
|
||||||
|
// Show message if blocked
|
||||||
|
if (isPending && blockKey) ...[
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.orange.shade50,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: const Row(
|
||||||
|
children: [
|
||||||
|
Icon(Icons.info_outline, size: 16, color: Colors.orange),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'Another quotation has been accepted',
|
||||||
|
style: TextStyle(fontSize: 12, color: Colors.orange),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDetailItem(String label, String value) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'$label: ',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF545454),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
value,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color _getStatusColor(String? status) {
|
||||||
|
switch (status) {
|
||||||
|
case 'Pending':
|
||||||
|
return Colors.orange;
|
||||||
|
case 'Accepted':
|
||||||
|
return Colors.green;
|
||||||
|
case 'Rejected':
|
||||||
|
return Colors.red;
|
||||||
|
default:
|
||||||
|
return Colors.grey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
height: MediaQuery.of(context).size.height,
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: isLoading
|
||||||
|
? const Center(child: CircularProgressIndicator())
|
||||||
|
: filteredData.isNotEmpty
|
||||||
|
? Column(
|
||||||
|
children: [
|
||||||
|
// Button to open popup
|
||||||
|
ElevatedButton.icon(
|
||||||
|
onPressed: _showQuotationPopup,
|
||||||
|
icon: const Icon(Icons.visibility),
|
||||||
|
label: Text('View Quotations (${filteredData.length})'),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: const Color(0xFF425B5B),
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 24,
|
||||||
|
vertical: 12,
|
||||||
|
),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
|
// Summary cards
|
||||||
|
Expanded(
|
||||||
|
child: GridView.count(
|
||||||
|
crossAxisCount: ResponsiveLayout.isMobile(context) ? 1 : 3,
|
||||||
|
crossAxisSpacing: 16,
|
||||||
|
mainAxisSpacing: 16,
|
||||||
|
childAspectRatio: ResponsiveLayout.isMobile(context)
|
||||||
|
? 3
|
||||||
|
: 2,
|
||||||
|
children: [
|
||||||
|
_buildSummaryCard(
|
||||||
|
'Total Quotations',
|
||||||
|
filteredData.length.toString(),
|
||||||
|
Icons.description,
|
||||||
|
Colors.blue,
|
||||||
|
),
|
||||||
|
_buildSummaryCard(
|
||||||
|
'Accepted',
|
||||||
|
filteredData
|
||||||
|
.where((e) => e['status'] == 'Accepted')
|
||||||
|
.length
|
||||||
|
.toString(),
|
||||||
|
Icons.check_circle,
|
||||||
|
Colors.green,
|
||||||
|
),
|
||||||
|
_buildSummaryCard(
|
||||||
|
'Pending',
|
||||||
|
filteredData
|
||||||
|
.where((e) => e['status'] == 'Pending')
|
||||||
|
.length
|
||||||
|
.toString(),
|
||||||
|
Icons.pending,
|
||||||
|
Colors.orange,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: const Center(child: Text('No Available Data')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSummaryCard(
|
||||||
|
String title,
|
||||||
|
String count,
|
||||||
|
IconData icon,
|
||||||
|
Color color,
|
||||||
|
) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: color.withOpacity(0.1),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(color: color.withOpacity(0.3)),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(icon, size: 32, color: color),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
count,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: color,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: color,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
582
lib/presentation/screens/handler/quotationPopUp.dart
Normal file
582
lib/presentation/screens/handler/quotationPopUp.dart
Normal file
@ -0,0 +1,582 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
|
||||||
|
import '../../../../core/config/env.dart';
|
||||||
|
import '../../../../core/services/api_service.dart';
|
||||||
|
import '../../../../data/services/auth_service.dart';
|
||||||
|
import '../../../../data/utils/toastNotification.dart';
|
||||||
|
import '../../layouts/responsive_layout.dart';
|
||||||
|
import '../../providers/manager_provider.dart';
|
||||||
|
|
||||||
|
class QuotationPopUpTab extends ConsumerStatefulWidget {
|
||||||
|
String? id;
|
||||||
|
final Future<void> Function()? onRefresh;
|
||||||
|
QuotationPopUpTab({super.key, this.id, this.onRefresh});
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<QuotationPopUpTab> createState() => QuotationTabState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class QuotationTabState extends ConsumerState<QuotationPopUpTab> {
|
||||||
|
late ApiService apiService;
|
||||||
|
|
||||||
|
bool isLoading = false;
|
||||||
|
bool blockKey = false;
|
||||||
|
|
||||||
|
String? _token;
|
||||||
|
dynamic userId;
|
||||||
|
dynamic managerId;
|
||||||
|
dynamic role;
|
||||||
|
|
||||||
|
List<Map<String, dynamic>> getQuotationData = [];
|
||||||
|
List<Map<String, dynamic>> originalData = [];
|
||||||
|
List<Map<String, dynamic>> filteredData = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
apiService = ApiService();
|
||||||
|
_initializeToken();
|
||||||
|
Future.microtask(() {
|
||||||
|
managerId = ref.watch(managerIdProvider);
|
||||||
|
userId = ref.watch(userIdProvider);
|
||||||
|
role = ref.watch(userRoleProvider);
|
||||||
|
getQuotationList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _initializeToken() async {
|
||||||
|
_token = await AuthService.getToken();
|
||||||
|
print("APISERTOKEN - $_token");
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh() {
|
||||||
|
getQuotationList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ✅ Instead of using `widget.data`, call the API directly
|
||||||
|
Future<void> getQuotationList() async {
|
||||||
|
print('Fetching quotation list from API...');
|
||||||
|
setState(() => isLoading = true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (widget.id == null) {
|
||||||
|
throw Exception('QuotationTab: ID is null');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example: adjust this endpoint based on your actual API
|
||||||
|
final response = await apiService.findEnqQuotePolicyView(widget.id);
|
||||||
|
|
||||||
|
// Extract quotation data safely
|
||||||
|
final quotations = (response["data"]?["quotations"] as List?) ?? [];
|
||||||
|
|
||||||
|
final data = quotations
|
||||||
|
.map((e) => Map<String, dynamic>.from(e as Map))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
getQuotationData = data;
|
||||||
|
filteredData = List.from(data);
|
||||||
|
blockKey = data.any((item) => item['status'] == 'Accepted');
|
||||||
|
});
|
||||||
|
|
||||||
|
print('Fetched quotation data: ${data.length}');
|
||||||
|
} catch (e, s) {
|
||||||
|
print('❌ Error fetching quotations: $e\n$s');
|
||||||
|
} finally {
|
||||||
|
setState(() => isLoading = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> handleAction(String action, String quotationId) async {
|
||||||
|
final String apiUrldata = '${Env.apiUrl}quotation/acceptOrRejectQuotation';
|
||||||
|
|
||||||
|
if (_token == null) {
|
||||||
|
throw Exception('Token not found. Please log in.');
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<String, dynamic> data = {
|
||||||
|
"id": quotationId,
|
||||||
|
"status": action,
|
||||||
|
"action_by": userId,
|
||||||
|
"action_user": role,
|
||||||
|
};
|
||||||
|
|
||||||
|
print("data------- $data");
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await http.post(
|
||||||
|
Uri.parse(apiUrldata),
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer $_token',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'app-signature': Env.App_Signature,
|
||||||
|
},
|
||||||
|
body: jsonEncode(data),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
print("Response: ${response.body}");
|
||||||
|
ToastHelper.showSuccessToast(context, 'Status Updated');
|
||||||
|
|
||||||
|
// Close popup
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
|
// Refresh parent
|
||||||
|
if (widget.onRefresh != null) {
|
||||||
|
await widget.onRefresh!();
|
||||||
|
}
|
||||||
|
} else if (response.statusCode == 403) {
|
||||||
|
await apiService.clearLocalStorageAndRedirect();
|
||||||
|
} else {
|
||||||
|
final responseBody = jsonDecode(response.body);
|
||||||
|
ToastHelper.showErrorToast(context, 'Status Updation Failed');
|
||||||
|
print("Failed to submit. Status: ${response.statusCode}");
|
||||||
|
print("Error: ${response.body}");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("Error submitting: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildQuotationPopupContent() {
|
||||||
|
return Container(
|
||||||
|
// width: ResponsiveLayout.isMobile(context)
|
||||||
|
// ? MediaQuery.of(context).size.width * 0.9
|
||||||
|
// : MediaQuery.of(context).size.width * 0.5,
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
// border: Border.all(color: const Color(0xFFD9EBE8)),
|
||||||
|
// boxShadow: [
|
||||||
|
// BoxShadow(
|
||||||
|
// color: Colors.black.withOpacity(0.05),
|
||||||
|
// blurRadius: 8,
|
||||||
|
// offset: const Offset(0, 4),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'Quotation Details',
|
||||||
|
style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
icon: Icon(Icons.close),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Flexible(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: _buildQuotationTable(), // ✅ Only one table
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildQuotationTable() {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(color: const Color(0xFFD9EBE8)),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// 🔹 Table Header
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
|
||||||
|
color: const Color(0xFFEFF6F5),
|
||||||
|
child: Row(
|
||||||
|
children: const [
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Text(
|
||||||
|
"IDV",
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: Text(
|
||||||
|
"Plan Type",
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Text(
|
||||||
|
"Premium",
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 3,
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
"Action",
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(height: 1, color: Color(0xFFD9EBE8)),
|
||||||
|
|
||||||
|
// 🔹 Table Rows
|
||||||
|
...filteredData.map((item) {
|
||||||
|
final bool isAccepted = item['status'] == 'Accepted';
|
||||||
|
final bool isRejected = item['status'] == 'Rejected';
|
||||||
|
final bool isPending = item['status'] == 'Pending';
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
bottom: BorderSide(color: Colors.grey.withOpacity(0.2)),
|
||||||
|
),
|
||||||
|
color: isAccepted
|
||||||
|
? Colors.green.withOpacity(0.05)
|
||||||
|
: isRejected
|
||||||
|
? Colors.red.withOpacity(0.05)
|
||||||
|
: Colors.white,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Text(
|
||||||
|
item['insured_declared_value']?.toString() ?? '-',
|
||||||
|
style: const TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: Text(
|
||||||
|
item['insurance_plan_type']?.toString() ?? '-',
|
||||||
|
style: const TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Text(
|
||||||
|
item['premium_amount']?.toString() ?? '-',
|
||||||
|
style: const TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 3,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
if (isPending && !blockKey) ...[
|
||||||
|
TextButton(
|
||||||
|
onPressed: () =>
|
||||||
|
handleAction('Rejected', item['id']),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
backgroundColor: Colors.red.shade50,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'Reject',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.red,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () =>
|
||||||
|
handleAction('Accepted', item['id']),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: const Color(0xFF425B5B),
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'Accept',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
if (isAccepted)
|
||||||
|
const Text(
|
||||||
|
'Accepted',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.green,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (isRejected)
|
||||||
|
const Text(
|
||||||
|
'Rejected',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.red,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildQuotationCard(Map<String, dynamic> item) {
|
||||||
|
final bool isAccepted = item['status'] == 'Accepted';
|
||||||
|
final bool isRejected = item['status'] == 'Rejected';
|
||||||
|
final bool isPending = item['status'] == 'Pending';
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
margin: const EdgeInsets.only(bottom: 16),
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: isAccepted
|
||||||
|
? Colors.green.withOpacity(0.1)
|
||||||
|
: isRejected
|
||||||
|
? Colors.red.withOpacity(0.1)
|
||||||
|
: const Color(0xFFF6FEFD),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(
|
||||||
|
color: isAccepted
|
||||||
|
? Colors.green
|
||||||
|
: isRejected
|
||||||
|
? Colors.red
|
||||||
|
: const Color(0xffD9EBE8),
|
||||||
|
width: 1.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Header with status
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
item['insurer_name'] ?? '-',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 12,
|
||||||
|
vertical: 4,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: _getStatusColor(item['status']),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
item['status'] ?? '-',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
|
// Details
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: _buildDetailItem(
|
||||||
|
'IDV',
|
||||||
|
item['insured_declared_value']?.toString() ?? '-',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: _buildDetailItem(
|
||||||
|
'Premium',
|
||||||
|
item['premium_amount']?.toString() ?? '-',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
_buildDetailItem(
|
||||||
|
'Plan Type',
|
||||||
|
item['insurance_plan_type']?.toString() ?? '-',
|
||||||
|
),
|
||||||
|
|
||||||
|
// Action buttons (only if pending and no other quotation is accepted)
|
||||||
|
if (isPending && !blockKey) ...[
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => handleAction('Rejected', item['id']),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 24,
|
||||||
|
vertical: 12,
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.red.shade50,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'Reject',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.red,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => handleAction('Accepted', item['id']),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 24,
|
||||||
|
vertical: 12,
|
||||||
|
),
|
||||||
|
backgroundColor: const Color(0xFF425B5B),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'Accept',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
|
||||||
|
// Show message if blocked
|
||||||
|
if (isPending && blockKey) ...[
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.orange.shade50,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: const Row(
|
||||||
|
children: [
|
||||||
|
Icon(Icons.info_outline, size: 16, color: Colors.orange),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'Another quotation has been accepted',
|
||||||
|
style: TextStyle(fontSize: 12, color: Colors.orange),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDetailItem(String label, String value) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'$label: ',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF545454),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
value,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color _getStatusColor(String? status) {
|
||||||
|
switch (status) {
|
||||||
|
case 'Pending':
|
||||||
|
return Colors.orange;
|
||||||
|
case 'Accepted':
|
||||||
|
return Colors.green;
|
||||||
|
case 'Rejected':
|
||||||
|
return Colors.red;
|
||||||
|
default:
|
||||||
|
return Colors.grey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
// height: MediaQuery.of(context).size.height,
|
||||||
|
// width: MediaQuery.of(context).size.width,
|
||||||
|
// padding: const EdgeInsets.all(16),
|
||||||
|
child: isLoading
|
||||||
|
? const Center(child: CircularProgressIndicator())
|
||||||
|
: filteredData.isNotEmpty
|
||||||
|
? SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
_buildQuotationPopupContent(), // ✅ now renders inline
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const Center(child: Text('No Available Data')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -263,9 +263,9 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
|
|||||||
|
|
||||||
final message = data['data']['message'];
|
final message = data['data']['message'];
|
||||||
|
|
||||||
// setState(() {
|
setState(() {
|
||||||
// enteredEmailOrMobile = true;
|
enteredEmailOrMobile = true;
|
||||||
// });
|
});
|
||||||
|
|
||||||
if (verification == true) {
|
if (verification == true) {
|
||||||
// if (switcherStatus == 1) {
|
// if (switcherStatus == 1) {
|
||||||
|
|||||||
2904
lib/presentation/screens/staff/Enquiry/enquiry_inline_list.dart
Normal file
2904
lib/presentation/screens/staff/Enquiry/enquiry_inline_list.dart
Normal file
File diff suppressed because it is too large
Load Diff
@ -1084,10 +1084,6 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
|
|||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
hoverColor: Color(0xFFEAF6F4),
|
hoverColor: Color(0xFFEAF6F4),
|
||||||
// hoverColor: const Color(0xffD9EBE8),
|
|
||||||
// focusColor: const Color(0xffD9EBE8),
|
|
||||||
// splashColor: const Color(0xffD9EBE8),
|
|
||||||
// highlightColor: const Color(0xffD9EBE8),
|
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
// ✅ Get overlay and button position RELATIVE to InkWell
|
// ✅ Get overlay and button position RELATIVE to InkWell
|
||||||
final RenderBox button =
|
final RenderBox button =
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -165,6 +165,7 @@ class QuotationStaffTabState extends ConsumerState<QuotationStaffTab> {
|
|||||||
|
|
||||||
void updateEnquiryData(enquiryData) {
|
void updateEnquiryData(enquiryData) {
|
||||||
print('updateEnquiryData - $enquiryData');
|
print('updateEnquiryData - $enquiryData');
|
||||||
|
if (!mounted) return;
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedInsurdId = enquiryData['insurer_id'];
|
selectedInsurdId = enquiryData['insurer_id'];
|
||||||
selectedEnquiryId = enquiryData['id'];
|
selectedEnquiryId = enquiryData['id'];
|
||||||
@ -192,13 +193,14 @@ class QuotationStaffTabState extends ConsumerState<QuotationStaffTab> {
|
|||||||
|
|
||||||
Future<void> getQuotationList(enqQuotation) async {
|
Future<void> getQuotationList(enqQuotation) async {
|
||||||
print('getClaimList called enqQuotation- $enqQuotation');
|
print('getClaimList called enqQuotation- $enqQuotation');
|
||||||
|
if (!mounted) return;
|
||||||
setState(() {
|
setState(() {
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final response = await apiService.findEnqQuotePolicyView(enqQuotation);
|
final response = await apiService.findEnqQuotePolicyView(enqQuotation);
|
||||||
|
if (!mounted) return;
|
||||||
if (response['status'] == 'success') {
|
if (response['status'] == 'success') {
|
||||||
print('quoationListData - ${response['data']}');
|
print('quoationListData - ${response['data']}');
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -226,6 +228,7 @@ class QuotationStaffTabState extends ConsumerState<QuotationStaffTab> {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Exception occurred: $e');
|
print('Exception occurred: $e');
|
||||||
} finally {
|
} finally {
|
||||||
|
if (!mounted) return;
|
||||||
setState(() {
|
setState(() {
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
});
|
});
|
||||||
@ -266,7 +269,8 @@ class QuotationStaffTabState extends ConsumerState<QuotationStaffTab> {
|
|||||||
// scrollDirection: Axis.vertical,
|
// scrollDirection: Axis.vertical,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
if (!blockKey && roleId != 'manager') ...[
|
if (!blockKey) ...[
|
||||||
|
// if (!blockKey && roleId != 'manager') ...[
|
||||||
CreateQuotationForm(
|
CreateQuotationForm(
|
||||||
key: ValueKey(selectedQuotationFrmListId ?? "new"),
|
key: ValueKey(selectedQuotationFrmListId ?? "new"),
|
||||||
userId: userId,
|
userId: userId,
|
||||||
|
|||||||
@ -39,6 +39,7 @@ class TabEnquiryStaffListState extends ConsumerState<TabEnquiryStaffList> {
|
|||||||
dynamic selectedInsuredName;
|
dynamic selectedInsuredName;
|
||||||
dynamic selectedVehicleNum;
|
dynamic selectedVehicleNum;
|
||||||
dynamic selectedVehicleType;
|
dynamic selectedVehicleType;
|
||||||
|
dynamic selectedBrokerName;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -97,8 +98,9 @@ class TabEnquiryStaffListState extends ConsumerState<TabEnquiryStaffList> {
|
|||||||
selectedInsuredName = data['enquiry']?['name'];
|
selectedInsuredName = data['enquiry']?['name'];
|
||||||
selectedVehicleNum = data['enquiry']?['reg_no'];
|
selectedVehicleNum = data['enquiry']?['reg_no'];
|
||||||
selectedVehicleType = data['enquiry']?['vehicle_type'];
|
selectedVehicleType = data['enquiry']?['vehicle_type'];
|
||||||
|
selectedBrokerName = data['enquiry']?['broker_name'];
|
||||||
print(
|
print(
|
||||||
'loadQuotationTab 4s - $selectedInsuredName - $selectedVehicleNum - $selectedVehicleType',
|
'loadQuotationTab 4s -$selectedBrokerName $selectedInsuredName - $selectedVehicleNum - $selectedVehicleType',
|
||||||
);
|
);
|
||||||
|
|
||||||
tabs = [
|
tabs = [
|
||||||
@ -126,6 +128,24 @@ class TabEnquiryStaffListState extends ConsumerState<TabEnquiryStaffList> {
|
|||||||
|
|
||||||
expandedIndex = selectedIndex;
|
expandedIndex = selectedIndex;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (selectedBrokerName == 'Nhance') {
|
||||||
|
print("Chooese name Nhance");
|
||||||
|
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
await prefs.remove('enqBrokerNameProvider');
|
||||||
|
|
||||||
|
// ✅ Save the new id
|
||||||
|
await prefs.setString(
|
||||||
|
'enqBrokerNameProvider',
|
||||||
|
selectedBrokerName.toString(),
|
||||||
|
);
|
||||||
|
ref.read(enqBrokerNameProvider.notifier).state = selectedBrokerName;
|
||||||
|
} else {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
await prefs.remove('enqBrokerNameProvider');
|
||||||
|
ref.read(enqBrokerNameProvider.notifier).state = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Public method to load data and select a tab
|
/// Public method to load data and select a tab
|
||||||
@ -146,9 +166,8 @@ class TabEnquiryStaffListState extends ConsumerState<TabEnquiryStaffList> {
|
|||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
content: Container(
|
content: Container(
|
||||||
width: MediaQuery.of(context).size.width * 0.6,
|
width: MediaQuery.of(context).size.width * 0.65,
|
||||||
height: MediaQuery.of(context).size.height * 0.8,
|
height: MediaQuery.of(context).size.height * 0.9,
|
||||||
|
|
||||||
child: isLoading
|
child: isLoading
|
||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
: tabs.isEmpty
|
: tabs.isEmpty
|
||||||
@ -211,6 +230,7 @@ class TabEnquiryStaffListState extends ConsumerState<TabEnquiryStaffList> {
|
|||||||
insured_name(context),
|
insured_name(context),
|
||||||
vehcile_num(context),
|
vehcile_num(context),
|
||||||
vehcile_Type(context),
|
vehcile_Type(context),
|
||||||
|
broker(context),
|
||||||
SizedBox.shrink(),
|
SizedBox.shrink(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -310,6 +330,24 @@ class TabEnquiryStaffListState extends ConsumerState<TabEnquiryStaffList> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget broker(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text('Broker', style: _textStyle),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Text(selectedBrokerName ?? '', style: _textDataStyle),
|
||||||
|
// ThemedFormField(
|
||||||
|
// controller: controllers['insurer']!,
|
||||||
|
// readOnly: true,
|
||||||
|
// txtwidth: ResponsiveLayout.isMobile(context)
|
||||||
|
// ? null
|
||||||
|
// : MediaQuery.of(context).size.width * 0.2,
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static final _textStyle = GoogleFonts.inter(
|
static final _textStyle = GoogleFonts.inter(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
|
|||||||
@ -51,19 +51,26 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
|
|||||||
List<Map<String, dynamic>> getInsurersData = [];
|
List<Map<String, dynamic>> getInsurersData = [];
|
||||||
List<Map<String, dynamic>> filteredInsurersData = [];
|
List<Map<String, dynamic>> filteredInsurersData = [];
|
||||||
String? selectedInsurer;
|
String? selectedInsurer;
|
||||||
|
List<Map<String, dynamic>> getBrokerData = [];
|
||||||
|
List<Map<String, dynamic>> filteredBrokerData = [];
|
||||||
|
String? selectedBroker;
|
||||||
|
|
||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
final _formKeyEndrosment = GlobalKey<FormState>();
|
final _formKeyEndrosment = GlobalKey<FormState>();
|
||||||
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKey =
|
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKey =
|
||||||
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
||||||
|
|
||||||
final GlobalKey<DropdownSearchState<Map<String, dynamic>>>
|
|
||||||
dropDownKeyInsurer = GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
|
||||||
|
|
||||||
List<String> tabHeader = ['regNum'];
|
List<String> tabHeader = ['regNum'];
|
||||||
|
|
||||||
List<Map<String, dynamic>> getStaffDetailsData = [];
|
final GlobalKey<DropdownSearchState<Map<String, dynamic>>>
|
||||||
List<Map<String, dynamic>> filteredStaffData = [];
|
dropDownKeyInsurerEnqAsgn =
|
||||||
|
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
||||||
|
|
||||||
|
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKeyBroker =
|
||||||
|
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
||||||
|
|
||||||
|
List<Map<String, dynamic>> getStaffDetailsDataEnqAsgn = [];
|
||||||
|
List<Map<String, dynamic>> filteredStaffDataEnqAsgn = [];
|
||||||
|
|
||||||
String? selectedStaff;
|
String? selectedStaff;
|
||||||
String? selectedRegNum;
|
String? selectedRegNum;
|
||||||
@ -74,6 +81,7 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
|
|||||||
"id": widget.enquiryPrimaryId,
|
"id": widget.enquiryPrimaryId,
|
||||||
"assigned_to": selectedStaff,
|
"assigned_to": selectedStaff,
|
||||||
"insurer_id": selectedInsurer,
|
"insurer_id": selectedInsurer,
|
||||||
|
"broker_id": selectedBroker,
|
||||||
"updated_by": widget.userId,
|
"updated_by": widget.userId,
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
@ -92,17 +100,19 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
|
|||||||
|
|
||||||
// 🔹 Init logic here (API calls, token fetch, etc.)
|
// 🔹 Init logic here (API calls, token fetch, etc.)
|
||||||
_initializeToken();
|
_initializeToken();
|
||||||
// getStaffDetails(1);
|
// getStaffDetailsForEnquiryAssignment(1);
|
||||||
getInsurers();
|
getInsurers();
|
||||||
|
getBroker();
|
||||||
Future.microtask(() {
|
Future.microtask(() {
|
||||||
final managerId = ref.watch(managerIdProvider);
|
final managerId = ref.watch(managerIdProvider);
|
||||||
final userID = ref.watch(userIdProvider);
|
|
||||||
// final handlerId = ref.watch(handlerIdProvider);
|
// final handlerId = ref.watch(handlerIdProvider);
|
||||||
role = ref.watch(userRoleProvider);
|
role = ref.watch(userRoleProvider);
|
||||||
|
final userID = ref.watch(userIdProvider);
|
||||||
|
|
||||||
print("managerId - $managerId");
|
print("managerId - $managerId");
|
||||||
if (userID != null) {
|
if (userID != null) {
|
||||||
print('hansles');
|
print('hansles');
|
||||||
getStaffDetails(userID);
|
getStaffDetailsForEnquiryAssignment(userID);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -143,8 +153,39 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getStaffDetails(int id) async {
|
Future<void> getBroker() async {
|
||||||
print('getStaffDetails called By handler');
|
print('getBroker called');
|
||||||
|
setState(() {
|
||||||
|
isLoading = 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(() {
|
||||||
|
isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getStaffDetailsForEnquiryAssignment(int id) async {
|
||||||
|
print('getStaffDetailsForEnquiryAssignment called By handler');
|
||||||
setState(() {
|
setState(() {
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
});
|
});
|
||||||
@ -157,19 +198,19 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (response['status'] == 'success') {
|
if (response['status'] == 'success') {
|
||||||
print('getStaffDetails - ${response['data']}');
|
print('getStaffDetailsForEnquiryAssignment - ${response['data']}');
|
||||||
setState(() {
|
setState(() {
|
||||||
getStaffDetailsData = List<Map<String, dynamic>>.from(
|
getStaffDetailsDataEnqAsgn = List<Map<String, dynamic>>.from(
|
||||||
response['data'],
|
response['data'],
|
||||||
);
|
);
|
||||||
print('API Data - $getStaffDetailsData');
|
print('API Data - $getStaffDetailsDataEnqAsgn');
|
||||||
|
|
||||||
filteredStaffData = List.from(getStaffDetailsData);
|
filteredStaffDataEnqAsgn = List.from(getStaffDetailsDataEnqAsgn);
|
||||||
print('originalData - $filteredStaffData');
|
print('originalData - $filteredStaffDataEnqAsgn');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
getStaffDetailsData = [];
|
getStaffDetailsDataEnqAsgn = [];
|
||||||
filteredStaffData = [];
|
filteredStaffDataEnqAsgn = [];
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Exception occurred: $e');
|
print('Exception occurred: $e');
|
||||||
@ -363,6 +404,7 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
|
|||||||
buildRegistrationNumber(context),
|
buildRegistrationNumber(context),
|
||||||
buildSelectStaffMem(context),
|
buildSelectStaffMem(context),
|
||||||
buildInsurer(context),
|
buildInsurer(context),
|
||||||
|
buildBroker(context),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -409,14 +451,14 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget buildSelectStaffMem(ctx) {
|
Widget buildSelectStaffMem(ctx) {
|
||||||
// Map<String, dynamic>? selectedVehicle = filteredStaffData.firstWhere(
|
// Map<String, dynamic>? selectedVehicle = filteredStaffDataEnqAsgn.firstWhere(
|
||||||
// (item) => item['id'].toString() == selectedStaff,
|
// (item) => item['id'].toString() == selectedStaff,
|
||||||
// orElse: () => {},
|
// orElse: () => {},
|
||||||
// );
|
// );
|
||||||
|
|
||||||
Map<String, dynamic>? selectedVehicle;
|
Map<String, dynamic>? selectedVehicle;
|
||||||
try {
|
try {
|
||||||
selectedVehicle = filteredStaffData.firstWhere(
|
selectedVehicle = filteredStaffDataEnqAsgn.firstWhere(
|
||||||
(item) => item['id'].toString() == selectedStaff,
|
(item) => item['id'].toString() == selectedStaff,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -439,7 +481,7 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
|
|||||||
// selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null,
|
// selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null,
|
||||||
selectedItem: selectedVehicle,
|
selectedItem: selectedVehicle,
|
||||||
items: (filter, infiniteScrollProps) {
|
items: (filter, infiniteScrollProps) {
|
||||||
return filteredStaffData;
|
return filteredStaffDataEnqAsgn;
|
||||||
},
|
},
|
||||||
|
|
||||||
itemAsString: (val) => val['name'].toString(),
|
itemAsString: (val) => val['name'].toString(),
|
||||||
@ -490,6 +532,19 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
// constraints: BoxConstraints(),
|
// constraints: BoxConstraints(),
|
||||||
|
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: 14, color: Colors.black),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
onChanged: (val) {
|
onChanged: (val) {
|
||||||
@ -528,7 +583,7 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
|
|||||||
: MediaQuery.of(context).size.width * 0.26,
|
: MediaQuery.of(context).size.width * 0.26,
|
||||||
// height: 40,
|
// height: 40,
|
||||||
child: DropdownSearch<Map<String, dynamic>>(
|
child: DropdownSearch<Map<String, dynamic>>(
|
||||||
key: dropDownKeyInsurer,
|
key: dropDownKeyInsurerEnqAsgn,
|
||||||
selectedItem: selectedInsurerd.isNotEmpty ? selectedInsurerd : null,
|
selectedItem: selectedInsurerd.isNotEmpty ? selectedInsurerd : null,
|
||||||
items: (filter, infiniteScrollProps) {
|
items: (filter, infiniteScrollProps) {
|
||||||
return filteredInsurersData;
|
return filteredInsurersData;
|
||||||
@ -581,6 +636,19 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
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: 14, color: Colors.black),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
// constraints: BoxConstraints(),
|
// constraints: BoxConstraints(),
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -599,6 +667,111 @@ class _AddDialogState extends ConsumerState<AssignStaffDialog> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget buildBroker(BuildContext context) {
|
||||||
|
Map<String, dynamic>? selectedBrokers = filteredBrokerData.firstWhere(
|
||||||
|
(item) => item['id'].toString() == selectedBroker,
|
||||||
|
orElse: () => {},
|
||||||
|
);
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text('Broker *', style: _textStyle),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
// borderRadius: BorderRadius.circular(10.0),
|
||||||
|
),
|
||||||
|
width: ResponsiveLayout.isMobile(context)
|
||||||
|
? null
|
||||||
|
: MediaQuery.of(context).size.width * 0.26,
|
||||||
|
// height: 40,
|
||||||
|
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;
|
||||||
|
},
|
||||||
|
decoratorProps: DropDownDecoratorProps(
|
||||||
|
decoration:
|
||||||
|
AppInputDecorations.dropdownDecoration(
|
||||||
|
label: "Select Broker",
|
||||||
|
).copyWith(
|
||||||
|
filled: true,
|
||||||
|
fillColor: Color(
|
||||||
|
0xFFEDF6F5,
|
||||||
|
), // 👈 makes the dropdown input white
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
popupProps: PopupProps.menu(
|
||||||
|
fit: FlexFit.loose,
|
||||||
|
constraints: BoxConstraints(maxHeight: 250),
|
||||||
|
menuProps: MenuProps(
|
||||||
|
backgroundColor:
|
||||||
|
Colors.white, // 👈 sets dropdown background to white
|
||||||
|
),
|
||||||
|
showSearchBox: true,
|
||||||
|
searchFieldProps: TextFieldProps(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
filled: true,
|
||||||
|
fillColor: Colors.white,
|
||||||
|
hintText: "Search Broker...",
|
||||||
|
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: 14, color: Colors.black),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
// constraints: BoxConstraints(),
|
||||||
|
),
|
||||||
|
|
||||||
|
onChanged: (val) {
|
||||||
|
if (val != null) {
|
||||||
|
print("Selected Broker : ${val['name']}");
|
||||||
|
print("Id: ${val['id']}");
|
||||||
|
selectedBroker = val['id'];
|
||||||
|
// controllers['agentId']?.text = val['agent_code'];
|
||||||
|
// agentId = agent['id'];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------- STyle ---------------------------------
|
// ------------------- STyle ---------------------------------
|
||||||
|
|
||||||
static final TextStyle _textStyle = TextStyle(
|
static final TextStyle _textStyle = TextStyle(
|
||||||
|
|||||||
@ -1,8 +1,157 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
|
||||||
import 'fileUploadService.dart';
|
import 'fileUploadService.dart';
|
||||||
|
|
||||||
|
class ThemedUploadField extends StatefulWidget {
|
||||||
|
final String? hintText;
|
||||||
|
final double? txtwidth;
|
||||||
|
final double? txtheight;
|
||||||
|
final Color? backgroundColor;
|
||||||
|
final Color? borderColor;
|
||||||
|
final Color? errorBorderColor;
|
||||||
|
final Function(String fileName, PlatformFile file)? onFileSelected;
|
||||||
|
FormFieldValidator<String>? validator;
|
||||||
|
final List<String>? allowedExtensions;
|
||||||
|
final bool isTxtBtnCase;
|
||||||
|
final String? txtName;
|
||||||
|
final double? padVertical;
|
||||||
|
final double? padHorizontal;
|
||||||
|
|
||||||
|
ThemedUploadField({
|
||||||
|
super.key,
|
||||||
|
this.hintText,
|
||||||
|
this.txtwidth,
|
||||||
|
this.txtheight,
|
||||||
|
this.backgroundColor,
|
||||||
|
this.borderColor,
|
||||||
|
this.errorBorderColor,
|
||||||
|
this.onFileSelected,
|
||||||
|
this.validator,
|
||||||
|
this.allowedExtensions,
|
||||||
|
this.isTxtBtnCase = false,
|
||||||
|
this.txtName,
|
||||||
|
this.padVertical,
|
||||||
|
this.padHorizontal,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ThemedUploadField> createState() => _ThemedUploadFieldState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ThemedUploadFieldState extends State<ThemedUploadField> {
|
||||||
|
final fileService = FileUploadService();
|
||||||
|
String? selectedFileName;
|
||||||
|
String? errorMessage;
|
||||||
|
|
||||||
|
Future<void> _pickFile() async {
|
||||||
|
final error = await fileService.pickSingleFile(
|
||||||
|
maxFileSizeInMB: 3,
|
||||||
|
allowedExtensions: widget.allowedExtensions,
|
||||||
|
);
|
||||||
|
if (error != null) {
|
||||||
|
setState(() => errorMessage = error);
|
||||||
|
ScaffoldMessenger.of(
|
||||||
|
context,
|
||||||
|
).showSnackBar(SnackBar(content: Text(error)));
|
||||||
|
} else if (fileService.singleFile != null) {
|
||||||
|
setState(() {
|
||||||
|
selectedFileName = fileService.singleFile!.name;
|
||||||
|
errorMessage = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
widget.onFileSelected?.call(
|
||||||
|
fileService.singleFile!.name,
|
||||||
|
fileService.singleFile!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: widget.txtwidth ?? MediaQuery.of(context).size.width,
|
||||||
|
height: widget.txtheight,
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: BoxDecoration(borderRadius: BorderRadius.circular(10)),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: _pickFile,
|
||||||
|
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
vertical: widget.padVertical ?? 10,
|
||||||
|
horizontal: widget.padHorizontal ?? 15,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: widget.backgroundColor ?? Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
border: Border.all(
|
||||||
|
color: errorMessage != null
|
||||||
|
? (widget.errorBorderColor ?? Colors.red)
|
||||||
|
: (widget.borderColor ??
|
||||||
|
widget.backgroundColor ??
|
||||||
|
Colors.grey.shade50),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
if (!widget.isTxtBtnCase) ...[
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
selectedFileName ??
|
||||||
|
widget.hintText ??
|
||||||
|
"Upload Document",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: errorMessage != null
|
||||||
|
? Colors.red
|
||||||
|
: Colors.black,
|
||||||
|
),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Icon(
|
||||||
|
Icons.file_upload_outlined,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
|
||||||
|
if (widget.isTxtBtnCase) ...[
|
||||||
|
Center(
|
||||||
|
child: Tooltip(
|
||||||
|
message: 'Upload Documents',
|
||||||
|
child: Text(
|
||||||
|
widget.txtName!,
|
||||||
|
style: GoogleFonts.inter(fontSize: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (errorMessage != null)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 8, top: 4),
|
||||||
|
child: Text(
|
||||||
|
errorMessage!,
|
||||||
|
style: const TextStyle(color: Colors.red, fontSize: 10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// class ThemedUploadField extends FormField<String> {
|
// class ThemedUploadField extends FormField<String> {
|
||||||
// ThemedUploadField({
|
// ThemedUploadField({
|
||||||
// Key? key,
|
// Key? key,
|
||||||
@ -98,124 +247,3 @@ import 'fileUploadService.dart';
|
|||||||
// },
|
// },
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
class ThemedUploadField extends StatefulWidget {
|
|
||||||
final String? hintText;
|
|
||||||
final double? txtwidth;
|
|
||||||
final double? txtheight;
|
|
||||||
final Color? backgroundColor;
|
|
||||||
final Color? borderColor;
|
|
||||||
final Color? errorBorderColor;
|
|
||||||
final Function(String fileName, PlatformFile file)? onFileSelected;
|
|
||||||
FormFieldValidator<String>? validator;
|
|
||||||
final List<String>? allowedExtensions;
|
|
||||||
|
|
||||||
ThemedUploadField({
|
|
||||||
super.key,
|
|
||||||
this.hintText,
|
|
||||||
this.txtwidth,
|
|
||||||
this.txtheight,
|
|
||||||
this.backgroundColor,
|
|
||||||
this.borderColor,
|
|
||||||
this.errorBorderColor,
|
|
||||||
this.onFileSelected,
|
|
||||||
this.validator,
|
|
||||||
this.allowedExtensions,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<ThemedUploadField> createState() => _ThemedUploadFieldState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ThemedUploadFieldState extends State<ThemedUploadField> {
|
|
||||||
final fileService = FileUploadService();
|
|
||||||
String? selectedFileName;
|
|
||||||
String? errorMessage;
|
|
||||||
|
|
||||||
Future<void> _pickFile() async {
|
|
||||||
final error = await fileService.pickSingleFile(
|
|
||||||
maxFileSizeInMB: 3,
|
|
||||||
allowedExtensions: widget.allowedExtensions,
|
|
||||||
);
|
|
||||||
if (error != null) {
|
|
||||||
setState(() => errorMessage = error);
|
|
||||||
ScaffoldMessenger.of(
|
|
||||||
context,
|
|
||||||
).showSnackBar(SnackBar(content: Text(error)));
|
|
||||||
} else if (fileService.singleFile != null) {
|
|
||||||
setState(() {
|
|
||||||
selectedFileName = fileService.singleFile!.name;
|
|
||||||
errorMessage = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
widget.onFileSelected?.call(
|
|
||||||
fileService.singleFile!.name,
|
|
||||||
fileService.singleFile!,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: widget.txtwidth ?? MediaQuery.of(context).size.width,
|
|
||||||
height: widget.txtheight,
|
|
||||||
child: DecoratedBox(
|
|
||||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(10)),
|
|
||||||
child: InkWell(
|
|
||||||
onTap: _pickFile,
|
|
||||||
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 10,
|
|
||||||
horizontal: 15,
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: widget.backgroundColor ?? Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
border: Border.all(
|
|
||||||
color: errorMessage != null
|
|
||||||
? (widget.errorBorderColor ?? Colors.red)
|
|
||||||
: (widget.borderColor ?? Colors.grey.shade50),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
selectedFileName ??
|
|
||||||
widget.hintText ??
|
|
||||||
"Upload Document",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: errorMessage != null
|
|
||||||
? Colors.red
|
|
||||||
: Colors.black,
|
|
||||||
),
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Icon(Icons.file_upload_outlined, color: Colors.black),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (errorMessage != null)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 8, top: 4),
|
|
||||||
child: Text(
|
|
||||||
errorMessage!,
|
|
||||||
style: const TextStyle(color: Colors.red, fontSize: 10),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -80,21 +80,21 @@ class ExportBtn extends HookWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
?txt!
|
// ?txt!
|
||||||
? Text(
|
// ? Text(
|
||||||
'Export',
|
// 'Export',
|
||||||
style: TextStyle(
|
// style: TextStyle(
|
||||||
color: Colors.white,
|
// color: Colors.white,
|
||||||
fontWeight: FontWeight.w600,
|
// fontWeight: FontWeight.w600,
|
||||||
fontSize: 14,
|
// fontSize: 14,
|
||||||
),
|
// ),
|
||||||
)
|
// )
|
||||||
: null,
|
// : null,
|
||||||
?txt! ? SizedBox(width: 15) : null,
|
// ?txt! ? SizedBox(width: 15) : null,
|
||||||
Image.asset(
|
Image.asset(
|
||||||
"assets/miscellaneous/export.png",
|
"assets/miscellaneous/export.png",
|
||||||
height: 25,
|
height: 15,
|
||||||
width: 25,
|
width: 15,
|
||||||
),
|
),
|
||||||
// Icon(Icons.input_sharp, color: Colors.white),
|
// Icon(Icons.input_sharp, color: Colors.white),
|
||||||
// Image.asset("assets/miscellaneous/export", height: 15, width: 15),
|
// Image.asset("assets/miscellaneous/export", height: 15, width: 15),
|
||||||
|
|||||||
@ -8,7 +8,8 @@ class AppInputDecorations {
|
|||||||
hintText: hint,
|
hintText: hint,
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: const Color(0xFFECECEC),
|
fillColor: const Color(0xFFECECEC),
|
||||||
contentPadding: const EdgeInsets.symmetric(vertical: 14, horizontal: 15),
|
|
||||||
|
contentPadding: const EdgeInsets.symmetric(vertical: 14, horizontal: 1),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
borderSide: const BorderSide(color: Color(0xFFFFFFFF)),
|
borderSide: const BorderSide(color: Color(0xFFFFFFFF)),
|
||||||
@ -16,7 +17,8 @@ class AppInputDecorations {
|
|||||||
errorStyle: const TextStyle(color: Colors.red, fontSize: 12),
|
errorStyle: const TextStyle(color: Colors.red, fontSize: 12),
|
||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
borderSide: const BorderSide(color: Color(0xFFFFFFFF)),
|
|
||||||
|
borderSide: const BorderSide(color: Color(0xFFFFFFFF), width: 1),
|
||||||
),
|
),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
|||||||
@ -6,9 +6,10 @@ import 'package:google_fonts/google_fonts.dart';
|
|||||||
// import 'package:uae_stat/config/my_theme.dart';
|
// import 'package:uae_stat/config/my_theme.dart';
|
||||||
|
|
||||||
class ThemedFormField extends HookWidget {
|
class ThemedFormField extends HookWidget {
|
||||||
const ThemedFormField({
|
ThemedFormField({
|
||||||
super.key,
|
super.key,
|
||||||
this.hintText,
|
this.hintText,
|
||||||
|
|
||||||
this.imgPath,
|
this.imgPath,
|
||||||
this.txtwidth,
|
this.txtwidth,
|
||||||
this.txtheight,
|
this.txtheight,
|
||||||
@ -21,13 +22,22 @@ class ThemedFormField extends HookWidget {
|
|||||||
this.errorBorderColor,
|
this.errorBorderColor,
|
||||||
this.errorTextColor,
|
this.errorTextColor,
|
||||||
this.readOnly = false, // ✅ new
|
this.readOnly = false, // ✅ new
|
||||||
|
this.isdense = false, // ✅ new
|
||||||
this.keyboardType, // ✅ new
|
this.keyboardType, // ✅ new
|
||||||
this.maxLength, // ✅ new
|
this.maxLength, // ✅ new
|
||||||
this.inputFormatters,
|
this.inputFormatters,
|
||||||
this.isShowCursor,
|
this.isShowCursor,
|
||||||
|
this.onChanged,
|
||||||
|
this.verticalPad,
|
||||||
|
this.horizonalPad,
|
||||||
|
this.enableBorderWidth,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final double? verticalPad;
|
||||||
|
final double? horizonalPad;
|
||||||
|
final double? enableBorderWidth;
|
||||||
final String? hintText;
|
final String? hintText;
|
||||||
|
|
||||||
final String? imgPath;
|
final String? imgPath;
|
||||||
final String? Function(String? text)? validator;
|
final String? Function(String? text)? validator;
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
@ -39,11 +49,15 @@ class ThemedFormField extends HookWidget {
|
|||||||
final Color? errorTextColor;
|
final Color? errorTextColor;
|
||||||
final double? txtwidth;
|
final double? txtwidth;
|
||||||
final bool readOnly;
|
final bool readOnly;
|
||||||
|
final bool isdense;
|
||||||
|
|
||||||
final bool? isShowCursor;
|
final bool? isShowCursor;
|
||||||
final TextInputType? keyboardType;
|
final TextInputType? keyboardType;
|
||||||
final int? maxLength;
|
final int? maxLength;
|
||||||
final double? txtheight;
|
final double? txtheight;
|
||||||
final List<TextInputFormatter>? inputFormatters;
|
final List<TextInputFormatter>? inputFormatters;
|
||||||
|
// void Function(dynamic value)? onChanged;
|
||||||
|
final ValueChanged<String>? onChanged;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -70,34 +84,49 @@ class ThemedFormField extends HookWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
final inputDecoration = InputDecoration(
|
final inputDecoration = InputDecoration(
|
||||||
// isDense: true,
|
isDense: isdense,
|
||||||
errorStyle: TextStyle(color: const Color(0xFFD83731)),
|
errorStyle: TextStyle(color: Color(0xFFD83731)),
|
||||||
errorBorder: OutlineInputBorder(
|
errorBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
borderSide: BorderSide(color: const Color(0xFFD83731), width: 1),
|
borderSide: BorderSide(
|
||||||
|
color: errorBorderColor ?? Color(0xFFD83731),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
focusedErrorBorder: OutlineInputBorder(
|
focusedErrorBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
borderSide: BorderSide(color: const Color(0xFFD83731), width: 1),
|
borderSide: BorderSide(
|
||||||
|
color: errorBorderColor ?? Color(0xFFD83731),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: backgroundColor ?? Colors.white,
|
fillColor: backgroundColor ?? Colors.white,
|
||||||
contentPadding: const EdgeInsets.symmetric(vertical: 14, horizontal: 15),
|
contentPadding: EdgeInsets.symmetric(
|
||||||
|
vertical: verticalPad ?? 14,
|
||||||
|
horizontal: horizonalPad ?? 15,
|
||||||
|
),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
// borderSide: BorderSide(color: Color(0xFF50A398)),
|
// borderSide: BorderSide(color: Color(0xFF50A398)),
|
||||||
borderSide: BorderSide(color: Color(0xFFFFFFFF)),
|
borderSide: BorderSide(
|
||||||
|
color: borderColor ?? Color(0xFFFFFFFF),
|
||||||
|
width: enableBorderWidth ?? 1,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
// borderSide: BorderSide(color: Color(0xFF50A398)),
|
// borderSide: BorderSide(color: Color(0xFF50A398)),
|
||||||
borderSide: BorderSide(color: Color(0xFFFFFFFF)),
|
borderSide: BorderSide(
|
||||||
|
color: borderColor ?? backgroundColor ?? Color(0xFFFFFFFF),
|
||||||
|
width: enableBorderWidth ?? 1,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
focusedBorder: readOnly
|
focusedBorder: readOnly
|
||||||
? OutlineInputBorder(
|
? OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
// borderSide: BorderSide(color: Color(0xFF50A398)),
|
// borderSide: BorderSide(color: Color(0xFF50A398)),
|
||||||
borderSide: BorderSide(color: Color(0xFFFFFFFF)),
|
borderSide: BorderSide(color: borderColor ?? Color(0xFFFFFFFF)),
|
||||||
)
|
)
|
||||||
: OutlineInputBorder(
|
: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
@ -135,6 +164,7 @@ class ThemedFormField extends HookWidget {
|
|||||||
);
|
);
|
||||||
return Container(
|
return Container(
|
||||||
width: txtwidth ?? MediaQuery.of(context).size.width,
|
width: txtwidth ?? MediaQuery.of(context).size.width,
|
||||||
|
|
||||||
height: txtheight ?? null,
|
height: txtheight ?? null,
|
||||||
child: DecoratedBox(
|
child: DecoratedBox(
|
||||||
decoration: boxDecoration,
|
decoration: boxDecoration,
|
||||||
@ -155,7 +185,7 @@ class ThemedFormField extends HookWidget {
|
|||||||
minLines: (keyboardType == TextInputType.multiline) ? 3 : 1,
|
minLines: (keyboardType == TextInputType.multiline) ? 3 : 1,
|
||||||
maxLines: (keyboardType == TextInputType.multiline) ? null : 1,
|
maxLines: (keyboardType == TextInputType.multiline) ? null : 1,
|
||||||
style: GoogleFonts.inter(
|
style: GoogleFonts.inter(
|
||||||
fontSize: 14, // 👈 Change this to your desired size
|
fontSize: 12, // 👈 Change this to your desired size
|
||||||
fontWeight: FontWeight.w400, // optional
|
fontWeight: FontWeight.w400, // optional
|
||||||
color: Colors.black, // optional
|
color: Colors.black, // optional
|
||||||
),
|
),
|
||||||
|
|||||||
@ -0,0 +1,199 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
|
||||||
|
// import 'package:uae_stat/config/my_theme.dart';
|
||||||
|
|
||||||
|
class ThemedFormInlineField extends HookWidget {
|
||||||
|
ThemedFormInlineField({
|
||||||
|
super.key,
|
||||||
|
this.hintText,
|
||||||
|
this.widthNone = false,
|
||||||
|
this.imgPath,
|
||||||
|
this.txtwidth,
|
||||||
|
this.txtheight,
|
||||||
|
required this.controller,
|
||||||
|
this.validator,
|
||||||
|
this.isObscurable = false,
|
||||||
|
this.hintColor,
|
||||||
|
this.backgroundColor,
|
||||||
|
this.borderColor,
|
||||||
|
this.errorBorderColor,
|
||||||
|
this.errorTextColor,
|
||||||
|
this.readOnly = false, // ✅ new
|
||||||
|
this.keyboardType, // ✅ new
|
||||||
|
this.maxLength, // ✅ new
|
||||||
|
this.inputFormatters,
|
||||||
|
this.isShowCursor,
|
||||||
|
this.onChanged,
|
||||||
|
this.isdense,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String? hintText;
|
||||||
|
final bool? widthNone;
|
||||||
|
final String? imgPath;
|
||||||
|
final String? Function(String? text)? validator;
|
||||||
|
final TextEditingController controller;
|
||||||
|
final bool isObscurable;
|
||||||
|
final Color? hintColor;
|
||||||
|
final Color? backgroundColor;
|
||||||
|
final Color? borderColor;
|
||||||
|
final Color? errorBorderColor;
|
||||||
|
final Color? errorTextColor;
|
||||||
|
final double? txtwidth;
|
||||||
|
final bool readOnly;
|
||||||
|
final bool? isdense;
|
||||||
|
final bool? isShowCursor;
|
||||||
|
final TextInputType? keyboardType;
|
||||||
|
final int? maxLength;
|
||||||
|
final double? txtheight;
|
||||||
|
final List<TextInputFormatter>? inputFormatters;
|
||||||
|
// void Function(dynamic value)? onChanged;
|
||||||
|
final ValueChanged<String>? onChanged;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final isObscured = useState<bool>(true);
|
||||||
|
final boxDecoration = BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
// boxShadow: [
|
||||||
|
// BoxShadow(
|
||||||
|
// color: Colors.black26, // shadow color
|
||||||
|
// offset: Offset(0, 2), // x=0, y=4 → shadow goes downward
|
||||||
|
// blurRadius: 2, // soften the shadow
|
||||||
|
// spreadRadius: 0.2, // expand shadow
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
);
|
||||||
|
final obscureBtn = IconButton(
|
||||||
|
onPressed: () => isObscured.value = !isObscured.value,
|
||||||
|
|
||||||
|
icon: Icon(
|
||||||
|
isObscured.value
|
||||||
|
? Icons.visibility_off_outlined
|
||||||
|
: Icons.visibility_outlined,
|
||||||
|
color: const Color(0xff9EA2A9),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final inputDecoration = InputDecoration(
|
||||||
|
isDense: isdense ?? false,
|
||||||
|
errorStyle: TextStyle(color: Color(0xFFD83731)),
|
||||||
|
errorBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: errorBorderColor ?? Color(0xFFD83731),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
focusedErrorBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: errorBorderColor ?? Color(0xFFD83731),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
filled: true,
|
||||||
|
fillColor: backgroundColor ?? Colors.white,
|
||||||
|
// contentPadding: const EdgeInsets.symmetric(vertical: 14, horizontal: 2),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(vertical: 8, horizontal: 10),
|
||||||
|
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
// borderSide: BorderSide(color: Color(0xFF50A398)),
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: borderColor ?? Color(0xFFFFFFFF),
|
||||||
|
width: 0.1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
// borderSide: BorderSide(color: Color(0xFF50A398)),
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: borderColor ?? backgroundColor ?? Color(0xFFFFFFFF),
|
||||||
|
width: 0.1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
focusedBorder: readOnly
|
||||||
|
? OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
// borderSide: BorderSide(color: Color(0xFF50A398)),
|
||||||
|
borderSide: BorderSide(color: borderColor ?? Color(0xFFFFFFFF)),
|
||||||
|
)
|
||||||
|
: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
borderSide: BorderSide(color: Color(0xFF50A398), width: 2),
|
||||||
|
),
|
||||||
|
hintText: hintText,
|
||||||
|
hintStyle: TextStyle(
|
||||||
|
// ✅ dynamic hint color
|
||||||
|
color: const Color(0xFFC3C6CB),
|
||||||
|
),
|
||||||
|
// labelText: hintText,
|
||||||
|
// labelStyle: GoogleFonts.inter(
|
||||||
|
// fontSize: 10,
|
||||||
|
// // color: Colors.black, // customize here
|
||||||
|
// color: Colors.red, // customize here
|
||||||
|
// fontWeight: FontWeight.w400,
|
||||||
|
// ),
|
||||||
|
prefixIconConstraints: const BoxConstraints(
|
||||||
|
maxWidth: 25 + 16 + 10,
|
||||||
|
maxHeight: 25 + (8 * 2),
|
||||||
|
),
|
||||||
|
prefixIcon: imgPath != null
|
||||||
|
? Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.only(start: 16, end: 10),
|
||||||
|
child: Image.asset(
|
||||||
|
imgPath!,
|
||||||
|
fit: BoxFit.fitHeight,
|
||||||
|
height: 25,
|
||||||
|
width: 25,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
|
||||||
|
suffixIcon: isObscurable ? obscureBtn : null,
|
||||||
|
);
|
||||||
|
return Container(
|
||||||
|
height: txtheight ?? null,
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: boxDecoration,
|
||||||
|
child: TextFormField(
|
||||||
|
controller: controller,
|
||||||
|
decoration: inputDecoration,
|
||||||
|
validator: validator,
|
||||||
|
obscureText: isObscurable && isObscured.value,
|
||||||
|
readOnly: readOnly, // ✅ now supported
|
||||||
|
keyboardType: keyboardType, // ✅ e.g. TextInputType.number
|
||||||
|
maxLength: maxLength, // ✅ max length
|
||||||
|
showCursor: isShowCursor ?? true,
|
||||||
|
enableInteractiveSelection: isShowCursor ?? true,
|
||||||
|
inputFormatters:
|
||||||
|
inputFormatters ??
|
||||||
|
[FilteringTextInputFormatter.allow(RegExp(r'[a-z A-Z]'))],
|
||||||
|
// ✅ allow multiline if user sets maxLines / minLines
|
||||||
|
minLines: (keyboardType == TextInputType.multiline) ? 3 : 1,
|
||||||
|
maxLines: (keyboardType == TextInputType.multiline) ? null : 1,
|
||||||
|
style: GoogleFonts.inter(
|
||||||
|
fontSize: 12, // 👈 Change this to your desired size
|
||||||
|
fontWeight: FontWeight.w400, // optional
|
||||||
|
color: Colors.black, // optional
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UpperCaseTextFormatter extends TextInputFormatter {
|
||||||
|
@override
|
||||||
|
TextEditingValue formatEditUpdate(
|
||||||
|
TextEditingValue oldValue,
|
||||||
|
TextEditingValue newValue,
|
||||||
|
) {
|
||||||
|
return TextEditingValue(
|
||||||
|
text: newValue.text.toUpperCase(),
|
||||||
|
selection: newValue.selection,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -144,7 +144,7 @@ class _DateFilterRowState extends ConsumerState<DateFilterRow> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final spacing = 10.0;
|
final spacing = 5.0;
|
||||||
|
|
||||||
// final rowChildren = [
|
// final rowChildren = [
|
||||||
// buildStartDate(context),
|
// buildStartDate(context),
|
||||||
@ -186,7 +186,7 @@ class _DateFilterRowState extends ConsumerState<DateFilterRow> {
|
|||||||
|
|
||||||
final buttons = [
|
final buttons = [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
padding: const EdgeInsets.symmetric(vertical: 0.0),
|
||||||
// child: GestureDetector(
|
// child: GestureDetector(
|
||||||
// onTap: () {
|
// onTap: () {
|
||||||
// if (formKey.currentState!.validate()) onFilter();
|
// if (formKey.currentState!.validate()) onFilter();
|
||||||
@ -206,7 +206,7 @@ class _DateFilterRowState extends ConsumerState<DateFilterRow> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(0.0),
|
||||||
// child: GestureDetector(onTap: onRefresh, child: Icon(Icons.refresh)),
|
// child: GestureDetector(onTap: onRefresh, child: Icon(Icons.refresh)),
|
||||||
child: Tooltip(
|
child: Tooltip(
|
||||||
message: 'Refresh',
|
message: 'Refresh',
|
||||||
@ -235,11 +235,11 @@ class _DateFilterRowState extends ConsumerState<DateFilterRow> {
|
|||||||
key: widget.formKey,
|
key: widget.formKey,
|
||||||
child: widget.isMobile
|
child: widget.isMobile
|
||||||
? Column(
|
? Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: getRowChildren(widget.isMobile, spacing),
|
children: getRowChildren(widget.isMobile, spacing),
|
||||||
)
|
)
|
||||||
: Row(
|
: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: getRowChildren(widget.isMobile, spacing),
|
children: getRowChildren(widget.isMobile, spacing),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -249,8 +249,8 @@ class _DateFilterRowState extends ConsumerState<DateFilterRow> {
|
|||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('Start Date', style: _textStyle),
|
// Text('Start Date', style: _textStyle),
|
||||||
SizedBox(height: 5),
|
// SizedBox(height: 5),
|
||||||
ThemedDateField(
|
ThemedDateField(
|
||||||
hintText: "Select Date",
|
hintText: "Select Date",
|
||||||
txtwidth: ResponsiveLayout.isMobile(context)
|
txtwidth: ResponsiveLayout.isMobile(context)
|
||||||
@ -274,8 +274,8 @@ class _DateFilterRowState extends ConsumerState<DateFilterRow> {
|
|||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('End Date', style: _textStyle),
|
// Text('End Date', style: _textStyle),
|
||||||
SizedBox(height: 5),
|
// SizedBox(height: 5),
|
||||||
ThemedDateField(
|
ThemedDateField(
|
||||||
hintText: "Select Date",
|
hintText: "Select Date",
|
||||||
txtwidth: ResponsiveLayout.isMobile(context)
|
txtwidth: ResponsiveLayout.isMobile(context)
|
||||||
@ -336,8 +336,8 @@ class _DateFilterRowState extends ConsumerState<DateFilterRow> {
|
|||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('Status', style: _textStyle),
|
// Text('Status', style: _textStyle),
|
||||||
SizedBox(height: 5),
|
// SizedBox(height: 5),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -362,6 +362,18 @@ class _DateFilterRowState extends ConsumerState<DateFilterRow> {
|
|||||||
compareFn: (item, selectedItem) =>
|
compareFn: (item, selectedItem) =>
|
||||||
item['id'] == selectedItem['id'],
|
item['id'] == selectedItem['id'],
|
||||||
|
|
||||||
|
dropdownBuilder: (context, selectedItem) => Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
|
||||||
|
child: Text(
|
||||||
|
selectedItem != null ? selectedItem['status'].toString() : "",
|
||||||
|
style: GoogleFonts.poppins(fontSize: 11, color: Colors.black),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
maxLines: 1,
|
||||||
|
softWrap: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
// validator: (val) {
|
// validator: (val) {
|
||||||
// if (val == null) {
|
// if (val == null) {
|
||||||
// return "Please select a status";
|
// return "Please select a status";
|
||||||
@ -369,9 +381,19 @@ class _DateFilterRowState extends ConsumerState<DateFilterRow> {
|
|||||||
// return null;
|
// return null;
|
||||||
// },
|
// },
|
||||||
decoratorProps: DropDownDecoratorProps(
|
decoratorProps: DropDownDecoratorProps(
|
||||||
decoration: AppInputDecorations.dropdownDecoration(
|
decoration:
|
||||||
label: "Select Status",
|
AppInputDecorations.dropdownDecoration(
|
||||||
).copyWith(filled: true, fillColor: Colors.white),
|
label: "Select Status",
|
||||||
|
).copyWith(
|
||||||
|
filled: true,
|
||||||
|
fillColor: Colors.white,
|
||||||
|
isDense: true, // 👈 reduces built-in vertical padding
|
||||||
|
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 2,
|
||||||
|
vertical: 1, // 👈 adjust this to make the field shorter
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
// popupProps: PopupProps.menu(
|
// popupProps: PopupProps.menu(
|
||||||
// fit: FlexFit.loose,
|
// fit: FlexFit.loose,
|
||||||
@ -455,104 +477,124 @@ class _DateFilterRowState extends ConsumerState<DateFilterRow> {
|
|||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text("Staff Name", style: _textStyle),
|
// Text("Staff Name", style: _textStyle),
|
||||||
SizedBox(height: 10),
|
// SizedBox(height: 10),
|
||||||
Container(
|
SizedBox(
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(5.0),
|
|
||||||
border: Border.all(color: Colors.grey.shade100),
|
|
||||||
// color: Colors.black,
|
|
||||||
),
|
|
||||||
|
|
||||||
width: ResponsiveLayout.isMobile(context)
|
|
||||||
? null
|
|
||||||
: MediaQuery.of(context).size.width * 0.13,
|
|
||||||
height: 40,
|
height: 40,
|
||||||
child: DropdownSearch<Map<String, dynamic>>(
|
child: Container(
|
||||||
// key: dropDownKey,
|
decoration: BoxDecoration(
|
||||||
key: ValueKey(selectedStaff),
|
borderRadius: BorderRadius.circular(5.0),
|
||||||
// selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null,
|
border: Border.all(color: Colors.grey.shade100),
|
||||||
selectedItem: selectedVehicle,
|
// color: Colors.black,
|
||||||
|
|
||||||
items: (filter, infiniteScrollProps) {
|
|
||||||
return filteredStaffData;
|
|
||||||
},
|
|
||||||
|
|
||||||
itemAsString: (val) => val['name'].toString(),
|
|
||||||
compareFn: (item, selectedItem) =>
|
|
||||||
item['id'] == selectedItem['id'], // ✅ compare by id
|
|
||||||
|
|
||||||
decoratorProps: DropDownDecoratorProps(
|
|
||||||
decoration:
|
|
||||||
AppInputDecorations.dropdownDecoration(
|
|
||||||
label: "Select Staff ",
|
|
||||||
).copyWith(
|
|
||||||
filled: true,
|
|
||||||
fillColor:
|
|
||||||
Colors.white, // 👈 makes the dropdown input white
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
|
||||||
popupProps: PopupProps.menu(
|
width: ResponsiveLayout.isMobile(context)
|
||||||
fit: FlexFit.loose,
|
? null
|
||||||
constraints: BoxConstraints(maxHeight: 250),
|
: MediaQuery.of(context).size.width * 0.13,
|
||||||
menuProps: MenuProps(
|
// height: 45,
|
||||||
backgroundColor:
|
child: DropdownSearch<Map<String, dynamic>>(
|
||||||
Colors.white, // 👈 sets dropdown background to white
|
// key: dropDownKey,
|
||||||
),
|
key: ValueKey(selectedStaff),
|
||||||
showSearchBox: true,
|
// selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null,
|
||||||
searchFieldProps: TextFieldProps(
|
selectedItem: selectedVehicle,
|
||||||
decoration: InputDecoration(
|
|
||||||
filled: true,
|
items: (filter, infiniteScrollProps) {
|
||||||
fillColor: Colors.white,
|
return filteredStaffData;
|
||||||
hintText: "Search Staff ...",
|
},
|
||||||
hintStyle: GoogleFonts.inter(
|
|
||||||
fontSize: 12,
|
itemAsString: (val) => val['name'].toString(),
|
||||||
color: Colors.black,
|
compareFn: (item, selectedItem) =>
|
||||||
),
|
item['id'] == selectedItem['id'], // ✅ compare by id
|
||||||
enabledBorder: OutlineInputBorder(
|
dropdownBuilder: (context, selectedItem) => Align(
|
||||||
borderSide: BorderSide(
|
alignment: Alignment.centerLeft,
|
||||||
color: Colors.white,
|
child: Text(
|
||||||
), // 👈 Normal border
|
selectedItem != null ? selectedItem['name'].toString() : "",
|
||||||
),
|
style: GoogleFonts.poppins(fontSize: 11, color: Colors.black),
|
||||||
focusedBorder: OutlineInputBorder(
|
overflow: TextOverflow.ellipsis,
|
||||||
borderSide: BorderSide(
|
maxLines: 1,
|
||||||
color: Colors.white,
|
softWrap: false,
|
||||||
width: 1.5,
|
|
||||||
), // 👈 Focused border
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
decoratorProps: DropDownDecoratorProps(
|
||||||
|
decoration:
|
||||||
|
AppInputDecorations.dropdownDecoration(
|
||||||
|
label: "Select Staff ",
|
||||||
|
).copyWith(
|
||||||
|
filled: true,
|
||||||
|
fillColor:
|
||||||
|
Colors.white, // 👈 makes the dropdown input white
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 2,
|
||||||
|
vertical: 1, // 👈 adjust this to make the field shorter
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
itemBuilder: (context, item, isDisabled, isSelected) {
|
popupProps: PopupProps.menu(
|
||||||
return Container(
|
fit: FlexFit.loose,
|
||||||
// color: isSelected ? Colors.blue.withOpacity(0.1) : null,
|
constraints: BoxConstraints(maxHeight: 250),
|
||||||
padding: const EdgeInsets.symmetric(
|
menuProps: MenuProps(
|
||||||
horizontal: 8,
|
backgroundColor:
|
||||||
vertical: 3,
|
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
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
),
|
||||||
item['name'].toString(),
|
|
||||||
style: GoogleFonts.inter(fontSize: 13, color: Colors.black),
|
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'];
|
||||||
|
|
||||||
|
if (widget.onFilterStaff != null)
|
||||||
|
widget.onFilterStaff!(val['id']);
|
||||||
|
// controllers['agentId']?.text = val['agent_code'];
|
||||||
|
// agentId = agent['id'];
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// constraints: BoxConstraints(),
|
|
||||||
),
|
),
|
||||||
|
|
||||||
onChanged: (val) {
|
|
||||||
if (val != null) {
|
|
||||||
print("Selected Staff : ${val['name']}");
|
|
||||||
print("Id: ${val['id']}");
|
|
||||||
selectedStaffName = val['name'];
|
|
||||||
selectedStaff = val['id'];
|
|
||||||
|
|
||||||
if (widget.onFilterStaff != null)
|
|
||||||
widget.onFilterStaff!(val['id']);
|
|
||||||
// controllers['agentId']?.text = val['agent_code'];
|
|
||||||
// agentId = agent['id'];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -65,6 +65,10 @@ class _TopBarState extends ConsumerState<TopBar> {
|
|||||||
titleSpacing: widget.isMobile ? 0 : 30,
|
titleSpacing: widget.isMobile ? 0 : 30,
|
||||||
title: Row(
|
title: Row(
|
||||||
children: [
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.menu, color: Colors.black87),
|
||||||
|
onPressed: widget.onMenuPressed,
|
||||||
|
),
|
||||||
if (!widget.isMobile)
|
if (!widget.isMobile)
|
||||||
Image.asset(
|
Image.asset(
|
||||||
"assets/login/nhance-partner-logo.png",
|
"assets/login/nhance-partner-logo.png",
|
||||||
@ -103,11 +107,7 @@ class _TopBarState extends ConsumerState<TopBar> {
|
|||||||
|
|
||||||
Spacer(),
|
Spacer(),
|
||||||
|
|
||||||
// else if (onMenuPressed != null)
|
// if (onMenuPressed != null)
|
||||||
// IconButton(
|
|
||||||
// icon: const Icon(Icons.menu, color: Colors.black87),
|
|
||||||
// onPressed: onMenuPressed,
|
|
||||||
// ),
|
|
||||||
if (role == 'agent') ...[
|
if (role == 'agent') ...[
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
|
|||||||
@ -70,6 +70,8 @@ dependencies:
|
|||||||
file_picker: ^10.3.3
|
file_picker: ^10.3.3
|
||||||
fluttertoast: ^9.0.0
|
fluttertoast: ^9.0.0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user