user mangement bugs
This commit is contained in:
parent
7c9968c159
commit
b246c79789
File diff suppressed because it is too large
Load Diff
@ -156,6 +156,8 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
_emailController.clear();
|
||||||
|
_passwordController.clear();
|
||||||
// Fluttertoast.showToast(
|
// Fluttertoast.showToast(
|
||||||
// msg: "Login Failed: $errorMessage",
|
// msg: "Login Failed: $errorMessage",
|
||||||
// toastLength: Toast.LENGTH_LONG,
|
// toastLength: Toast.LENGTH_LONG,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -15,8 +15,6 @@ import '../../utils/auth_utils.dart';
|
|||||||
import '../../utils/pagination.dart';
|
import '../../utils/pagination.dart';
|
||||||
import 'groupDetails.dart';
|
import 'groupDetails.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class GroupList extends StatefulWidget {
|
class GroupList extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
_GroupListState createState() => _GroupListState();
|
_GroupListState createState() => _GroupListState();
|
||||||
@ -39,7 +37,6 @@ class _GroupListState extends State<GroupList> {
|
|||||||
List filteredGroups = [];
|
List filteredGroups = [];
|
||||||
TextEditingController searchController = TextEditingController();
|
TextEditingController searchController = TextEditingController();
|
||||||
|
|
||||||
|
|
||||||
int currentPage = 0;
|
int currentPage = 0;
|
||||||
int itemsPerPage = 10;
|
int itemsPerPage = 10;
|
||||||
|
|
||||||
@ -71,14 +68,14 @@ class _GroupListState extends State<GroupList> {
|
|||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
layoutColor =
|
layoutColor =
|
||||||
layoutString != null
|
layoutString != null
|
||||||
? Color(int.parse(layoutString))
|
? Color(int.parse(layoutString))
|
||||||
: Colors.redAccent;
|
: Colors.redAccent;
|
||||||
|
|
||||||
bodyColor =
|
bodyColor =
|
||||||
bodyStringColor != null
|
bodyStringColor != null
|
||||||
? Color(int.parse(bodyStringColor))
|
? Color(int.parse(bodyStringColor))
|
||||||
: Colors.white;
|
: Colors.white;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,15 +84,11 @@ class _GroupListState extends State<GroupList> {
|
|||||||
return prefs.getString('auth_token');
|
return prefs.getString('auth_token');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Future<List<dynamic>> fetchGroups() async {
|
Future<List<dynamic>> fetchGroups() async {
|
||||||
final result = await apiService.fetchAllGroup();
|
final result = await apiService.fetchAllGroup();
|
||||||
return result; // Returning raw JSON list
|
return result; // Returning raw JSON list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<void> loadAllGroups() async {
|
Future<void> loadAllGroups() async {
|
||||||
try {
|
try {
|
||||||
final result = await apiService.fetchAllGroup();
|
final result = await apiService.fetchAllGroup();
|
||||||
@ -116,14 +109,21 @@ class _GroupListState extends State<GroupList> {
|
|||||||
filteredGroups =
|
filteredGroups =
|
||||||
allGroups.where((group) {
|
allGroups.where((group) {
|
||||||
return (group['name']?.toLowerCase().contains(lowerQuery) ??
|
return (group['name']?.toLowerCase().contains(lowerQuery) ??
|
||||||
false) ||
|
|
||||||
(group['domestic_policy_name']?.toLowerCase().contains(lowerQuery) ??
|
|
||||||
false)
|
|
||||||
(group['international_policy_name']?.toLowerCase().contains(lowerQuery) ??
|
|
||||||
false) ||
|
false) ||
|
||||||
|
(group['domestic_policy_name']?.toLowerCase().contains(
|
||||||
|
lowerQuery,
|
||||||
|
) ??
|
||||||
|
false)(
|
||||||
|
group['international_policy_name']?.toLowerCase().contains(
|
||||||
|
lowerQuery,
|
||||||
|
) ??
|
||||||
|
false,
|
||||||
|
) ||
|
||||||
(group['description']?.toLowerCase().contains(lowerQuery) ??
|
(group['description']?.toLowerCase().contains(lowerQuery) ??
|
||||||
false) ||
|
false) ||
|
||||||
(group['is_active']?.toLowerCase().contains(lowerQuery) ?? false);}).toList();
|
(group['is_active']?.toLowerCase().contains(lowerQuery) ??
|
||||||
|
false);
|
||||||
|
}).toList();
|
||||||
currentPage = 0;
|
currentPage = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -131,10 +131,10 @@ class _GroupListState extends State<GroupList> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void handleActiveStatus(
|
void handleActiveStatus(
|
||||||
Map<String, dynamic> groupData,
|
Map<String, dynamic> groupData,
|
||||||
String groupId,
|
String groupId,
|
||||||
String currentStatus,
|
String currentStatus,
|
||||||
) async {
|
) async {
|
||||||
print("Toggling group status - $groupId (Current: $currentStatus)");
|
print("Toggling group status - $groupId (Current: $currentStatus)");
|
||||||
|
|
||||||
final String apiUrlData =
|
final String apiUrlData =
|
||||||
@ -159,7 +159,7 @@ class _GroupListState extends State<GroupList> {
|
|||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: jsonEncode({
|
body: jsonEncode({
|
||||||
"is_active": newStatus // Set new status dynamically
|
"is_active": newStatus, // Set new status dynamically
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -189,7 +189,6 @@ class _GroupListState extends State<GroupList> {
|
|||||||
loadAllGroups();
|
loadAllGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
@ -203,21 +202,17 @@ class _GroupListState extends State<GroupList> {
|
|||||||
drawer: CustomDrawer(isDesktop: false),
|
drawer: CustomDrawer(isDesktop: false),
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding:
|
padding:
|
||||||
isDesktop
|
isDesktop
|
||||||
? EdgeInsets.symmetric(
|
? EdgeInsets.symmetric(
|
||||||
horizontal:
|
horizontal:
|
||||||
MediaQuery.of(context).size.width *
|
MediaQuery.of(context).size.width *
|
||||||
0.1, // 30% of screen width as horizontal padding
|
0.1, // 30% of screen width as horizontal padding
|
||||||
vertical:
|
vertical:
|
||||||
MediaQuery.of(context).size.height *
|
MediaQuery.of(context).size.height *
|
||||||
0, // 5% of screen height as vertical padding
|
0, // 5% of screen height as vertical padding
|
||||||
)
|
)
|
||||||
: EdgeInsets.all(0),
|
: EdgeInsets.all(0),
|
||||||
child: Row(
|
child: Row(children: [Expanded(child: buildGroupList(isDesktop))]),
|
||||||
children: [
|
|
||||||
Expanded(child: buildGroupList(isDesktop)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -250,9 +245,9 @@ class _GroupListState extends State<GroupList> {
|
|||||||
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
|
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
|
||||||
// padding: const EdgeInsets.all(10),
|
// padding: const EdgeInsets.all(10),
|
||||||
height:
|
height:
|
||||||
isDesktop
|
isDesktop
|
||||||
? MediaQuery.of(context).size.height * 0.98
|
? MediaQuery.of(context).size.height * 0.98
|
||||||
: MediaQuery.of(context).size.height,
|
: MediaQuery.of(context).size.height,
|
||||||
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(10.0),
|
padding: const EdgeInsets.all(10.0),
|
||||||
@ -342,23 +337,22 @@ class _GroupListState extends State<GroupList> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
// List<dynamic> groups = await futureGroups;
|
// List<dynamic> groups = await futureGroups;
|
||||||
// context.go('/CreateGroup');
|
// context.go('/CreateGroup');
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => GroupData(
|
builder:
|
||||||
isDesktop: isDesktop,
|
(context) => GroupData(
|
||||||
groupId: null,
|
isDesktop: isDesktop,
|
||||||
layoutColor: layoutColor!,
|
groupId: null,
|
||||||
fetchGetGroup: refreshData
|
layoutColor: layoutColor!,
|
||||||
),
|
fetchGetGroup: refreshData,
|
||||||
);
|
),
|
||||||
|
);
|
||||||
|
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize:
|
mainAxisSize:
|
||||||
MainAxisSize.min, // Ensures content fits nicely
|
MainAxisSize.min, // Ensures content fits nicely
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Add New Group",
|
"Add New Group",
|
||||||
@ -382,49 +376,49 @@ class _GroupListState extends State<GroupList> {
|
|||||||
isDesktop
|
isDesktop
|
||||||
? SizedBox.shrink()
|
? SizedBox.shrink()
|
||||||
: Row(
|
: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
width: MediaQuery.of(context).size.width * 0.8,
|
width: MediaQuery.of(context).size.width * 0.8,
|
||||||
height: 35,
|
height: 35,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: searchController,
|
controller: searchController,
|
||||||
onChanged: filterGroups,
|
onChanged: filterGroups,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "Search for a Group",
|
hintText: "Search for a Group",
|
||||||
hintStyle: TextStyle(
|
hintStyle: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: Color(0xFF9E9DBD),
|
color: Color(0xFF9E9DBD),
|
||||||
),
|
),
|
||||||
prefixIcon: Icon(
|
prefixIcon: Icon(
|
||||||
Icons.search,
|
Icons.search,
|
||||||
color: Color(0xFF9E9DBD),
|
color: Color(0xFF9E9DBD),
|
||||||
size: 18,
|
size: 18,
|
||||||
),
|
),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Colors.grey.shade200,
|
color: Colors.grey.shade200,
|
||||||
width: 0.5,
|
width: 0.5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Colors.grey.shade300,
|
color: Colors.grey.shade300,
|
||||||
width: 1,
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
style: GoogleFonts.poppins(fontSize: 12),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
style: GoogleFonts.poppins(fontSize: 12),
|
// SizedBox(width: 16),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
// SizedBox(width: 16),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
FutureBuilder<List<dynamic>>(
|
FutureBuilder<List<dynamic>>(
|
||||||
future: futureGroups,
|
future: futureGroups,
|
||||||
@ -467,7 +461,7 @@ class _GroupListState extends State<GroupList> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<dynamic> groups =
|
List<dynamic> groups =
|
||||||
filteredGroups.isNotEmpty ? filteredGroups : allGroups;
|
filteredGroups.isNotEmpty ? filteredGroups : allGroups;
|
||||||
|
|
||||||
groups.sort((a, b) {
|
groups.sort((a, b) {
|
||||||
DateTime dateA = DateTime.parse(a['created_on']);
|
DateTime dateA = DateTime.parse(a['created_on']);
|
||||||
@ -477,10 +471,10 @@ class _GroupListState extends State<GroupList> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
List paginatedGroup =
|
List paginatedGroup =
|
||||||
groups
|
groups
|
||||||
.skip(currentPage * itemsPerPage)
|
.skip(currentPage * itemsPerPage)
|
||||||
.take(itemsPerPage)
|
.take(itemsPerPage)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
Widget table = LayoutBuilder(
|
Widget table = LayoutBuilder(
|
||||||
builder: (context, constraints) {
|
builder: (context, constraints) {
|
||||||
@ -554,128 +548,146 @@ class _GroupListState extends State<GroupList> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
rows:
|
rows:
|
||||||
paginatedGroup.map((group) {
|
paginatedGroup.map((group) {
|
||||||
String groupId =
|
String groupId =
|
||||||
group['group_id'].toString(); // Get group ID
|
group['group_id']
|
||||||
bool isSelected = selectedGroupId == groupId;
|
.toString(); // Get group ID
|
||||||
|
bool isSelected = selectedGroupId == groupId;
|
||||||
|
|
||||||
return DataRow(
|
return DataRow(
|
||||||
cells: [
|
cells: [
|
||||||
DataCell(
|
DataCell(
|
||||||
Text(
|
Text(
|
||||||
"${group['name'] ?? ''}",
|
"${group['name'] ?? ''}",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
DataCell(
|
||||||
),
|
Text(
|
||||||
DataCell(
|
"${group['domestic_policy_name'] ?? 'N/A'}",
|
||||||
Text("${group['domestic_policy_name'] ?? 'N/A'}",
|
style: TextStyle(
|
||||||
style: TextStyle(
|
fontSize: 13,
|
||||||
fontSize: 13,
|
fontFamily: "Inter",
|
||||||
fontFamily: "Inter",
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
DataCell(
|
||||||
),
|
Text(
|
||||||
DataCell(
|
"${group['international_policy_name'] ?? 'N/A'}",
|
||||||
Text(
|
style: TextStyle(
|
||||||
"${group['international_policy_name'] ?? 'N/A'}",
|
fontSize: 13,
|
||||||
style: TextStyle(
|
fontFamily: "Inter",
|
||||||
fontSize: 13,
|
),
|
||||||
fontFamily: "Inter",
|
),
|
||||||
),
|
),
|
||||||
),
|
DataCell(
|
||||||
),
|
Text(
|
||||||
DataCell(
|
"${group['description'] ?? 'N/A'}",
|
||||||
Text(
|
style: TextStyle(
|
||||||
"${group['description'] ?? 'N/A'}",
|
fontSize: 13,
|
||||||
style: TextStyle(
|
fontFamily: "Inter",
|
||||||
fontSize: 13,
|
),
|
||||||
fontFamily: "Inter",
|
),
|
||||||
),
|
),
|
||||||
),
|
DataCell(
|
||||||
),
|
Text(
|
||||||
DataCell(
|
|
||||||
Text(
|
|
||||||
group['is_active'] == "1"
|
|
||||||
? "Active"
|
|
||||||
: "Inactive",
|
|
||||||
style: TextStyle(
|
|
||||||
color:
|
|
||||||
group['is_active'] == "1"
|
group['is_active'] == "1"
|
||||||
? Colors.green
|
? "Active"
|
||||||
: Colors.grey,
|
: "Inactive",
|
||||||
fontFamily: "Inter",
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w400,
|
color:
|
||||||
|
group['is_active'] == "1"
|
||||||
|
? Colors.green
|
||||||
|
: Colors.grey,
|
||||||
|
fontFamily: "Inter",
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
DataCell(
|
||||||
DataCell(
|
Row(
|
||||||
Row(
|
mainAxisAlignment:
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
if (group['group_id'] != null) {
|
if (group['group_id'] != null) {
|
||||||
final newGroupID = int.tryParse(
|
final newGroupID = int.tryParse(
|
||||||
group['group_id'].toString());
|
group['group_id'].toString(),
|
||||||
if (newGroupID != null) {
|
);
|
||||||
final data = await apiService.getGroupDetailsFind(
|
if (newGroupID != null) {
|
||||||
newGroupID); // ✅ Always an int
|
final data = await apiService
|
||||||
showDialog(
|
.getGroupDetailsFind(
|
||||||
context: context,
|
newGroupID,
|
||||||
builder: (context) =>
|
); // ✅ Always an int
|
||||||
GroupData(
|
showDialog(
|
||||||
isDesktop: isDesktop,
|
context: context,
|
||||||
groupId: newGroupID,
|
builder:
|
||||||
// Pass the ID
|
(context) => GroupData(
|
||||||
groupData: data,
|
isDesktop: isDesktop,
|
||||||
layoutColor: layoutColor!,
|
groupId: newGroupID,
|
||||||
fetchGetGroup: refreshData
|
// Pass the ID
|
||||||
),
|
groupData: data,
|
||||||
|
layoutColor:
|
||||||
|
layoutColor!,
|
||||||
|
fetchGetGroup:
|
||||||
|
refreshData,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print(
|
||||||
|
"something went wrong check properly",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// onTap: () {
|
||||||
|
// context.go("/CreateGroup", extra: group);
|
||||||
|
// },
|
||||||
|
child: Tooltip(
|
||||||
|
message: 'Edit Group Details',
|
||||||
|
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(),
|
||||||
);
|
);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print("something went wrong check properly");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// onTap: () {
|
if (id == null) {
|
||||||
// context.go("/CreateGroup", extra: group);
|
print("group_id is null");
|
||||||
// },
|
return;
|
||||||
child: Tooltip(
|
}
|
||||||
message: 'Edit Group Details',
|
final status = group['is_active'];
|
||||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
// print("GroupId : ${group['group_id']} ");
|
||||||
width: 20, height: 15), ),
|
deleteGroup(group, id, status);
|
||||||
|
},
|
||||||
|
child: Tooltip(
|
||||||
|
message: 'Delete Group Details',
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/IconsImg/delete.png',
|
||||||
|
width: 20,
|
||||||
|
height: 15,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
SizedBox(
|
),
|
||||||
width: 5,
|
],
|
||||||
),
|
);
|
||||||
GestureDetector(
|
}).toList(),
|
||||||
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: Tooltip(
|
|
||||||
message: 'Delete Group Details',
|
|
||||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
|
||||||
width: 20, height: 15),),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -688,7 +700,10 @@ class _GroupListState extends State<GroupList> {
|
|||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
margin: EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
margin: EdgeInsets.symmetric(
|
||||||
|
horizontal: 12,
|
||||||
|
vertical: 6,
|
||||||
|
),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
@ -700,7 +715,8 @@ class _GroupListState extends State<GroupList> {
|
|||||||
children: [
|
children: [
|
||||||
// Row 1: Policy Name and Actions
|
// Row 1: Policy Name and Actions
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: RichText(
|
child: RichText(
|
||||||
@ -718,11 +734,12 @@ class _GroupListState extends State<GroupList> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: "${object['name'] ?? 'N/A'}",
|
text:
|
||||||
|
"${object['name'] ?? 'N/A'}",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
fontWeight: FontWeight.normal
|
fontWeight: FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -736,42 +753,54 @@ class _GroupListState extends State<GroupList> {
|
|||||||
onTap: () async {
|
onTap: () async {
|
||||||
if (object['group_id'] != null) {
|
if (object['group_id'] != null) {
|
||||||
final newGroupID = int.tryParse(
|
final newGroupID = int.tryParse(
|
||||||
object['group_id'].toString());
|
object['group_id'].toString(),
|
||||||
|
);
|
||||||
if (newGroupID != null) {
|
if (newGroupID != null) {
|
||||||
final data = await apiService.getGroupDetailsFind(
|
final data = await apiService
|
||||||
newGroupID); // ✅ Always an int
|
.getGroupDetailsFind(
|
||||||
|
newGroupID,
|
||||||
|
); // ✅ Always an int
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) =>
|
builder:
|
||||||
GroupData(
|
(context) => GroupData(
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
groupId: newGroupID,
|
groupId: newGroupID,
|
||||||
// Pass the ID
|
// Pass the ID
|
||||||
groupData: data,
|
groupData: data,
|
||||||
layoutColor: layoutColor!,
|
layoutColor:
|
||||||
fetchGetGroup: refreshData
|
layoutColor!,
|
||||||
|
fetchGetGroup:
|
||||||
|
refreshData,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
print("something went wrong check properly");
|
print(
|
||||||
|
"something went wrong check properly",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// onTap: () {
|
// onTap: () {
|
||||||
// context.go("/CreateGroup", extra: group);
|
// context.go("/CreateGroup", extra: group);
|
||||||
// },
|
// },
|
||||||
child: Tooltip( message: 'Edit Group Details',
|
child: Tooltip(
|
||||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
message: 'Edit Group Details',
|
||||||
width: 20, height: 15),),
|
child: Image.asset(
|
||||||
),
|
'assets/images/IconsImg/edit.png',
|
||||||
SizedBox(
|
width: 20,
|
||||||
width: 5,
|
height: 15,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
SizedBox(width: 5),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
final idStr = object['group_id'];
|
final idStr = object['group_id'];
|
||||||
final id = int.tryParse(idStr.toString());
|
final id = int.tryParse(
|
||||||
|
idStr.toString(),
|
||||||
|
);
|
||||||
|
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
print("group_id is null");
|
print("group_id is null");
|
||||||
@ -783,8 +812,12 @@ class _GroupListState extends State<GroupList> {
|
|||||||
},
|
},
|
||||||
child: Tooltip(
|
child: Tooltip(
|
||||||
message: 'Edit Group Details',
|
message: 'Edit Group Details',
|
||||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
child: Image.asset(
|
||||||
width: 20, height: 15),),
|
'assets/images/IconsImg/delete.png',
|
||||||
|
width: 20,
|
||||||
|
height: 15,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -792,7 +825,6 @@ class _GroupListState extends State<GroupList> {
|
|||||||
),
|
),
|
||||||
|
|
||||||
SizedBox(height: 8), // Spacing
|
SizedBox(height: 8), // Spacing
|
||||||
|
|
||||||
// Row 2:
|
// Row 2:
|
||||||
RichText(
|
RichText(
|
||||||
text: TextSpan(
|
text: TextSpan(
|
||||||
@ -809,18 +841,19 @@ class _GroupListState extends State<GroupList> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: "${object['domestic_policy_name'] ?? 'N/A'}",
|
text:
|
||||||
|
"${object['domestic_policy_name'] ?? 'N/A'}",
|
||||||
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
fontWeight: FontWeight.normal
|
fontWeight: FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 8), // Spacing
|
SizedBox(height: 8), // Spacing
|
||||||
|
|
||||||
// Row 3:
|
// Row 3:
|
||||||
RichText(
|
RichText(
|
||||||
text: TextSpan(
|
text: TextSpan(
|
||||||
@ -837,18 +870,18 @@ class _GroupListState extends State<GroupList> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: "${object['international_policy_name']}",
|
text:
|
||||||
|
"${object['international_policy_name'] ?? 'N/A'}",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
fontWeight: FontWeight.normal
|
fontWeight: FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 8), // Spacing
|
SizedBox(height: 8), // Spacing
|
||||||
|
|
||||||
// Row 4:
|
// Row 4:
|
||||||
RichText(
|
RichText(
|
||||||
text: TextSpan(
|
text: TextSpan(
|
||||||
@ -865,11 +898,12 @@ class _GroupListState extends State<GroupList> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: "${object['description'] ?? 'N/A'}",
|
text:
|
||||||
|
"${object['description'] ?? 'N/A'}",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
fontWeight: FontWeight.normal
|
fontWeight: FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -889,12 +923,12 @@ class _GroupListState extends State<GroupList> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child:
|
child:
|
||||||
isDesktop
|
isDesktop
|
||||||
? SingleChildScrollView(
|
? SingleChildScrollView(
|
||||||
scrollDirection: Axis.vertical,
|
scrollDirection: Axis.vertical,
|
||||||
child: table, // <-- your existing table
|
child: table, // <-- your existing table
|
||||||
)
|
)
|
||||||
: buildMobileCardView(paginatedGroup),
|
: buildMobileCardView(paginatedGroup),
|
||||||
),
|
),
|
||||||
PaginationControls(
|
PaginationControls(
|
||||||
currentPage: currentPage,
|
currentPage: currentPage,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -14,12 +14,13 @@ class TaxiScreen extends StatefulWidget {
|
|||||||
final Map<String, dynamic>? selectedItem;
|
final Map<String, dynamic>? selectedItem;
|
||||||
final String? loginUser;
|
final String? loginUser;
|
||||||
|
|
||||||
TaxiScreen(
|
TaxiScreen({
|
||||||
{required this.onClose,
|
required this.onClose,
|
||||||
this.apiData,
|
this.apiData,
|
||||||
required this.onSavetaxi,
|
required this.onSavetaxi,
|
||||||
required this.selectedItem,
|
required this.selectedItem,
|
||||||
required this.loginUser});
|
required this.loginUser,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_TaxiScreenState createState() => _TaxiScreenState();
|
_TaxiScreenState createState() => _TaxiScreenState();
|
||||||
@ -97,13 +98,17 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
_addFocusListener(
|
_addFocusListener(
|
||||||
_destinationFocusNode, (focus) => _destinationFocus = focus);
|
_destinationFocusNode,
|
||||||
|
(focus) => _destinationFocus = focus,
|
||||||
|
);
|
||||||
_addFocusListener(_locationFocusNode, (focus) => _locationFocus = focus);
|
_addFocusListener(_locationFocusNode, (focus) => _locationFocus = focus);
|
||||||
_addFocusListener(_dateFocusNode, (focus) => _dateFocus = focus);
|
_addFocusListener(_dateFocusNode, (focus) => _dateFocus = focus);
|
||||||
_addFocusListener(_timeFocusNode, (focus) => _timeFocus = focus);
|
_addFocusListener(_timeFocusNode, (focus) => _timeFocus = focus);
|
||||||
_addFocusListener(_taxiReqFocusNode, (focus) => _taxiReqFocused = focus);
|
_addFocusListener(_taxiReqFocusNode, (focus) => _taxiReqFocused = focus);
|
||||||
_addFocusListener(
|
_addFocusListener(
|
||||||
_numPassengerFocusNode, (focus) => _numPassengerFocus = focus);
|
_numPassengerFocusNode,
|
||||||
|
(focus) => _numPassengerFocus = focus,
|
||||||
|
);
|
||||||
_addFocusListener(_commentsFocusNode, (focus) => _commentsFocus = focus);
|
_addFocusListener(_commentsFocusNode, (focus) => _commentsFocus = focus);
|
||||||
|
|
||||||
_destinationController = initController("destination_city");
|
_destinationController = initController("destination_city");
|
||||||
@ -168,7 +173,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
"location_of_pickup",
|
"location_of_pickup",
|
||||||
"no_of_passengers",
|
"no_of_passengers",
|
||||||
"date",
|
"date",
|
||||||
"time"
|
"time",
|
||||||
];
|
];
|
||||||
|
|
||||||
// Check validation for each field
|
// Check validation for each field
|
||||||
@ -199,30 +204,33 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(
|
||||||
bool isMobile = sizingInfo.isMobile;
|
builder: (context, sizingInfo) {
|
||||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
bool isMobile = sizingInfo.isMobile;
|
||||||
|
bool isDesktop =
|
||||||
|
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
// color: Color(0xFFF4F4FB),
|
// color: Color(0xFFF4F4FB),
|
||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(28.0),
|
padding: const EdgeInsets.all(28.0),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Column(children: _buildAccomadtionForm(isDesktop)),
|
child: Column(children: _buildAccomadtionForm(isDesktop)),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
},
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _buildAccomadtionForm(bool isDesktop) {
|
List<Widget> _buildAccomadtionForm(bool isDesktop) {
|
||||||
@ -235,7 +243,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
|
|
||||||
List<List<Widget>> rowBuilders = [
|
List<List<Widget>> rowBuilders = [
|
||||||
// _builClassType(isDesktop),
|
// _builClassType(isDesktop),
|
||||||
_buildSecondRow(isDesktop)
|
_buildSecondRow(isDesktop),
|
||||||
];
|
];
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@ -253,19 +261,24 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
List<Widget> _buildFirstRow(isDesktop) {
|
List<Widget> _buildFirstRow(isDesktop) {
|
||||||
List<dynamic> purposeList = widget.apiData?['taxt_car_type'] ?? [];
|
List<dynamic> purposeList = widget.apiData?['taxt_car_type'] ?? [];
|
||||||
|
|
||||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
List<DropdownMenuItem<String>> dropdownItems =
|
||||||
.map((item) => DropdownMenuItem<String>(
|
purposeList
|
||||||
value: item['dropdown_key'],
|
.map(
|
||||||
child: Text(item['dropdown_value']),
|
(item) => DropdownMenuItem<String>(
|
||||||
))
|
value: item['dropdown_key'],
|
||||||
.toList();
|
child: Text(item['dropdown_value']),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (dropdownItems.isEmpty) {
|
if (dropdownItems.isEmpty) {
|
||||||
dropdownItems.add(
|
dropdownItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
value: null,
|
value: null,
|
||||||
child: Text("No options available",
|
child: Text(
|
||||||
style: TextStyle(color: Colors.grey)),
|
"No options available",
|
||||||
|
style: TextStyle(color: Colors.grey),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -281,31 +294,28 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
Text(
|
Text(
|
||||||
"Taxi Required For",
|
"Taxi Required For",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
isDesktop
|
isDesktop
|
||||||
? Row(children: _buildTripType(isDesktop))
|
? Row(children: _buildTripType(isDesktop))
|
||||||
: Column(children: _buildTripType(isDesktop))
|
: Column(children: _buildTripType(isDesktop)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||||
Spacer()
|
|
||||||
else
|
|
||||||
SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Number of Passenger",
|
"Number of Passenger",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
CustomTextFieldItnerarySubWrapper(
|
CustomTextFieldItnerarySubWrapper(
|
||||||
@ -319,8 +329,9 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||||
inputFormatters: [
|
inputFormatters: [
|
||||||
FilteringTextInputFormatter.allow(RegExp(
|
FilteringTextInputFormatter.allow(
|
||||||
r'^\d*\.?\d*$')), // Allow only positive numbers with optional decimal
|
RegExp(r'^\d*\.?\d*$'),
|
||||||
|
), // Allow only positive numbers with optional decimal
|
||||||
],
|
],
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: "Number of Passenger",
|
labelText: "Number of Passenger",
|
||||||
@ -334,28 +345,21 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
),
|
),
|
||||||
if (errorMessages["no_of_passengers"] != null) ...[
|
if (errorMessages["no_of_passengers"] != null) ...[
|
||||||
SizedBox(height: 5), // Space before error message
|
SizedBox(height: 5), // Space before error message
|
||||||
Text(
|
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
|
||||||
"Required",
|
|
||||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||||
Spacer()
|
|
||||||
else
|
|
||||||
SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Car Type",
|
"Car Type",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
CustomTextFieldItnerarySubWrapper(
|
CustomTextFieldItnerarySubWrapper(
|
||||||
@ -369,18 +373,21 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding:
|
contentPadding: EdgeInsets.symmetric(
|
||||||
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
horizontal: 10,
|
||||||
|
), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: purposeList.isNotEmpty
|
onChanged:
|
||||||
? (newValue) {
|
purposeList.isNotEmpty
|
||||||
setState(() {
|
? (newValue) {
|
||||||
selectedCarType = newValue;
|
setState(() {
|
||||||
});
|
selectedCarType = newValue;
|
||||||
print(
|
});
|
||||||
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}");
|
print(
|
||||||
}
|
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}",
|
||||||
: null,
|
);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
|
||||||
items: dropdownItems,
|
items: dropdownItems,
|
||||||
),
|
),
|
||||||
@ -388,31 +395,31 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop) SizedBox.shrink() else SizedBox(height: 8),
|
||||||
SizedBox.shrink()
|
|
||||||
else
|
|
||||||
SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _buildTripType(bool isDesktop) {
|
List<Widget> _buildTripType(bool isDesktop) {
|
||||||
List<dynamic> purposeList = widget.apiData?['taxi_car_required_for'] ?? [];
|
List<dynamic> purposeList = widget.apiData?['taxi_car_required_for'] ?? [];
|
||||||
|
|
||||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
List<DropdownMenuItem<String>> dropdownItems =
|
||||||
.map((item) => DropdownMenuItem<String>(
|
purposeList
|
||||||
value: item['dropdown_key'],
|
.map(
|
||||||
child: Text(item['dropdown_value']),
|
(item) => DropdownMenuItem<String>(
|
||||||
))
|
value: item['dropdown_key'],
|
||||||
.toList();
|
child: Text(item['dropdown_value']),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (dropdownItems.isEmpty) {
|
if (dropdownItems.isEmpty) {
|
||||||
dropdownItems.add(
|
dropdownItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
value: null,
|
value: null,
|
||||||
child: Text("No options available",
|
child: Text(
|
||||||
style: TextStyle(color: Colors.grey)),
|
"No options available",
|
||||||
|
style: TextStyle(color: Colors.grey),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -425,9 +432,10 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: _taxiReqFocused,
|
isFocused: _taxiReqFocused,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
width: isDesktop
|
width:
|
||||||
? MediaQuery.of(context).size.width * 0.34
|
isDesktop
|
||||||
: MediaQuery.of(context).size.width * 0.66,
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: DropdownButtonFormField<String>(
|
child: DropdownButtonFormField<String>(
|
||||||
@ -436,18 +444,21 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding:
|
contentPadding: EdgeInsets.symmetric(
|
||||||
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
horizontal: 10,
|
||||||
|
), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: purposeList.isNotEmpty
|
onChanged:
|
||||||
? (newValue) {
|
purposeList.isNotEmpty
|
||||||
setState(() {
|
? (newValue) {
|
||||||
selectedReqTaxi = newValue;
|
setState(() {
|
||||||
});
|
selectedReqTaxi = newValue;
|
||||||
print(
|
});
|
||||||
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}");
|
print(
|
||||||
}
|
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}",
|
||||||
: null,
|
);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
|
||||||
items: dropdownItems,
|
items: dropdownItems,
|
||||||
),
|
),
|
||||||
@ -466,10 +477,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
|
|
||||||
DateTime? pickedDate = await showDatePicker(
|
DateTime? pickedDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
initialDate: _selectedCheckOutDate != null &&
|
initialDate:
|
||||||
_selectedCheckOutDate!.isAfter(today)
|
_selectedCheckOutDate != null &&
|
||||||
? _selectedCheckOutDate!
|
_selectedCheckOutDate!.isAfter(today)
|
||||||
: today,
|
? _selectedCheckOutDate!
|
||||||
|
: today,
|
||||||
firstDate: today,
|
firstDate: today,
|
||||||
lastDate: DateTime(2100),
|
lastDate: DateTime(2100),
|
||||||
);
|
);
|
||||||
@ -494,8 +506,13 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
// Formatting time to HH:mm (24-hour format)
|
// Formatting time to HH:mm (24-hour format)
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
final formattedTime = DateFormat('HH:mm').format(
|
final formattedTime = DateFormat('HH:mm').format(
|
||||||
DateTime(now.year, now.month, now.day, pickedTime.hour,
|
DateTime(
|
||||||
pickedTime.minute),
|
now.year,
|
||||||
|
now.month,
|
||||||
|
now.day,
|
||||||
|
pickedTime.hour,
|
||||||
|
pickedTime.minute,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
_timeController.text = formattedTime;
|
_timeController.text = formattedTime;
|
||||||
});
|
});
|
||||||
@ -509,9 +526,10 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
Text(
|
Text(
|
||||||
"City",
|
"City",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
CustomTextFieldItnerarySubWrapper(
|
CustomTextFieldItnerarySubWrapper(
|
||||||
@ -535,28 +553,21 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
),
|
),
|
||||||
if (errorMessages["destination_city"] != null) ...[
|
if (errorMessages["destination_city"] != null) ...[
|
||||||
SizedBox(height: 5), // Space before error message
|
SizedBox(height: 5), // Space before error message
|
||||||
Text(
|
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
|
||||||
"Required",
|
|
||||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||||
Spacer()
|
|
||||||
else
|
|
||||||
SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Location of Pickup",
|
"Pickup Location",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
CustomTextFieldItnerarySubWrapper(
|
CustomTextFieldItnerarySubWrapper(
|
||||||
@ -569,7 +580,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
controller: _locationController,
|
controller: _locationController,
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: "Location of Pickup",
|
labelText: "Pickup Location",
|
||||||
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
@ -580,28 +591,21 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
),
|
),
|
||||||
if (errorMessages["location_of_pickup"] != null) ...[
|
if (errorMessages["location_of_pickup"] != null) ...[
|
||||||
SizedBox(height: 5), // Space before error message
|
SizedBox(height: 5), // Space before error message
|
||||||
Text(
|
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
|
||||||
"Required",
|
|
||||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||||
Spacer()
|
|
||||||
else
|
|
||||||
SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Date",
|
"Date",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
CustomTextFieldItnerarySubWrapper(
|
CustomTextFieldItnerarySubWrapper(
|
||||||
@ -622,8 +626,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
suffixIcon: Icon(Icons.calendar_today,
|
suffixIcon: Icon(
|
||||||
size: 16, color: Colors.grey),
|
Icons.calendar_today,
|
||||||
|
size: 16,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -632,28 +639,21 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
),
|
),
|
||||||
if (errorMessages["date"] != null) ...[
|
if (errorMessages["date"] != null) ...[
|
||||||
SizedBox(height: 5), // Space before error message
|
SizedBox(height: 5), // Space before error message
|
||||||
Text(
|
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
|
||||||
"Required",
|
|
||||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||||
Spacer()
|
|
||||||
else
|
|
||||||
SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Time",
|
"Time",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
CustomTextFieldItnerarySubWrapper(
|
CustomTextFieldItnerarySubWrapper(
|
||||||
@ -674,8 +674,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
suffixIcon:
|
suffixIcon: Icon(
|
||||||
Icon(Icons.access_time, size: 16, color: Colors.grey),
|
Icons.access_time,
|
||||||
|
size: 16,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -684,10 +687,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
),
|
),
|
||||||
if (errorMessages["time"] != null) ...[
|
if (errorMessages["time"] != null) ...[
|
||||||
SizedBox(height: 5), // Space before error message
|
SizedBox(height: 5), // Space before error message
|
||||||
Text(
|
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
|
||||||
"Required",
|
|
||||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -702,17 +702,19 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
Text(
|
Text(
|
||||||
"Comments",
|
"Comments",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
width: isDesktop
|
width:
|
||||||
? MediaQuery.of(context).size.width * 0.34
|
isDesktop
|
||||||
: MediaQuery.of(context).size.width * 0.66,
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
|
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
@ -733,9 +735,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop) Spacer(),
|
if (isDesktop) Spacer(),
|
||||||
SizedBox(
|
SizedBox(height: 5),
|
||||||
height: 5,
|
|
||||||
),
|
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
@ -756,9 +756,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.grey[400], // Light grey color
|
backgroundColor: Colors.grey[400], // Light grey color
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -767,7 +765,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 10), // Space between buttons
|
SizedBox(width: 10), // Space between buttons
|
||||||
|
|
||||||
// Save Changes Button
|
// Save Changes Button
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@ -775,9 +772,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|||||||
@ -85,7 +85,8 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
|||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: const Text('Select Trip Type'),
|
title: const Text('Select Trip Type'),
|
||||||
content: const Text(
|
content: const Text(
|
||||||
'Please select a trip type before adding a flight.'),
|
'Please select a trip type before adding a flight.',
|
||||||
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
@ -118,16 +119,18 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
|||||||
// style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
// style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
// ),
|
// ),
|
||||||
MouseRegion(
|
MouseRegion(
|
||||||
cursor: widget.isViewMode
|
cursor:
|
||||||
? SystemMouseCursors.forbidden
|
widget.isViewMode
|
||||||
: SystemMouseCursors.click,
|
? SystemMouseCursors.forbidden
|
||||||
|
: SystemMouseCursors.click,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: widget.isViewMode
|
onTap:
|
||||||
? null
|
widget.isViewMode
|
||||||
: () {
|
? null
|
||||||
checkClass();
|
: () {
|
||||||
print("New data");
|
checkClass();
|
||||||
},
|
print("New data");
|
||||||
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize:
|
mainAxisSize:
|
||||||
MainAxisSize.min, // Ensures content fits nicely
|
MainAxisSize.min, // Ensures content fits nicely
|
||||||
@ -141,7 +144,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
|||||||
Icons.add_circle_sharp,
|
Icons.add_circle_sharp,
|
||||||
size: 30,
|
size: 30,
|
||||||
color: Color(0xFF114D8B),
|
color: Color(0xFF114D8B),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -149,9 +152,9 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
// Scroll behavior based on device
|
|
||||||
|
|
||||||
_buildData(context, isDesktop)
|
// Scroll behavior based on device
|
||||||
|
_buildData(context, isDesktop),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -224,8 +227,11 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
|||||||
|
|
||||||
if (hour == 24 && minute == 0) {
|
if (hour == 24 && minute == 0) {
|
||||||
// 24:00 is treated as 00:00 on the next day
|
// 24:00 is treated as 00:00 on the next day
|
||||||
dateTime = DateTime(now.year, now.month, now.day)
|
dateTime = DateTime(
|
||||||
.add(const Duration(days: 1));
|
now.year,
|
||||||
|
now.month,
|
||||||
|
now.day,
|
||||||
|
).add(const Duration(days: 1));
|
||||||
} else {
|
} else {
|
||||||
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
|
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
|
||||||
throw FormatException("Invalid hour or minute");
|
throw FormatException("Invalid hour or minute");
|
||||||
@ -245,7 +251,21 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
|||||||
itemCount: filteredList.length,
|
itemCount: filteredList.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final item = filteredList[index];
|
final item = filteredList[index];
|
||||||
|
String? tripTypeName = '';
|
||||||
|
switch (item["trip_type"]?.toString()) {
|
||||||
|
case "Roundtrip":
|
||||||
|
tripTypeName = "Round Trip";
|
||||||
|
break;
|
||||||
|
case "Multitrip":
|
||||||
|
tripTypeName = "Multi-Trip";
|
||||||
|
break;
|
||||||
|
case "Oneway":
|
||||||
|
tripTypeName = "One-Way";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
tripTypeName = item["trip_type"]?.toString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -281,7 +301,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
item["trip_type"]?.toString() ?? "N/A",
|
tripTypeName ?? "N/A",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w800,
|
fontWeight: FontWeight.w800,
|
||||||
@ -313,59 +333,53 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Divider(
|
Divider(color: Colors.blueGrey.shade50),
|
||||||
color: Colors.blueGrey.shade50,
|
|
||||||
),
|
|
||||||
SizedBox(height: 4),
|
SizedBox(height: 4),
|
||||||
if (isDesktop)
|
if (isDesktop)
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text(
|
||||||
"Class",
|
"Class",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(fontSize: 11),
|
||||||
fontSize: 11,
|
),
|
||||||
),
|
),
|
||||||
)),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 4,
|
flex: 4,
|
||||||
child: Text(
|
child: Text(
|
||||||
"Sector",
|
"Sector",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(fontSize: 11),
|
||||||
fontSize: 11,
|
),
|
||||||
),
|
),
|
||||||
)),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text(
|
||||||
"Date",
|
"Date",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(fontSize: 11),
|
||||||
fontSize: 11,
|
),
|
||||||
),
|
),
|
||||||
)),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text(
|
||||||
"Time",
|
"Time",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(fontSize: 11),
|
||||||
fontSize: 11,
|
),
|
||||||
),
|
),
|
||||||
)),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 4),
|
SizedBox(height: 4),
|
||||||
// Trip Rows
|
|
||||||
|
|
||||||
|
// Trip Rows
|
||||||
if (isDesktop)
|
if (isDesktop)
|
||||||
if (item["trips"] != null && item["trips"].isNotEmpty)
|
if (item["trips"] != null && item["trips"].isNotEmpty)
|
||||||
...item["trips"].map<Widget>((trip) {
|
...item["trips"].map<Widget>((trip) {
|
||||||
String fromPlaceCountry =
|
String fromPlaceCountry =
|
||||||
countryMap[trip["from_place"]?.toString()] ??
|
countryMap[trip["from_place"]?.toString()] ??
|
||||||
"Unknown Country";
|
"Unknown Country";
|
||||||
String toPlaceCountry =
|
String toPlaceCountry =
|
||||||
countryMap[trip["to_place"]?.toString()] ??
|
countryMap[trip["to_place"]?.toString()] ??
|
||||||
"Unknown Country";
|
"Unknown Country";
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||||
@ -385,7 +399,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
flex: 4,
|
flex: 4,
|
||||||
child: Text(
|
child: Text(
|
||||||
"$fromPlaceCountry (from) - (to) $toPlaceCountry",
|
"$fromPlaceCountry (From) - (To) $toPlaceCountry",
|
||||||
// "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}",
|
// "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
@ -435,15 +449,22 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildKeyValueRow(
|
_buildKeyValueRow(
|
||||||
"Class",
|
"Class",
|
||||||
getRequestForClass(trip["class"].toString()) ??
|
getRequestForClass(trip["class"].toString()) ??
|
||||||
"N/A"),
|
"N/A",
|
||||||
_buildKeyValueRow("Sector",
|
),
|
||||||
"${trip["from_place"] ?? "N/A"} - ${trip["to_place"] ?? "N/A"}"),
|
|
||||||
_buildKeyValueRow(
|
_buildKeyValueRow(
|
||||||
"Date", formatDate(trip["date"] ?? "")),
|
"Sector",
|
||||||
|
"${trip["from_place"] ?? "N/A"} - ${trip["to_place"] ?? "N/A"}",
|
||||||
|
),
|
||||||
_buildKeyValueRow(
|
_buildKeyValueRow(
|
||||||
"Time", formatTime(trip["time"] ?? "")),
|
"Date",
|
||||||
|
formatDate(trip["date"] ?? ""),
|
||||||
|
),
|
||||||
|
_buildKeyValueRow(
|
||||||
|
"Time",
|
||||||
|
formatTime(trip["time"] ?? ""),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -474,12 +495,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(value, style: GoogleFonts.poppins(fontSize: 12)),
|
||||||
value,
|
|
||||||
style: GoogleFonts.poppins(
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@ -131,7 +131,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
"delegationEndDate",
|
"delegationEndDate",
|
||||||
// "dateOfIssue",
|
// "dateOfIssue",
|
||||||
// "dateOfExpiry",
|
// "dateOfExpiry",
|
||||||
"changePassword"
|
"changePassword",
|
||||||
];
|
];
|
||||||
|
|
||||||
Color? layoutColor;
|
Color? layoutColor;
|
||||||
@ -202,7 +202,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
|
|
||||||
print("API Selected User Has Data - $apiselectedUser");
|
print("API Selected User Has Data - $apiselectedUser");
|
||||||
}
|
}
|
||||||
userIdApi = apiselectedUser?["user_id"] ?? "";
|
userIdApi = apiselectedUser?["user_id"] ?? "";
|
||||||
controllers["Fname"]?.text = apiselectedUser?["first_name"] ?? "";
|
controllers["Fname"]?.text = apiselectedUser?["first_name"] ?? "";
|
||||||
controllers["Lname"]?.text = apiselectedUser?["last_name"] ?? "";
|
controllers["Lname"]?.text = apiselectedUser?["last_name"] ?? "";
|
||||||
controllers["email"]?.text = apiselectedUser?["email"] ?? "";
|
controllers["email"]?.text = apiselectedUser?["email"] ?? "";
|
||||||
@ -286,7 +286,8 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
|
|
||||||
if (apiselectedUser?["delegated_to_user_id"] != null) {
|
if (apiselectedUser?["delegated_to_user_id"] != null) {
|
||||||
print(
|
print(
|
||||||
"UPDADele- ${apiselectedUser?["delegated_to_user_id"]?.toString()}");
|
"UPDADele- ${apiselectedUser?["delegated_to_user_id"]?.toString()}",
|
||||||
|
);
|
||||||
selectedSubstituteApprover =
|
selectedSubstituteApprover =
|
||||||
apiselectedUser?["delegated_to_user_id"]?.toString() ?? "";
|
apiselectedUser?["delegated_to_user_id"]?.toString() ?? "";
|
||||||
|
|
||||||
@ -303,12 +304,11 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
|
|
||||||
List<dynamic> decodedList = jsonDecode(fixedJson);
|
List<dynamic> decodedList = jsonDecode(fixedJson);
|
||||||
|
|
||||||
selectedServiceIds = decodedList.map<Map<String, dynamic>>((item) {
|
selectedServiceIds =
|
||||||
final map = Map<String, dynamic>.from(item);
|
decodedList.map<Map<String, dynamic>>((item) {
|
||||||
return {
|
final map = Map<String, dynamic>.from(item);
|
||||||
"service_id": map['service_id'].toString(),
|
return {"service_id": map['service_id'].toString()};
|
||||||
};
|
}).toList();
|
||||||
}).toList();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("❌ Error decoding fixed agent_supported_service_ids: $e");
|
print("❌ Error decoding fixed agent_supported_service_ids: $e");
|
||||||
selectedServiceIds = [];
|
selectedServiceIds = [];
|
||||||
@ -380,8 +380,9 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
// userIdsApi = userMap.keys.toList();
|
// userIdsApi = userMap.keys.toList();
|
||||||
|
|
||||||
// Handle selectedUser as a Map (not a List)
|
// Handle selectedUser as a Map (not a List)
|
||||||
apiselectedUser = extraData['selectedUser']
|
apiselectedUser =
|
||||||
as Map<String, dynamic>?; // Cast it as a Map
|
extraData['selectedUser']
|
||||||
|
as Map<String, dynamic>?; // Cast it as a Map
|
||||||
isViewMode = extraData['isViewMode'] ?? false;
|
isViewMode = extraData['isViewMode'] ?? false;
|
||||||
isEditProfile = extraData['isEditProfile'] ?? false;
|
isEditProfile = extraData['isEditProfile'] ?? false;
|
||||||
});
|
});
|
||||||
@ -443,7 +444,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
userMap = {
|
userMap = {
|
||||||
for (var user in userList)
|
for (var user in userList)
|
||||||
user['user_id'].toString():
|
user['user_id'].toString():
|
||||||
"${user['first_name']} ${user['last_name']}"
|
"${user['first_name']} ${user['last_name']}",
|
||||||
};
|
};
|
||||||
userIdsApi = userMap.keys.toList();
|
userIdsApi = userMap.keys.toList();
|
||||||
});
|
});
|
||||||
@ -481,13 +482,15 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
String? bodyStringColor = await getBodyColor();
|
String? bodyStringColor = await getBodyColor();
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
layoutColor = layoutString != null
|
layoutColor =
|
||||||
? Color(int.parse(layoutString))
|
layoutString != null
|
||||||
: Colors.redAccent;
|
? Color(int.parse(layoutString))
|
||||||
|
: Colors.redAccent;
|
||||||
|
|
||||||
bodyColor = bodyStringColor != null
|
bodyColor =
|
||||||
? Color(int.parse(bodyStringColor))
|
bodyStringColor != null
|
||||||
: Colors.white;
|
? Color(int.parse(bodyStringColor))
|
||||||
|
: Colors.white;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,6 +541,11 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handleGoBack() async {
|
||||||
|
print("hello, please Go Back");
|
||||||
|
printFormData();
|
||||||
|
}
|
||||||
|
|
||||||
void handleNext() async {
|
void handleNext() async {
|
||||||
print("USR Detail Next");
|
print("USR Detail Next");
|
||||||
printFormData();
|
printFormData();
|
||||||
@ -552,35 +560,67 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
|
|
||||||
print("USERDETAILS : $data");
|
print("USERDETAILS : $data");
|
||||||
|
|
||||||
if (!isValidData(data)) {
|
final tabs = {
|
||||||
print("USERDETAILS : $userDetials");
|
"personal": "Personal Details",
|
||||||
print("Validation Failed: Required fields are missing.");
|
"office": "Office Details",
|
||||||
setState(() {});
|
"travel": "Travel Details",
|
||||||
return; // Stop execution if validation fails
|
};
|
||||||
|
|
||||||
|
final tabKeys = tabs.keys.toList(); // ["personal", "office", "travel"]
|
||||||
|
|
||||||
|
final currentIndex = tabKeys.indexOf(selectedTab ?? "personal");
|
||||||
|
|
||||||
|
print("currentIndex - $currentIndex");
|
||||||
|
|
||||||
|
bool isValid = false;
|
||||||
|
|
||||||
|
final currentTab = tabKeys[currentIndex];
|
||||||
|
if (currentTab == "personal") {
|
||||||
|
isValid = isValidData(userDetials);
|
||||||
|
} else if (currentTab == "office") {
|
||||||
|
isValid = isValidDataTwo(userDetials);
|
||||||
} else {
|
} else {
|
||||||
print("USERDETAILS : $userDetials");
|
isValid = true; // Travel tab might not need validation at this point
|
||||||
|
|
||||||
final tabs = {
|
|
||||||
"personal": "Personal Details",
|
|
||||||
"office": "Office Details",
|
|
||||||
"travel": "Travel Details",
|
|
||||||
};
|
|
||||||
|
|
||||||
final tabKeys = tabs.keys.toList(); // ["personal", "office", "travel"]
|
|
||||||
|
|
||||||
final currentIndex = tabKeys.indexOf(selectedTab ?? "personal");
|
|
||||||
|
|
||||||
if (currentIndex < tabKeys.length - 1) {
|
|
||||||
// Move to next tab
|
|
||||||
setState(() {
|
|
||||||
selectedTab = tabKeys[currentIndex + 1];
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Already at last tab (travel), maybe submit form or show done message
|
|
||||||
print("All tabs completed!");
|
|
||||||
// You can trigger full form submit here
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isValid) {
|
||||||
|
print("Validation Failed on $currentTab: $userDetials");
|
||||||
|
setState(() {}); // To trigger UI update showing errors
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentIndex < tabKeys.length - 1) {
|
||||||
|
// Move to next tab
|
||||||
|
setState(() {
|
||||||
|
selectedTab = tabKeys[currentIndex + 1];
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Final step — submit or show done
|
||||||
|
print("All tabs completed!");
|
||||||
|
// Submit the full form here
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (!isValidData(data))
|
||||||
|
// {
|
||||||
|
// print("USERDETAILS : $userDetials");
|
||||||
|
// print("Validation Failed: Required fields are missing.");
|
||||||
|
// setState(() {});
|
||||||
|
// return; // Stop execution if validation fails
|
||||||
|
// } else
|
||||||
|
// {
|
||||||
|
// print("USERDETAILS : $userDetials");
|
||||||
|
//
|
||||||
|
// if (currentIndex < tabKeys.length - 1) {
|
||||||
|
// // Move to next tab
|
||||||
|
// setState(() {
|
||||||
|
// selectedTab = tabKeys[currentIndex + 1];
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
// // Already at last tab (travel), maybe submit form or show done message
|
||||||
|
// print("All tabs completed!");
|
||||||
|
// // You can trigger full form submit here
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleSubmit() async {
|
void handleSubmit() async {
|
||||||
@ -601,7 +641,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
|
|
||||||
// Map<String, dynamic> data = userDetials;
|
// Map<String, dynamic> data = userDetials;
|
||||||
|
|
||||||
if (!isValidData(data)) {
|
if (!isValidData(data) && isValidDataTwo(data)) {
|
||||||
print("USERDETAILS : $userDetials");
|
print("USERDETAILS : $userDetials");
|
||||||
print("Validation Failed: Required fields are missing.");
|
print("Validation Failed: Required fields are missing.");
|
||||||
setState(() {});
|
setState(() {});
|
||||||
@ -623,7 +663,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
"last_name",
|
"last_name",
|
||||||
"email",
|
"email",
|
||||||
"mobile_no",
|
"mobile_no",
|
||||||
// "employeeCode"
|
// "employeeCode",
|
||||||
];
|
];
|
||||||
|
|
||||||
if (apiselectedUser == null) {
|
if (apiselectedUser == null) {
|
||||||
@ -647,8 +687,9 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
|
|
||||||
if (data["alternate_mobile_no"] != null &&
|
if (data["alternate_mobile_no"] != null &&
|
||||||
data["alternate_mobile_no"].toString().isNotEmpty) {
|
data["alternate_mobile_no"].toString().isNotEmpty) {
|
||||||
if (!RegExp(r"^\d{10}$")
|
if (!RegExp(
|
||||||
.hasMatch(data["alternate_mobile_no"].toString())) {
|
r"^\d{10}$",
|
||||||
|
).hasMatch(data["alternate_mobile_no"].toString())) {
|
||||||
errorMessages["alternate_mobile_no"] =
|
errorMessages["alternate_mobile_no"] =
|
||||||
"Enter 10 digits"; // Invalid mobile number format
|
"Enter 10 digits"; // Invalid mobile number format
|
||||||
}
|
}
|
||||||
@ -656,14 +697,31 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
|
|
||||||
// Email validation
|
// Email validation
|
||||||
if (data["email"] != null && data["email"].toString().isNotEmpty) {
|
if (data["email"] != null && data["email"].toString().isNotEmpty) {
|
||||||
if (!RegExp(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")
|
if (!RegExp(
|
||||||
.hasMatch(data["email"].toString())) {
|
r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
|
||||||
|
).hasMatch(data["email"].toString())) {
|
||||||
errorMessages["email"] = "Invalid email format"; // Invalid email format
|
errorMessages["email"] = "Invalid email format"; // Invalid email format
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return errorMessages.isEmpty; // Valid if there are no errors
|
return errorMessages.isEmpty; // Valid if there are no errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isValidDataTwo(Map<String, dynamic> data) {
|
||||||
|
errorMessages.clear(); // Reset errors
|
||||||
|
|
||||||
|
// Required fields that must not be empty
|
||||||
|
List<String> requiredFields = ["employee_code"];
|
||||||
|
|
||||||
|
// Check validation for each field
|
||||||
|
for (String field in requiredFields) {
|
||||||
|
if (data[field] == null || data[field].toString().trim().isEmpty) {
|
||||||
|
errorMessages[field] = "Required";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errorMessages.isEmpty; // Valid if there are no errors
|
||||||
|
}
|
||||||
|
|
||||||
void _clearError(String field) {
|
void _clearError(String field) {
|
||||||
if (mounted && errorMessages.containsKey(field)) {
|
if (mounted && errorMessages.containsKey(field)) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -814,8 +872,10 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
print("enteredPassword - $enteredPassword ");
|
print("enteredPassword - $enteredPassword ");
|
||||||
|
|
||||||
if (hashedPassword != null && hashedPassword.isNotEmpty) {
|
if (hashedPassword != null && hashedPassword.isNotEmpty) {
|
||||||
bool isMatch =
|
bool isMatch = BCrypt.checkpw(
|
||||||
BCrypt.checkpw(enteredPassword, hashedPassword); // Compare passwords
|
enteredPassword,
|
||||||
|
hashedPassword,
|
||||||
|
); // Compare passwords
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
// ✅ Ensure UI updates
|
// ✅ Ensure UI updates
|
||||||
@ -825,8 +885,9 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
print(" Password match!");
|
print(" Password match!");
|
||||||
} else {
|
} else {
|
||||||
print(" Password NOT match!");
|
print(" Password NOT match!");
|
||||||
errorMessages
|
errorMessages.remove(
|
||||||
.remove("password"); // Clear error if password is different
|
"password",
|
||||||
|
); // Clear error if password is different
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -836,32 +897,36 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(
|
||||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
builder: (context, sizingInfo) {
|
||||||
|
bool isDesktop =
|
||||||
|
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Color(0xFFf5f5f5),
|
backgroundColor: Color(0xFFf5f5f5),
|
||||||
// appBar: isDesktop ? null : const CustomAppBar(title: 'Create User '),
|
// appBar: isDesktop ? null : const CustomAppBar(title: 'Create User '),
|
||||||
// drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
|
// drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
|
||||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||||
drawer: CustomDrawer(isDesktop: false),
|
drawer: CustomDrawer(isDesktop: false),
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: isDesktop
|
padding:
|
||||||
? EdgeInsets.symmetric(
|
isDesktop
|
||||||
horizontal: MediaQuery.of(context).size.width *
|
? EdgeInsets.symmetric(
|
||||||
0.1, // 30% of screen width as horizontal padding
|
horizontal:
|
||||||
vertical: MediaQuery.of(context).size.height *
|
MediaQuery.of(context).size.width *
|
||||||
0, // 5% of screen height as vertical padding
|
0.1, // 30% of screen width as horizontal padding
|
||||||
)
|
vertical:
|
||||||
: EdgeInsets.all(0),
|
MediaQuery.of(context).size.height *
|
||||||
child: Row(
|
0, // 5% of screen height as vertical padding
|
||||||
children: [
|
)
|
||||||
Expanded(child: buildData(isDesktop, context)),
|
: EdgeInsets.all(0),
|
||||||
],
|
child: Row(
|
||||||
|
children: [Expanded(child: buildData(isDesktop, context))],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
},
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildData(bool isDesktop, context) {
|
Widget buildData(bool isDesktop, context) {
|
||||||
@ -875,9 +940,10 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
height: isDesktop
|
height:
|
||||||
? MediaQuery.of(context).size.height * 0.98
|
isDesktop
|
||||||
: MediaQuery.of(context).size.height,
|
? MediaQuery.of(context).size.height * 0.98
|
||||||
|
: MediaQuery.of(context).size.height,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.all(0.0),
|
padding: EdgeInsets.all(0.0),
|
||||||
child: _buildUserDetails(isDesktop),
|
child: _buildUserDetails(isDesktop),
|
||||||
@ -887,25 +953,32 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
Container(
|
Container(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: isDesktop
|
child:
|
||||||
? Row(
|
isDesktop
|
||||||
|
? Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: (selectedTab == "travel" ||
|
children:
|
||||||
selectedRole == "5" ||
|
(selectedTab == "travel" ||
|
||||||
setSelectesUserType == true)
|
selectedRole == "5" ||
|
||||||
? _buildSubmit(isDesktop, layoutColor!)
|
setSelectesUserType == true)
|
||||||
: _buildNext(isDesktop, layoutColor!),
|
? _buildSubmit(isDesktop, layoutColor!)
|
||||||
|
: _buildNext(
|
||||||
|
isDesktop,
|
||||||
|
layoutColor!,
|
||||||
|
), // _buildGoBack(isDesktop, layoutColor!),
|
||||||
)
|
)
|
||||||
: Row(
|
: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: (selectedTab == "travel" ||
|
children:
|
||||||
selectedRole == "5" ||
|
(selectedTab == "travel" ||
|
||||||
setSelectesUserType == true)
|
selectedRole == "5" ||
|
||||||
? _buildSubmit(isDesktop, layoutColor!)
|
setSelectesUserType == true)
|
||||||
: _buildNext(isDesktop, layoutColor!),
|
? _buildSubmit(isDesktop, layoutColor!)
|
||||||
)),
|
: _buildNext(isDesktop, layoutColor!),
|
||||||
)
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -944,25 +1017,22 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
// })
|
// })
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(height: 18),
|
||||||
height: 18,
|
|
||||||
),
|
|
||||||
isDesktop
|
isDesktop
|
||||||
? buildTabsForUser()
|
? buildTabsForUser()
|
||||||
: SingleChildScrollView(
|
: SingleChildScrollView(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
child: buildTabsForUser(),
|
child: buildTabsForUser(),
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
// color: Colors.yellow.shade50,
|
// color: Colors.yellow.shade50,
|
||||||
|
|
||||||
height: MediaQuery.of(context).size.height * 0.64,
|
height: MediaQuery.of(context).size.height * 0.64,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(child: buildTabContents(isDesktop, isViewMode)),
|
Expanded(child: buildTabContents(isDesktop, isViewMode)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -977,7 +1047,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
personalDetailsKey: personalDetailsKey,
|
personalDetailsKey: personalDetailsKey,
|
||||||
isDesktop: isDesktop, // pass isDesktop as a named argument
|
isDesktop: isDesktop, // pass isDesktop as a named argument
|
||||||
isViewMode: isViewMode,
|
isViewMode: isViewMode,
|
||||||
userIdApi:userIdApi,
|
userIdApi: userIdApi,
|
||||||
controllers: controllers,
|
controllers: controllers,
|
||||||
errorMessages: errorMessages,
|
errorMessages: errorMessages,
|
||||||
selectedGender: selectedGender,
|
selectedGender: selectedGender,
|
||||||
@ -1012,7 +1082,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
return OfficeDetails(
|
return OfficeDetails(
|
||||||
isDesktop: isDesktop, // pass isDesktop as a named argument
|
isDesktop: isDesktop, // pass isDesktop as a named argument
|
||||||
isViewMode: isViewMode,
|
isViewMode: isViewMode,
|
||||||
userIdApi:userIdApi,
|
userIdApi: userIdApi,
|
||||||
controllers: controllers,
|
controllers: controllers,
|
||||||
errorMessages: errorMessages,
|
errorMessages: errorMessages,
|
||||||
selectedLevel: selectedLevel,
|
selectedLevel: selectedLevel,
|
||||||
@ -1063,14 +1133,14 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
errorMessages: errorMessages,
|
errorMessages: errorMessages,
|
||||||
travelDetails: travelDetailsDataFromAPI, // 👈 Pass this down
|
travelDetails: travelDetailsDataFromAPI, // 👈 Pass this down
|
||||||
passportFileUrlFromApi: passportFileUrlFromApi,
|
passportFileUrlFromApi: passportFileUrlFromApi,
|
||||||
userIdApi:userIdApi,
|
userIdApi: userIdApi,
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
return PersonalDetails(
|
return PersonalDetails(
|
||||||
personalDetailsKey: personalDetailsKey,
|
personalDetailsKey: personalDetailsKey,
|
||||||
isDesktop: isDesktop, // pass isDesktop as a named argument
|
isDesktop: isDesktop, // pass isDesktop as a named argument
|
||||||
isViewMode: isViewMode,
|
isViewMode: isViewMode,
|
||||||
userIdApi:userIdApi,
|
userIdApi: userIdApi,
|
||||||
controllers: controllers,
|
controllers: controllers,
|
||||||
errorMessages: errorMessages,
|
errorMessages: errorMessages,
|
||||||
selectedGender: selectedGender,
|
selectedGender: selectedGender,
|
||||||
@ -1101,9 +1171,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
|
|
||||||
Map<String, String> getTabs(bool setSelectesUserType) {
|
Map<String, String> getTabs(bool setSelectesUserType) {
|
||||||
if (setSelectesUserType || selectedRole == "5") {
|
if (setSelectesUserType || selectedRole == "5") {
|
||||||
return {
|
return {"personal": "Personal Details"};
|
||||||
"personal": "Personal Details",
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
return allTabs;
|
return allTabs;
|
||||||
}
|
}
|
||||||
@ -1113,50 +1181,102 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end, // important
|
crossAxisAlignment: CrossAxisAlignment.end, // important
|
||||||
children: tabs.entries.map((entry) {
|
children:
|
||||||
final isSelected = selectedTab == entry.key;
|
tabs.entries.map((entry) {
|
||||||
return GestureDetector(
|
final isSelected = selectedTab == entry.key;
|
||||||
onTap: () {
|
return GestureDetector(
|
||||||
setState(() {
|
onTap: () {
|
||||||
selectedTab = entry.key;
|
setState(() {
|
||||||
});
|
bool isValid = false;
|
||||||
},
|
|
||||||
child: Padding(
|
final currentTab = selectedTab;
|
||||||
padding: const EdgeInsets.only(right: 24.0), // space between tabs
|
if (currentTab == "personal") {
|
||||||
child: Column(
|
isValid = isValidData(userDetials);
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
if (isValid) {
|
||||||
Text(
|
selectedTab = entry.key;
|
||||||
entry.value,
|
}
|
||||||
style: GoogleFonts.poppins(
|
} else if (currentTab == "office") {
|
||||||
fontSize: 12,
|
isValid = isValidDataTwo(userDetials);
|
||||||
fontWeight: FontWeight.w600,
|
if (isValid) {
|
||||||
color: isSelected ? Color(0xFF114D8B) : Color(0xFF475569),
|
selectedTab = entry.key;
|
||||||
),
|
}
|
||||||
|
} else {
|
||||||
|
isValid =
|
||||||
|
true; // Travel tab might not need validation at this point
|
||||||
|
selectedTab = entry.key;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
right: 24.0,
|
||||||
|
), // space between tabs
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
entry.value,
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color:
|
||||||
|
isSelected ? Color(0xFF114D8B) : Color(0xFF475569),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
AnimatedContainer(
|
||||||
|
duration: Duration(milliseconds: 300),
|
||||||
|
height: 2,
|
||||||
|
width: isSelected ? 50 : 0, // small line
|
||||||
|
color: Color(0xFF114D8B),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
),
|
||||||
AnimatedContainer(
|
);
|
||||||
duration: Duration(milliseconds: 300),
|
}).toList(),
|
||||||
height: 2,
|
|
||||||
width: isSelected ? 50 : 0, // small line
|
|
||||||
color: Color(0xFF114D8B),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Submit ---------------------------------------
|
// ---- Submit ---------------------------------------
|
||||||
|
|
||||||
|
List<Widget> _buildGoBack(isDesktop, Color layoutColor) {
|
||||||
|
return [
|
||||||
|
MouseRegion(
|
||||||
|
cursor:
|
||||||
|
isViewMode
|
||||||
|
? SystemMouseCursors.forbidden
|
||||||
|
: SystemMouseCursors.click,
|
||||||
|
child: ElevatedButton(
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor:
|
||||||
|
isViewMode ? layoutColor : layoutColor, // Keep original color
|
||||||
|
foregroundColor:
|
||||||
|
isViewMode ? Colors.white : Colors.white, // Keep original color
|
||||||
|
disabledBackgroundColor:
|
||||||
|
layoutColor, // Ensure color remains when disabled
|
||||||
|
disabledForegroundColor: Colors.white,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
side: BorderSide(color: layoutColor, width: 2),
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
|
),
|
||||||
|
onPressed: handleGoBack,
|
||||||
|
child: Text("Back"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
List<Widget> _buildNext(isDesktop, Color layoutColor) {
|
List<Widget> _buildNext(isDesktop, Color layoutColor) {
|
||||||
return [
|
return [
|
||||||
MouseRegion(
|
MouseRegion(
|
||||||
cursor: isViewMode
|
cursor:
|
||||||
? SystemMouseCursors.forbidden
|
isViewMode
|
||||||
: SystemMouseCursors.click,
|
? SystemMouseCursors.forbidden
|
||||||
|
: SystemMouseCursors.click,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
@ -1177,41 +1297,42 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
// isViewMode ? null : handleNext, // Disable when in view mode
|
// isViewMode ? null : handleNext, // Disable when in view mode
|
||||||
child: Text("Next"),
|
child: Text("Next"),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _buildSubmit(isDesktop, Color layoutColor) {
|
List<Widget> _buildSubmit(isDesktop, Color layoutColor) {
|
||||||
return [
|
return [
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
foregroundColor: layoutColor,
|
foregroundColor: layoutColor,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
side: BorderSide(color: layoutColor, width: 2),
|
side: BorderSide(color: layoutColor, width: 2),
|
||||||
),
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
|
||||||
),
|
),
|
||||||
onPressed: () {
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
isEditProfile ? context.go('/listPlan') : context.go('/listUser');
|
),
|
||||||
},
|
onPressed: () {
|
||||||
child: Text("Cancel")),
|
isEditProfile ? context.go('/listPlan') : context.go('/listUser');
|
||||||
SizedBox(
|
},
|
||||||
width: 20,
|
child: Text("Cancel"),
|
||||||
),
|
),
|
||||||
|
SizedBox(width: 20),
|
||||||
if (!isViewMode)
|
if (!isViewMode)
|
||||||
MouseRegion(
|
MouseRegion(
|
||||||
cursor: isViewMode
|
cursor:
|
||||||
? SystemMouseCursors.forbidden
|
isViewMode
|
||||||
: SystemMouseCursors.click,
|
? SystemMouseCursors.forbidden
|
||||||
|
: SystemMouseCursors.click,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
isViewMode ? layoutColor : layoutColor, // Keep original color
|
isViewMode ? layoutColor : layoutColor, // Keep original color
|
||||||
foregroundColor: isViewMode
|
foregroundColor:
|
||||||
? Colors.white
|
isViewMode
|
||||||
: Colors.white, // Keep original color
|
? Colors.white
|
||||||
|
: Colors.white, // Keep original color
|
||||||
disabledBackgroundColor:
|
disabledBackgroundColor:
|
||||||
layoutColor, // Ensure color remains when disabled
|
layoutColor, // Ensure color remains when disabled
|
||||||
disabledForegroundColor: Colors.white,
|
disabledForegroundColor: Colors.white,
|
||||||
@ -1225,7 +1346,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
isViewMode ? null : handleSubmit, // Disable when in view mode
|
isViewMode ? null : handleSubmit, // Disable when in view mode
|
||||||
child: Text("Submit"),
|
child: Text("Submit"),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,6 @@ class OfficeDetails extends StatefulWidget {
|
|||||||
final bool isViewMode;
|
final bool isViewMode;
|
||||||
final String? userIdApi;
|
final String? userIdApi;
|
||||||
|
|
||||||
|
|
||||||
final ValueChanged<String?>? onLevelChanged;
|
final ValueChanged<String?>? onLevelChanged;
|
||||||
final ValueChanged<String?>? onDepartmentChanged;
|
final ValueChanged<String?>? onDepartmentChanged;
|
||||||
final ValueChanged<String?>? onFirstApproverChanged;
|
final ValueChanged<String?>? onFirstApproverChanged;
|
||||||
@ -157,17 +156,25 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
fetchFindGroup();
|
fetchFindGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> apiCheckDuplicate(String label, String field, String value, String? userId) async {
|
Future<void> apiCheckDuplicate(
|
||||||
|
String label,
|
||||||
|
String field,
|
||||||
|
String value,
|
||||||
|
String? userId,
|
||||||
|
) async {
|
||||||
try {
|
try {
|
||||||
|
// Basic validation: Check mobile number length
|
||||||
|
|
||||||
if (field == "employeeCode") {
|
final response = await apiService.CheckDuplicate(
|
||||||
field = "employee_code";
|
label,
|
||||||
}
|
field,
|
||||||
|
value,
|
||||||
final response = await apiService.CheckDuplicate(label, field, value, userId);
|
userId,
|
||||||
|
);
|
||||||
if (response.isNotEmpty) {
|
if (response.isNotEmpty) {
|
||||||
_clearError(field);
|
_clearError(field);
|
||||||
widget.errorMessages[field] = response['message'] ?? "$label already exists";
|
widget.errorMessages[field] =
|
||||||
|
response['message'] ?? "$label Already Exists";
|
||||||
print("Duplicate found: ${response['message']}");
|
print("Duplicate found: ${response['message']}");
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -290,7 +297,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 20),
|
||||||
_buildFirstRow(widget.isDesktop),
|
_buildFirstRow(widget.isDesktop),
|
||||||
if (widget.isDesktop) SizedBox(height: 10),
|
if (widget.isDesktop) SizedBox(height: 10),
|
||||||
_buildSecondRow(widget.isDesktop),
|
_buildSecondRow(widget.isDesktop),
|
||||||
@ -407,7 +414,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Employee Code",
|
"Employee Code *",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -425,8 +432,13 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
controller: widget.controllers["employeeCode"],
|
controller: widget.controllers["employeeCode"],
|
||||||
enabled: !widget.isViewMode,
|
enabled: !widget.isViewMode,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
_clearError("employeeCode");
|
_clearError("employee_code");
|
||||||
apiCheckDuplicate("Employee Code", "employeeCode",value,widget.userIdApi);
|
apiCheckDuplicate(
|
||||||
|
"Employee Code",
|
||||||
|
"employee_code",
|
||||||
|
value,
|
||||||
|
widget.userIdApi,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: "Employee Code",
|
labelText: "Employee Code",
|
||||||
@ -441,10 +453,10 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (widget.errorMessages["employeeCode"] != null) ...[
|
if (widget.errorMessages["employee_code"] != null) ...[
|
||||||
SizedBox(height: 5), // Space before error message
|
SizedBox(height: 5), // Space before error message
|
||||||
Text(
|
Text(
|
||||||
widget.errorMessages["employeeCode"]!,
|
widget.errorMessages["employee_code"]!,
|
||||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -452,7 +464,71 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Widget buildDepartmentFieldOld() {
|
||||||
|
// return Column(
|
||||||
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
// children: [
|
||||||
|
// Text(
|
||||||
|
// "Department",
|
||||||
|
// style: GoogleFonts.poppins(
|
||||||
|
// fontSize: 12,
|
||||||
|
// fontWeight: FontWeight.w600,
|
||||||
|
// color: Color(0xFF575A74),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SizedBox(height: 5),
|
||||||
|
// CustomTextFieldUserWrapper(
|
||||||
|
// isFocused: false, // Dropdown doesn't use focus
|
||||||
|
// isDesktop: widget.isDesktop,
|
||||||
|
// child: SizedBox(
|
||||||
|
// height: 45, // Set appropriate height
|
||||||
|
// child: DropdownButtonFormField<String>(
|
||||||
|
// value: selectedDepartment,
|
||||||
|
// // value: widget.isViewMode ? null : selectedDepartment,
|
||||||
|
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||||
|
// decoration: InputDecoration(
|
||||||
|
// border: InputBorder.none,
|
||||||
|
// contentPadding: EdgeInsets.symmetric(
|
||||||
|
// horizontal: 10,
|
||||||
|
// ), // Proper padding
|
||||||
|
// ),
|
||||||
|
// onChanged:
|
||||||
|
// widget.isViewMode
|
||||||
|
// ? null
|
||||||
|
// : (newValue) {
|
||||||
|
// setState(() {
|
||||||
|
// selectedDepartment = newValue;
|
||||||
|
// });
|
||||||
|
// widget.onDepartmentChanged?.call(newValue);
|
||||||
|
// },
|
||||||
|
//
|
||||||
|
// items:
|
||||||
|
// apiCostData?.map<DropdownMenuItem<String>>((item) {
|
||||||
|
// return DropdownMenuItem(
|
||||||
|
//
|
||||||
|
// value: item['department_id'], // ID as value
|
||||||
|
// child: Text(item['name'] ?? "Unknown"),
|
||||||
|
// );
|
||||||
|
// }).toList(),
|
||||||
|
// hint: Text("Select"),
|
||||||
|
// disabledHint: Text(
|
||||||
|
// selectedDepartment ?? "Select Department",
|
||||||
|
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
Widget buildDepartmentField() {
|
Widget buildDepartmentField() {
|
||||||
|
// Map department_id to department_name
|
||||||
|
Map<String, String> departmentMap = {
|
||||||
|
for (var item in apiCostData ?? [])
|
||||||
|
item['department_id'] as String: item['name'] as String,
|
||||||
|
};
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -466,41 +542,74 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
CustomTextFieldUserWrapper(
|
CustomTextFieldUserWrapper(
|
||||||
isFocused: false, // Dropdown doesn't use focus
|
isFocused: false,
|
||||||
isDesktop: widget.isDesktop,
|
isDesktop: widget.isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 45, // Set appropriate height
|
height: 40,
|
||||||
child: DropdownButtonFormField<String>(
|
child: DropdownSearch<String>(
|
||||||
value: selectedDepartment,
|
selectedItem: departmentMap[selectedDepartment],
|
||||||
// value: widget.isViewMode ? null : selectedDepartment,
|
enabled: !widget.isViewMode,
|
||||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
popupProps: PopupProps.menu(
|
||||||
decoration: InputDecoration(
|
showSearchBox: true,
|
||||||
border: InputBorder.none,
|
fit: FlexFit.loose,
|
||||||
contentPadding: EdgeInsets.symmetric(
|
menuProps: const MenuProps(backgroundColor: Colors.white),
|
||||||
horizontal: 10,
|
itemBuilder:
|
||||||
), // Proper padding
|
(context, item, isSelected) => Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 6,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
item,
|
||||||
|
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
constraints: BoxConstraints(maxHeight: 200),
|
||||||
|
searchFieldProps: TextFieldProps(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: "Search Department...",
|
||||||
|
contentPadding: EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
items: departmentMap.values.toList(),
|
||||||
|
|
||||||
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
|
dropdownSearchDecoration: InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dropdownBuilder:
|
||||||
|
(context, selectedItem) => Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
selectedItem ?? "Select Department",
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 12,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
onChanged:
|
onChanged:
|
||||||
widget.isViewMode
|
widget.isViewMode
|
||||||
? null
|
? null
|
||||||
: (newValue) {
|
: (String? newValue) {
|
||||||
|
if (newValue == null) return;
|
||||||
|
|
||||||
|
final departmentId =
|
||||||
|
departmentMap.entries
|
||||||
|
.firstWhere((entry) => entry.value == newValue)
|
||||||
|
.key;
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedDepartment = newValue;
|
selectedDepartment = departmentId;
|
||||||
});
|
});
|
||||||
widget.onDepartmentChanged?.call(newValue);
|
|
||||||
|
widget.onDepartmentChanged?.call(
|
||||||
|
departmentId,
|
||||||
|
); // Send department_id
|
||||||
},
|
},
|
||||||
items:
|
|
||||||
apiCostData?.map<DropdownMenuItem<String>>((item) {
|
|
||||||
return DropdownMenuItem(
|
|
||||||
value: item['department_id'], // ID as value
|
|
||||||
child: Text(item['name'] ?? "Unknown"),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
hint: Text("Select"),
|
|
||||||
disabledHint: Text(
|
|
||||||
selectedDepartment ?? "Select Department",
|
|
||||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -585,6 +694,17 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
popupProps: PopupProps.menu(
|
popupProps: PopupProps.menu(
|
||||||
showSearchBox: true,
|
showSearchBox: true,
|
||||||
fit: FlexFit.loose, // Allows flexible height
|
fit: FlexFit.loose, // Allows flexible height
|
||||||
|
itemBuilder:
|
||||||
|
(context, item, isSelected) => Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 6,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
item,
|
||||||
|
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
constraints: BoxConstraints(maxHeight: 250),
|
constraints: BoxConstraints(maxHeight: 250),
|
||||||
searchFieldProps: TextFieldProps(
|
searchFieldProps: TextFieldProps(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@ -686,6 +806,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
popupProps: PopupProps.menu(
|
popupProps: PopupProps.menu(
|
||||||
showSearchBox: true,
|
showSearchBox: true,
|
||||||
fit: FlexFit.loose, // Allows flexible height
|
fit: FlexFit.loose, // Allows flexible height
|
||||||
|
menuProps: const MenuProps(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
),
|
||||||
|
itemBuilder:
|
||||||
|
(context, item, isSelected) => Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 6,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
item,
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 11.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
constraints: BoxConstraints(maxHeight: 250),
|
constraints: BoxConstraints(maxHeight: 250),
|
||||||
searchFieldProps: TextFieldProps(
|
searchFieldProps: TextFieldProps(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@ -806,6 +942,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
popupProps: PopupProps.menu(
|
popupProps: PopupProps.menu(
|
||||||
showSearchBox: true,
|
showSearchBox: true,
|
||||||
fit: FlexFit.loose, // Allows flexible height
|
fit: FlexFit.loose, // Allows flexible height
|
||||||
|
menuProps: const MenuProps(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
),
|
||||||
|
itemBuilder:
|
||||||
|
(context, item, isSelected) => Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 6,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
item,
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 11.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
constraints: BoxConstraints(maxHeight: 250),
|
constraints: BoxConstraints(maxHeight: 250),
|
||||||
searchFieldProps: TextFieldProps(
|
searchFieldProps: TextFieldProps(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@ -925,6 +1077,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
popupProps: PopupProps.menu(
|
popupProps: PopupProps.menu(
|
||||||
showSearchBox: true,
|
showSearchBox: true,
|
||||||
fit: FlexFit.loose, // Allows flexible height
|
fit: FlexFit.loose, // Allows flexible height
|
||||||
|
menuProps: const MenuProps(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
),
|
||||||
|
itemBuilder:
|
||||||
|
(context, item, isSelected) => Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 6,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
item,
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 11.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
constraints: BoxConstraints(maxHeight: 250),
|
constraints: BoxConstraints(maxHeight: 250),
|
||||||
searchFieldProps: TextFieldProps(
|
searchFieldProps: TextFieldProps(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@ -1047,6 +1215,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
popupProps: PopupProps.menu(
|
popupProps: PopupProps.menu(
|
||||||
showSearchBox: true,
|
showSearchBox: true,
|
||||||
fit: FlexFit.loose, // Allows flexible height
|
fit: FlexFit.loose, // Allows flexible height
|
||||||
|
menuProps: const MenuProps(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
),
|
||||||
|
itemBuilder:
|
||||||
|
(context, item, isSelected) => Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 6,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
item,
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 11.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
constraints: BoxConstraints(maxHeight: 250),
|
constraints: BoxConstraints(maxHeight: 250),
|
||||||
searchFieldProps: TextFieldProps(
|
searchFieldProps: TextFieldProps(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
|
|||||||
@ -157,7 +157,12 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> apiCheckDuplicate(String label, String field, String value, String? userId) async {
|
Future<void> apiCheckDuplicate(
|
||||||
|
String label,
|
||||||
|
String field,
|
||||||
|
String value,
|
||||||
|
String? userId,
|
||||||
|
) async {
|
||||||
try {
|
try {
|
||||||
// Basic validation: Check mobile number length
|
// Basic validation: Check mobile number length
|
||||||
if (field == "mobile_no" && value.length != 10) {
|
if (field == "mobile_no" && value.length != 10) {
|
||||||
@ -167,10 +172,16 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
return; // Skip the API call if input is invalid
|
return; // Skip the API call if input is invalid
|
||||||
}
|
}
|
||||||
|
|
||||||
final response = await apiService.CheckDuplicate(label, field, value, userId);
|
final response = await apiService.CheckDuplicate(
|
||||||
|
label,
|
||||||
|
field,
|
||||||
|
value,
|
||||||
|
userId,
|
||||||
|
);
|
||||||
if (response.isNotEmpty) {
|
if (response.isNotEmpty) {
|
||||||
_clearError(field);
|
_clearError(field);
|
||||||
widget.errorMessages[field] = response['message'] ?? "$label already exists";
|
widget.errorMessages[field] =
|
||||||
|
response['message'] ?? "$label Already Exists";
|
||||||
print("Duplicate found: ${response['message']}");
|
print("Duplicate found: ${response['message']}");
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -182,9 +193,6 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _clearError(String field) {
|
void _clearError(String field) {
|
||||||
setState(() {
|
setState(() {
|
||||||
widget.errorMessages.remove(field);
|
widget.errorMessages.remove(field);
|
||||||
@ -305,11 +313,11 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 20),
|
||||||
_buildFirstRow(widget.isDesktop),
|
_buildFirstRow(widget.isDesktop),
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
_buildSecondRow(widget.isDesktop),
|
_buildSecondRow(widget.isDesktop),
|
||||||
// SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
_buildThirdRow(widget.isDesktop),
|
_buildThirdRow(widget.isDesktop),
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
_buildForthRow(widget.isDesktop),
|
_buildForthRow(widget.isDesktop),
|
||||||
@ -731,7 +739,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"First Name",
|
"First Name *",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -781,7 +789,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Last Name",
|
"Last Name*",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -822,7 +830,107 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Widget buildGenderFieldOld() {
|
||||||
|
// return Column(
|
||||||
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
// children: [
|
||||||
|
// Text(
|
||||||
|
// "Gender",
|
||||||
|
// style: GoogleFonts.poppins(
|
||||||
|
// fontSize: 12,
|
||||||
|
// fontWeight: FontWeight.w600,
|
||||||
|
// color: Color(0xFF575A74),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SizedBox(height: 5),
|
||||||
|
// CustomTextFieldUserWrapper(
|
||||||
|
// width:
|
||||||
|
// widget.isDesktop
|
||||||
|
// ? MediaQuery.of(context).size.width * 0.12
|
||||||
|
// : null,
|
||||||
|
// isFocused: false,
|
||||||
|
// isDesktop: widget.isDesktop,
|
||||||
|
// child: SizedBox(
|
||||||
|
// height: 40,
|
||||||
|
// child: DropdownButtonFormField<String>(
|
||||||
|
// // value: selectedGender,
|
||||||
|
// value: widget.isViewMode ? null : selectedGender,
|
||||||
|
// onChanged:
|
||||||
|
// widget.isViewMode
|
||||||
|
// ? null
|
||||||
|
// : (String? newValue) {
|
||||||
|
// setState(() {
|
||||||
|
// selectedGender = newValue;
|
||||||
|
// print("selectedGender - $selectedGender");
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// widget.onGenderChanged?.call(newValue);
|
||||||
|
// },
|
||||||
|
// decoration: InputDecoration(
|
||||||
|
// border: InputBorder.none,
|
||||||
|
// enabled: !widget.isViewMode, // Disables input when in view mode
|
||||||
|
// ),
|
||||||
|
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||||
|
// items: [
|
||||||
|
// DropdownMenuItem(value: "Male", child: Text("Male")),
|
||||||
|
// DropdownMenuItem(value: "Female", child: Text("Female")),
|
||||||
|
// ],
|
||||||
|
// hint: Text(
|
||||||
|
// selectedGender ?? "Select Gender",
|
||||||
|
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||||
|
// ),
|
||||||
|
// disabledHint: Text(
|
||||||
|
// selectedGender ?? "Select Gender",
|
||||||
|
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
//
|
||||||
|
// // child: DropdownSearch<String>(
|
||||||
|
// // selectedItem: selectedGender,
|
||||||
|
// // // key: ValueKey(selectedGender),
|
||||||
|
// // popupProps: PopupProps.menu(
|
||||||
|
// // fit: FlexFit.loose, // Allows flexible height
|
||||||
|
// // constraints: BoxConstraints(maxHeight: 250),
|
||||||
|
// //
|
||||||
|
// // ),
|
||||||
|
// // items: ["Male", "Female", "Others"],
|
||||||
|
// // dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
|
// // dropdownSearchDecoration: InputDecoration(
|
||||||
|
// // border: InputBorder.none,
|
||||||
|
// // contentPadding: EdgeInsets.symmetric(horizontal: 1,),
|
||||||
|
// // ),
|
||||||
|
// // ),
|
||||||
|
// // dropdownBuilder: (context, selectedItem) => Align( // Center-align selected item
|
||||||
|
// // alignment: Alignment.centerLeft,
|
||||||
|
// // child: Text(
|
||||||
|
// // selectedItem ?? "Select",
|
||||||
|
// // style: TextStyle(fontSize: 12),
|
||||||
|
// // ),
|
||||||
|
// // ),
|
||||||
|
// // onChanged: isViewMode
|
||||||
|
// // ? null
|
||||||
|
// // : (String? newValue) {
|
||||||
|
// // setState(() {
|
||||||
|
// // // Find the country_code based on selected country_name
|
||||||
|
// // selectedGender = newValue;
|
||||||
|
// // print("selectedGender - $selectedGender");
|
||||||
|
// // // if (selectedCountry!.isNotEmpty) {
|
||||||
|
// // // errorMessages.remove("country_code");
|
||||||
|
// // // }
|
||||||
|
// // });
|
||||||
|
// // },
|
||||||
|
// //
|
||||||
|
// //
|
||||||
|
// // ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
Widget buildGenderField() {
|
Widget buildGenderField() {
|
||||||
|
List<String> genderOptions = ["Male", "Female"];
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -844,9 +952,45 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
isDesktop: widget.isDesktop,
|
isDesktop: widget.isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: DropdownButtonFormField<String>(
|
child: DropdownSearch<String>(
|
||||||
// value: selectedGender,
|
selectedItem: selectedGender,
|
||||||
value: widget.isViewMode ? null : selectedGender,
|
enabled: !widget.isViewMode,
|
||||||
|
|
||||||
|
popupProps: PopupProps.menu(
|
||||||
|
showSearchBox: false, // Set true if you want search
|
||||||
|
fit: FlexFit.loose,
|
||||||
|
constraints: BoxConstraints(maxHeight: 200),
|
||||||
|
itemBuilder:
|
||||||
|
(context, item, isSelected) => Container(
|
||||||
|
color: Colors.white,
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 6,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
item,
|
||||||
|
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
items: genderOptions,
|
||||||
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
|
dropdownSearchDecoration: InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dropdownBuilder:
|
||||||
|
(context, selectedItem) => Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
selectedItem ?? "Select Gender",
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 12,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
onChanged:
|
onChanged:
|
||||||
widget.isViewMode
|
widget.isViewMode
|
||||||
? null
|
? null
|
||||||
@ -855,65 +999,9 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
selectedGender = newValue;
|
selectedGender = newValue;
|
||||||
print("selectedGender - $selectedGender");
|
print("selectedGender - $selectedGender");
|
||||||
});
|
});
|
||||||
|
|
||||||
widget.onGenderChanged?.call(newValue);
|
widget.onGenderChanged?.call(newValue);
|
||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
|
||||||
border: InputBorder.none,
|
|
||||||
enabled: !widget.isViewMode, // Disables input when in view mode
|
|
||||||
),
|
|
||||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
|
||||||
items: [
|
|
||||||
DropdownMenuItem(value: "Male", child: Text("Male")),
|
|
||||||
DropdownMenuItem(value: "Female", child: Text("Female")),
|
|
||||||
],
|
|
||||||
hint: Text(
|
|
||||||
selectedGender ?? "Select Gender",
|
|
||||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
|
||||||
),
|
|
||||||
disabledHint: Text(
|
|
||||||
selectedGender ?? "Select Gender",
|
|
||||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
|
||||||
// child: DropdownSearch<String>(
|
|
||||||
// selectedItem: selectedGender,
|
|
||||||
// // key: ValueKey(selectedGender),
|
|
||||||
// popupProps: PopupProps.menu(
|
|
||||||
// fit: FlexFit.loose, // Allows flexible height
|
|
||||||
// constraints: BoxConstraints(maxHeight: 250),
|
|
||||||
//
|
|
||||||
// ),
|
|
||||||
// items: ["Male", "Female", "Others"],
|
|
||||||
// dropdownDecoratorProps: DropDownDecoratorProps(
|
|
||||||
// dropdownSearchDecoration: InputDecoration(
|
|
||||||
// border: InputBorder.none,
|
|
||||||
// contentPadding: EdgeInsets.symmetric(horizontal: 1,),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// dropdownBuilder: (context, selectedItem) => Align( // Center-align selected item
|
|
||||||
// alignment: Alignment.centerLeft,
|
|
||||||
// child: Text(
|
|
||||||
// selectedItem ?? "Select",
|
|
||||||
// style: TextStyle(fontSize: 12),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// onChanged: isViewMode
|
|
||||||
// ? null
|
|
||||||
// : (String? newValue) {
|
|
||||||
// setState(() {
|
|
||||||
// // Find the country_code based on selected country_name
|
|
||||||
// selectedGender = newValue;
|
|
||||||
// print("selectedGender - $selectedGender");
|
|
||||||
// // if (selectedCountry!.isNotEmpty) {
|
|
||||||
// // errorMessages.remove("country_code");
|
|
||||||
// // }
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// ),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -1014,7 +1102,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Email",
|
"Email *",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -1032,7 +1120,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
controller: widget.controllers["email"],
|
controller: widget.controllers["email"],
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
_clearError("email");
|
_clearError("email");
|
||||||
apiCheckDuplicate("Email", "email",value,widget.userIdApi);
|
apiCheckDuplicate("Email", "email", value, widget.userIdApi);
|
||||||
},
|
},
|
||||||
enabled: !widget.isViewMode,
|
enabled: !widget.isViewMode,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@ -1064,7 +1152,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Mobile Number",
|
"Mobile Number *",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -1083,7 +1171,12 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
enabled: !widget.isViewMode,
|
enabled: !widget.isViewMode,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
_clearError("mobile_no");
|
_clearError("mobile_no");
|
||||||
apiCheckDuplicate("Mobile Number", "mobile_no",value,widget.userIdApi);
|
apiCheckDuplicate(
|
||||||
|
"Mobile Number",
|
||||||
|
"mobile_no",
|
||||||
|
value,
|
||||||
|
widget.userIdApi,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||||
inputFormatters: [
|
inputFormatters: [
|
||||||
@ -1208,6 +1301,18 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
popupProps: PopupProps.menu(
|
popupProps: PopupProps.menu(
|
||||||
showSearchBox: true, // Enables search functionality
|
showSearchBox: true, // Enables search functionality
|
||||||
fit: FlexFit.loose, // Allows flexible height
|
fit: FlexFit.loose, // Allows flexible height
|
||||||
|
menuProps: const MenuProps(backgroundColor: Colors.white),
|
||||||
|
itemBuilder:
|
||||||
|
(context, item, isSelected) => Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 6,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
item,
|
||||||
|
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
constraints: BoxConstraints(maxHeight: 200),
|
constraints: BoxConstraints(maxHeight: 200),
|
||||||
searchFieldProps: TextFieldProps(
|
searchFieldProps: TextFieldProps(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@ -1323,12 +1428,79 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Widget buildRoleOld() {
|
||||||
|
// return Column(
|
||||||
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
// children: [
|
||||||
|
// Text(
|
||||||
|
// "Role ",
|
||||||
|
// style: GoogleFonts.poppins(
|
||||||
|
// fontSize: 12,
|
||||||
|
// fontWeight: FontWeight.w600,
|
||||||
|
// color: Color(0xFF575A74),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SizedBox(height: 5),
|
||||||
|
// CustomTextFieldUserWrapper(
|
||||||
|
// isFocused: false, // Dropdown doesn't use focus
|
||||||
|
// isDesktop: widget.isDesktop,
|
||||||
|
// child: SizedBox(
|
||||||
|
// height: 45, // Set appropriate height
|
||||||
|
// child: DropdownButtonFormField<String>(
|
||||||
|
// // value: widget.isViewMode ? null : selectedRole,
|
||||||
|
// value: selectedRole,
|
||||||
|
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||||
|
// decoration: InputDecoration(
|
||||||
|
// border: InputBorder.none,
|
||||||
|
// contentPadding: EdgeInsets.symmetric(
|
||||||
|
// horizontal: 10,
|
||||||
|
// ), // Proper padding
|
||||||
|
// ),
|
||||||
|
// onChanged:
|
||||||
|
// widget.isViewMode
|
||||||
|
// ? null
|
||||||
|
// : (newValue) {
|
||||||
|
// setState(() {
|
||||||
|
// selectedRole = newValue;
|
||||||
|
// isTravelAgent = selectedRole == "5";
|
||||||
|
// // Pass the result back to parent
|
||||||
|
// widget.onUserTypeChanged?.call(isTravelAgent);
|
||||||
|
// });
|
||||||
|
// widget.onRoleChanged?.call(newValue);
|
||||||
|
// },
|
||||||
|
// items:
|
||||||
|
// apiRoleData?.map<DropdownMenuItem<String>>((item) {
|
||||||
|
// return DropdownMenuItem(
|
||||||
|
// value: item['dropdown_key'], // ID as value
|
||||||
|
// child: Text(item['dropdown_value'] ?? "Select Role"),
|
||||||
|
// );
|
||||||
|
// }).toList(),
|
||||||
|
// hint: Text("Select Role"),
|
||||||
|
// disabledHint: Text(
|
||||||
|
// selectedRole ?? "Select Role",
|
||||||
|
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
Widget buildRole() {
|
Widget buildRole() {
|
||||||
|
// Map dropdown_key (ID) -> dropdown_value (Name)
|
||||||
|
Map<String, String> roleMap = {
|
||||||
|
for (var item in apiRoleData ?? [])
|
||||||
|
item['dropdown_key'] as String: item['dropdown_value'] as String,
|
||||||
|
};
|
||||||
|
|
||||||
|
List<String> roleNames = roleMap.values.toList();
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Role ",
|
"Role",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -1337,44 +1509,73 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
CustomTextFieldUserWrapper(
|
CustomTextFieldUserWrapper(
|
||||||
isFocused: false, // Dropdown doesn't use focus
|
isFocused: false,
|
||||||
isDesktop: widget.isDesktop,
|
isDesktop: widget.isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 45, // Set appropriate height
|
height: 40,
|
||||||
child: DropdownButtonFormField<String>(
|
child: DropdownSearch<String>(
|
||||||
// value: widget.isViewMode ? null : selectedRole,
|
selectedItem: selectedRole != null ? roleMap[selectedRole] : null,
|
||||||
value: selectedRole,
|
enabled: !widget.isViewMode,
|
||||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
popupProps: PopupProps.menu(
|
||||||
decoration: InputDecoration(
|
showSearchBox: true,
|
||||||
border: InputBorder.none,
|
fit: FlexFit.loose,
|
||||||
contentPadding: EdgeInsets.symmetric(
|
constraints: BoxConstraints(maxHeight: 250),
|
||||||
horizontal: 10,
|
menuProps: const MenuProps(backgroundColor: Colors.white),
|
||||||
), // Proper padding
|
itemBuilder:
|
||||||
|
(context, item, isSelected) => Container(
|
||||||
|
color: Colors.white,
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 6,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
item,
|
||||||
|
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
searchFieldProps: TextFieldProps(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: "Search Role...",
|
||||||
|
contentPadding: EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
items: roleNames,
|
||||||
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
|
dropdownSearchDecoration: InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dropdownBuilder:
|
||||||
|
(context, selectedItem) => Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
selectedItem ?? "Select Role",
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 12,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
onChanged:
|
onChanged:
|
||||||
widget.isViewMode
|
widget.isViewMode
|
||||||
? null
|
? null
|
||||||
: (newValue) {
|
: (String? newValue) {
|
||||||
|
if (newValue == null) return;
|
||||||
|
final selectedKey =
|
||||||
|
roleMap.entries
|
||||||
|
.firstWhere((entry) => entry.value == newValue)
|
||||||
|
.key;
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedRole = newValue;
|
selectedRole = selectedKey;
|
||||||
isTravelAgent = selectedRole == "5";
|
isTravelAgent = selectedKey == "5";
|
||||||
// Pass the result back to parent
|
|
||||||
widget.onUserTypeChanged?.call(isTravelAgent);
|
|
||||||
});
|
});
|
||||||
widget.onRoleChanged?.call(newValue);
|
|
||||||
|
widget.onUserTypeChanged?.call(isTravelAgent);
|
||||||
|
widget.onRoleChanged?.call(selectedKey);
|
||||||
},
|
},
|
||||||
items:
|
|
||||||
apiRoleData?.map<DropdownMenuItem<String>>((item) {
|
|
||||||
return DropdownMenuItem(
|
|
||||||
value: item['dropdown_key'], // ID as value
|
|
||||||
child: Text(item['dropdown_value'] ?? "Select Role"),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
hint: Text("Select Role"),
|
|
||||||
disabledHint: Text(
|
|
||||||
selectedRole ?? "Select Role",
|
|
||||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -1429,7 +1630,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Password",
|
"Password *",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|||||||
@ -33,7 +33,6 @@ class TravellerDetails extends StatefulWidget {
|
|||||||
final String? passportFileUrlFromApi;
|
final String? passportFileUrlFromApi;
|
||||||
final String? userIdApi;
|
final String? userIdApi;
|
||||||
|
|
||||||
|
|
||||||
const TravellerDetails({
|
const TravellerDetails({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.controllers,
|
required this.controllers,
|
||||||
@ -149,15 +148,24 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> apiCheckDuplicate(String label, String field, String value, String? userId) async {
|
Future<void> apiCheckDuplicate(
|
||||||
|
String label,
|
||||||
|
String field,
|
||||||
|
String value,
|
||||||
|
String? userId,
|
||||||
|
) async {
|
||||||
|
var newField = "";
|
||||||
try {
|
try {
|
||||||
if(field == "forex_card_num"){
|
final response = await apiService.CheckDuplicate(
|
||||||
field = "forex_pre_paid_card_number";
|
label,
|
||||||
}
|
newField,
|
||||||
final response = await apiService.CheckDuplicate(label, field, value, userId);
|
value,
|
||||||
|
userId,
|
||||||
|
);
|
||||||
if (response.isNotEmpty) {
|
if (response.isNotEmpty) {
|
||||||
_clearError(field);
|
_clearError(field);
|
||||||
widget.errorMessages[field] = response['message'] ?? "$label already exists";
|
widget.errorMessages[field] =
|
||||||
|
response['message'] ?? "$label already exists";
|
||||||
print("Duplicate found: ${response['message']}");
|
print("Duplicate found: ${response['message']}");
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -705,6 +713,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
height: MediaQuery.of(context).size.height,
|
height: MediaQuery.of(context).size.height,
|
||||||
|
padding: const EdgeInsets.only(top: 8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border(
|
border: Border(
|
||||||
top: BorderSide(
|
top: BorderSide(
|
||||||
@ -1107,7 +1116,13 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
controller: controllers["passportNumber"],
|
controller: controllers["passportNumber"],
|
||||||
enabled: !widget.isViewMode,
|
enabled: !widget.isViewMode,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
_clearError("last_name");
|
_clearError("passport_number");
|
||||||
|
apiCheckDuplicate(
|
||||||
|
"Passport Number",
|
||||||
|
"passport_number",
|
||||||
|
value,
|
||||||
|
widget.userIdApi,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: "Passport Number",
|
labelText: "Passport Number",
|
||||||
@ -1122,6 +1137,13 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (widget.errorMessages["passport_number"] != null) ...[
|
||||||
|
SizedBox(height: 5), // Space before error message
|
||||||
|
Text(
|
||||||
|
widget.errorMessages["passport_number"]!,
|
||||||
|
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||||
|
),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1181,7 +1203,8 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
_selectedDateOfIssue != null && _selectedDateOfIssue!.isAfter(today)
|
_selectedDateOfIssue != null && _selectedDateOfIssue!.isAfter(today)
|
||||||
? _selectedDateOfIssue!
|
? _selectedDateOfIssue!
|
||||||
: today,
|
: today,
|
||||||
firstDate: today,
|
// firstDate: today,
|
||||||
|
firstDate: DateTime(1900),
|
||||||
lastDate: DateTime(2100),
|
lastDate: DateTime(2100),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1271,7 +1294,8 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
_selectedDateOfExpiry!.isAfter(today)
|
_selectedDateOfExpiry!.isAfter(today)
|
||||||
? _selectedDateOfExpiry!
|
? _selectedDateOfExpiry!
|
||||||
: today,
|
: today,
|
||||||
firstDate: today,
|
// firstDate: today,
|
||||||
|
firstDate: DateTime(1900),
|
||||||
lastDate: DateTime(2100),
|
lastDate: DateTime(2100),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2330,8 +2354,13 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
controller: controllers["forex_card_num"],
|
controller: controllers["forex_card_num"],
|
||||||
enabled: !widget.isViewMode,
|
enabled: !widget.isViewMode,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
_clearError("forex_card_num");
|
_clearError("forex_pre_paid_card_number");
|
||||||
apiCheckDuplicate("Forex Pre-Paid Card Number", "forex_card_num",value,widget.userIdApi);
|
apiCheckDuplicate(
|
||||||
|
"Forex Pre-Paid Card Number",
|
||||||
|
"forex_pre_paid_card_number",
|
||||||
|
value,
|
||||||
|
widget.userIdApi,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: "Card Number",
|
labelText: "Card Number",
|
||||||
@ -2467,9 +2496,16 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
height: 60,
|
height: 60,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(top: 20, left: 8), // 👈 Add top padding here
|
padding: EdgeInsets.only(
|
||||||
|
top: 20,
|
||||||
|
left: 8,
|
||||||
|
), // 👈 Add top padding here
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
|
icon: Icon(
|
||||||
|
Icons.remove_circle_sharp,
|
||||||
|
color: Colors.red,
|
||||||
|
size: 15,
|
||||||
|
),
|
||||||
tooltip: 'Cancel the Details',
|
tooltip: 'Cancel the Details',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -2480,7 +2516,6 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: Column(
|
: Column(
|
||||||
@ -2491,7 +2526,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
buildFrequentFlierInformation(entry),
|
buildFrequentFlierInformation(entry),
|
||||||
SizedBox(width: 15),
|
SizedBox(width: 15),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
|
icon: Icon(
|
||||||
|
Icons.remove_circle_sharp,
|
||||||
|
color: Colors.red,
|
||||||
|
size: 15,
|
||||||
|
),
|
||||||
tooltip: 'Cancel the Details',
|
tooltip: 'Cancel the Details',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -2773,30 +2812,37 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
child:
|
child:
|
||||||
widget.isDesktop
|
widget.isDesktop
|
||||||
? Row(
|
? Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
buildHotel(entry),
|
buildHotel(entry),
|
||||||
SizedBox(width: 25),
|
SizedBox(width: 25),
|
||||||
buildHotelMembershipNum(entry),
|
buildHotelMembershipNum(entry),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 60,
|
height: 60,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(top: 20, left: 8), // 👈 Add top padding here
|
padding: EdgeInsets.only(
|
||||||
child: IconButton(
|
top: 20,
|
||||||
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
|
left: 8,
|
||||||
tooltip: 'Cancel the Details',
|
), // 👈 Add top padding here
|
||||||
onPressed: () {
|
child: IconButton(
|
||||||
setState(() {
|
icon: Icon(
|
||||||
removeHotelLoyaltyEntry(entry);
|
Icons.remove_circle_sharp,
|
||||||
});
|
color: Colors.red,
|
||||||
},
|
size: 15,
|
||||||
|
),
|
||||||
|
tooltip: 'Cancel the Details',
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
removeHotelLoyaltyEntry(entry);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
),
|
)
|
||||||
],
|
|
||||||
)
|
|
||||||
: Column(
|
: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -2804,7 +2850,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
buildHotelMembershipNum(entry),
|
buildHotelMembershipNum(entry),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
|
icon: Icon(
|
||||||
|
Icons.remove_circle_sharp,
|
||||||
|
color: Colors.red,
|
||||||
|
size: 15,
|
||||||
|
),
|
||||||
tooltip: 'Cancel the Details',
|
tooltip: 'Cancel the Details',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -3035,9 +3085,16 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
height: 60,
|
height: 60,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(top: 20, left: 8), // 👈 Add top padding here
|
padding: EdgeInsets.only(
|
||||||
|
top: 20,
|
||||||
|
left: 8,
|
||||||
|
), // 👈 Add top padding here
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
|
icon: Icon(
|
||||||
|
Icons.remove_circle_sharp,
|
||||||
|
color: Colors.red,
|
||||||
|
size: 15,
|
||||||
|
),
|
||||||
tooltip: 'Cancel the Details',
|
tooltip: 'Cancel the Details',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -3061,7 +3118,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
buildVisaValidUpTo(entry),
|
buildVisaValidUpTo(entry),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
|
icon: Icon(
|
||||||
|
Icons.remove_circle_sharp,
|
||||||
|
color: Colors.red,
|
||||||
|
size: 15,
|
||||||
|
),
|
||||||
tooltip: 'Cancel the Details',
|
tooltip: 'Cancel the Details',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -3187,6 +3248,116 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<dynamic> purposeList = apiData?['visa_type_of_visa'];
|
||||||
|
|
||||||
|
// Map for id => name
|
||||||
|
Map<String, String> visaTypeMap = {
|
||||||
|
for (var item in purposeList)
|
||||||
|
item['dropdown_key'].toString(): item['dropdown_value'].toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Selected value from entry
|
||||||
|
String? selectedPurpose = entry['visa_type_id']?.toString();
|
||||||
|
|
||||||
|
if (!visaTypeMap.containsKey(selectedPurpose)) {
|
||||||
|
selectedPurpose = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Visa Type",
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 5),
|
||||||
|
CustomTextFieldUserTravellerWrapper(
|
||||||
|
width:
|
||||||
|
widget.isDesktop
|
||||||
|
? MediaQuery.of(context).size.width * 0.17
|
||||||
|
: null,
|
||||||
|
isFocused: false,
|
||||||
|
isDesktop: widget.isDesktop,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 40,
|
||||||
|
child: DropdownSearch<String>(
|
||||||
|
selectedItem: visaTypeMap[selectedPurpose],
|
||||||
|
enabled: purposeList.isNotEmpty,
|
||||||
|
popupProps: PopupProps.menu(
|
||||||
|
showSearchBox: true,
|
||||||
|
fit: FlexFit.loose,
|
||||||
|
menuProps: const MenuProps(backgroundColor: Colors.white),
|
||||||
|
constraints: BoxConstraints(maxHeight: 200),
|
||||||
|
itemBuilder:
|
||||||
|
(context, item, isSelected) => Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 6,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
item,
|
||||||
|
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
searchFieldProps: TextFieldProps(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: "Search Visa Type...",
|
||||||
|
hintStyle: GoogleFonts.poppins(fontSize: 11.5),
|
||||||
|
contentPadding: EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
items: visaTypeMap.values.toList(),
|
||||||
|
|
||||||
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
|
dropdownSearchDecoration: InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dropdownBuilder:
|
||||||
|
(context, selectedItem) => Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
selectedItem ?? "Select Visa Type",
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 12,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onChanged: (newValue) {
|
||||||
|
if (newValue == null) return;
|
||||||
|
|
||||||
|
final selectedId =
|
||||||
|
visaTypeMap.entries
|
||||||
|
.firstWhere((entry) => entry.value == newValue)
|
||||||
|
.key;
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
entry['visa_type_id'] = selectedId;
|
||||||
|
});
|
||||||
|
|
||||||
|
print("Updating form data: visa_type_id -> $selectedId");
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildVisaType3(entry) {
|
||||||
|
if (apiData == null || apiData?['visa_type_of_visa'] == null) {
|
||||||
|
return Center(
|
||||||
|
child: Transform.scale(scale: 0.5, child: CircularProgressIndicator()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// List<dynamic> purposeList = apiData?['visa_type_of_visa'] ?? [];
|
// List<dynamic> purposeList = apiData?['visa_type_of_visa'] ?? [];
|
||||||
// List<dynamic> purposeList = [];
|
// List<dynamic> purposeList = [];
|
||||||
List<dynamic> purposeList = apiData?['visa_type_of_visa'];
|
List<dynamic> purposeList = apiData?['visa_type_of_visa'];
|
||||||
@ -3402,8 +3573,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
|
|
||||||
final pickedDate = await showDatePicker(
|
final pickedDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
initialDate: initialDate,
|
// initialDate: initialDate,
|
||||||
firstDate: initialDate,
|
// firstDate: initialDate,
|
||||||
|
firstDate: DateTime(1900),
|
||||||
lastDate: DateTime(2100),
|
lastDate: DateTime(2100),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3490,8 +3662,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
|
|
||||||
final pickedDate = await showDatePicker(
|
final pickedDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
initialDate: initialDate,
|
// initialDate: initialDate,
|
||||||
firstDate: initialDate,
|
// firstDate: initialDate,
|
||||||
|
firstDate: DateTime(1900),
|
||||||
lastDate: DateTime(2100),
|
lastDate: DateTime(2100),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
// import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'dart:html' as html;
|
import 'dart:html' as html;
|
||||||
import 'package:frontend/config/apiUrl.dart'; // 1 newly added
|
import 'package:frontend/config/apiUrl.dart'; // 1 newly added
|
||||||
import 'package:frontend/services/apiService.dart';
|
import 'package:frontend/services/apiService.dart';
|
||||||
@ -31,7 +31,7 @@ class _MyAppState extends State<MyApp> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
// SemanticsBinding.instance.ensureSemantics(); // ✅ Safe here
|
SemanticsBinding.instance.ensureSemantics(); // ✅ Safe here
|
||||||
if (kIsWeb) {
|
if (kIsWeb) {
|
||||||
final uri = Uri.parse(html.window.location.href);
|
final uri = Uri.parse(html.window.location.href);
|
||||||
if (uri.path == '/authredirection' &&
|
if (uri.path == '/authredirection' &&
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
//api url
|
//api url
|
||||||
const String apiUrl = 'http://apitest.tripapprovaltool.com';
|
const String apiUrl = 'http://apitest.tripapprovaltool.com/tstat_be';
|
||||||
// const String apiUrl = 'https://uat.tripapprovaltool.com';
|
// const String apiUrl = 'https://uat.tripapprovaltool.com';
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user