ui changes
This commit is contained in:
parent
e0ed41ad35
commit
ceb6aece50
@ -434,26 +434,43 @@ class _ApprovalListState extends State<ApprovalList> {
|
|||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontFamily: "Archivo",
|
fontFamily: "Archivo",
|
||||||
))),
|
))),
|
||||||
DataCell(Container(
|
DataCell(
|
||||||
padding: const EdgeInsets.symmetric(
|
Container(
|
||||||
vertical: 4, horizontal: 10),
|
width: double
|
||||||
decoration: BoxDecoration(
|
.infinity, // Set your desired fixed size (equal width and height)
|
||||||
color: plan.status == "Active"
|
height: 25,
|
||||||
? layoutColor
|
alignment: Alignment.center,
|
||||||
: Colors.grey.shade50,
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(10),
|
color: plan.statusValue ==
|
||||||
),
|
"Partially Approved"
|
||||||
child: Text(
|
? Colors.yellow.shade100
|
||||||
plan.statusValue,
|
: plan.statusValue == "Approved"
|
||||||
style: TextStyle(
|
? Colors.green.shade100
|
||||||
color: plan.status == "Active"
|
: plan.statusValue == "Completed"
|
||||||
? Colors.white
|
? Colors.green.shade500
|
||||||
: Colors.grey,
|
: plan.statusValue == "Rejected"
|
||||||
fontSize: 13,
|
? Colors.red.shade100
|
||||||
fontWeight: FontWeight.bold,
|
: Colors.grey.shade100,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
plan.statusValue,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: (plan.statusValue ==
|
||||||
|
"Partially Approved" ||
|
||||||
|
plan.statusValue == "Approved" ||
|
||||||
|
plan.statusValue == "Rejected")
|
||||||
|
? Colors.black
|
||||||
|
: plan.statusValue == "Completed"
|
||||||
|
? Colors.white
|
||||||
|
: Colors.grey,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)),
|
),
|
||||||
DataCell(Row(children: [
|
DataCell(Row(children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
@ -480,6 +497,17 @@ class _ApprovalListState extends State<ApprovalList> {
|
|||||||
// color: Colors.green),
|
// color: Colors.green),
|
||||||
// onPressed: () => viewPlanforApprover(plan.planId,
|
// onPressed: () => viewPlanforApprover(plan.planId,
|
||||||
// isViewMode: false) ),
|
// isViewMode: false) ),
|
||||||
|
|
||||||
|
SizedBox(
|
||||||
|
width: 5,
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => (),
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/IconsImg/delete.png',
|
||||||
|
width: 20,
|
||||||
|
height: 15),
|
||||||
|
),
|
||||||
])),
|
])),
|
||||||
]);
|
]);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
|
|||||||
@ -396,6 +396,9 @@ class _groupState extends State<Group> {
|
|||||||
child: TextField(
|
child: TextField(
|
||||||
controller: controllers["name"],
|
controller: controllers["name"],
|
||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
|
onChanged: (value) {
|
||||||
|
_clearError("name");
|
||||||
|
},
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: "group name",
|
labelText: "group name",
|
||||||
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
@ -436,6 +439,9 @@ class _groupState extends State<Group> {
|
|||||||
height: 40,
|
height: 40,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: controllers["description"],
|
controller: controllers["description"],
|
||||||
|
onChanged: (value) {
|
||||||
|
_clearError("description");
|
||||||
|
},
|
||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: "description",
|
labelText: "description",
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:frontend/Screens/group/group.dart';
|
import 'package:frontend/Screens/group/group.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:responsive_builder/responsive_builder.dart';
|
import 'package:responsive_builder/responsive_builder.dart';
|
||||||
|
|
||||||
|
import '../../config/apiUrl.dart';
|
||||||
import '../../routes/custom_appBar.dart';
|
import '../../routes/custom_appBar.dart';
|
||||||
import '../../routes/custom_drawer.dart';
|
import '../../routes/custom_drawer.dart';
|
||||||
import '../../services/apiService.dart';
|
import '../../services/apiService.dart';
|
||||||
@ -57,10 +61,59 @@ class _GroupListState extends State<GroupList> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void deleteGroup(int groupId) {
|
void handleActiveStatus(
|
||||||
setState(() {
|
Map<String, dynamic> groupData,
|
||||||
apiAllGroups?.removeWhere((group) => group['group_id'] == groupId);
|
String groupId,
|
||||||
});
|
String currentStatus,
|
||||||
|
) async {
|
||||||
|
print("Toggling user status - $groupId (Current: $currentStatus)");
|
||||||
|
|
||||||
|
final String apiUrlData =
|
||||||
|
'$apiUrl/api/groups/update/$groupId'; // API for updating user
|
||||||
|
final String? token = await getToken();
|
||||||
|
|
||||||
|
if (token == null) {
|
||||||
|
print("Error: Token not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle status: If active ("1"), set to inactive ("0"); otherwise, activate ("1")
|
||||||
|
String newStatus = (currentStatus == "1") ? "0" : "1";
|
||||||
|
|
||||||
|
print("STatus 1 - $newStatus");
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await http.put(
|
||||||
|
Uri.parse(apiUrlData),
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer $token',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: jsonEncode({
|
||||||
|
"is_active": newStatus // Set new status dynamically
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||||
|
print("User status updated successfully to $newStatus!");
|
||||||
|
loadAllGroups(); // Refresh users list after update
|
||||||
|
} else {
|
||||||
|
print("Failed to update user status. Status: ${response.statusCode}");
|
||||||
|
print("Error: ${response.body}");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("Error updating user status: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteGroup(Map<String, dynamic> groupdata, groupId, status) {
|
||||||
|
print("GroupId : $groupId");
|
||||||
|
print("Groupstatus: $status");
|
||||||
|
print("GroupsData: $groupdata");
|
||||||
|
|
||||||
|
// handleActiveStatus(groupdata, groupId, status);
|
||||||
|
print("Calling handleActiveStatus with: id=$groupId, status=$status");
|
||||||
|
handleActiveStatus(groupdata, groupId.toString(), status.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Future<void> deleteGroupFromApi(int groupId) async {
|
// Future<void> deleteGroupFromApi(int groupId) async {
|
||||||
@ -192,7 +245,8 @@ class _GroupListState extends State<GroupList> {
|
|||||||
final group = apiAllGroups![index];
|
final group = apiAllGroups![index];
|
||||||
return Card(
|
return Card(
|
||||||
// color: bodyColor,
|
// color: bodyColor,
|
||||||
color: Color(0xFFF5F5F5),
|
// color: Color(0xFFF5F5F5),
|
||||||
|
color: Colors.white,
|
||||||
margin: EdgeInsets.symmetric(vertical: 6, horizontal: 10),
|
margin: EdgeInsets.symmetric(vertical: 6, horizontal: 10),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(12.0),
|
padding: const EdgeInsets.all(12.0),
|
||||||
@ -209,13 +263,31 @@ class _GroupListState extends State<GroupList> {
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
TextButton(
|
GestureDetector(
|
||||||
onPressed: () {
|
onTap: () {
|
||||||
context.go("/CreateGroup", extra: group);
|
context.go("/CreateGroup", extra: group);
|
||||||
|
|
||||||
print("Edit ${group['group_id']} $group");
|
|
||||||
},
|
},
|
||||||
child: Text("Edit"),
|
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||||
|
width: 20, height: 15),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 5,
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
final idStr = group['group_id'];
|
||||||
|
final id = int.tryParse(idStr.toString());
|
||||||
|
|
||||||
|
if (id == null) {
|
||||||
|
print("group_id is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final status = group['is_active'];
|
||||||
|
// print("GroupId : ${group['group_id']} ");
|
||||||
|
deleteGroup(group, id, status);
|
||||||
|
},
|
||||||
|
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||||
|
width: 20, height: 15),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@ -609,12 +609,15 @@ class _MailSettingState extends State<MailSetting> {
|
|||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||||
),
|
),
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
padding: EdgeInsets.symmetric(horizontal: 18, vertical: 12),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
handleTestMailSubmit();
|
handleTestMailSubmit();
|
||||||
},
|
},
|
||||||
child: Text("Test Email"))
|
child: Text(
|
||||||
|
"Test Email",
|
||||||
|
style: TextStyle(fontSize: 12),
|
||||||
|
))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|||||||
@ -344,6 +344,41 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget buildOrganizationLayout(isDesktop) {
|
Widget buildOrganizationLayout(isDesktop) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
// color: Colors.amber,
|
||||||
|
color: bodyColor,
|
||||||
|
border: Border.all(color: Color(0xFFF7F7FB), width: 3.5)),
|
||||||
|
child: Column(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
color: bodyColor,
|
||||||
|
child: buildOrgLayout(isDesktop),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
color: Colors.white,
|
||||||
|
child: isDesktop
|
||||||
|
? Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
// children: [Text("Button")],
|
||||||
|
children:
|
||||||
|
_buildSubmit(isDesktop, isViewMode, layoutColor),
|
||||||
|
)
|
||||||
|
: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children:
|
||||||
|
_buildSubmit(isDesktop, isViewMode, layoutColor),
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildOrgLayout(bool isDesktop) {
|
||||||
Future<void> _pickImage() async {
|
Future<void> _pickImage() async {
|
||||||
final picker = ImagePicker();
|
final picker = ImagePicker();
|
||||||
final XFile? pickedFile =
|
final XFile? pickedFile =
|
||||||
@ -365,317 +400,297 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
|
margin: isDesktop
|
||||||
|
? EdgeInsets.all(10.0)
|
||||||
|
: EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
|
||||||
|
height: isDesktop
|
||||||
|
? MediaQuery.of(context).size.height * 0.98
|
||||||
|
: MediaQuery.of(context).size.height,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
// color: Colors.amber,
|
border: isDesktop
|
||||||
color: bodyColor,
|
? Border.all(
|
||||||
border: Border.all(color: Color(0xFFF7F7FB), width: 3.5)),
|
width: 2,
|
||||||
child: Column(
|
color: Color(0xFFF7F7FB),
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
)
|
||||||
children: [
|
: null,
|
||||||
Expanded(
|
color: Colors.white,
|
||||||
child: Container(
|
// color: Color(0xFFF7F7FB),
|
||||||
// color: bodyColor,
|
|
||||||
// color: Colors.grey,
|
// color: Colors.amber,
|
||||||
width: double.infinity,
|
),
|
||||||
// height: MediaQuery.of(context).size.height,
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(8),
|
scrollDirection: Axis.vertical,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
// height: MediaQuery.of(context).size.height * 0.8,
|
||||||
|
color: Colors.white,
|
||||||
child: Column(
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
SingleChildScrollView(
|
Container(
|
||||||
scrollDirection: Axis.vertical,
|
color: Colors.white,
|
||||||
child: Container(
|
child: Row(
|
||||||
padding: const EdgeInsets.all(20),
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
// height: MediaQuery.of(context).size.height * 0.8,
|
children: [
|
||||||
color: Colors.white,
|
Text(
|
||||||
child: Column(
|
selectedOrg != null && selectedOrg!.isNotEmpty
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
? "Update Organization"
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
: "Create Organization",
|
||||||
children: [
|
style: TextStyle(
|
||||||
Container(
|
fontSize: 15, fontWeight: FontWeight.w800),
|
||||||
color: Colors.white,
|
),
|
||||||
child: Row(
|
],
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
),
|
||||||
children: [
|
),
|
||||||
Text(
|
Container(
|
||||||
"Create Organization",
|
color: Colors.white,
|
||||||
style: TextStyle(
|
child: Row(
|
||||||
fontSize: 16,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
fontWeight: FontWeight.w600),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
),
|
children: [
|
||||||
],
|
const Padding(
|
||||||
),
|
padding: EdgeInsets.only(top: 1.0),
|
||||||
),
|
child: Text(
|
||||||
Container(
|
"Name:",
|
||||||
color: Colors.white,
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.only(top: 1.0),
|
|
||||||
child: Text(
|
|
||||||
"Name:",
|
|
||||||
style: TextStyle(
|
|
||||||
fontFamily: "Archivo",
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
color: Color(0xFF212121)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
Expanded(
|
|
||||||
child: TextFormField(
|
|
||||||
controller: _orgNameController,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
color: Color(0xFF114D8B),
|
|
||||||
),
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: "Enter Organization Name",
|
|
||||||
hintStyle: TextStyle(
|
|
||||||
fontSize: 14, color: Colors.grey),
|
|
||||||
floatingLabelBehavior:
|
|
||||||
FloatingLabelBehavior.never,
|
|
||||||
border: InputBorder.none,
|
|
||||||
isDense: true,
|
|
||||||
// contentPadding:
|
|
||||||
// EdgeInsets.symmetric(vertical: 14),
|
|
||||||
),
|
|
||||||
// textAlignVertical: TextAlignVertical.center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Spacer(),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: _pickImage,
|
|
||||||
child: _imageBytes != null
|
|
||||||
? ClipOval(
|
|
||||||
child: Image.memory(
|
|
||||||
_imageBytes!,
|
|
||||||
width: 50,
|
|
||||||
height: 50,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: selectedOrg?['logo'] != null
|
|
||||||
? ClipOval(
|
|
||||||
child: Image.network(
|
|
||||||
selectedOrg!['logo'],
|
|
||||||
width: 50,
|
|
||||||
height: 50,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
errorBuilder: (context, error,
|
|
||||||
stackTrace) {
|
|
||||||
return const CircleAvatar(
|
|
||||||
radius: 20,
|
|
||||||
backgroundColor:
|
|
||||||
Colors.redAccent,
|
|
||||||
child: Icon(Icons.error,
|
|
||||||
size: 10),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: const CircleAvatar(
|
|
||||||
radius: 20,
|
|
||||||
backgroundColor: Colors.amber,
|
|
||||||
child: Icon(Icons.add_a_photo,
|
|
||||||
size: 10),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 5,
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
color: Colors.white,
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"Mail Settings",
|
|
||||||
style: TextStyle(
|
|
||||||
fontFamily: "Archivo",
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
color: Color(0xFF212121)),
|
|
||||||
),
|
|
||||||
|
|
||||||
// GestureDetector(
|
|
||||||
// onTap: () {
|
|
||||||
// setState(() {
|
|
||||||
// showMail = !showMail;
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// child: Icon(
|
|
||||||
// Icons.keyboard_arrow_down_outlined,
|
|
||||||
// color: Color(0xFF114D8B),
|
|
||||||
// size: 30,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
// if (showMail)
|
|
||||||
|
|
||||||
SizedBox(
|
|
||||||
height: 3,
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
// width: double.infinity,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border.all(
|
|
||||||
color: Color(0xFFF5F5F5),
|
|
||||||
// color: bodyColor ?? Colors.grey,
|
|
||||||
width: 1.0,
|
|
||||||
),
|
|
||||||
// color: bodyColor,
|
|
||||||
color: Color(0xFFF5F5F5),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: isDesktop
|
|
||||||
? MainAxisAlignment.start
|
|
||||||
: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
mailConfig['sender_email'] != null
|
|
||||||
? MailSetting(
|
|
||||||
isDesktop: isDesktop,
|
|
||||||
initialMailData: mailConfig,
|
|
||||||
onMailDataChanged:
|
|
||||||
(updatedData) {
|
|
||||||
// You can setState here or do something else with updatedData
|
|
||||||
print(
|
|
||||||
"Updated Mail Data: $updatedData");
|
|
||||||
|
|
||||||
mailConfig = updatedData;
|
|
||||||
},
|
|
||||||
)
|
|
||||||
: CircularProgressIndicator(),
|
|
||||||
],
|
|
||||||
))
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
SizedBox(
|
|
||||||
height: 5,
|
|
||||||
),
|
|
||||||
|
|
||||||
Text(
|
|
||||||
"Services",
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontFamily: "Archivo",
|
fontFamily: "Archivo",
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF212121)),
|
color: Color(0xFF212121)),
|
||||||
),
|
),
|
||||||
SizedBox(
|
),
|
||||||
height: 5,
|
SizedBox(width: 8),
|
||||||
),
|
Expanded(
|
||||||
Container(
|
child: TextFormField(
|
||||||
decoration: BoxDecoration(
|
controller: _orgNameController,
|
||||||
border: Border.all(color: Color(0xFFF4F4FB)),
|
style: TextStyle(
|
||||||
borderRadius: BorderRadius.circular(1),
|
fontSize: 16,
|
||||||
// color: bodyColor,
|
color: Color(0xFF114D8B),
|
||||||
color: Color(0xFFF5F5F5),
|
|
||||||
),
|
),
|
||||||
padding: EdgeInsets.only(
|
decoration: InputDecoration(
|
||||||
left: 5, right: 5, top: 15, bottom: 15),
|
hintText: "Enter Organization Name",
|
||||||
child: isDesktop
|
hintStyle:
|
||||||
? Row(
|
TextStyle(fontSize: 14, color: Colors.grey),
|
||||||
mainAxisAlignment:
|
floatingLabelBehavior:
|
||||||
MainAxisAlignment.spaceEvenly,
|
FloatingLabelBehavior.never,
|
||||||
// mainAxisSize: MainAxisSize.min,
|
border: InputBorder.none,
|
||||||
children: _buildOptions(),
|
isDense: true,
|
||||||
)
|
// contentPadding:
|
||||||
: Expanded(
|
// EdgeInsets.symmetric(vertical: 14),
|
||||||
child: SingleChildScrollView(
|
),
|
||||||
scrollDirection: Axis.horizontal,
|
// textAlignVertical: TextAlignVertical.center,
|
||||||
child: Row(
|
),
|
||||||
children: _buildOptions(),
|
),
|
||||||
),
|
Spacer(),
|
||||||
),
|
GestureDetector(
|
||||||
|
onTap: _pickImage,
|
||||||
|
child: _imageBytes != null
|
||||||
|
? ClipOval(
|
||||||
|
child: Image.memory(
|
||||||
|
_imageBytes!,
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
SizedBox(
|
: selectedOrg?['logo'] != null
|
||||||
height: 5,
|
? ClipOval(
|
||||||
),
|
child: Image.network(
|
||||||
|
selectedOrg!['logo'],
|
||||||
Column(
|
width: 50,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
height: 50,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder:
|
||||||
|
(context, error, stackTrace) {
|
||||||
|
return const CircleAvatar(
|
||||||
|
radius: 20,
|
||||||
|
backgroundColor: Colors.redAccent,
|
||||||
|
child: Icon(Icons.error, size: 10),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const CircleAvatar(
|
||||||
|
radius: 20,
|
||||||
|
backgroundColor: Colors.amber,
|
||||||
|
child: Icon(Icons.add_a_photo, size: 10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 5,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
color: Colors.white,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Choose Theme",
|
"Mail Settings",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontFamily: "Archivo",
|
fontFamily: "Archivo",
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF212121)),
|
color: Color(0xFF212121)),
|
||||||
),
|
),
|
||||||
Container(
|
|
||||||
decoration: BoxDecoration(
|
// GestureDetector(
|
||||||
// border: Border.all(color: Color(0xFFF4F4FB)),
|
// onTap: () {
|
||||||
borderRadius: BorderRadius.circular(1),
|
// setState(() {
|
||||||
// color: Color(0xFFF4F4FB),
|
// showMail = !showMail;
|
||||||
),
|
// });
|
||||||
padding: EdgeInsets.only(
|
// },
|
||||||
left: 5, right: 5, top: 15, bottom: 5),
|
// child: Icon(
|
||||||
child: layoutColor != null && bodyColor != null
|
// Icons.keyboard_arrow_down_outlined,
|
||||||
? ColorThemePickerWidget(
|
// color: Color(0xFF114D8B),
|
||||||
initialLayoutColor: layoutColor,
|
// size: 30,
|
||||||
initialBodyColor: bodyColor,
|
// ),
|
||||||
onLayoutColorSelected:
|
// ),
|
||||||
(Color selectedLayoutColor) {
|
|
||||||
setState(() {
|
|
||||||
layoutColor = selectedLayoutColor;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onBodyColorSelected:
|
|
||||||
(Color selectedBodyColor) {
|
|
||||||
setState(() {
|
|
||||||
bodyColor = selectedBodyColor;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
)
|
|
||||||
: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
// if (showMail)
|
||||||
|
|
||||||
// isDesktop
|
SizedBox(
|
||||||
// ? Row(
|
height: 3,
|
||||||
// mainAxisAlignment: MainAxisAlignment.end,
|
),
|
||||||
// children: _buildSubmit(isDesktop),
|
Container(
|
||||||
// )
|
// width: double.infinity,
|
||||||
// : Row(
|
decoration: BoxDecoration(
|
||||||
// mainAxisAlignment: MainAxisAlignment.center,
|
border: Border.all(
|
||||||
// children: _buildSubmit(isDesktop),
|
color: Color(0xFFF5F5F5),
|
||||||
// )
|
// color: bodyColor ?? Colors.grey,
|
||||||
|
width: 1.5,
|
||||||
|
),
|
||||||
|
// color: bodyColor,
|
||||||
|
color: Colors.white70,
|
||||||
|
// color: Color(0xFFF5F5F5),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: isDesktop
|
||||||
|
? MainAxisAlignment.start
|
||||||
|
: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
mailConfig['sender_email'] != null
|
||||||
|
? MailSetting(
|
||||||
|
isDesktop: isDesktop,
|
||||||
|
initialMailData: mailConfig,
|
||||||
|
onMailDataChanged: (updatedData) {
|
||||||
|
// You can setState here or do something else with updatedData
|
||||||
|
print(
|
||||||
|
"Updated Mail Data: $updatedData");
|
||||||
|
|
||||||
|
mailConfig = updatedData;
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: CircularProgressIndicator(),
|
||||||
|
],
|
||||||
|
))
|
||||||
],
|
],
|
||||||
),
|
)),
|
||||||
),
|
SizedBox(
|
||||||
|
height: 5,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
Text(
|
||||||
|
"Services",
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: "Archivo",
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF212121)),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 5,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(color: Color(0xFFF4F4FB)),
|
||||||
|
borderRadius: BorderRadius.circular(1),
|
||||||
|
// color: bodyColor,
|
||||||
|
// color: Color(0xFFF5F5F5),
|
||||||
|
color: Colors.white),
|
||||||
|
padding:
|
||||||
|
EdgeInsets.only(left: 5, right: 5, top: 15, bottom: 5),
|
||||||
|
child: isDesktop
|
||||||
|
? Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
// mainAxisSize: MainAxisSize.min,
|
||||||
|
children: _buildOptions(),
|
||||||
|
)
|
||||||
|
: Expanded(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
child: Row(
|
||||||
|
children: _buildOptions(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 5,
|
||||||
|
),
|
||||||
|
|
||||||
|
Row(
|
||||||
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Choose Theme",
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: "Archivo",
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF212121)),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
// border: Border.all(color: Color(0xFFF4F4FB)),
|
||||||
|
borderRadius: BorderRadius.circular(1),
|
||||||
|
// color: Color(0xFFF4F4FB),
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
left: 5, right: 5, top: 15, bottom: 5),
|
||||||
|
child: layoutColor != null && bodyColor != null
|
||||||
|
? ColorThemePickerWidget(
|
||||||
|
initialLayoutColor: layoutColor,
|
||||||
|
initialBodyColor: bodyColor,
|
||||||
|
onLayoutColorSelected:
|
||||||
|
(Color selectedLayoutColor) {
|
||||||
|
setState(() {
|
||||||
|
layoutColor = selectedLayoutColor;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onBodyColorSelected: (Color selectedBodyColor) {
|
||||||
|
setState(() {
|
||||||
|
bodyColor = selectedBodyColor;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
// isDesktop
|
||||||
|
// ? Row(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
// children: _buildSubmit(isDesktop),
|
||||||
|
// )
|
||||||
|
// : Row(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
// children: _buildSubmit(isDesktop),
|
||||||
|
// )
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
Container(
|
),
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
color: Colors.white,
|
|
||||||
child: isDesktop
|
|
||||||
? Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
// children: [Text("Button")],
|
|
||||||
children:
|
|
||||||
_buildSubmit(isDesktop, isViewMode, layoutColor),
|
|
||||||
)
|
|
||||||
: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children:
|
|
||||||
_buildSubmit(isDesktop, isViewMode, layoutColor),
|
|
||||||
))
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -273,6 +273,9 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
List<dynamic>? apiCountryData;
|
List<dynamic>? apiCountryData;
|
||||||
List<dynamic>? apiCostData; // Store API response here
|
List<dynamic>? apiCostData; // Store API response here
|
||||||
bool isLoading = true; // Track loading state
|
bool isLoading = true; // Track loading state
|
||||||
|
String? TripPlanAction;
|
||||||
|
bool showDomestic = false;
|
||||||
|
bool showInternational = false;
|
||||||
|
|
||||||
String? orgId;
|
String? orgId;
|
||||||
String? planUsrId;
|
String? planUsrId;
|
||||||
@ -469,6 +472,24 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setTripPlanAction() {
|
||||||
|
setState(() {
|
||||||
|
if (TripPlanAction == "Plan Creation Not Allowed") {
|
||||||
|
showDomestic = false;
|
||||||
|
showInternational = false;
|
||||||
|
} else if (TripPlanAction == "Only Domestic Plan Creation Allowed") {
|
||||||
|
showDomestic = true;
|
||||||
|
showInternational = false;
|
||||||
|
} else if (TripPlanAction == "Only International Plan Creation Allowed") {
|
||||||
|
showDomestic = false;
|
||||||
|
showInternational = true;
|
||||||
|
} else if (TripPlanAction == "Both Type Plan Creation Allowed") {
|
||||||
|
showDomestic = true;
|
||||||
|
showInternational = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void getSelectedPlanFor() {
|
void getSelectedPlanFor() {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
|
|
||||||
@ -492,7 +513,8 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
|
|
||||||
void fetchUserDetails() async {
|
void fetchUserDetails() async {
|
||||||
final details = await getUserDetails();
|
final details = await getUserDetails();
|
||||||
|
TripPlanAction = await getTripPlanAction();
|
||||||
|
print("TripPlanAction- $TripPlanAction");
|
||||||
print("details- $details");
|
print("details- $details");
|
||||||
|
|
||||||
if (details != null) {
|
if (details != null) {
|
||||||
@ -505,6 +527,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
orgId = await getOrgId();
|
orgId = await getOrgId();
|
||||||
print("userDetails - $selfId");
|
print("userDetails - $selfId");
|
||||||
getSelectedPlanFor();
|
getSelectedPlanFor();
|
||||||
|
setTripPlanAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String?> getToken() async {
|
Future<String?> getToken() async {
|
||||||
@ -692,7 +715,8 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final requiredFields = {
|
final requiredFields = {
|
||||||
"trip_type": _selectedTripType,
|
if (TripPlanAction != "Plan Creation Not Allowed") //
|
||||||
|
"trip_type": _selectedTripType,
|
||||||
"cost_center_id": selectedCostCenterId,
|
"cost_center_id": selectedCostCenterId,
|
||||||
"functional_department": selectedFuncDept,
|
"functional_department": selectedFuncDept,
|
||||||
"purpose_of_travel": selectedPurpose,
|
"purpose_of_travel": selectedPurpose,
|
||||||
@ -1193,7 +1217,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Trip Type *", // Your label
|
"Trip Type ( $TripPlanAction )", // Your label
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -1609,142 +1633,148 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
|
|
||||||
List<Widget> _buildTripType(bool isMobile) {
|
List<Widget> _buildTripType(bool isMobile) {
|
||||||
return [
|
return [
|
||||||
CustomTextFieldWrapper(
|
if (showDomestic == true)
|
||||||
color: Color(0xFFF4F4FB),
|
CustomTextFieldWrapper(
|
||||||
layoutColor: widget.layoutColor,
|
color: Color(0xFFF4F4FB),
|
||||||
borderRadius: BorderRadius.circular(25),
|
layoutColor: widget.layoutColor,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
borderRadius: BorderRadius.circular(25),
|
||||||
width: 130,
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||||
isFocused: _selectedTripType == "1",
|
width: 130,
|
||||||
isDesktop: widget.isDesktop,
|
isFocused: _selectedTripType == "1",
|
||||||
child: Row(
|
isDesktop: widget.isDesktop,
|
||||||
mainAxisSize: MainAxisSize.min,
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
Text(
|
children: [
|
||||||
"Domestic",
|
Text(
|
||||||
style: TextStyle(
|
"Domestic",
|
||||||
color: _selectedTripType == "1" ? Colors.white : Colors.black,
|
style: TextStyle(
|
||||||
fontWeight: _selectedTripType == "1" ? FontWeight.w600 : null,
|
|
||||||
fontSize: 13),
|
|
||||||
),
|
|
||||||
|
|
||||||
// Radio<String>(
|
|
||||||
// activeColor: Colors.blueAccent,
|
|
||||||
// // contentPadding: EdgeInsets.zero,
|
|
||||||
// visualDensity: VisualDensity.compact,
|
|
||||||
// // dense: true,
|
|
||||||
// value: "1",
|
|
||||||
// groupValue: _selectedTripType,
|
|
||||||
// onChanged: widget.isViewMode
|
|
||||||
// ? null
|
|
||||||
// : (value) {
|
|
||||||
// setState(() {
|
|
||||||
// _selectedTripType = value!;
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
|
|
||||||
GestureDetector(
|
|
||||||
onTap: widget.isViewMode
|
|
||||||
? null
|
|
||||||
: () {
|
|
||||||
setState(() {
|
|
||||||
_selectedTripType = "1";
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
width: 15,
|
|
||||||
height: 15,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.rectangle,
|
|
||||||
// color: _selectedOption == option["value"]
|
|
||||||
// ? Colors.blueAccent
|
|
||||||
// : Colors.transparent,
|
|
||||||
borderRadius: BorderRadius.circular(4), // Rounded rectangle
|
|
||||||
border: Border.all(
|
|
||||||
color:
|
color:
|
||||||
_selectedTripType == "1" ? Colors.white : Colors.black,
|
_selectedTripType == "1" ? Colors.white : Colors.black,
|
||||||
width: _selectedTripType == "1" ? 2 : 1,
|
fontWeight:
|
||||||
),
|
_selectedTripType == "1" ? FontWeight.w600 : null,
|
||||||
),
|
fontSize: 13),
|
||||||
child: _selectedTripType == "1"
|
|
||||||
? Icon(Icons.rectangle, size: 8, color: Colors.white)
|
|
||||||
: null, // Add checkmark if selected
|
|
||||||
),
|
),
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 20),
|
|
||||||
CustomTextFieldWrapper(
|
|
||||||
color: Color(0xFFF4F4FB),
|
|
||||||
layoutColor: widget.layoutColor,
|
|
||||||
borderRadius: BorderRadius.circular(25),
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
|
||||||
width: 150,
|
|
||||||
// padding: EdgeInsets.symmetric(horizontal: 5, vertical: 2),
|
|
||||||
isFocused: _selectedTripType == "2",
|
|
||||||
isDesktop: widget.isDesktop,
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"International",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 13,
|
|
||||||
color: _selectedTripType == "2" ? Colors.white : Colors.black,
|
|
||||||
fontWeight: _selectedTripType == "2" ? FontWeight.w600 : null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: widget.isViewMode
|
|
||||||
? null
|
|
||||||
: () {
|
|
||||||
setState(() {
|
|
||||||
_selectedTripType = "2";
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
width: 15,
|
|
||||||
height: 15,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.rectangle,
|
|
||||||
// color: _selectedOption == option["value"]
|
|
||||||
// ? Colors.blueAccent
|
|
||||||
// : Colors.transparent,
|
|
||||||
borderRadius: BorderRadius.circular(4), // Rounded rectangle
|
|
||||||
border: Border.all(
|
|
||||||
color:
|
|
||||||
_selectedTripType == "2" ? Colors.white : Colors.black,
|
|
||||||
width: _selectedTripType == "2" ? 2 : 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: _selectedTripType == "2"
|
|
||||||
? Icon(Icons.rectangle, size: 8, color: Colors.white)
|
|
||||||
: null, // Add checkmark if selected
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
// RadioListTile<String>(
|
// Radio<String>(
|
||||||
// activeColor: Colors.blueAccent,
|
// activeColor: Colors.blueAccent,
|
||||||
// contentPadding: EdgeInsets.zero,
|
// // contentPadding: EdgeInsets.zero,
|
||||||
// dense: true,
|
// visualDensity: VisualDensity.compact,
|
||||||
// title: Text("International"),
|
// // dense: true,
|
||||||
// value: "2",
|
// value: "1",
|
||||||
// groupValue: _selectedTripType,
|
// groupValue: _selectedTripType,
|
||||||
// onChanged: widget.isViewMode
|
// onChanged: widget.isViewMode
|
||||||
// ? null
|
// ? null
|
||||||
// : (value) {
|
// : (value) {
|
||||||
// setState(() {
|
// setState(() {
|
||||||
// _selectedTripType = value!;
|
// _selectedTripType = value!;
|
||||||
// });
|
// });
|
||||||
// },
|
// },
|
||||||
// ),
|
// ),
|
||||||
),
|
|
||||||
|
GestureDetector(
|
||||||
|
onTap: widget.isViewMode
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
setState(() {
|
||||||
|
_selectedTripType = "1";
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 15,
|
||||||
|
height: 15,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.rectangle,
|
||||||
|
// color: _selectedOption == option["value"]
|
||||||
|
// ? Colors.blueAccent
|
||||||
|
// : Colors.transparent,
|
||||||
|
borderRadius: BorderRadius.circular(4), // Rounded rectangle
|
||||||
|
border: Border.all(
|
||||||
|
color: _selectedTripType == "1"
|
||||||
|
? Colors.white
|
||||||
|
: Colors.black,
|
||||||
|
width: _selectedTripType == "1" ? 2 : 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: _selectedTripType == "1"
|
||||||
|
? Icon(Icons.rectangle, size: 8, color: Colors.white)
|
||||||
|
: null, // Add checkmark if selected
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 20),
|
||||||
|
if (showInternational)
|
||||||
|
CustomTextFieldWrapper(
|
||||||
|
color: Color(0xFFF4F4FB),
|
||||||
|
layoutColor: widget.layoutColor,
|
||||||
|
borderRadius: BorderRadius.circular(25),
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||||
|
width: 150,
|
||||||
|
// padding: EdgeInsets.symmetric(horizontal: 5, vertical: 2),
|
||||||
|
isFocused: _selectedTripType == "2",
|
||||||
|
isDesktop: widget.isDesktop,
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"International",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
color: _selectedTripType == "2" ? Colors.white : Colors.black,
|
||||||
|
fontWeight: _selectedTripType == "2" ? FontWeight.w600 : null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: widget.isViewMode
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
setState(() {
|
||||||
|
_selectedTripType = "2";
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 15,
|
||||||
|
height: 15,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.rectangle,
|
||||||
|
// color: _selectedOption == option["value"]
|
||||||
|
// ? Colors.blueAccent
|
||||||
|
// : Colors.transparent,
|
||||||
|
borderRadius: BorderRadius.circular(4), // Rounded rectangle
|
||||||
|
border: Border.all(
|
||||||
|
color: _selectedTripType == "2"
|
||||||
|
? Colors.white
|
||||||
|
: Colors.black,
|
||||||
|
width: _selectedTripType == "2" ? 2 : 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: _selectedTripType == "2"
|
||||||
|
? Icon(Icons.rectangle, size: 8, color: Colors.white)
|
||||||
|
: null, // Add checkmark if selected
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
// RadioListTile<String>(
|
||||||
|
// activeColor: Colors.blueAccent,
|
||||||
|
// contentPadding: EdgeInsets.zero,
|
||||||
|
// dense: true,
|
||||||
|
// title: Text("International"),
|
||||||
|
// value: "2",
|
||||||
|
// groupValue: _selectedTripType,
|
||||||
|
// onChanged: widget.isViewMode
|
||||||
|
// ? null
|
||||||
|
// : (value) {
|
||||||
|
// setState(() {
|
||||||
|
// _selectedTripType = value!;
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:easy_stepper/easy_stepper.dart';
|
import 'package:easy_stepper/easy_stepper.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:frontend/Screens/itnerary_list/accomodation_list.dart';
|
import 'package:frontend/Screens/itnerary_list/accomodation_list.dart';
|
||||||
@ -54,7 +56,10 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
|||||||
Map<String, dynamic>? selectedItem;
|
Map<String, dynamic>? selectedItem;
|
||||||
int? selectedIndex;
|
int? selectedIndex;
|
||||||
|
|
||||||
List<dynamic>? apiAllServices;
|
List<dynamic>? selectedAllServices;
|
||||||
|
List<Map<String, String>> selectedOrgServiceIds = [];
|
||||||
|
List<dynamic>? ServicesChoosed;
|
||||||
|
List<String> filledItineraryKeys = [];
|
||||||
|
|
||||||
// List<Map<String, dynamic>> miscellaneousList = [];
|
// List<Map<String, dynamic>> miscellaneousList = [];
|
||||||
|
|
||||||
@ -87,21 +92,98 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
handleSelectedPlan();
|
handleSelectedPlan();
|
||||||
loadAllServices();
|
updateSelectedServices();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> loadAllServices() async {
|
Future<void> loadAllServices() async {
|
||||||
try {
|
try {
|
||||||
final result = await apiService.fetchAllServices();
|
final result = await apiService.fetchAllServices();
|
||||||
setState(() {
|
setState(() {
|
||||||
apiAllServices = result;
|
selectedAllServices = result;
|
||||||
});
|
});
|
||||||
print("Fetched services: $apiAllServices");
|
print("Fetched services: $selectedAllServices");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error fetching role list: $e');
|
print('Error fetching role list: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> loadOrgSelectedAlServices() async {
|
||||||
|
try {
|
||||||
|
final result = await apiService.fetchOrganization();
|
||||||
|
|
||||||
|
if (result != null && result is Map<String, dynamic>) {
|
||||||
|
final rawServices = result['services_ids'];
|
||||||
|
|
||||||
|
if (rawServices != null && rawServices is String) {
|
||||||
|
try {
|
||||||
|
List<dynamic> decoded = json.decode(rawServices);
|
||||||
|
List<Map<String, String>> formatted = decoded
|
||||||
|
.map((e) => {"service_id": e['service_id'].toString()})
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
selectedOrgServiceIds = formatted;
|
||||||
|
});
|
||||||
|
print("selectedOrgServiceIds: ${selectedOrgServiceIds}");
|
||||||
|
|
||||||
|
for (var service in selectedOrgServiceIds) {
|
||||||
|
print("service_id: ${service['service_id']}");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("Failed to decode services_ids: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('Error fetching role list: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateSelectedServices() async {
|
||||||
|
await loadAllServices();
|
||||||
|
await loadOrgSelectedAlServices();
|
||||||
|
|
||||||
|
if (hasAnyItineraryData()) {
|
||||||
|
print("SELCTSplanChhose: ${filledItineraryKeys}");
|
||||||
|
|
||||||
|
final selectedIds =
|
||||||
|
selectedOrgServiceIds.map((e) => e['service_id']).toSet();
|
||||||
|
|
||||||
|
// Filter services that match filled keys (name match) and are not already selected
|
||||||
|
final additionalServices = selectedAllServices!.where((service) {
|
||||||
|
final name = (service['name'] ?? "").toString().toLowerCase();
|
||||||
|
final id = service['service_id'].toString();
|
||||||
|
return filledItineraryKeys.contains(name) && !selectedIds.contains(id);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
final originalFiltered = selectedAllServices!
|
||||||
|
.where((service) =>
|
||||||
|
selectedIds.contains(service['service_id'].toString()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
ServicesChoosed = [...originalFiltered, ...additionalServices];
|
||||||
|
});
|
||||||
|
|
||||||
|
print(
|
||||||
|
"Services chosen based on filled keys + selected: $ServicesChoosed");
|
||||||
|
} else {
|
||||||
|
final selectedIds =
|
||||||
|
selectedOrgServiceIds.map((e) => e['service_id']).toSet();
|
||||||
|
|
||||||
|
final filtered = selectedAllServices!
|
||||||
|
.where((service) =>
|
||||||
|
selectedIds.contains(service['service_id'].toString()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
ServicesChoosed = filtered;
|
||||||
|
});
|
||||||
|
|
||||||
|
print("Filtered Selected Services Chooesed: $ServicesChoosed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void handleSelectedPlan() {
|
void handleSelectedPlan() {
|
||||||
// Check if selectedPlanData has itinerary data
|
// Check if selectedPlanData has itinerary data
|
||||||
if (hasAnyItineraryData()) {
|
if (hasAnyItineraryData()) {
|
||||||
@ -147,13 +229,30 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
|||||||
"forex"
|
"forex"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// for (String key in keys) {
|
||||||
|
// if (widget.selectedPlanData.containsKey(key) &&
|
||||||
|
// widget.selectedPlanData[key] is List &&
|
||||||
|
// (widget.selectedPlanData[key] as List).isNotEmpty) {
|
||||||
|
// print("SelectedPLANDFDDSF- ${widget.selectedPlanData}");
|
||||||
|
// return true; // At least one list has data
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
filledItineraryKeys.clear(); // Clear previous results
|
||||||
|
|
||||||
for (String key in keys) {
|
for (String key in keys) {
|
||||||
if (widget.selectedPlanData.containsKey(key) &&
|
if (widget.selectedPlanData.containsKey(key) &&
|
||||||
widget.selectedPlanData[key] is List &&
|
widget.selectedPlanData[key] is List &&
|
||||||
(widget.selectedPlanData[key] as List).isNotEmpty) {
|
(widget.selectedPlanData[key] as List).isNotEmpty) {
|
||||||
return true; // At least one list has data
|
filledItineraryKeys.add(key); // Store key with data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filledItineraryKeys.isNotEmpty) {
|
||||||
|
print("Selected keys with data: $filledItineraryKeys");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false; // No itinerary data available
|
return false; // No itinerary data available
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,9 +643,9 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _buildOptions() {
|
List<Widget> _buildOptions() {
|
||||||
if (apiAllServices == null) return [];
|
if (ServicesChoosed == null) return [];
|
||||||
|
|
||||||
return apiAllServices!.map((service) {
|
return ServicesChoosed!.map((service) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(right: 20.0),
|
padding: const EdgeInsets.only(right: 20.0),
|
||||||
child: _buildOption(
|
child: _buildOption(
|
||||||
|
|||||||
@ -24,6 +24,7 @@ class _ListPlansState extends State<ListPlans> {
|
|||||||
String? userId;
|
String? userId;
|
||||||
String? orgId;
|
String? orgId;
|
||||||
String? token;
|
String? token;
|
||||||
|
String? TripPlanAction;
|
||||||
|
|
||||||
Color? layoutColor;
|
Color? layoutColor;
|
||||||
Color? bodyColor;
|
Color? bodyColor;
|
||||||
@ -60,6 +61,7 @@ class _ListPlansState extends State<ListPlans> {
|
|||||||
token = await getToken();
|
token = await getToken();
|
||||||
userId = await getUserId();
|
userId = await getUserId();
|
||||||
orgId = await getOrgId();
|
orgId = await getOrgId();
|
||||||
|
TripPlanAction = await getTripPlanAction();
|
||||||
|
|
||||||
if (token == null || userId == null) {
|
if (token == null || userId == null) {
|
||||||
print("Token or USerId missing");
|
print("Token or USerId missing");
|
||||||
@ -290,10 +292,34 @@ class _ListPlansState extends State<ListPlans> {
|
|||||||
EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.go('/createPlan', extra: {
|
if (TripPlanAction == "Plan Creation Not Allowed") {
|
||||||
'orgId': orgId,
|
showDialog(
|
||||||
});
|
context: context,
|
||||||
if (!isDesktop) Navigator.pop(context);
|
builder: (context) => AlertDialog(
|
||||||
|
title: Text(
|
||||||
|
"Action Not Allowed",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
content: Text(
|
||||||
|
"Plan Creation Not Allowed For This User."),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
child: Text(
|
||||||
|
"OK",
|
||||||
|
style: TextStyle(color: layoutColor),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
context.go('/createPlan', extra: {
|
||||||
|
'orgId': orgId,
|
||||||
|
});
|
||||||
|
if (!isDesktop) Navigator.pop(context);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize:
|
mainAxisSize:
|
||||||
@ -450,26 +476,43 @@ class _ListPlansState extends State<ListPlans> {
|
|||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontFamily: "Archivo",
|
fontFamily: "Archivo",
|
||||||
))),
|
))),
|
||||||
DataCell(Container(
|
DataCell(
|
||||||
padding: const EdgeInsets.symmetric(
|
Container(
|
||||||
vertical: 4, horizontal: 10),
|
width: double
|
||||||
decoration: BoxDecoration(
|
.infinity, // Set your desired fixed size (equal width and height)
|
||||||
color: plan.status == "Active"
|
height: 25,
|
||||||
? layoutColor
|
alignment: Alignment.center,
|
||||||
: Colors.grey.shade50,
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(10),
|
color: plan.statusValue ==
|
||||||
),
|
"Partially Approved"
|
||||||
child: Text(
|
? Colors.yellow.shade100
|
||||||
plan.statusValue,
|
: plan.statusValue == "Approved"
|
||||||
style: TextStyle(
|
? Colors.green.shade100
|
||||||
color: plan.status == "Active"
|
: plan.statusValue == "Completed"
|
||||||
? Colors.white
|
? Colors.green.shade500
|
||||||
: Colors.grey,
|
: plan.statusValue == "Rejected"
|
||||||
fontSize: 13,
|
? Colors.red.shade100
|
||||||
fontWeight: FontWeight.bold,
|
: Colors.grey.shade100,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
plan.statusValue,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: (plan.statusValue ==
|
||||||
|
"Partially Approved" ||
|
||||||
|
plan.statusValue == "Approved" ||
|
||||||
|
plan.statusValue == "Rejected")
|
||||||
|
? Colors.black
|
||||||
|
: plan.statusValue == "Completed"
|
||||||
|
? Colors.white
|
||||||
|
: Colors.grey,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)),
|
),
|
||||||
DataCell(Row(children: [
|
DataCell(Row(children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
@ -494,6 +537,17 @@ class _ListPlansState extends State<ListPlans> {
|
|||||||
// color: Colors.green),
|
// color: Colors.green),
|
||||||
// onPressed: () => viewPlan(plan.planId,
|
// onPressed: () => viewPlan(plan.planId,
|
||||||
// isViewMode: false) ),
|
// isViewMode: false) ),
|
||||||
|
|
||||||
|
SizedBox(
|
||||||
|
width: 5,
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => (),
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/IconsImg/delete.png',
|
||||||
|
width: 20,
|
||||||
|
height: 15),
|
||||||
|
),
|
||||||
])),
|
])),
|
||||||
]);
|
]);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
|
|||||||
@ -1,5 +1,15 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
import 'dart:ui' as html;
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:html' as html;
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'dart:html' as html;
|
||||||
|
import 'dart:ui' as web;
|
||||||
|
|
||||||
|
import 'package:web/web.dart' as web;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:frontend/Screens/policy/policyCriteria.dart';
|
import 'package:frontend/Screens/policy/policyCriteria.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
@ -9,12 +19,18 @@ import 'package:responsive_builder/responsive_builder.dart';
|
|||||||
import '../../config/apiUrl.dart';
|
import '../../config/apiUrl.dart';
|
||||||
import '../../routes/custom_appBar.dart';
|
import '../../routes/custom_appBar.dart';
|
||||||
import '../../routes/custom_drawer.dart';
|
import '../../routes/custom_drawer.dart';
|
||||||
|
import '../../services/apiService.dart';
|
||||||
import '../../utils/auth_utils.dart';
|
import '../../utils/auth_utils.dart';
|
||||||
import '../../widgets/custom_text_field.dart';
|
import '../../widgets/custom_text_field.dart';
|
||||||
import '../../widgets/custom_user_form.dart';
|
import '../../widgets/custom_user_form.dart';
|
||||||
|
|
||||||
class Policy extends StatefulWidget {
|
class Policy extends StatefulWidget {
|
||||||
const Policy({super.key});
|
final Map<String, dynamic>? policy;
|
||||||
|
const Policy({super.key, required this.policy});
|
||||||
|
|
||||||
|
static Policy fromState(GoRouterState state) {
|
||||||
|
return Policy(policy: state.extra as Map<String, dynamic>?);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_PolicyState createState() => _PolicyState();
|
_PolicyState createState() => _PolicyState();
|
||||||
@ -24,17 +40,23 @@ class _PolicyState extends State<Policy> {
|
|||||||
final GlobalKey<PolicyCriteriaState> policyCriteriaKey =
|
final GlobalKey<PolicyCriteriaState> policyCriteriaKey =
|
||||||
GlobalKey<PolicyCriteriaState>();
|
GlobalKey<PolicyCriteriaState>();
|
||||||
|
|
||||||
|
final ApiService apiService = ApiService();
|
||||||
|
|
||||||
Color? layoutColor;
|
Color? layoutColor;
|
||||||
Color? bodyColor;
|
Color? bodyColor;
|
||||||
late String policyType = "domestic";
|
late String policyType = "domestic";
|
||||||
// int? selectedServiceIndex = 1;
|
// int? selectedServiceIndex = 1;
|
||||||
ValueNotifier<String> selectedServiceIndex = ValueNotifier("1");
|
ValueNotifier<String> selectedServiceIndex = ValueNotifier("1");
|
||||||
late String selectedService = "Train";
|
String selectedService = "train";
|
||||||
// ValueNotifier<String> selectedService = ValueNotifier("Train");
|
// ValueNotifier<String> selectedService = ValueNotifier("Train");
|
||||||
bool isViewMode = false;
|
bool isViewMode = false;
|
||||||
|
|
||||||
|
Map<String, String> errorMessages = {};
|
||||||
|
|
||||||
|
String? selectedPolicyId;
|
||||||
String? _selectedTripType;
|
String? _selectedTripType;
|
||||||
String? PolicyName;
|
String? PolicyName;
|
||||||
String? SelectedDomestic = "1";
|
String? SelectedDomestic = "0";
|
||||||
String? SelectedInternational = "0";
|
String? SelectedInternational = "0";
|
||||||
String? orgId;
|
String? orgId;
|
||||||
String? userId;
|
String? userId;
|
||||||
@ -42,6 +64,11 @@ class _PolicyState extends State<Policy> {
|
|||||||
bool showClass = true;
|
bool showClass = true;
|
||||||
bool showCost = true;
|
bool showCost = true;
|
||||||
|
|
||||||
|
List<dynamic>? selectedAllServices;
|
||||||
|
List<Map<String, String>> selectedOrgServiceIds = [];
|
||||||
|
List<dynamic>? ServicesChoosed;
|
||||||
|
List<String> filledItineraryKeys = [];
|
||||||
|
|
||||||
TextEditingController _policyController = TextEditingController();
|
TextEditingController _policyController = TextEditingController();
|
||||||
List<Map<String, dynamic>>? policy_details = [];
|
List<Map<String, dynamic>>? policy_details = [];
|
||||||
|
|
||||||
@ -79,13 +106,20 @@ class _PolicyState extends State<Policy> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
loadinitializeData();
|
loadinitializeData();
|
||||||
loadInitialData();
|
loadInitialData();
|
||||||
});
|
|
||||||
|
|
||||||
// updateData();
|
if (widget.policy != null) {
|
||||||
|
final details =
|
||||||
|
List<Map<String, dynamic>>.from(widget.policy!['policy_details']);
|
||||||
|
policyCriteriaKey.currentState?.loadPolicyDetails(details);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
updateSelectedServices();
|
||||||
|
updateData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadInitialData() async {
|
void loadInitialData() async {
|
||||||
@ -108,7 +142,121 @@ class _PolicyState extends State<Policy> {
|
|||||||
userId = await getUserId();
|
userId = await getUserId();
|
||||||
}
|
}
|
||||||
|
|
||||||
// void updateData(){}
|
Future<void> loadAllServices() async {
|
||||||
|
try {
|
||||||
|
final result = await apiService.fetchAllServices();
|
||||||
|
setState(() {
|
||||||
|
selectedAllServices = result;
|
||||||
|
});
|
||||||
|
print("Fetched services: $selectedAllServices");
|
||||||
|
} catch (e) {
|
||||||
|
print('Error fetching role list: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> loadOrgSelectedAlServices() async {
|
||||||
|
try {
|
||||||
|
final result = await apiService.fetchOrganization();
|
||||||
|
|
||||||
|
if (result != null && result is Map<String, dynamic>) {
|
||||||
|
final rawServices = result['services_ids'];
|
||||||
|
|
||||||
|
if (rawServices != null && rawServices is String) {
|
||||||
|
try {
|
||||||
|
List<dynamic> decoded = json.decode(rawServices);
|
||||||
|
List<Map<String, String>> formatted = decoded
|
||||||
|
.map((e) => {"service_id": e['service_id'].toString()})
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
selectedOrgServiceIds = formatted;
|
||||||
|
});
|
||||||
|
print("selectedOrgServiceIds: ${selectedOrgServiceIds}");
|
||||||
|
|
||||||
|
for (var service in selectedOrgServiceIds) {
|
||||||
|
print("service_id: ${service['service_id']}");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("Failed to decode services_ids: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('Error fetching role list: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateSelectedServices() async {
|
||||||
|
await loadAllServices();
|
||||||
|
await loadOrgSelectedAlServices();
|
||||||
|
|
||||||
|
final selectedIds =
|
||||||
|
selectedOrgServiceIds.map((e) => e['service_id']).toSet();
|
||||||
|
|
||||||
|
if (widget.policy != null) {
|
||||||
|
final details =
|
||||||
|
List<Map<String, dynamic>>.from(widget.policy!['policy_details']);
|
||||||
|
|
||||||
|
print("Filtered Selected Services - $details");
|
||||||
|
|
||||||
|
final filtered = selectedAllServices!
|
||||||
|
.where((service) =>
|
||||||
|
selectedIds.contains(service['service_id'].toString()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
ServicesChoosed = filtered;
|
||||||
|
});
|
||||||
|
|
||||||
|
print("Filtered Selected Services Chooesed1: $ServicesChoosed");
|
||||||
|
|
||||||
|
if (ServicesChoosed!.isNotEmpty) {
|
||||||
|
String firstServiceName = ServicesChoosed?.first['name'];
|
||||||
|
print("✅ First service name selected for filter: $firstServiceName");
|
||||||
|
selectedService = firstServiceName;
|
||||||
|
}
|
||||||
|
print("Filtered Selected Services Added to Policy: $ServicesChoosed");
|
||||||
|
} else {
|
||||||
|
final filtered = selectedAllServices!
|
||||||
|
.where((service) =>
|
||||||
|
selectedIds.contains(service['service_id'].toString()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
ServicesChoosed = filtered;
|
||||||
|
});
|
||||||
|
|
||||||
|
print("Filtered Selected Services Chooesed1: $ServicesChoosed");
|
||||||
|
|
||||||
|
if (ServicesChoosed!.isNotEmpty) {
|
||||||
|
String firstServiceName = ServicesChoosed?.first['name'];
|
||||||
|
print("✅ First service name selected for filter: $firstServiceName");
|
||||||
|
selectedService = firstServiceName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateData() {
|
||||||
|
if (widget.policy != null) {
|
||||||
|
setState(() {
|
||||||
|
selectedPolicyId = widget.policy?["policy_id"] ?? "";
|
||||||
|
_policyController.text = widget.policy?["name"] ?? "";
|
||||||
|
SelectedDomestic = widget.policy?["domestic"] ?? "";
|
||||||
|
SelectedInternational = widget.policy?["international"] ?? "";
|
||||||
|
|
||||||
|
if (SelectedDomestic == "1") {
|
||||||
|
_selectedTripType = "1";
|
||||||
|
} else if (SelectedInternational == "1") {
|
||||||
|
_selectedTripType = "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ✅ Load policy_details list safely
|
||||||
|
policy_details = List<Map<String, dynamic>>.from(
|
||||||
|
widget.policy?["policy_details"] ?? [],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void handleSubmit() async {
|
void handleSubmit() async {
|
||||||
print("USR Detail Submit - $policyData");
|
print("USR Detail Submit - $policyData");
|
||||||
@ -120,19 +268,69 @@ class _PolicyState extends State<Policy> {
|
|||||||
|
|
||||||
Map<String, dynamic> data = policyData;
|
Map<String, dynamic> data = policyData;
|
||||||
|
|
||||||
createPolicyData(data);
|
if (!isValidData(data)) {
|
||||||
|
print("USERDETAILS : $policyData");
|
||||||
|
print("Validation Failed: Required fields are missing.");
|
||||||
|
setState(() {});
|
||||||
|
return; // Stop execution if validation fails
|
||||||
|
} else {
|
||||||
|
// print("USERDETAILS : $policyData");
|
||||||
|
// orgId = await getOrgId();
|
||||||
|
|
||||||
// if (!isValidData(data)) {
|
createPolicyData(data);
|
||||||
// print("USERDETAILS : $policyData");
|
}
|
||||||
// print("Validation Failed: Required fields are missing.");
|
}
|
||||||
// setState(() {});
|
|
||||||
// return; // Stop execution if validation fails
|
bool isValidData(Map<String, dynamic> data) {
|
||||||
// } else {
|
errorMessages.clear(); // Reset previous errors
|
||||||
// // print("USERDETAILS : $policyData");
|
|
||||||
// // orgId = await getOrgId();
|
// Validate required fields
|
||||||
//
|
if (data["name"] == null || data["name"].toString().trim().isEmpty) {
|
||||||
// createPolicyData(policyData);
|
errorMessages["name"] = "Policy name is required.";
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
// Validate that either domestic or international is selected
|
||||||
|
final domestic = data["domestic"]?.toString() ?? "0";
|
||||||
|
final international = data["international"]?.toString() ?? "0";
|
||||||
|
|
||||||
|
print(
|
||||||
|
"domestic: ${data["domestic"]}, international: ${data["international"]}");
|
||||||
|
|
||||||
|
if (domestic != "1" && international != "1") {
|
||||||
|
errorMessages["trip_type"] = "Please select Domestic or International.";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate at least one policy_detail with valid content
|
||||||
|
final policyDetails = data["policy_details"] as List<Map<String, dynamic>>;
|
||||||
|
|
||||||
|
bool hasAtLeastOneDetail = policyDetails.any((service) {
|
||||||
|
final fieldsToCheck = [
|
||||||
|
'cost',
|
||||||
|
'class',
|
||||||
|
'a1_action',
|
||||||
|
'a2_action',
|
||||||
|
'a3_action'
|
||||||
|
];
|
||||||
|
return fieldsToCheck.any((field) {
|
||||||
|
final value = service[field];
|
||||||
|
return value != null && value.toString().trim().isNotEmpty;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!hasAtLeastOneDetail) {
|
||||||
|
errorMessages["policy_details"] =
|
||||||
|
"At least one valid policy detail is required.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return errorMessages.isEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _clearError(String field) {
|
||||||
|
if (mounted && errorMessages.containsKey(field)) {
|
||||||
|
setState(() {
|
||||||
|
errorMessages.remove(field);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> createPolicyData(Map<String, dynamic> policyData) async {
|
Future<void> createPolicyData(Map<String, dynamic> policyData) async {
|
||||||
@ -143,9 +341,12 @@ class _PolicyState extends State<Policy> {
|
|||||||
throw Exception('Token not found. Please log in.');
|
throw Exception('Token not found. Please log in.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (selectedPlanId != null && selectedPlanId!.isNotEmpty) {
|
final int? policyId;
|
||||||
// planData['plan_id'] = selectedPlanId; // Add plan_id for update
|
|
||||||
// }
|
if (selectedPolicyId != null && selectedPolicyId!.isNotEmpty) {
|
||||||
|
policyId = int.tryParse(selectedPolicyId!);
|
||||||
|
policyData['policy_id'] = policyId; // Add only if updating
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
@ -186,28 +387,17 @@ class _PolicyState extends State<Policy> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
if (isDesktop) CustomDrawer(isDesktop: true),
|
if (isDesktop) CustomDrawer(isDesktop: true),
|
||||||
Expanded(
|
|
||||||
child: Container(
|
Expanded(child: buildData(isDesktop, context)),
|
||||||
color: bodyColor,
|
// Expanded(
|
||||||
child: buildPolicyLayout(isDesktop),
|
// child: Container(
|
||||||
),
|
// color: bodyColor,
|
||||||
),
|
// child: buildPolicyLayout(isDesktop),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
|
||||||
color: Colors.white,
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: isDesktop
|
|
||||||
? Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: _buildSubmit(isDesktop),
|
|
||||||
)
|
|
||||||
: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: _buildSubmit(isDesktop),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -246,153 +436,206 @@ class _PolicyState extends State<Policy> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildPolicyLayout(bool isDesktop) {
|
Widget buildData(bool isDesktop, context) {
|
||||||
return SingleChildScrollView(
|
return Container(
|
||||||
scrollDirection: Axis.vertical,
|
// margin: const EdgeInsets.only(left: 10.0, right: 15.0, top: 10.0, bottom: 10.0),
|
||||||
child: Container(
|
decoration: BoxDecoration(
|
||||||
margin: isDesktop
|
|
||||||
? EdgeInsets.all(10.0)
|
|
||||||
: EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
|
|
||||||
height: isDesktop
|
|
||||||
? MediaQuery.of(context).size.height * 0.98
|
|
||||||
: MediaQuery.of(context).size.height,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: isDesktop
|
|
||||||
? Border.all(
|
|
||||||
width: 2,
|
|
||||||
color: Color(0xFFF7F7FB),
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
color: Colors.white,
|
|
||||||
// color: Color(0xFFF7F7FB),
|
|
||||||
|
|
||||||
// color: Colors.amber,
|
// color: Colors.amber,
|
||||||
),
|
color: bodyColor,
|
||||||
child: Column(
|
border: Border.all(color: Color(0xFFF7F7FB), width: 3.5)),
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Expanded(
|
||||||
// color: Color(0xFFF7F7FB),
|
child: Container(
|
||||||
child: Column(
|
color: bodyColor,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
child: buildPolicyLayout(isDesktop),
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
padding: isDesktop ? EdgeInsets.all(6) : EdgeInsets.all(3),
|
|
||||||
// color: Colors.white, // Background to avoid overlapping
|
|
||||||
color: Colors.white,
|
|
||||||
// color: isDesktop ? Color(0xFFF7F7FB) : Colors.white,
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"Choose Policy Type",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
color: Colors.black,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
isDesktop ? SizedBox(height: 0) : SizedBox(height: 5),
|
),
|
||||||
Container(
|
Container(
|
||||||
// color: Colors.amber,
|
color: Colors.white,
|
||||||
// color: isDesktop ? Color(0xFFF7F7FB) : Colors.white,
|
padding: const EdgeInsets.all(8.0),
|
||||||
padding: isDesktop ? const EdgeInsets.only(left: 35) : null,
|
child: isDesktop
|
||||||
child: Column(
|
? Row(
|
||||||
children: [
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
Row(
|
children: _buildSubmit(isDesktop),
|
||||||
children: [
|
)
|
||||||
Column(
|
: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: _buildSubmit(isDesktop),
|
||||||
Text("Policy Name",
|
),
|
||||||
style: TextStyle(
|
),
|
||||||
fontSize: 12,
|
],
|
||||||
fontWeight: FontWeight.w200,
|
),
|
||||||
color: Colors.black)),
|
);
|
||||||
SizedBox(height: 5),
|
}
|
||||||
CustomTextFieldUserWrapper(
|
|
||||||
isFocused: false,
|
Widget buildPolicyLayout(bool isDesktop) {
|
||||||
isDesktop: isDesktop,
|
return Container(
|
||||||
child: SizedBox(
|
margin: isDesktop
|
||||||
height: 40,
|
? EdgeInsets.all(10.0)
|
||||||
child: TextField(
|
: EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
|
||||||
style: TextStyle(fontSize: 12),
|
height: isDesktop
|
||||||
controller: _policyController,
|
? MediaQuery.of(context).size.height * 0.98
|
||||||
// enabled: !isViewMode,
|
: MediaQuery.of(context).size.height,
|
||||||
onChanged: (value) {},
|
decoration: BoxDecoration(
|
||||||
decoration: InputDecoration(
|
border: isDesktop
|
||||||
labelText: "Policy Name",
|
? Border.all(
|
||||||
labelStyle: TextStyle(
|
width: 2,
|
||||||
fontSize: 12, color: Colors.grey),
|
color: Color(0xFFF7F7FB),
|
||||||
floatingLabelBehavior:
|
)
|
||||||
FloatingLabelBehavior.never,
|
: null,
|
||||||
border: InputBorder.none,
|
color: Colors.white,
|
||||||
contentPadding:
|
// color: Color(0xFFF7F7FB),
|
||||||
EdgeInsets.symmetric(vertical: 16),
|
|
||||||
),
|
// color: Colors.amber,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
// color: Color(0xFFF7F7FB),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: isDesktop ? EdgeInsets.all(6) : EdgeInsets.all(3),
|
||||||
|
// color: Colors.white, // Background to avoid overlapping
|
||||||
|
color: Colors.white,
|
||||||
|
// color: isDesktop ? Color(0xFFF7F7FB) : Colors.white,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Choose Policy Type",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
isDesktop ? SizedBox(height: 0) : SizedBox(height: 5),
|
||||||
|
Container(
|
||||||
|
// color: Colors.amber,
|
||||||
|
// color: isDesktop ? Color(0xFFF7F7FB) : Colors.white,
|
||||||
|
padding: isDesktop ? const EdgeInsets.only(left: 35) : null,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text("Policy Name",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w200,
|
||||||
|
color: Colors.black)),
|
||||||
|
SizedBox(height: 5),
|
||||||
|
CustomTextFieldUserWrapper(
|
||||||
|
isFocused: false,
|
||||||
|
isDesktop: isDesktop,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 40,
|
||||||
|
child: TextField(
|
||||||
|
style: TextStyle(fontSize: 12),
|
||||||
|
controller: _policyController,
|
||||||
|
// enabled: !isViewMode,
|
||||||
|
onChanged: (value) {
|
||||||
|
_clearError("name");
|
||||||
|
},
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: "Policy Name",
|
||||||
|
labelStyle: TextStyle(
|
||||||
|
fontSize: 12, color: Colors.grey),
|
||||||
|
floatingLabelBehavior:
|
||||||
|
FloatingLabelBehavior.never,
|
||||||
|
border: InputBorder.none,
|
||||||
|
contentPadding:
|
||||||
|
EdgeInsets.symmetric(vertical: 16),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
if (errorMessages["name"] != null) ...[
|
||||||
|
SizedBox(height: 5), // Space before error message
|
||||||
|
Text(
|
||||||
|
errorMessages["name"]!,
|
||||||
|
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
SizedBox(
|
|
||||||
height: 5,
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text("Policy Type",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: FontWeight.w200,
|
|
||||||
color: Colors.black)),
|
|
||||||
SizedBox(height: 5),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: _buildTripType(isDesktop),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
SizedBox(
|
|
||||||
height: 10,
|
|
||||||
),
|
|
||||||
Divider(
|
|
||||||
thickness: 0.2,
|
|
||||||
color: Colors.grey,
|
|
||||||
),
|
|
||||||
isDesktop
|
|
||||||
? Expanded(
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
_buildPolicyCategoryList(isDesktop),
|
|
||||||
_buildPolicyCategory(isDesktop),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: Expanded(
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
_buildPolicyCategoryList(isDesktop),
|
|
||||||
_buildPolicyCategory(isDesktop),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 5,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text("Policy Type",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w200,
|
||||||
|
color: Colors.black)),
|
||||||
|
SizedBox(height: 5),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: _buildTripType(isDesktop),
|
||||||
|
),
|
||||||
|
if (errorMessages["trip_type"] != null) ...[
|
||||||
|
SizedBox(height: 5), // Space before error message
|
||||||
|
Text(
|
||||||
|
errorMessages["trip_type"]!,
|
||||||
|
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
Divider(
|
||||||
|
thickness: 0.2,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
if (errorMessages["policy_details"] != null) ...[
|
||||||
|
SizedBox(height: 5), // Space before error message
|
||||||
|
Text(
|
||||||
|
errorMessages["policy_details"]!,
|
||||||
|
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
isDesktop
|
||||||
|
? Expanded(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
_buildPolicyCategoryList(isDesktop),
|
||||||
|
_buildPolicyCategory(isDesktop),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Expanded(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
_buildPolicyCategoryList(isDesktop),
|
||||||
|
_buildPolicyCategory(isDesktop),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -420,17 +663,24 @@ class _PolicyState extends State<Policy> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildPolicySubCategoryList(bool isDesktop) {
|
Widget _buildPolicySubCategoryList(bool isDesktop) {
|
||||||
List<String> services = [
|
// List<String> services = [
|
||||||
"Flight",
|
// "Flight",
|
||||||
"Train",
|
// "Train",
|
||||||
"Bus",
|
// "Bus",
|
||||||
"Taxi",
|
// "Taxi",
|
||||||
"Forex",
|
// "Forex",
|
||||||
"Accommodation",
|
// "Accommodation",
|
||||||
"Insurance",
|
// "Insurance",
|
||||||
"Visa",
|
// "Visa",
|
||||||
"Miscellaneous"
|
// "Miscellaneous"
|
||||||
];
|
// ];
|
||||||
|
|
||||||
|
if (ServicesChoosed == null) {
|
||||||
|
return const Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> services =
|
||||||
|
ServicesChoosed!.map((service) => service['name'].toString()).toList();
|
||||||
|
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
@ -476,10 +726,21 @@ class _PolicyState extends State<Policy> {
|
|||||||
: EdgeInsets.only(top: 3, bottom: 3, left: 8, right: 8),
|
: EdgeInsets.only(top: 3, bottom: 3, left: 8, right: 8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
// color: Colors.blue,
|
// color: Colors.blue,
|
||||||
color:
|
color: isSelected ? Color(0xFF114D8B) : Colors.white,
|
||||||
isSelected ? Color(0xFF114D8B) : Colors.grey.shade100,
|
|
||||||
// : Color(0xFFEBEBF7),
|
// : Color(0xFFEBEBF7),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.white, // Light grey border
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.grey.withAlpha(90), // Shadow color
|
||||||
|
blurRadius: 1, // Blur radius
|
||||||
|
spreadRadius: 1, // Spread radius
|
||||||
|
offset: Offset(0, 1), // Shadow position
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -518,6 +779,7 @@ class _PolicyState extends State<Policy> {
|
|||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
setState(() {
|
setState(() {
|
||||||
policy_details = policyData;
|
policy_details = policyData;
|
||||||
|
_clearError("policy_details");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -566,6 +828,7 @@ class _PolicyState extends State<Policy> {
|
|||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
_clearError("trip_type");
|
||||||
_selectedTripType = "1";
|
_selectedTripType = "1";
|
||||||
PolicyName = "Domestic Policy";
|
PolicyName = "Domestic Policy";
|
||||||
SelectedDomestic = "1";
|
SelectedDomestic = "1";
|
||||||
@ -620,6 +883,7 @@ class _PolicyState extends State<Policy> {
|
|||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
_clearError("trip_type");
|
||||||
_selectedTripType = "2";
|
_selectedTripType = "2";
|
||||||
PolicyName = "International Policy";
|
PolicyName = "International Policy";
|
||||||
SelectedDomestic = "0";
|
SelectedDomestic = "0";
|
||||||
|
|||||||
@ -81,6 +81,27 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loadPolicyDetails(List<Map<String, dynamic>> details) {
|
||||||
|
for (var item in details) {
|
||||||
|
final serviceId = item['service_id'].toString();
|
||||||
|
|
||||||
|
costController[serviceId] =
|
||||||
|
TextEditingController(text: item['cost'] ?? '');
|
||||||
|
classController[serviceId] =
|
||||||
|
TextEditingController(text: item['class'] ?? '');
|
||||||
|
|
||||||
|
FirstApproverAction[serviceId] = item['a1_action']?.toString();
|
||||||
|
SecondApproverAction[serviceId] = item['a2_action']?.toString();
|
||||||
|
ThirdApproverAction[serviceId] = item['a3_action']?.toString();
|
||||||
|
SelectedParallelProcess[serviceId] =
|
||||||
|
item['parallel_process_from']?.toString() ?? "3";
|
||||||
|
}
|
||||||
|
|
||||||
|
policyData = details;
|
||||||
|
widget.onPolicyDataChanged(policyData);
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
void addOrUpdatePolicy(String serviceId) {
|
void addOrUpdatePolicy(String serviceId) {
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
"service_id": serviceId,
|
"service_id": serviceId,
|
||||||
@ -161,7 +182,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
widget.isDesktop ? SizedBox(height: 10) : SizedBox(height: 5),
|
// widget.isDesktop ? SizedBox(height: 10) : SizedBox(height: 5),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -175,7 +196,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (widget.isClass!)
|
if (widget.isClass!)
|
||||||
widget.isDesktop ? SizedBox(height: 15) : SizedBox(height: 5),
|
widget.isDesktop ? SizedBox(height: 5) : SizedBox(height: 5),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(right: 18.0),
|
padding: const EdgeInsets.only(right: 18.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -231,7 +252,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
// color: Color(0xFFEBEBF7),
|
// color: Color(0xFFEBEBF7),
|
||||||
// ),
|
// ),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
color: Colors.brown.shade200,
|
// color: Colors.brown.shade200,
|
||||||
),
|
),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
@ -241,7 +262,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.grey.shade100,
|
// color: Colors.grey.shade100,
|
||||||
width: widget.isDesktop
|
width: widget.isDesktop
|
||||||
? MediaQuery.of(context).size.width * 0.63
|
? MediaQuery.of(context).size.width * 0.63
|
||||||
: 600,
|
: 600,
|
||||||
@ -250,11 +271,11 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.only(right: 0),
|
margin: const EdgeInsets.only(right: 0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.grey.shade100,
|
// color: Colors.grey.shade100,
|
||||||
border: Border.all(
|
// border: Border.all(
|
||||||
color: Colors.grey.shade100,
|
// color: Colors.grey.shade100,
|
||||||
),
|
// ),
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
top: 10, bottom: 10, left: 35, right: 35),
|
top: 10, bottom: 10, left: 35, right: 35),
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -262,19 +283,25 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
? MainAxisAlignment.spaceAround
|
? MainAxisAlignment.spaceAround
|
||||||
: MainAxisAlignment.spaceBetween,
|
: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Expanded(
|
||||||
"Approver Name",
|
flex: 2,
|
||||||
style: TextStyle(
|
child: Text(
|
||||||
color: Color(0xFF9E9DBD),
|
"Approver Name",
|
||||||
fontWeight: FontWeight.bold,
|
style: TextStyle(
|
||||||
fontSize: 12),
|
color: Color(0xFF9E9DBD),
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 12),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Expanded(
|
||||||
"Notification",
|
flex: 2,
|
||||||
style: TextStyle(
|
child: Text(
|
||||||
color: Color(0xFF9E9DBD),
|
"Notification",
|
||||||
fontWeight: FontWeight.bold,
|
style: TextStyle(
|
||||||
fontSize: 12),
|
color: Color(0xFF9E9DBD),
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 12),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"Select",
|
"Select",
|
||||||
@ -286,22 +313,28 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Divider(
|
||||||
|
thickness: 0.2,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 200,
|
height: 180,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
scrollDirection: Axis.vertical,
|
scrollDirection: Axis.vertical,
|
||||||
child: Container(
|
child: Container(
|
||||||
// color: Colors.grey,
|
// color: Colors.grey,
|
||||||
margin: const EdgeInsets.only(right: 20),
|
margin: const EdgeInsets.only(
|
||||||
color: Colors.grey.shade100,
|
right: 20, left: 20),
|
||||||
|
// color: Colors.grey.shade100,
|
||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
MainAxisAlignment.spaceAround,
|
MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
Text("Approver 1"),
|
Text("Approver 1"),
|
||||||
|
Spacer(),
|
||||||
CustomTextFieldUserWrapper(
|
CustomTextFieldUserWrapper(
|
||||||
isFocused: false,
|
isFocused: false,
|
||||||
isDesktop: widget.isDesktop,
|
isDesktop: widget.isDesktop,
|
||||||
@ -318,6 +351,23 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
.loose, // Allows flexible height
|
.loose, // Allows flexible height
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
maxHeight: 250),
|
maxHeight: 250),
|
||||||
|
itemBuilder: (context, item,
|
||||||
|
isSelected) =>
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets
|
||||||
|
.symmetric(
|
||||||
|
horizontal: 16.0,
|
||||||
|
vertical: 8.0),
|
||||||
|
child: Text(
|
||||||
|
item,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize:
|
||||||
|
12, // 👈 Smaller text size here
|
||||||
|
color: Colors
|
||||||
|
.black, // You can customize this
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
items: [
|
items: [
|
||||||
"Approval",
|
"Approval",
|
||||||
@ -366,6 +416,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Spacer(),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -408,9 +459,10 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
MainAxisAlignment.spaceAround,
|
MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
Text("Approver 2"),
|
Text("Approver 2"),
|
||||||
|
Spacer(),
|
||||||
CustomTextFieldUserWrapper(
|
CustomTextFieldUserWrapper(
|
||||||
isFocused: false,
|
isFocused: false,
|
||||||
isDesktop: widget.isDesktop,
|
isDesktop: widget.isDesktop,
|
||||||
@ -427,6 +479,23 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
.loose, // Allows flexible height
|
.loose, // Allows flexible height
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
maxHeight: 250),
|
maxHeight: 250),
|
||||||
|
itemBuilder: (context, item,
|
||||||
|
isSelected) =>
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets
|
||||||
|
.symmetric(
|
||||||
|
horizontal: 16.0,
|
||||||
|
vertical: 8.0),
|
||||||
|
child: Text(
|
||||||
|
item,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize:
|
||||||
|
12, // 👈 Smaller text size here
|
||||||
|
color: Colors
|
||||||
|
.black, // You can customize this
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
items: [
|
items: [
|
||||||
"Approval",
|
"Approval",
|
||||||
@ -475,6 +544,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Spacer(),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -522,9 +592,10 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
MainAxisAlignment.spaceAround,
|
MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
Text("Approver 3"),
|
Text("Approver 3"),
|
||||||
|
Spacer(),
|
||||||
CustomTextFieldUserWrapper(
|
CustomTextFieldUserWrapper(
|
||||||
isFocused: false,
|
isFocused: false,
|
||||||
isDesktop: widget.isDesktop,
|
isDesktop: widget.isDesktop,
|
||||||
@ -541,6 +612,23 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
.loose, // Allows flexible height
|
.loose, // Allows flexible height
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
maxHeight: 250),
|
maxHeight: 250),
|
||||||
|
itemBuilder: (context, item,
|
||||||
|
isSelected) =>
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets
|
||||||
|
.symmetric(
|
||||||
|
horizontal: 16.0,
|
||||||
|
vertical: 8.0),
|
||||||
|
child: Text(
|
||||||
|
item,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize:
|
||||||
|
12, // 👈 Smaller text size here
|
||||||
|
color: Colors
|
||||||
|
.black, // You can customize this
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
items: [
|
items: [
|
||||||
"Approval",
|
"Approval",
|
||||||
@ -589,6 +677,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Spacer(),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:frontend/Screens/group/group.dart';
|
import 'package:frontend/Screens/group/group.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:responsive_builder/responsive_builder.dart';
|
import 'package:responsive_builder/responsive_builder.dart';
|
||||||
|
|
||||||
|
import '../../config/apiUrl.dart';
|
||||||
import '../../routes/custom_appBar.dart';
|
import '../../routes/custom_appBar.dart';
|
||||||
import '../../routes/custom_drawer.dart';
|
import '../../routes/custom_drawer.dart';
|
||||||
import '../../services/apiService.dart';
|
import '../../services/apiService.dart';
|
||||||
@ -57,10 +61,67 @@ class _PolicyListState extends State<PolicyList> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void deleteGroup(int groupId) {
|
void handleActiveStatus(
|
||||||
setState(() {
|
Map<String, dynamic> policyData,
|
||||||
apiAllGroups?.removeWhere((group) => group['group_id'] == groupId);
|
String policyId,
|
||||||
});
|
String currentStatus,
|
||||||
|
) async {
|
||||||
|
print("Toggling user status - $policyId (Current: $currentStatus)");
|
||||||
|
|
||||||
|
final String apiUrlData =
|
||||||
|
'$apiUrl/api/policy/createOrUpdate'; // API for updating user
|
||||||
|
final String? token = await getToken();
|
||||||
|
|
||||||
|
if (token == null) {
|
||||||
|
print("Error: Token not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle status: If active ("1"), set to inactive ("0"); otherwise, activate ("1")
|
||||||
|
String newStatus = (currentStatus == "1") ? "0" : "1";
|
||||||
|
|
||||||
|
print("STatus 1 - $newStatus");
|
||||||
|
|
||||||
|
final int? selectedPolicyId;
|
||||||
|
|
||||||
|
if (policyId.isNotEmpty) {
|
||||||
|
selectedPolicyId = int.tryParse(policyId);
|
||||||
|
policyData['policy_id'] = selectedPolicyId; // Add only if updating
|
||||||
|
policyData['is_active'] = newStatus; // Add only if updating
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await http.post(
|
||||||
|
Uri.parse(apiUrlData),
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer $token',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: jsonEncode(policyData), // Convert map to JSON
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
print("policyData submitted successfully!");
|
||||||
|
print("Response: ${response.body}");
|
||||||
|
|
||||||
|
loadAllGroups();
|
||||||
|
} else {
|
||||||
|
print("Failed to submit policyData. Status: ${response.statusCode}");
|
||||||
|
print("Error: ${response.body}");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print(" Error submitting policyData: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void deletePolicy(Map<String, dynamic> policydata, policyId, status) {
|
||||||
|
print("policyId : $policyId");
|
||||||
|
print("policystatus: $status");
|
||||||
|
print("policysData: $policydata");
|
||||||
|
|
||||||
|
// handleActiveStatus(groupdata, groupId, status);
|
||||||
|
print("Calling handleActiveStatus with: id=$policyId, status=$status");
|
||||||
|
handleActiveStatus(policydata, policyId.toString(), status.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Future<void> deleteGroupFromApi(int groupId) async {
|
// Future<void> deleteGroupFromApi(int groupId) async {
|
||||||
@ -189,10 +250,11 @@ class _PolicyListState extends State<PolicyList> {
|
|||||||
physics: NeverScrollableScrollPhysics(),
|
physics: NeverScrollableScrollPhysics(),
|
||||||
itemCount: apiAllGroups!.length,
|
itemCount: apiAllGroups!.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final group = apiAllGroups![index];
|
final policy = apiAllGroups![index];
|
||||||
return Card(
|
return Card(
|
||||||
// color: bodyColor,
|
// color: bodyColor,
|
||||||
color: Color(0xFFF5F5F5),
|
// color: Color(0xFFF5F5F5),
|
||||||
|
color: Colors.white,
|
||||||
margin: EdgeInsets.symmetric(vertical: 6, horizontal: 10),
|
margin: EdgeInsets.symmetric(vertical: 6, horizontal: 10),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(12.0),
|
padding: const EdgeInsets.all(12.0),
|
||||||
@ -203,25 +265,53 @@ class _PolicyListState extends State<PolicyList> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text("Group Name: ${group['name']}",
|
child: Text("Policy Name: ${policy['name']}",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13, fontWeight: FontWeight.bold)),
|
fontSize: 13, fontWeight: FontWeight.bold)),
|
||||||
),
|
),
|
||||||
Expanded(flex: 1, child: Text(" ${group['created_on']}")),
|
Expanded(flex: 1, child: Text(" ${policy['created_on']}")),
|
||||||
Expanded(flex: 1, child: Text("${group['created_by']}")),
|
Expanded(flex: 1, child: Text("${policy['created_by']}")),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 4),
|
SizedBox(height: 4),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
TextButton(
|
GestureDetector(
|
||||||
onPressed: () {
|
onTap: () async {
|
||||||
context.go("/CreateGroup", extra: group);
|
final rawId = policy['policy_id'];
|
||||||
|
final intPolicyId = rawId is int
|
||||||
|
? rawId
|
||||||
|
: int.tryParse(rawId.toString()) ?? 0;
|
||||||
|
|
||||||
print("Edit ${group['group_id']} $group");
|
Map<String, dynamic> policyData =
|
||||||
|
await apiService.getSinglePolicy(intPolicyId);
|
||||||
|
|
||||||
|
print("PolicyDATa: $policyData");
|
||||||
|
|
||||||
|
context.go("/Policy", extra: policyData);
|
||||||
},
|
},
|
||||||
child: Text("Edit"),
|
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||||
|
width: 20, height: 15),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 5,
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
final idStr = policy['policy_id'];
|
||||||
|
final id = int.tryParse(idStr.toString());
|
||||||
|
|
||||||
|
if (id == null) {
|
||||||
|
print("group_id is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final status = policy['is_active'];
|
||||||
|
|
||||||
|
deletePolicy(policy, id, status);
|
||||||
|
},
|
||||||
|
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||||
|
width: 20, height: 15),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -69,6 +69,7 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
"user_id": userDetails["user_id"].toString(),
|
"user_id": userDetails["user_id"].toString(),
|
||||||
"name": "${userDetails["first_name"]} ${userDetails["last_name"]}",
|
"name": "${userDetails["first_name"]} ${userDetails["last_name"]}",
|
||||||
"email": userDetails["email"] ?? "",
|
"email": userDetails["email"] ?? "",
|
||||||
|
"role": userDetails["role"] ?? "",
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Error decoding user data: $e");
|
print("Error decoding user data: $e");
|
||||||
@ -99,11 +100,19 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
selectedOrg!['color'].toString().replaceFirst('0x', ''),
|
selectedOrg!['color'].toString().replaceFirst('0x', ''),
|
||||||
radix: 16))
|
radix: 16))
|
||||||
: Colors.blue;
|
: Colors.blue;
|
||||||
|
|
||||||
|
String? rawLogoPath = selectedOrg?['logo'];
|
||||||
|
if (rawLogoPath != null && rawLogoPath.contains('/assets')) {
|
||||||
|
const baseUrl = "https://apitest.tripapprovaltool.com";
|
||||||
|
final assetPath = rawLogoPath.split('/assets').last;
|
||||||
|
selectedOrg!['logo'] = "$baseUrl/assets$assetPath";
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Save to SharedPreferences
|
// Save to SharedPreferences
|
||||||
await prefs.setString('layout_color', selectedOrg?['layout_color']);
|
await prefs.setString('layout_color', selectedOrg?['layout_color']);
|
||||||
await prefs.setString('body_color', selectedOrg?['color']);
|
await prefs.setString('body_color', selectedOrg?['color']);
|
||||||
|
await prefs.setString('body_color', selectedOrg?['plan_action']);
|
||||||
|
|
||||||
print(
|
print(
|
||||||
"Layout Color- ${selectedOrg?['layout_color']} - $layoutColor ---------- bodyColor - $bodyColor");
|
"Layout Color- ${selectedOrg?['layout_color']} - $layoutColor ---------- bodyColor - $bodyColor");
|
||||||
@ -128,12 +137,27 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Image.asset(
|
selectedOrg?['logo'] != null
|
||||||
'assets/images/login/travelSpend_Logo.png',
|
? ClipOval(
|
||||||
width: 160,
|
child: Image.network(
|
||||||
height: 40,
|
selectedOrg!['logo'],
|
||||||
fit: BoxFit.contain,
|
width: 50,
|
||||||
),
|
height: 50,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder: (context, error, stackTrace) {
|
||||||
|
return const CircleAvatar(
|
||||||
|
radius: 20,
|
||||||
|
backgroundColor: Colors.redAccent,
|
||||||
|
child: Icon(Icons.error, size: 10),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const CircleAvatar(
|
||||||
|
radius: 20,
|
||||||
|
backgroundColor: Colors.amber,
|
||||||
|
child: Icon(Icons.add_a_photo, size: 10),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -157,33 +181,36 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Row(
|
MouseRegion(
|
||||||
children: [
|
cursor: SystemMouseCursors.click,
|
||||||
GestureDetector(
|
child: Row(
|
||||||
onTap: () {
|
children: [
|
||||||
print("ONTAP Custom");
|
GestureDetector(
|
||||||
print("ONTAP Custom- $userDetails ");
|
onTap: () {
|
||||||
context.go(
|
print("ONTAP Custom");
|
||||||
"/CreateUserDetails",
|
print("ONTAP Custom- $userDetails ");
|
||||||
extra: {
|
context.go(
|
||||||
"selectedUser": userDetails,
|
"/CreateUserDetails",
|
||||||
"isEditProfile": true,
|
extra: {
|
||||||
"isViewMode": true
|
"selectedUser": userDetails,
|
||||||
},
|
"isEditProfile": true,
|
||||||
);
|
"isViewMode": true
|
||||||
},
|
},
|
||||||
child: Text(
|
);
|
||||||
userData?["name"] ?? "N/A",
|
},
|
||||||
style: TextStyle(
|
child: Text(
|
||||||
fontSize: 13,
|
userData?["name"] ?? "N/A",
|
||||||
fontWeight: FontWeight.w600,
|
style: TextStyle(
|
||||||
fontFamily: "Archivo",
|
fontSize: 13,
|
||||||
// color: Color(0xFF12B24B),
|
fontWeight: FontWeight.w600,
|
||||||
color: layoutColor,
|
fontFamily: "Archivo",
|
||||||
|
// color: Color(0xFF12B24B),
|
||||||
|
color: layoutColor,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -247,60 +274,51 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 15,
|
height: 15,
|
||||||
),
|
),
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"Components",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontFamily: "Archivo",
|
|
||||||
color: Colors.black87,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
SizedBox(
|
|
||||||
height: 10,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
_buildDrawerItem(context, Icons.home_outlined, 'Home', '/home'),
|
_buildDrawerItem(context, Icons.home_outlined, 'Home', '/home'),
|
||||||
_buildExpandableItem(
|
_buildDrawerItem(context, Icons.request_page_outlined,
|
||||||
|
'My Travel Request', '/listPlan'),
|
||||||
|
_buildDrawerItem(context, Icons.assessment_outlined, 'My Approvals',
|
||||||
|
'/ApprovalList'),
|
||||||
|
if (userData?["role"] != "User")
|
||||||
|
_buildDrawerItem(context, Icons.account_circle_outlined,
|
||||||
|
'User List', '/listUser'),
|
||||||
|
// _buildExpandableItem(
|
||||||
|
// context,
|
||||||
|
// Icons.assessment_outlined,
|
||||||
|
// 'Plans',
|
||||||
|
// [
|
||||||
|
// _buildSubDrawerItem(
|
||||||
|
// context, 'My Travel Request', '/listPlan'),
|
||||||
|
// _buildSubDrawerItem(context, 'My Approvals', '/ApprovalList')
|
||||||
|
// ],
|
||||||
|
// '/listPlan'),
|
||||||
|
//
|
||||||
|
// _buildExpandableItem(
|
||||||
|
// context,
|
||||||
|
// Icons.account_circle_outlined,
|
||||||
|
// 'User ',
|
||||||
|
// [
|
||||||
|
// _buildSubDrawerItem(context, 'User List', '/listUser'),
|
||||||
|
// // _buildSubDrawerItem(context,'PlanB','/PlanB')
|
||||||
|
// ],
|
||||||
|
// '/listUser'),
|
||||||
|
if (userData?["role"] != "User")
|
||||||
|
_buildExpandableItem(
|
||||||
context,
|
context,
|
||||||
Icons.assessment_outlined,
|
Icons.settings_outlined,
|
||||||
'Plans',
|
'Settings ',
|
||||||
[
|
[
|
||||||
_buildSubDrawerItem(
|
_buildSubDrawerItem(
|
||||||
context, 'My Travel Request', '/listPlan'),
|
context, 'Organization', '/OrganizationSetup'),
|
||||||
_buildSubDrawerItem(context, 'My Approvals', '/ApprovalList')
|
_buildSubDrawerItem(context, 'Group', '/group'),
|
||||||
],
|
_buildSubDrawerItem(context, 'Policy', '/PolicyList'),
|
||||||
'/listPlan'),
|
|
||||||
_buildExpandableItem(
|
|
||||||
context,
|
|
||||||
Icons.account_circle_outlined,
|
|
||||||
'User ',
|
|
||||||
[
|
|
||||||
_buildSubDrawerItem(context, 'User List', '/listUser'),
|
|
||||||
// _buildSubDrawerItem(context,'PlanB','/PlanB')
|
// _buildSubDrawerItem(context,'PlanB','/PlanB')
|
||||||
],
|
],
|
||||||
'/listUser'),
|
'/OrganizationSetup',
|
||||||
_buildExpandableItem(
|
),
|
||||||
context,
|
|
||||||
Icons.settings_outlined,
|
|
||||||
'Settings ',
|
|
||||||
[
|
|
||||||
_buildSubDrawerItem(
|
|
||||||
context, 'Organization', '/OrganizationSetup'),
|
|
||||||
_buildSubDrawerItem(context, 'Group', '/group'),
|
|
||||||
_buildSubDrawerItem(context, 'Policy', '/PolicyList'),
|
|
||||||
// _buildSubDrawerItem(context,'PlanB','/PlanB')
|
|
||||||
],
|
|
||||||
'/OrganizationSetup',
|
|
||||||
),
|
|
||||||
_buildDrawerItem(context, Icons.login_outlined, 'Logout', '/'),
|
_buildDrawerItem(context, Icons.login_outlined, 'Logout', '/'),
|
||||||
if (widget.isDesktop) Spacer(),
|
if (widget.isDesktop) Spacer(),
|
||||||
Container(
|
Container(
|
||||||
@ -400,7 +418,7 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
title: Text(
|
title: Text(
|
||||||
title,
|
title,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF475569),
|
color: Color(0xFF475569),
|
||||||
fontFamily: "Archivo"),
|
fontFamily: "Archivo"),
|
||||||
@ -450,7 +468,7 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF475569),
|
color: Color(0xFF475569),
|
||||||
fontFamily: "Archivo",
|
fontFamily: "Archivo",
|
||||||
|
|||||||
@ -63,7 +63,10 @@ final GoRouter router = GoRouter(
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/Policy',
|
path: '/Policy',
|
||||||
builder: (context, state) => Policy(),
|
// builder: (context, state) => Policy(),
|
||||||
|
pageBuilder: (context, state) => MaterialPage(
|
||||||
|
child: Policy.fromState(state),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/PolicyList',
|
path: '/PolicyList',
|
||||||
|
|||||||
@ -265,6 +265,44 @@ class ApiService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Map<String, dynamic>> getSinglePolicy(int policyId) async {
|
||||||
|
final String apiUrldata = '$apiUrl/api/policy/find/${policyId}';
|
||||||
|
|
||||||
|
final token = await getToken();
|
||||||
|
|
||||||
|
if (token == null) {
|
||||||
|
throw Exception('Token not found. Please log in.');
|
||||||
|
}
|
||||||
|
|
||||||
|
final response = await http.get(
|
||||||
|
Uri.parse(apiUrldata),
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer $token',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
try {
|
||||||
|
final data = json.decode(response.body);
|
||||||
|
print(data);
|
||||||
|
if (!data.containsKey('data') || data['data'] is! Map) {
|
||||||
|
throw Exception(
|
||||||
|
"Invalid response format: 'data' field is missing or not a Map");
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> plansJson =
|
||||||
|
data['data']; // 'data' is a Map, not a List
|
||||||
|
|
||||||
|
return plansJson;
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception('Error parsing response: $e');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception('Failed to load plans');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> fetchOrganization() async {
|
Future<Map<String, dynamic>> fetchOrganization() async {
|
||||||
String? orgId = await getOrgId();
|
String? orgId = await getOrgId();
|
||||||
|
|
||||||
|
|||||||
@ -47,6 +47,21 @@ Future<String?> getOrgId() async {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<String?> getTripPlanAction() async {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
final String? userDataString = prefs.getString('user_data');
|
||||||
|
|
||||||
|
if (userDataString != null) {
|
||||||
|
try {
|
||||||
|
final Map<String, dynamic> userData = jsonDecode(userDataString);
|
||||||
|
return userData["plan_action"]?.toString();
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<Map<String, dynamic>>?> getUserServices() async {
|
Future<List<Map<String, dynamic>>?> getUserServices() async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
final String? userDataString = prefs.getString('user_data');
|
final String? userDataString = prefs.getString('user_data');
|
||||||
|
|||||||
@ -47,7 +47,6 @@ dependencies:
|
|||||||
image_picker: ^1.1.2
|
image_picker: ^1.1.2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user