quick_proceed status_changes

This commit is contained in:
venbaittech 2025-12-01 14:57:35 +05:30
parent 485894ba98
commit fcdc9da609
13 changed files with 8893 additions and 589 deletions

File diff suppressed because one or more lines are too long

View File

@ -30,6 +30,7 @@ import '../../presentation/screens/splash/splash_screen.dart';
import '../../presentation/screens/staff/Enquiry/enquiry_inline_Edit_17Nov.dart';
import '../../presentation/screens/staff/Enquiry/enquiry_inline_list.dart';
import '../../presentation/screens/staff/Enquiry/enquiry_list.dart';
import '../../presentation/screens/staff/Enquiry/staff_policy.dart';
import '../../presentation/screens/staff/policy/policy.dart';
import '../../presentation/screens/staff/policy/policy_list.dart';
import '../../presentation/screens/staff/quotations/quotation.dart';
@ -176,6 +177,11 @@ final GoRouter appRouter = GoRouter(
builder: (context, state) => const PolicyScreen(),
),
GoRoute(
path: AppRoutes.policyStaffEnq,
builder: (context, state) => PolicyStaffEnqList(),
),
GoRoute(
path: AppRoutes.enquiryForStaff,
builder: (context, state) => const EnquiryListStaffInline(),

View File

@ -21,6 +21,7 @@ class AppRoutes {
static const String policylist = '/policylist';
static const String quotation = '/QuotationScreen';
static const String policy = '/PolicyScreen';
static const String policyStaffEnq = '/policyStaffEnq';
static const String payout = '/payout';
static const String invoiceList = '/invoiceList';

View File

@ -576,6 +576,8 @@ class ApiService {
Future<Map<String, dynamic>> fetchStaffUserList(int managerId, role) async {
// print(_token);
print('rolemanagerId - $managerId');
if (_token == null) {
await _initializeToken();
}
@ -587,6 +589,7 @@ class ApiService {
dynamic url;
if (role == 'manager') {
print('manager');
// url = Uri.parse('${Env.apiUrl}staff/staffList');
url = Uri.parse('${Env.apiUrl}staff/staffList?manager_id=${managerId}');
} else {
print('handler');
@ -770,6 +773,22 @@ class ApiService {
return response;
}
Future<Map<String, dynamic>> updateEnquiryInProgress(id) async {
// print(_token);
if (_token == null) {
await _initializeToken();
}
final url = Uri.parse(
'${Env.apiUrl}enquiry/updateEnquiryInProgress?enquiry_id=$id',
);
final headers = {
'Authorization': 'Bearer $_token' ?? '',
'app-signature': Env.App_Signature,
};
final response = await _makeGetRequest(url, headers);
return response;
}
Future<Map<String, dynamic>> findEnqQuotePolicyView(id) async {
print('findEnqQuotePolicyVie2w - $id');
if (_token == null) {

View File

@ -384,11 +384,11 @@ class _AppHeaderState extends ConsumerState<AppHeader> {
onPressed: () {
SideDrawerPanel.show(
context: context,
title: 'Proposal Creation',
title: 'Quote Creation',
child: CreateProposal_Quick(),
);
},
tooltip: 'Create Proposal',
tooltip: 'Quick Quote',
),
),

View File

@ -135,7 +135,12 @@ class MainLayoutState extends ConsumerState<MainLayout> {
// debugPrint("Notifications tapped");
// },
// ),
appBar: AppHeader(),
// appBar: AppHeader(),
appBar: PreferredSize(
preferredSize: AppHeader().preferredSize,
child: ExcludeFocus(child: AppHeader()),
),
body: Row(
children: [
// AnimatedContainer(

View File

@ -97,6 +97,8 @@ class CreateProposal_QuickFormState
List<String> tabHeader = ['idv', 'premium_Amount', 'insurer', 'regNo'];
late FocusNode partnerFocusNode;
List<QuotationRow> rows = [];
List<Map<String, dynamic>> getBrokerData = [];
@ -125,6 +127,8 @@ class CreateProposal_QuickFormState
dynamic userId;
dynamic managerId;
bool isSingleSave = false;
List<Map<String, dynamic>> quotationList = [];
Map<String, dynamic> quotationData() {
@ -153,7 +157,8 @@ class CreateProposal_QuickFormState
// "vehicle_type_id": selectedVehicleType,
"is_quick_quote": "1",
"quotation": quotationList,
// "quotation": quotationList,
"quotation": jsonEncode(quotationList),
// "is_data_created_by_handler": roleId == 'handler' ? '1' : '0',
// "is_data_created_by_manager": roleId == 'manager' ? '1' : '0',
"is_data_created_by_staff": roleId != null ? '1' : '0',
@ -163,6 +168,7 @@ class CreateProposal_QuickFormState
// "previous_policy_file_name": "previous_policy.pdf",
"remarks": controllers["remarks"]?.text,
// "assigned_to": (roleId == 'staff') ? userId : selectedStaff,
"assigned_to": userId,
"insurer_id": selectedInsurer,
"broker_id": selectedBroker,
"manager_id": managerId,
@ -179,6 +185,7 @@ class CreateProposal_QuickFormState
for (String field in tabHeader) {
controllers[field] = TextEditingController();
}
partnerFocusNode = FocusNode();
Future.microtask(() async {
roleId = ref.read(userRoleProvider);
@ -212,6 +219,7 @@ class CreateProposal_QuickFormState
// Dispose all TextEditingControllers
for (var controller in controllers.values) {
controller.dispose();
partnerFocusNode.dispose();
}
super.dispose();
}
@ -495,6 +503,10 @@ class CreateProposal_QuickFormState
dropDownKeyInsurerEnqAsgn.currentState?.changeSelectedItem(null);
dropDownKey.currentState?.changeSelectedItem(null);
});
if (isSingleSave) {
handleDone();
}
}
}
@ -533,6 +545,14 @@ class CreateProposal_QuickFormState
dataDetails();
final dataSet = dataDetails();
print("dataSetAgent - $dataSet");
if (quotationList.isEmpty) {
print("Please add at least one quotation before saving.");
// You can also show a snackbar or dialog
ToastHelper.showErrorToast(context, 'Add atleast one proposal');
return; // stop execution
}
// print("managerId - $managerId ,userId - $userId ");
createUserData(dataSet);
} else {
@ -567,11 +587,23 @@ class CreateProposal_QuickFormState
print("USerDAta - $userData");
// userData.forEach((key, value) {
// // if (key != 'certificate_file_name') {
// request.fields[key] = value.toString();
// print("✅ Encoded $key: ${request.fields[key]}");
// // }
// });
userData.forEach((key, value) {
// if (key != 'certificate_file_name') {
request.fields[key] = value.toString();
print("✅ Encoded $key: ${request.fields[key]}");
// }
if (value is List || value is Map) {
// List, Map convert to JSON
request.fields[key] = jsonEncode(value);
} else {
// normal value
request.fields[key] = value?.toString() ?? "";
}
print("$key: ${request.fields[key]}");
});
if (docUploadedFile != null) {
@ -612,7 +644,8 @@ class CreateProposal_QuickFormState
print("Response: ${response.body}");
// ToastHelper.showErrorToast(context, 'Proposal Created');
reset();
Navigator.of(context).pop();
getQuickQuotationList(managerId);
// Navigator.of(context).pop();
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else {
@ -628,10 +661,70 @@ class CreateProposal_QuickFormState
}
}
Future<void> handleProceed(val, id) async {
print('handleProceed -1 ');
final String apiUrldata;
apiUrldata = '${Env.apiUrl}quotation/acceptOrRejectQuotation';
// final token = await getToken(); // Fetch token
print('handleProceed -2 ');
if (_token == null) {
throw Exception('Token not found. Please log in.');
}
final Map<String, dynamic> data = {
"id": id,
// "status": 'Accepted',
"status": val,
"action_by": userId,
// "action_user": (role == 'agent') ? 'agent' : 'handler',
"action_user": roleId,
};
print('handleProceed -3 ');
// data['id'] = selectedId; // Add plan_id for update
// data['status'] = val;
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), // Convert map to JSON
);
if (response.statusCode == 200) {
print("Response: ${response.body}");
ToastHelper.showSuccessToast(context, 'Status Updated');
print("tre1");
selectedId = null; // just update field
Navigator.of(context).pop();
context.go('/enquiryForStaff');
print("tre11");
getQuickQuotationList(managerId);
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else {
final responseBody = jsonDecode(response.body);
dynamic msg = responseBody['data'];
ToastHelper.showErrorToast(context, 'Status Updation Failed');
print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}");
}
} catch (e) {
print(" Error submitting Staff: $e");
}
}
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
return FocusTraversalGroup(
child: Column(
children: [
Container(
@ -651,6 +744,8 @@ class CreateProposal_QuickFormState
),
borderRadius: BorderRadius.circular(8.0),
),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -661,6 +756,7 @@ class CreateProposal_QuickFormState
buildVehicleNumber(context),
],
),
Divider(thickness: 0.3, color: Colors.blueGrey.shade100),
SizedBox(height: 2),
Row(
@ -674,14 +770,66 @@ class CreateProposal_QuickFormState
const SizedBox(width: 10),
Row(
children: [
// SizedBox(width: 10),
// GestureDetector(
// onTap: () {
// setState(() {
// isSingleSave = true;
// });
// addQuotationRow();
// },
// child: Container(
// padding: const EdgeInsets.symmetric(
// horizontal: 5,
// vertical: 5,
// ),
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(5.0),
// color: Colors.blue,
// ),
// child: Text(
// 'Save',
// style: GoogleFonts.poppins(
// color: Colors.white,
// fontSize: 10,
// ),
// ),
// ),
// ),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 4,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
onPressed: () {
setState(() {
isSingleSave = true;
});
addQuotationRow();
},
child: Text(
'Save',
style: GoogleFonts.poppins(
color: Colors.white,
fontSize: 10,
),
),
),
SizedBox(width: 10),
GestureDetector(
onTap: () {
addQuotationRow();
},
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 2,
vertical: 2,
horizontal: 5,
vertical: 5,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
@ -703,7 +851,7 @@ class CreateProposal_QuickFormState
const SizedBox(height: 10),
Text(
'Added Proposal (${quotationList.length})',
'Added Quote(${quotationList.length})',
style: GoogleFonts.poppins(
fontSize: 12,
color: Color(0xFF334155),
@ -813,26 +961,24 @@ class CreateProposal_QuickFormState
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: () {
handleDone();
},
child: Container(
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF2E7D6E),
padding: const EdgeInsets.symmetric(
horizontal: 5,
vertical: 5,
horizontal: 18,
vertical: 12,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.0),
color: const Color(0xFF2E7D6E),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
),
onPressed: handleDone,
child: Text(
'Save',
'Save All Quotes',
style: GoogleFonts.poppins(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.w400,
),
fontSize: 13,
fontWeight: FontWeight.w500,
),
),
),
@ -841,6 +987,7 @@ class CreateProposal_QuickFormState
],
),
),
),
SizedBox(height: 10),
Container(
@ -864,14 +1011,61 @@ class CreateProposal_QuickFormState
dividerThickness: 0.3,
columnSpacing: 10,
columns: [
DataColumn(label: Text("Agent Name", style: _tableHeaderStyle)),
DataColumn(label: Text("Reg No", style: _tableHeaderStyle)),
DataColumn(label: Text("Partner", style: _tableHeaderStyle)),
DataColumn(
label: Text("Vehicle Number", style: _tableHeaderStyle),
),
DataColumn(label: Text("Insurer", style: _tableHeaderStyle)),
DataColumn(label: Text("Plan Type", style: _tableHeaderStyle)),
DataColumn(label: Text("Premium", style: _tableHeaderStyle)),
DataColumn(label: Text("Action", style: _tableHeaderStyle)),
],
rows: filteredCreatedProposalData.expand((item) {
List quotationList = item["quotation_data"] ?? [];
rows: filteredCreatedProposalData.map((item) {
if (quotationList.isEmpty) {
// If no quotation, show single empty row
return [
DataRow(
cells: [
DataCell(
Text(
item["agent_name"] ?? "-",
style: _tableDataStyle,
),
),
DataCell(
Text(item["reg_no"] ?? "-", style: _tableDataStyle),
),
DataCell(Text("-", style: _tableDataStyle)),
DataCell(Text("-", style: _tableDataStyle)),
DataCell(Text("-", style: _tableDataStyle)),
DataCell(
ElevatedButton(
onPressed: () {
print('handleProceed - Accepted');
// Navigator.pop(context);
Navigator.of(context).pop();
context.go('/enquiryForStaff');
// handleProceed('Accepted');
},
child: Text(
'PROCEED',
style: GoogleFonts.poppins(
fontSize: 10,
fontWeight: FontWeight.w500,
),
),
),
),
],
),
];
}
// Multiple quotations return multiple DataRow
return quotationList.map<DataRow>((quote) {
return DataRow(
cells: [
DataCell(
@ -882,19 +1076,28 @@ class CreateProposal_QuickFormState
),
DataCell(
Text(
item["insurer_short_name"] ?? "-",
quote["insurer_short_name"] ?? "-",
style: _tableDataStyle,
),
),
DataCell(
Text(
item["premium_amount"]?.toString() ?? "-",
quote["insurance_plan_type"] ?? "-",
style: _tableDataStyle,
),
),
DataCell(
TextButton(
onPressed: () {},
Text(
"${quote["premium_amount"]}",
style: _tableDataStyle,
),
),
DataCell(
ElevatedButton(
onPressed: () {
print('handleProceed - Accepted');
handleProceed('Accepted', quote['id']);
},
child: Text(
'PROCEED',
style: GoogleFonts.poppins(
@ -906,6 +1109,7 @@ class CreateProposal_QuickFormState
),
],
);
}).toList();
}).toList(),
),
),
@ -1139,7 +1343,8 @@ class CreateProposal_QuickFormState
highlightColor: Color(0xFF50A398),
padVertical: 10,
isdense: true,
errFieldHgt: 0.0,
errFieldFont: 0.0,
inputFormatters: [
UpperCaseTextFormatter(), // 👈 custom formatter for uppercase
FilteringTextInputFormatter.allow(RegExp(r'[A-Za-z0-9- ]')),
@ -1183,12 +1388,12 @@ class CreateProposal_QuickFormState
itemAsString: (val) => val['short_name'].toString(), // what to show
compareFn: (item, selectedItem) =>
item['id'] == selectedItem['id'], // compare by id
validator: (val) {
if (val == null) {
return "Required"; // error message
}
return null;
},
// validator: (val) {
// if (val == null) {
// return "Required"; // error message
// }
// return null;
// },
suffixProps: DropdownSuffixProps(
// make sure the dropdown button is visible
dropdownButtonProps: DropdownButtonProps(
@ -1330,8 +1535,8 @@ class CreateProposal_QuickFormState
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')),
],
validator: (value) =>
Validators.doubleNumber(value, "PremiumAmount"),
// validator: (value) =>
// Validators.doubleNumber(value, "PremiumAmount"),
// validator: (value) => Validators.number(value, "PremiumAmount "),
txtwidth: ResponsiveLayout.isMobile(context)
? null
@ -1360,8 +1565,24 @@ class CreateProposal_QuickFormState
? null
: MediaQuery.of(context).size.width * 0.12,
height: 30,
child: FocusableActionDetector(
focusNode: partnerFocusNode,
autofocus: false,
onShowFocusHighlight: (hasFocus) {
setState(() {
focusedBorder:
OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(
color: Color(0xFF50A398),
width: 2,
),
);
}); // redraw to show highlight border
},
child: DropdownSearch<Map<String, dynamic>>(
key: dropDownKey,
// focusNode: partnerFocusNode,
selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null,
// items: (filter, infiniteScrollProps) {
// return filteredInsuranceData;
@ -1376,16 +1597,30 @@ class CreateProposal_QuickFormState
);
}).toList();
},
suffixProps: DropdownSuffixProps(
// make sure the dropdown button is visible
dropdownButtonProps: DropdownButtonProps(
isVisible: true,
padding: EdgeInsets.zero, // remove default padding
constraints: const BoxConstraints(
// shrink icon tap area
minWidth: 12,
minHeight: 12,
),
iconSize: 15, // smaller icon
// icon: const Icon(Icons.arrow_drop_down),
),
),
itemAsString: (val) => val['insurance_plan_type'].toString(),
compareFn: (item, selectedItem) =>
item['id'] == selectedItem['id'], // compare by id
validator: (val) {
if (val == null) {
return "Required"; // error message
}
return null;
},
// validator: (val) {
// if (val == null) {
// return "Required"; // error message
// }
// return null;
// },
decoratorProps: DropDownDecoratorProps(
decoration:
AppInputDecorations.dropdownDecoration(
@ -1458,7 +1693,10 @@ class CreateProposal_QuickFormState
),
child: Text(
item['insurance_plan_type'].toString(),
style: GoogleFonts.inter(fontSize: 12, color: Colors.black),
style: GoogleFonts.inter(
fontSize: 12,
color: Colors.black,
),
),
);
},
@ -1494,6 +1732,7 @@ class CreateProposal_QuickFormState
},
),
),
),
],
);
}

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,7 @@ import 'package:intl/intl.dart';
import 'package:nhance_partner/presentation/screens/dashboard/dashboard.dart';
import 'package:nhance_partner/presentation/screens/staff/Enquiry/quotationPopUpAccptReject.dart';
import 'package:nhance_partner/presentation/screens/staff/Enquiry/raise_enq_form.dart';
import 'package:nhance_partner/presentation/screens/staff/Enquiry/staff_policy.dart';
import 'package:nhance_partner/presentation/screens/staff/Enquiry/tabs/tab.dart';
import 'package:nhance_partner/presentation/themes/indicators/customizd_multi_file_upload.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -134,6 +135,10 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
String? selectedId;
int selectedIndex = 0;
final List<String> enquiryTabs = ["In Progress", "Completed"];
Map<String, dynamic> dataDetails() {
final data = {
"agent_id":
@ -211,7 +216,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
super.initState();
apiService = ApiService();
timer = Timer.periodic(Duration(seconds: 3), (Timer t) => callRefresh());
timer = Timer.periodic(Duration(seconds: 10), (Timer t) => callRefresh());
for (String field in tabHeader) {
controllers[field] = TextEditingController();
}
@ -2420,77 +2425,77 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
buildPhNumber(context),
buildRemarks(context),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Builder(
builder: (buttonContext) => Material(
// color: Color(0xFFFFFCF2),
color: Color(0xFFF8F9FF),
child: InkWell(
hoverColor: Color(0xFFF8F9FF),
// hoverColor: const Color(0xFFFFFCF2),
// hoverColor: const Color(0xFFEAF6F4),
onTap: () async {
// Get overlay and button position RELATIVE to InkWell
final RenderBox button =
buttonContext.findRenderObject() as RenderBox;
final RenderBox overlay =
Overlay.of(buttonContext).context.findRenderObject()
as RenderBox;
final Offset position = button.localToGlobal(
Offset.zero,
ancestor: overlay,
);
await showMenu(
context: buttonContext,
position: RelativeRect.fromLTRB(
position.dx,
position.dy + button.size.height,
overlay.size.width,
0,
),
items: [
PopupMenuItem(
child: Column(
mainAxisSize: MainAxisSize.min,
children: _buildPopupDownload(
buttonContext,
selectId,
),
),
),
],
// Padding(
// padding: const EdgeInsets.only(top: 8.0),
// child: Builder(
// builder: (buttonContext) => Material(
// // color: Color(0xFFFFFCF2),
// color: Color(0xFFF8F9FF),
// child: InkWell(
// hoverColor: Color(0xFFF8F9FF),
// // hoverColor: const Color(0xFFFFFCF2),
// // hoverColor: const Color(0xFFEAF6F4),
// onTap: () async {
// // Get overlay and button position RELATIVE to InkWell
// final RenderBox button =
// buttonContext.findRenderObject() as RenderBox;
// final RenderBox overlay =
// Overlay.of(buttonContext).context.findRenderObject()
// as RenderBox;
//
// final Offset position = button.localToGlobal(
// Offset.zero,
// ancestor: overlay,
// );
//
// await showMenu(
// context: buttonContext,
// position: RelativeRect.fromLTRB(
// position.dx,
// position.dy + button.size.height,
// overlay.size.width,
// 0,
// ),
// items: [
// PopupMenuItem(
// child: Column(
// mainAxisSize: MainAxisSize.min,
// children: _buildPopupDownload(
// buttonContext,
// selectId,
// ),
// ),
// ),
// ],
// // color: Colors.white,
// // color: Color(0xFFFFFCF2),
// color: Color(0xFFF8F9FF),
// );
// },
// child: Tooltip(
// message: 'Click To Upload Documents',
//
// waitDuration: const Duration(milliseconds: 500),
// showDuration: const Duration(seconds: 2),
// child: Container(
// padding: EdgeInsets.all(8.0),
// decoration: BoxDecoration(
// color: Colors.white,
// color: Color(0xFFFFFCF2),
color: Color(0xFFF8F9FF),
);
},
child: Tooltip(
message: 'Click To Upload Documents',
waitDuration: const Duration(milliseconds: 500),
showDuration: const Duration(seconds: 2),
child: Container(
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(50),
),
child: Icon(
Icons.upload_file,
color: Color(0XFF6366F1),
// editing ? Icons.upload_file : Icons.download_for_offline,
// color: editing ? Colors.b lue : Colors.green,
size: 20,
),
),
),
),
),
),
),
// borderRadius: BorderRadius.circular(50),
// ),
// child: Icon(
// Icons.upload_file,
// color: Color(0XFF6366F1),
// // editing ? Icons.upload_file : Icons.download_for_offline,
// // color: editing ? Colors.b lue : Colors.green,
// size: 20,
// ),
// ),
// ),
// ),
// ),
// ),
// ),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: IconButton(
@ -2863,12 +2868,15 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
// ],
// ),
width: MediaQuery.of(context).size.width,
// height: MediaQuery.of(context).size.height * 0.1,
// padding: EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
RaiseEnqForm(
Container(
// height: MediaQuery.of(context).size.height*0.
child: RaiseEnqForm(
key: raiseEnqKey,
onSubmit: (dataSet) async {
print('Check checking dataSet $dataSet');
@ -2894,6 +2902,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
}
},
),
),
// SizedBox(height: 5),
ResponsiveLayout.isMobile(context)
@ -2920,29 +2929,29 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
),
// ),
Container(
// height: 20,
width: MediaQuery.of(context).size.width,
// color: Colors.green.shade50,
child: PaginationControls(
currentPage: currentPage,
itemsPerPage: itemsPerPage,
// totalItems: dataVal.length,
totalItems: filteredData.length,
// activeColor: layoutColor, // your theme color
onPageChanged: (page) {
setState(() {
currentPage = page;
});
},
onItemsPerPageChanged: (items) {
setState(() {
itemsPerPage = items;
currentPage = 1;
});
},
),
),
// Container(
// // height: 20,
// width: MediaQuery.of(context).size.width,
// // color: Colors.green.shade50,
// child: PaginationControls(
// currentPage: currentPage,
// itemsPerPage: itemsPerPage,
// // totalItems: dataVal.length,
// totalItems: filteredData.length,
// // activeColor: layoutColor, // your theme color
// onPageChanged: (page) {
// setState(() {
// currentPage = page;
// });
// },
// onItemsPerPageChanged: (items) {
// setState(() {
// itemsPerPage = items;
// currentPage = 1;
// });
// },
// ),
// ),
],
),
),
@ -2971,6 +2980,37 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
refrshfilterDateRange();
}
Future<void> buildPolicyCreatedStatusActions(
BuildContext context,
status,
id,
) async {
print("Actionsstatus - $status -$id");
dynamic val;
if (status == 'Awaiting Proposal' || status == 'Proposal Created') {
val = '';
} else {
val = 'Policy';
}
final result = await showDialog(
context: context,
barrierDismissible:
false, // optional - prevents closing by tapping outside
builder: (context) => PolicyStaffEnqList(),
);
// Code here runs *after* the dialog is closed
print("Dialog closed");
print("Dialog result: $result");
if (result) {
setState(() {
isActionable = false;
});
refrshfilterDateRange();
}
}
Widget _buildContent(BuildContext context) {
final isDesktop = !ResponsiveLayout.isMobile(context);
return Column(
@ -3076,8 +3116,8 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
),
),
SizedBox(height: 5),
// SizedBox(height: 5),
SizedBox(child: _buildStyledTabs()),
ResponsiveLayout.isMobile(context)
? _buildDataTable(context)
:
@ -3095,59 +3135,135 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
// 1. Add group expansion state tracking
Map<String, bool> groupExpanded = {
'Awaiting Proposal': true,
'Proposal Created': true,
// 'Awaiting Proposal': true,
// 'Proposal Created': true,
// 'Proposal Accepted': true,
// 'Proposal Rejected': true,
'Policy Created': true,
// 'Awaiting Payment': true,
// 'Policy Created': true,
'To be assigned': true,
'Assigned': true,
'In progress': true,
};
Map<String, String> statusGroupMap = {
'Awaiting Proposal': 'Awaiting Proposal',
'Proposal Created': 'Proposal Created',
'Proposal Accepted': 'Proposal Created',
'Proposal Rejected': 'Proposal Created',
'Policy Created': 'Policy Created',
// 'Awaiting Proposal': 'Awaiting Proposal',
// 'Proposal Created': 'Proposal Created',
// 'Proposal Accepted': 'Proposal Created',
// 'Proposal Rejected': 'Proposal Created',
// 'Proposal Created': 'Awaiting Payment',
// 'Proposal Accepted': 'Awaiting Payment',
// 'Proposal Rejected': 'Awaiting Payment',
// 'Policy Created': 'Policy Created',
// 'Policy Created': 'Policy Created',
'To be assigned': 'To be assigned',
'Assigned': 'Assigned',
'In progress': 'In progress',
};
List<Map<String, dynamic>> get filteredDataByTab {
if (selectedIndex == 0) {
// Progress enquiries
final sortedData = [...filteredData]
..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
if (sortedData.isEmpty) return [];
return sortedData.where((e) {
return [
"To be assigned",
"Assigned",
"In progress",
].contains(e['enquiry_status']);
}).toList();
} else {
final sortedData = [...filteredData]
..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
if (sortedData.isEmpty) return [];
// Completed enquiries
return sortedData.where((e) {
return e['enquiry_status'] == "Completed";
}).toList();
}
}
// Add group enquiries by status
Map<String, List<Map<String, dynamic>>> get _groupedEnquiries {
final grouped = <String, List<Map<String, dynamic>>>{};
final Map<String, List<Map<String, dynamic>>> grouped = {};
// Initialize all status groups
grouped['Awaiting Proposal'] = [];
grouped['Proposal Created'] = [];
grouped['Proposal Accepted'] = [];
grouped['Proposal Rejected'] = [];
grouped['Policy Created'] = [];
if (selectedIndex == 0) {
grouped["To be assigned"] = [];
grouped["Assigned"] = [];
grouped["In progress"] = [];
} else {
grouped["Completed"] = [];
}
// Initialize only the groups you need
grouped['Awaiting Proposal'] = [];
grouped['Proposal Created'] = [];
grouped['Policy Created'] = [];
// Group the filtered/paginated data by status
// for (var item in _paginatedData) {
// final status = item['status']?.toString() ?? 'Unknown';
// if (grouped.containsKey(status)) {
// grouped[status]!.add(item);
// }
// }
for (var item in _paginatedData) {
final status = item['status']?.toString() ?? 'Unknown';
// Map actual status to grouped status
final groupKey = statusGroupMap[status];
if (groupKey != null) {
grouped[groupKey]!.add(item);
for (var item in filteredDataByTab) {
final status = (item['enquiry_status'] ?? '').toString();
if (grouped.containsKey(status)) {
grouped[status]!.add(item);
}
}
return grouped;
}
// Map<String, List<Map<String, dynamic>>> get _groupedEnquiries {
// final grouped = <String, List<Map<String, dynamic>>>{};
//
// // Initialize all status groups
// // grouped['Awaiting Proposal'] = [];
// // grouped['Proposal Created'] = [];
// // grouped['Proposal Accepted'] = [];
// // grouped['Proposal Rejected'] = [];
// // grouped['Policy Created'] = [];
// // grouped['Awaiting Payment'] = [];
//
// // Initialize only the groups you need
// // grouped['Awaiting Proposal'] = [];
// // grouped['Proposal Created'] = [];
// // grouped['Policy Created'] = [];
//
// grouped['To be assigned'] = [];
// grouped['Assigned'] = [];
// grouped['In progress'] = [];
//
// // Group the filtered/paginated data by status
// // for (var item in _paginatedData) {
// // final status = item['status']?.toString() ?? 'Unknown';
// // if (grouped.containsKey(status)) {
// // grouped[status]!.add(item);
// // }
// // }
//
// for (var item in filteredData) {
// // final status = item['status']?.toString() ?? 'Unknown';
// final status = item['enquiry_status']?.toString() ?? 'Unknown';
//
// // Map actual status to grouped status
// final groupKey = statusGroupMap[status];
//
// if (groupKey != null) {
// grouped[groupKey]!.add(item);
// }
// }
//
// // for (var item in _paginatedData) {
// // // final status = item['status']?.toString() ?? 'Unknown';
// // final status = item['enquiry_status']?.toString() ?? 'Unknown';
// //
// // // Map actual status to grouped status
// // final groupKey = statusGroupMap[status];
// //
// // if (groupKey != null) {
// // grouped[groupKey]!.add(item);
// // }
// // }
//
// return grouped;
// }
Map<String, dynamic> _getStatusConfig(String status) {
switch (status) {
case 'Awaiting Proposal':
@ -3170,7 +3286,12 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
'Proposal Created': const Color(0xFFF0F9FF), // Cyan 50
'Proposal Accepted': const Color(0xFFF0FDF4), // Green 50
'Proposal Rejected': const Color(0xFFFEF9C3), // Yellow 50
'Policy Created': const Color(0xFFF3F0FF), // Purple 50 (generated)
'Policy Created': const Color(0xFFF3F0FF),
'To be assigned': const Color(0xFFEFF6FF), // Blue 50
'Assigned': const Color(0xFFFEF9C3), // Cyan 50
'In progress': const Color(0xFFF0FDF4), // Green 50
'Completed': const Color(0xFFF3F0FF), // Purple 50 (generated)
};
final Map<String, Color> statusBorderColors = {
@ -3179,6 +3300,11 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
'Proposal Accepted': const Color(0xFFDCFCE7), // Green 100
'Proposal Rejected': const Color(0xFFFEF3C7), // Yellow 100
'Policy Created': const Color(0xFFF0E4FF), // Purple 200
'To be assigned': const Color(0xFFDBEAFE), // Blue 100
'Assigned': const Color(0xFFFEF3C7), // Cyan 100
'In progress': const Color(0xFFDCFCE7), // Green 100
'Completed': const Color(0xFFF0E4FF), // Purple 200
// 'Policy Created': const Color(0xFFE5CCFF), // Purple 200
};
@ -3202,7 +3328,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
});
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 4),
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2),
child: Row(
children: [
Icon(
@ -3348,6 +3474,8 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
mainAxisSize: MainAxisSize.min,
children: [
// Group Header
// if (status != 'Proposal Accepted' &&
// status != 'Proposal Rejected') ...[
if (status != 'Proposal Accepted' &&
status != 'Proposal Rejected') ...[
Container(
@ -3487,7 +3615,8 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
final editing = isEditingRow[id] ?? false;
final controllers = rowControllers[id];
String status = item['status'] ?? '-';
// String status = item['status'] ?? '-';
String status = item['enquiry_status'] ?? '-';
Color bgColor = statusColors[status] ?? Color(0xFFF9FAFB);
Color borderColor = statusBorderColors[status] ?? Color(0xFFE2E8F0);
@ -3774,6 +3903,91 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
),
),
DataCell(
SizedBox(
width: 120,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (item['enquiry_status'] != 'Assigned') ...[
Material(
color: Colors.white,
child: InkWell(
// hoverColor: Color(0xFFEAF6F4),
onTap: null,
// onTap: () async {
// setState(() {
// isActionable = true;
// });
// buildPolicyCreatedStatusActions(
// context,
// item['status'],
// item['id'],
// );
// },
child: Tooltip(
message: 'Click to View or Process Enquiry', //
waitDuration: const Duration(
milliseconds: 500,
), // optional
showDuration: const Duration(seconds: 2), // optional
child: Container(
padding: EdgeInsets.symmetric(vertical: 2.0),
margin: EdgeInsets.symmetric(vertical: 2),
decoration: BoxDecoration(
// color: Color(0xFFF9FAFB),
// border: Border.all(color: Color(0xFFE2E8F0)),
color: bgColor,
border: Border.all(color: borderColor),
borderRadius: BorderRadius.circular(5),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
item['enquiry_status'] ?? '-',
// item['status'] ?? '-',
style: GoogleFonts.inter(
fontSize: 10,
color: Color(0XFF1e293b),
// color: statusTextColors[status] ?? Colors.black,
fontWeight: FontWeight.w500,
),
// overflow: TextOverflow.clip, //
),
],
),
),
),
// child: Text(item['status'] ?? '-', style: _dataBold),
),
),
],
if (item['enquiry_status'] == 'Assigned') ...[
TextButton(
onPressed: () async {
final res = await apiService.updateEnquiryInProgress(id);
if (res['status'] == 'success') {
refrshfilterDateRange();
}
print('updateEnquiryInProgress - $res');
},
child: Text(
'PROCEED',
style: GoogleFonts.poppins(
fontSize: 11,
fontWeight: FontWeight.w500,
color: Colors.green,
),
),
),
],
],
),
),
),
// Assigned Date (formatted)
// DataCell(
// SizedBox(
@ -4285,65 +4499,65 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
),
),
DataCell(
SizedBox(
width: 120,
child: Material(
color: Colors.white,
child: InkWell(
// hoverColor: Color(0xFFEAF6F4),
onTap: () async {
var status = item['status'];
var enqId = item['id'];
final prefs = await SharedPreferences.getInstance();
// Remove old value (if any)
await prefs.remove('enqStaffDataId');
// Save the new id
await prefs.setString('enqStaffDataId', enqId.toString());
ref.read(quotationStaffIdProvider.notifier).state = enqId;
buildStatusActions(context, status, enqId);
},
child: Tooltip(
message: 'Click to View or Process Enquiry', //
waitDuration: const Duration(milliseconds: 500), // optional
showDuration: const Duration(seconds: 2), // optional
child: Container(
padding: EdgeInsets.symmetric(vertical: 2.0),
margin: EdgeInsets.symmetric(vertical: 2),
decoration: BoxDecoration(
// color: Color(0xFFF9FAFB),
// border: Border.all(color: Color(0xFFE2E8F0)),
color: bgColor,
border: Border.all(color: borderColor),
borderRadius: BorderRadius.circular(5),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
item['status'] ?? '-',
style: GoogleFonts.inter(
fontSize: 10,
color: Color(0XFF1e293b),
// color: statusTextColors[status] ?? Colors.black,
fontWeight: FontWeight.w500,
),
// overflow: TextOverflow.clip, //
),
],
),
),
),
// child: Text(item['status'] ?? '-', style: _dataBold),
),
),
),
),
// DataCell(
// SizedBox(
// width: 120,
//
// child: Material(
// color: Colors.white,
// child: InkWell(
// // hoverColor: Color(0xFFEAF6F4),
// onTap: () async {
// var status = item['status'];
// var enqId = item['id'];
//
// final prefs = await SharedPreferences.getInstance();
//
// // Remove old value (if any)
// await prefs.remove('enqStaffDataId');
//
// // Save the new id
// await prefs.setString('enqStaffDataId', enqId.toString());
// ref.read(quotationStaffIdProvider.notifier).state = enqId;
// buildStatusActions(context, status, enqId);
// },
// child: Tooltip(
// message: 'Click to View or Process Enquiry', //
// waitDuration: const Duration(milliseconds: 500), // optional
// showDuration: const Duration(seconds: 2), // optional
// child: Container(
// padding: EdgeInsets.symmetric(vertical: 2.0),
// margin: EdgeInsets.symmetric(vertical: 2),
// decoration: BoxDecoration(
// // color: Color(0xFFF9FAFB),
// // border: Border.all(color: Color(0xFFE2E8F0)),
// color: bgColor,
// border: Border.all(color: borderColor),
// borderRadius: BorderRadius.circular(5),
// ),
//
// child: Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Text(
// item['status'] ?? '-',
// style: GoogleFonts.inter(
// fontSize: 10,
// color: Color(0XFF1e293b),
// // color: statusTextColors[status] ?? Colors.black,
// fontWeight: FontWeight.w500,
// ),
// // overflow: TextOverflow.clip, //
// ),
// ],
// ),
// ),
// ),
// // child: Text(item['status'] ?? '-', style: _dataBold),
// ),
// ),
// ),
// ),
],
);
}
@ -4360,12 +4574,12 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
DataColumn(label: Text('Insured Name *', style: _headerStyle)),
DataColumn(label: Text('Vehicle No *', style: _headerStyle)),
DataColumn(label: Text('Action', style: _headerStyle)),
DataColumn(label: Text('Status', style: _headerStyle)),
// const DataColumn(label: Text('Assigned Date', style: _headerStyle)),
// DataColumn(label: Text('Premium', style: _headerStyle)),
DataColumn(label: Text('Payment Mode', style: _headerStyle)),
DataColumn(label: Text('Plan Type', style: _headerStyle)),
DataColumn(label: Text('Policy Number', style: _headerStyle)),
DataColumn(label: Text('Status', style: _headerStyle)),
DataColumn(label: Text('Policy', style: _headerStyle)),
];
}
@ -4383,14 +4597,14 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
_buildHeaderCell('Insurer *', 90),
_buildHeaderCell('Insured Name *', 110),
_buildHeaderCell('Vehicle No *', 90),
_buildHeaderCell('Action', 80),
_buildHeaderCell('Action', 110),
_buildHeaderCell('Status', 100),
// _buildHeaderCell('Assigned Date', 100),
// _buildHeaderCell('Premium', 100),
_buildHeaderCell('Payment Mode', 130),
_buildHeaderCell('Plan Type', 130),
_buildHeaderCell('Policy Number', 120),
_buildHeaderCell('Status', 100),
_buildHeaderCell('Policy', 120),
],
),
);
@ -4452,6 +4666,76 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
);
}
Widget _buildStyledTabs() {
return Container(
padding: const EdgeInsets.symmetric(vertical: 4),
decoration: const BoxDecoration(
color: Colors.white,
// color: Colors.amber,
// border: Border(bottom: BorderSide(color: Color(0xFFE5E5E5), width: 1)),
),
child: Row(
children: List.generate(enquiryTabs.length, (index) {
final bool isSelected = selectedIndex == index;
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () {
setState(() {
selectedIndex = index;
});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 250),
curve: Curves.easeOut,
padding: const EdgeInsets.symmetric(
vertical: 5,
horizontal: 20,
),
margin: const EdgeInsets.only(right: 24),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: isSelected
? const Color(0xFF2E7D6E).withOpacity(0.08)
: Colors.transparent,
),
child: Column(
// mainAxisSize: MainAxisSize.min,
children: [
Text(
enquiryTabs[index],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: isSelected
? const Color(0xFF2E7D6E)
: Colors.black87,
),
),
// const SizedBox(height: 3),
// Underline Indicator
AnimatedContainer(
duration: const Duration(milliseconds: 250),
height: 3,
width: isSelected ? 40 : 0,
decoration: BoxDecoration(
color: const Color(0xFF2E7D6E),
borderRadius: BorderRadius.circular(50),
),
),
],
),
),
),
);
}),
),
);
}
static final _dataBold = GoogleFonts.inter(
fontSize: 11,

View File

@ -381,6 +381,7 @@ class RaiseEnqFormState extends ConsumerState<RaiseEnqForm> {
),
],
),
child: FocusTraversalGroup(
child: Form(
key: _formKey,
child: Row(
@ -405,6 +406,7 @@ class RaiseEnqFormState extends ConsumerState<RaiseEnqForm> {
],
),
),
),
);
}

File diff suppressed because it is too large Load Diff

View File

@ -52,7 +52,7 @@ class SideDrawerPanel extends StatelessWidget {
children: [
if (title != null)
Text(
'Proposal Creation',
title!,
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w600,

View File

@ -31,6 +31,8 @@ class ThemedFormInlineField extends HookWidget {
this.onChanged,
this.isdense,
this.padVertical,
this.errFieldFont,
this.errFieldHgt,
});
final String? hintText;
@ -47,6 +49,8 @@ class ThemedFormInlineField extends HookWidget {
final Color? highlightColor;
final Color? textColr;
final double? txtwidth;
final double? errFieldFont;
final double? errFieldHgt;
final bool readOnly;
final bool? isdense;
final bool? isShowCursor;
@ -84,7 +88,16 @@ class ThemedFormInlineField extends HookWidget {
);
final inputDecoration = InputDecoration(
isDense: isdense ?? false,
errorStyle: TextStyle(color: Color(0xFFD83731)),
// errorStyle: const TextStyle(
// fontSize: 9,
//
// // height: 0.0
// ),
errorStyle: TextStyle(
color: Color(0xFFD83731),
fontSize: errFieldFont ?? 12,
height: errFieldHgt ?? 10,
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: BorderSide(