OrgLevel Data, UserDetails
This commit is contained in:
parent
1f28816021
commit
886bef2baa
@ -4,17 +4,21 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:responsive_builder/responsive_builder.dart';
|
import 'package:responsive_builder/responsive_builder.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
|
||||||
import '../../config/apiUrl.dart';
|
import '../../config/apiUrl.dart';
|
||||||
import '../../data/models/Searchtraveller.dart';
|
import '../../data/models/Searchtraveller.dart';
|
||||||
import '../../data/models/searchUser.dart';
|
import '../../data/models/searchUser.dart';
|
||||||
|
import '../../utils/auth_utils.dart';
|
||||||
import '../../widgets/custom_text_traveller.dart';
|
import '../../widgets/custom_text_traveller.dart';
|
||||||
|
|
||||||
class UserSelectionDialog extends StatefulWidget {
|
class UserSelectionDialog extends StatefulWidget {
|
||||||
final String title;
|
final String title;
|
||||||
final void Function(String, String, bool) onSubmit;
|
final void Function(String, String, bool) onSubmit;
|
||||||
|
|
||||||
UserSelectionDialog({Key? key, required this.title, required this.onSubmit,}) : super(key: key);
|
UserSelectionDialog({
|
||||||
|
Key? key,
|
||||||
|
required this.title,
|
||||||
|
required this.onSubmit,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_UserSelectionDialogState createState() => _UserSelectionDialogState();
|
_UserSelectionDialogState createState() => _UserSelectionDialogState();
|
||||||
@ -31,21 +35,23 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
List<Map<String, dynamic>> _filteredList = [];
|
List<Map<String, dynamic>> _filteredList = [];
|
||||||
List<SearchTraveler> _filteredTraveller = [];
|
List<SearchTraveler> _filteredTraveller = [];
|
||||||
String userIdSelected = " ";
|
String userIdSelected = " ";
|
||||||
bool isTraveller = false;
|
|
||||||
|
|
||||||
|
bool isTraveller = false;
|
||||||
bool _showTravellerForm = false;
|
bool _showTravellerForm = false;
|
||||||
|
|
||||||
final _formKey = GlobalKey<FormState>();
|
String? orgId;
|
||||||
|
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
Future<String?> getToken() async {
|
Future<String?> getToken() async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
return prefs.getString('auth_token');
|
return prefs.getString('auth_token');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<void> fetchUsers() async {
|
Future<void> fetchUsers() async {
|
||||||
final String apiUrldata = '$apiUrl/api/users';
|
orgId = await getOrgId();
|
||||||
|
// final String apiUrlData = '$apiUrl/api/users?org_id=$orgId';
|
||||||
|
final String apiUrldata = '$apiUrl/api/users?org_id=$orgId';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final token = await getToken();
|
final token = await getToken();
|
||||||
@ -64,7 +70,6 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final Map<String, dynamic> responseBody = json.decode(response.body);
|
final Map<String, dynamic> responseBody = json.decode(response.body);
|
||||||
|
|
||||||
|
|
||||||
print("API Response: $responseBody"); // Debugging
|
print("API Response: $responseBody"); // Debugging
|
||||||
|
|
||||||
if (responseBody.containsKey('data') && responseBody['data'] is List) {
|
if (responseBody.containsKey('data') && responseBody['data'] is List) {
|
||||||
@ -88,18 +93,69 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
for (var user in _users) {
|
for (var user in _users) {
|
||||||
print("${user.firstName} ${user.lastName}");
|
print("${user.firstName} ${user.lastName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw Exception("Unexpected response format: Expected a List but got ${responseBody.runtimeType}");
|
throw Exception(
|
||||||
|
"Unexpected response format: Expected a List but got ${responseBody.runtimeType}");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw Exception('Failed to load users. Status Code: ${response.statusCode}');
|
throw Exception(
|
||||||
|
'Failed to load users. Status Code: ${response.statusCode}');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Error fetching users: $e");
|
print("Error fetching users: $e");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> fetchTraveller() async {
|
||||||
|
orgId = await getOrgId();
|
||||||
|
final String apiUrldata = '$apiUrl/api/travellers?org_id=$orgId';
|
||||||
|
|
||||||
|
try {
|
||||||
|
final token = await getToken();
|
||||||
|
if (token == null) {
|
||||||
|
throw Exception('Token not found. Please log in.');
|
||||||
|
}
|
||||||
|
|
||||||
|
final response = await http.get(
|
||||||
|
Uri.parse(apiUrldata),
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer $token',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final Map<String, dynamic> responseBody = json.decode(response.body);
|
||||||
|
|
||||||
|
print("API Response: $responseBody"); // Debugging
|
||||||
|
|
||||||
|
if (responseBody.containsKey('data') && responseBody['data'] is List) {
|
||||||
|
List<dynamic> travellerList = responseBody['data'];
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_traveller = travellerList
|
||||||
|
.map((user) => SearchTraveler.fromJson(user))
|
||||||
|
.toList();
|
||||||
|
_filteredTraveller = List.from(_traveller);
|
||||||
|
});
|
||||||
|
|
||||||
|
print("Users fetched: ${_users.length}");
|
||||||
|
for (var travvelr in _traveller) {
|
||||||
|
print("${travvelr.firstName} ${travvelr.lastName}");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception(
|
||||||
|
"Unexpected response format: Expected a List but got ${responseBody.runtimeType}");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception(
|
||||||
|
'Failed to load users. Status Code: ${response.statusCode}');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("Error fetching traveller: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _filterUsers1(String query) {
|
void _filterUsers1(String query) {
|
||||||
print("Filtering users...");
|
print("Filtering users...");
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -115,7 +171,8 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
user.alternateMobileNo ?? ""
|
user.alternateMobileNo ?? ""
|
||||||
];
|
];
|
||||||
|
|
||||||
return searchFields.any((field) => field.contains(query.toLowerCase()));
|
return searchFields
|
||||||
|
.any((field) => field.contains(query.toLowerCase()));
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -126,7 +183,6 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _filterUsers(String query) {
|
void _filterUsers(String query) {
|
||||||
print("Filtering _filterUsersTravellers...");
|
print("Filtering _filterUsersTravellers...");
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -146,9 +202,9 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
user.mobileNo ?? "",
|
user.mobileNo ?? "",
|
||||||
user.alternateMobileNo ?? ""
|
user.alternateMobileNo ?? ""
|
||||||
];
|
];
|
||||||
return searchFields.any((field) => field.contains(query.toLowerCase()));
|
return searchFields
|
||||||
|
.any((field) => field.contains(query.toLowerCase()));
|
||||||
}).map((user) => {"type": "user", "data": user}),
|
}).map((user) => {"type": "user", "data": user}),
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -156,7 +212,8 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
print("Filtered List:");
|
print("Filtered List:");
|
||||||
for (var item in _filteredList) {
|
for (var item in _filteredList) {
|
||||||
var user = item["data"];
|
var user = item["data"];
|
||||||
print("${item["type"].toUpperCase()} - ${user.firstName} ${user.lastName}");
|
print(
|
||||||
|
"${item["type"].toUpperCase()} - ${user.firstName} ${user.lastName}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +225,8 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
if (query.isEmpty) {
|
if (query.isEmpty) {
|
||||||
_filteredList = [
|
_filteredList = [
|
||||||
..._users.map((user) => {"type": "user", "data": user}),
|
..._users.map((user) => {"type": "user", "data": user}),
|
||||||
..._traveller.map((traveller) => {"type": "traveller", "data": traveller}),
|
..._traveller
|
||||||
|
.map((traveller) => {"type": "traveller", "data": traveller}),
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
_filteredList = [
|
_filteredList = [
|
||||||
@ -180,9 +238,9 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
user.mobileNo ?? "",
|
user.mobileNo ?? "",
|
||||||
user.alternateMobileNo ?? ""
|
user.alternateMobileNo ?? ""
|
||||||
];
|
];
|
||||||
return searchFields.any((field) => field.contains(query.toLowerCase()));
|
return searchFields
|
||||||
|
.any((field) => field.contains(query.toLowerCase()));
|
||||||
}).map((user) => {"type": "user", "data": user}),
|
}).map((user) => {"type": "user", "data": user}),
|
||||||
|
|
||||||
..._traveller.where((traveller) {
|
..._traveller.where((traveller) {
|
||||||
List<String> searchFields = [
|
List<String> searchFields = [
|
||||||
"${traveller.firstName} ${traveller.lastName}".toLowerCase(),
|
"${traveller.firstName} ${traveller.lastName}".toLowerCase(),
|
||||||
@ -190,7 +248,8 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
traveller.travellerId.toLowerCase() ?? "",
|
traveller.travellerId.toLowerCase() ?? "",
|
||||||
traveller.mobileNo ?? "",
|
traveller.mobileNo ?? "",
|
||||||
];
|
];
|
||||||
return searchFields.any((field) => field.contains(query.toLowerCase()));
|
return searchFields
|
||||||
|
.any((field) => field.contains(query.toLowerCase()));
|
||||||
}).map((traveller) => {"type": "traveller", "data": traveller}),
|
}).map((traveller) => {"type": "traveller", "data": traveller}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -199,58 +258,10 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
print("Filtered List:");
|
print("Filtered List:");
|
||||||
for (var item in _filteredList) {
|
for (var item in _filteredList) {
|
||||||
var user = item["data"];
|
var user = item["data"];
|
||||||
print("${item["type"].toUpperCase()} - ${user.firstName} ${user.lastName}");
|
print(
|
||||||
|
"${item["type"].toUpperCase()} - ${user.firstName} ${user.lastName}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Future<void> fetchTraveller() async {
|
|
||||||
final String apiUrldata = '$apiUrl/api/travellers';
|
|
||||||
|
|
||||||
try {
|
|
||||||
final token = await getToken();
|
|
||||||
if (token == null) {
|
|
||||||
throw Exception('Token not found. Please log in.');
|
|
||||||
}
|
|
||||||
|
|
||||||
final response = await http.get(
|
|
||||||
Uri.parse(apiUrldata),
|
|
||||||
headers: {
|
|
||||||
'Authorization': 'Bearer $token',
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
|
||||||
final Map<String,dynamic> responseBody = json.decode(response.body);
|
|
||||||
|
|
||||||
|
|
||||||
print("API Response: $responseBody"); // Debugging
|
|
||||||
|
|
||||||
if (responseBody.containsKey('data') && responseBody['data'] is List) {
|
|
||||||
List<dynamic> travellerList = responseBody['data'];
|
|
||||||
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
_traveller = travellerList.map((user) => SearchTraveler.fromJson(user)).toList();
|
|
||||||
_filteredTraveller = List.from(_traveller);
|
|
||||||
});
|
|
||||||
|
|
||||||
print("Users fetched: ${_users.length}");
|
|
||||||
for (var travvelr in _traveller) {
|
|
||||||
print("${travvelr.firstName} ${travvelr.lastName}");
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw Exception("Unexpected response format: Expected a List but got ${responseBody.runtimeType}");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw Exception('Failed to load users. Status Code: ${response.statusCode}');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
print("Error fetching traveller: $e");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -268,7 +279,8 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
width: 400, // Adjust width as needed
|
width: 400, // Adjust width as needed
|
||||||
padding: EdgeInsets.all(16),
|
padding: EdgeInsets.all(16),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min, // Ensures content doesn't expand unnecessarily
|
mainAxisSize:
|
||||||
|
MainAxisSize.min, // Ensures content doesn't expand unnecessarily
|
||||||
children: [
|
children: [
|
||||||
Text("Please Select User", style: TextStyle(fontSize: 14)),
|
Text("Please Select User", style: TextStyle(fontSize: 14)),
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
@ -280,15 +292,16 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
setState(() {
|
setState(() {
|
||||||
_showTravellerForm = false;
|
_showTravellerForm = false;
|
||||||
});
|
});
|
||||||
widget.title == "Others"? _filterUsersTravellers(query):
|
widget.title == "Others"
|
||||||
_filterUsers(query);
|
? _filterUsersTravellers(query)
|
||||||
|
: _filterUsers(query);
|
||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "Search for a user",
|
hintText: "Search for a user",
|
||||||
hintStyle: TextStyle(fontSize: 14),
|
hintStyle: TextStyle(fontSize: 14),
|
||||||
prefixIcon: Icon(Icons.search),
|
prefixIcon: Icon(Icons.search),
|
||||||
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
|
border:
|
||||||
|
OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
borderSide: BorderSide(color: Colors.blueAccent, width: 2),
|
borderSide: BorderSide(color: Colors.blueAccent, width: 2),
|
||||||
@ -301,7 +314,8 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text("or create a new traveler", style: TextStyle(fontSize: 14, color: Color(0xFF575A74))),
|
Text("or create a new traveler",
|
||||||
|
style: TextStyle(fontSize: 14, color: Color(0xFF575A74))),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -309,7 +323,9 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
_searchController.clear();
|
_searchController.clear();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Text("Create", style: TextStyle(fontSize: 14, color: Colors.blueAccent)),
|
child: Text("Create",
|
||||||
|
style:
|
||||||
|
TextStyle(fontSize: 14, color: Colors.blueAccent)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -326,7 +342,8 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
? Center(
|
? Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
"No users found",
|
"No users found",
|
||||||
style: TextStyle(fontSize: 14, color: Colors.grey),
|
style:
|
||||||
|
TextStyle(fontSize: 14, color: Colors.grey),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: ListView.builder(
|
: ListView.builder(
|
||||||
@ -337,25 +354,33 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
|
|
||||||
final item = _filteredList[index];
|
final item = _filteredList[index];
|
||||||
final user = item["data"]; // Extract user object
|
final user = item["data"]; // Extract user object
|
||||||
final userType = item["type"]; // "user" or "traveller"
|
final userType =
|
||||||
|
item["type"]; // "user" or "traveller"
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text("${user.firstName ?? "Unknown"} ${user.lastName ?? ""}"),
|
title: Text(
|
||||||
subtitle: Text("ID: ${userType == "user" ? user.userId : user.travellerId}"),
|
"${user.firstName ?? "Unknown"} ${user.lastName ?? ""}"),
|
||||||
|
subtitle: Text(
|
||||||
|
"ID: ${userType == "user" ? user.userId : user.travellerId}"),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
String selectedUser = "${user.firstName ?? "Unknown"} ${user.lastName ?? ""}";
|
String selectedUser =
|
||||||
|
"${user.firstName ?? "Unknown"} ${user.lastName ?? ""}";
|
||||||
setState(() {
|
setState(() {
|
||||||
_searchController.text = selectedUser;
|
_searchController.text = selectedUser;
|
||||||
userIdSelected = userType == "user" ? user.userId : user.travellerId;
|
userIdSelected = userType == "user"
|
||||||
|
? user.userId
|
||||||
|
: user.travellerId;
|
||||||
isTraveller = userType == "traveller";
|
isTraveller = userType == "traveller";
|
||||||
});
|
});
|
||||||
print("Selected: $selectedUser, ID: ${userType == "user" ? user.userId : user.travellerId},"
|
print(
|
||||||
|
"Selected: $selectedUser, ID: ${userType == "user" ? user.userId : user.travellerId},"
|
||||||
" isTraveller: $userIdSelected");
|
" isTraveller: $userIdSelected");
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
) : SizedBox.shrink(),
|
)
|
||||||
|
: SizedBox.shrink(),
|
||||||
|
|
||||||
// Traveler Form
|
// Traveler Form
|
||||||
if (_showTravellerForm)
|
if (_showTravellerForm)
|
||||||
@ -366,13 +391,16 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: TravelerForm(
|
child: TravelerForm(
|
||||||
formKey: _formKey,
|
formKey: _formKey,
|
||||||
onSubmit: (String fullName, String travellerId, bool isTraveller) {
|
onSubmit: (String fullName, String travellerId,
|
||||||
widget.onSubmit(fullName, travellerId,isTraveller); // Pass the data up
|
bool isTraveller) {
|
||||||
|
widget.onSubmit(fullName, travellerId,
|
||||||
|
isTraveller); // Pass the data up
|
||||||
},
|
},
|
||||||
firstNameController: TextEditingController(),
|
firstNameController: TextEditingController(),
|
||||||
lastNameController: TextEditingController(),
|
lastNameController: TextEditingController(),
|
||||||
emailController: TextEditingController(),
|
emailController: TextEditingController(),
|
||||||
mobileController: TextEditingController(),
|
mobileController: TextEditingController(),
|
||||||
|
orgId: orgId,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -392,7 +420,9 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
),
|
),
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
child: Text("Cancel",),
|
child: Text(
|
||||||
|
"Cancel",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
@ -406,8 +436,10 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
print("Submitting: ${_searchController.text}, ID: $userIdSelected");
|
print(
|
||||||
widget.onSubmit(_searchController.text,userIdSelected,isTraveller);
|
"Submitting: ${_searchController.text}, ID: $userIdSelected");
|
||||||
|
widget.onSubmit(
|
||||||
|
_searchController.text, userIdSelected, isTraveller);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
child: Text("Submit"),
|
child: Text("Submit"),
|
||||||
@ -419,7 +451,6 @@ class _UserSelectionDialogState extends State<UserSelectionDialog>{
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TravelerForm extends StatefulWidget {
|
class TravelerForm extends StatefulWidget {
|
||||||
@ -427,25 +458,24 @@ class TravelerForm extends StatefulWidget {
|
|||||||
final TextEditingController lastNameController;
|
final TextEditingController lastNameController;
|
||||||
final TextEditingController emailController;
|
final TextEditingController emailController;
|
||||||
final TextEditingController mobileController;
|
final TextEditingController mobileController;
|
||||||
|
final String? orgId;
|
||||||
final GlobalKey<FormState> formKey;
|
final GlobalKey<FormState> formKey;
|
||||||
final void Function(String, String, bool) onSubmit;
|
final void Function(String, String, bool) onSubmit;
|
||||||
|
|
||||||
TravelerForm({
|
TravelerForm(
|
||||||
required this.formKey,
|
{required this.formKey,
|
||||||
|
required this.orgId,
|
||||||
required this.firstNameController,
|
required this.firstNameController,
|
||||||
required this.lastNameController,
|
required this.lastNameController,
|
||||||
required this.emailController,
|
required this.emailController,
|
||||||
required this.mobileController,
|
required this.mobileController,
|
||||||
required this.onSubmit
|
required this.onSubmit});
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_TravelerFormState createState() => _TravelerFormState();
|
_TravelerFormState createState() => _TravelerFormState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _TravelerFormState extends State<TravelerForm> {
|
class _TravelerFormState extends State<TravelerForm> {
|
||||||
|
|
||||||
|
|
||||||
Future<String?> getToken() async {
|
Future<String?> getToken() async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
return prefs.getString('auth_token');
|
return prefs.getString('auth_token');
|
||||||
@ -472,27 +502,29 @@ class _TravelerFormState extends State<TravelerForm> {
|
|||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return 'Email is required';
|
return 'Email is required';
|
||||||
}
|
}
|
||||||
if (!RegExp(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$').hasMatch(value)) {
|
if (!RegExp(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$')
|
||||||
|
.hasMatch(value)) {
|
||||||
return 'Enter a valid email address';
|
return 'Enter a valid email address';
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onSubmit(BuildContext context) {
|
Future<void> _onSubmit(BuildContext context) async {
|
||||||
bool isValid = _validateForm();
|
bool isValid = _validateForm();
|
||||||
print("Form Validation Result: $isValid");
|
print("Form Validation Result: $isValid");
|
||||||
|
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
print("Validation Success");
|
print("Validation Success");
|
||||||
|
|
||||||
_submitForm(context);
|
_submitForm(context);
|
||||||
} else {
|
} else {
|
||||||
print("Validation Failed"); // This should now print if validation fails
|
print("Validation Failed"); // This should now print if validation fails
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<void> _submitForm(BuildContext context) async {
|
Future<void> _submitForm(BuildContext context) async {
|
||||||
Map<String, String> requestBody = {
|
Map<String, String> requestBody = {
|
||||||
|
"org_id": widget.orgId!,
|
||||||
"first_name": widget.firstNameController.text,
|
"first_name": widget.firstNameController.text,
|
||||||
"last_name": widget.lastNameController.text,
|
"last_name": widget.lastNameController.text,
|
||||||
"email": widget.emailController.text,
|
"email": widget.emailController.text,
|
||||||
@ -516,24 +548,24 @@ class _TravelerFormState extends State<TravelerForm> {
|
|||||||
body: jsonEncode(requestBody),
|
body: jsonEncode(requestBody),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||||
|
|
||||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||||
final Map<String, dynamic> responseData = jsonDecode(response.body); // Parse response
|
final Map<String, dynamic> responseData =
|
||||||
if (responseData["success"] == true && responseData.containsKey("data")) {
|
jsonDecode(response.body); // Parse response
|
||||||
|
if (responseData["success"] == true &&
|
||||||
|
responseData.containsKey("data")) {
|
||||||
final travellerData = responseData["data"];
|
final travellerData = responseData["data"];
|
||||||
|
|
||||||
String travellerId = travellerData["traveller_id"];
|
String travellerId = travellerData["traveller_id"];
|
||||||
String firstName = travellerData["first_name"];
|
String firstName = travellerData["first_name"];
|
||||||
String lastName = travellerData["last_name"];
|
String lastName = travellerData["last_name"];
|
||||||
|
|
||||||
print("Traveller Added: ID: $travellerId, Name: $firstName $lastName");
|
print(
|
||||||
|
"Traveller Added: ID: $travellerId, Name: $firstName $lastName");
|
||||||
|
|
||||||
// Pass data to callback
|
// Pass data to callback
|
||||||
widget.onSubmit("$firstName $lastName", travellerId, true);
|
widget.onSubmit("$firstName $lastName", travellerId, true);
|
||||||
|
|
||||||
|
|
||||||
// Close the dialog
|
// Close the dialog
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
@ -545,7 +577,8 @@ class _TravelerFormState extends State<TravelerForm> {
|
|||||||
"Traveller added successfully!",
|
"Traveller added successfully!",
|
||||||
style: TextStyle(color: Colors.white), // ✅ Set text color
|
style: TextStyle(color: Colors.white), // ✅ Set text color
|
||||||
),
|
),
|
||||||
backgroundColor: Colors.green,),
|
backgroundColor: Colors.green,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
@ -564,7 +597,8 @@ class _TravelerFormState extends State<TravelerForm> {
|
|||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInfo) {
|
builder: (context, sizingInfo) {
|
||||||
double widthFactor;
|
double widthFactor;
|
||||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
bool isDesktop =
|
||||||
|
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||||
|
|
||||||
if (sizingInfo.deviceScreenType == DeviceScreenType.desktop) {
|
if (sizingInfo.deviceScreenType == DeviceScreenType.desktop) {
|
||||||
widthFactor = 0.23;
|
widthFactor = 0.23;
|
||||||
@ -599,7 +633,8 @@ class _TravelerFormState extends State<TravelerForm> {
|
|||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => _onSubmit(context),
|
onPressed: () => _onSubmit(context),
|
||||||
child: Text("Add", style: TextStyle(color: Colors.blueAccent)),
|
child:
|
||||||
|
Text("Add", style: TextStyle(color: Colors.blueAccent)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@ -6,15 +6,16 @@ import '../../widgets/custom_text_field.dart';
|
|||||||
import '../../widgets/custom_text_itnerary_sub.dart';
|
import '../../widgets/custom_text_itnerary_sub.dart';
|
||||||
|
|
||||||
class AccomodationScreen extends StatefulWidget {
|
class AccomodationScreen extends StatefulWidget {
|
||||||
|
|
||||||
final Function(bool) onClose; // Callback function
|
final Function(bool) onClose; // Callback function
|
||||||
final Function(Map<String, dynamic>) onSaveAccomadation;
|
final Function(Map<String, dynamic>) onSaveAccomadation;
|
||||||
final Map<String, dynamic>? selectedItem;
|
final Map<String, dynamic>? selectedItem;
|
||||||
final String? loginUser;
|
final String? loginUser;
|
||||||
|
|
||||||
|
AccomodationScreen(
|
||||||
AccomodationScreen({
|
{required this.onClose,
|
||||||
required this.onClose, required this.onSaveAccomadation, required this.selectedItem, required this.loginUser});
|
required this.onSaveAccomadation,
|
||||||
|
required this.selectedItem,
|
||||||
|
required this.loginUser});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_AccomodationScreenState createState() => _AccomodationScreenState();
|
_AccomodationScreenState createState() => _AccomodationScreenState();
|
||||||
@ -31,7 +32,6 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
final FocusNode _checkOutTimeFocusNode = FocusNode();
|
final FocusNode _checkOutTimeFocusNode = FocusNode();
|
||||||
final FocusNode _commentsFocusNode = FocusNode();
|
final FocusNode _commentsFocusNode = FocusNode();
|
||||||
|
|
||||||
|
|
||||||
late TextEditingController _destinationController = TextEditingController();
|
late TextEditingController _destinationController = TextEditingController();
|
||||||
late TextEditingController _hotelNameController = TextEditingController();
|
late TextEditingController _hotelNameController = TextEditingController();
|
||||||
late TextEditingController _checkInController = TextEditingController();
|
late TextEditingController _checkInController = TextEditingController();
|
||||||
@ -59,7 +59,6 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
Map<String, String> errorMessages = {};
|
Map<String, String> errorMessages = {};
|
||||||
|
|
||||||
Map<String, dynamic> get accomadationData {
|
Map<String, dynamic> get accomadationData {
|
||||||
|
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
"destination_city": _destinationController.text,
|
"destination_city": _destinationController.text,
|
||||||
"hotel_name": _hotelNameController.text,
|
"hotel_name": _hotelNameController.text,
|
||||||
@ -73,9 +72,11 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (widget.selectedItem != null) {
|
if (widget.selectedItem != null) {
|
||||||
if (widget.selectedItem?["indx"] != null && widget.selectedItem?["indx"] != 0) {
|
if (widget.selectedItem?["indx"] != null &&
|
||||||
|
widget.selectedItem?["indx"] != 0) {
|
||||||
data["indx"] = widget.selectedItem!["indx"];
|
data["indx"] = widget.selectedItem!["indx"];
|
||||||
} else if (widget.selectedItem?["accomodation_id"] != null && widget.selectedItem?["accomodation_id"] != 0) {
|
} else if (widget.selectedItem?["accomodation_id"] != null &&
|
||||||
|
widget.selectedItem?["accomodation_id"] != 0) {
|
||||||
data["accomodation_id"] = widget.selectedItem!["accomodation_id"];
|
data["accomodation_id"] = widget.selectedItem!["accomodation_id"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,16 +87,19 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
return TextEditingController(text: widget.selectedItem?[key] ?? "");
|
return TextEditingController(text: widget.selectedItem?[key] ?? "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_addFocusListener(_destinationFocusNode, (focus) => _destinationFocused = focus);
|
_addFocusListener(
|
||||||
_addFocusListener(_hotelNameFocusNode, (focus) => _isHotelNameFocused = focus);
|
_destinationFocusNode, (focus) => _destinationFocused = focus);
|
||||||
|
_addFocusListener(
|
||||||
|
_hotelNameFocusNode, (focus) => _isHotelNameFocused = focus);
|
||||||
_addFocusListener(_checkInFocusNode, (focus) => _checkInFocus = focus);
|
_addFocusListener(_checkInFocusNode, (focus) => _checkInFocus = focus);
|
||||||
_addFocusListener(_checkInTimeFocusNode, (focus) => _checkInTimeFocus = focus);
|
_addFocusListener(
|
||||||
|
_checkInTimeFocusNode, (focus) => _checkInTimeFocus = focus);
|
||||||
_addFocusListener(_checkOutFocusNode, (focus) => _checkOutFocus = focus);
|
_addFocusListener(_checkOutFocusNode, (focus) => _checkOutFocus = focus);
|
||||||
_addFocusListener(_checkOutTimeFocusNode, (focus) => _checkOutTimeFocus = focus);
|
_addFocusListener(
|
||||||
|
_checkOutTimeFocusNode, (focus) => _checkOutTimeFocus = focus);
|
||||||
_addFocusListener(_commentsFocusNode, (focus) => _commentsFocus = focus);
|
_addFocusListener(_commentsFocusNode, (focus) => _commentsFocus = focus);
|
||||||
|
|
||||||
_destinationController = initController("destination_city");
|
_destinationController = initController("destination_city");
|
||||||
@ -106,7 +110,6 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
_checkOutTimeController = initController("checkout_time");
|
_checkOutTimeController = initController("checkout_time");
|
||||||
_commentsController = initController("comments");
|
_commentsController = initController("comments");
|
||||||
|
|
||||||
|
|
||||||
_destinationController.addListener(() => _clearError("destination_city"));
|
_destinationController.addListener(() => _clearError("destination_city"));
|
||||||
_hotelNameController.addListener(() => _clearError("hotel_name"));
|
_hotelNameController.addListener(() => _clearError("hotel_name"));
|
||||||
_checkInController.addListener(() => _clearError("checkin_date"));
|
_checkInController.addListener(() => _clearError("checkin_date"));
|
||||||
@ -115,8 +118,6 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
_checkOutTimeController.addListener(() => _clearError("checkout_time"));
|
_checkOutTimeController.addListener(() => _clearError("checkout_time"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_destinationFocusNode.dispose();
|
_destinationFocusNode.dispose();
|
||||||
@ -137,12 +138,19 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isValidData(Map<String, dynamic> data) {
|
bool isValidData(Map<String, dynamic> data) {
|
||||||
errorMessages.clear(); // Reset errors
|
errorMessages.clear(); // Reset errors
|
||||||
|
|
||||||
// Required fields that must not be empty
|
// Required fields that must not be empty
|
||||||
List<String> requiredFields = ["destination_city", "hotel_name","checkin_date","checkin_time","checkout_date",
|
List<String> requiredFields = [
|
||||||
"checkout_time"];
|
"destination_city",
|
||||||
|
"hotel_name",
|
||||||
|
"checkin_date",
|
||||||
|
"checkin_time",
|
||||||
|
"checkout_date",
|
||||||
|
"checkout_time"
|
||||||
|
];
|
||||||
|
|
||||||
// Check validation for each field
|
// Check validation for each field
|
||||||
for (String field in requiredFields) {
|
for (String field in requiredFields) {
|
||||||
@ -154,9 +162,7 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
return errorMessages.isEmpty; // Valid if there are no errors
|
return errorMessages.isEmpty; // Valid if there are no errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void handleSave() {
|
void handleSave() {
|
||||||
|
|
||||||
print("Handle Save accomadationData $accomadationData");
|
print("Handle Save accomadationData $accomadationData");
|
||||||
|
|
||||||
Map<String, dynamic> data = accomadationData;
|
Map<String, dynamic> data = accomadationData;
|
||||||
@ -172,7 +178,6 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
widget.onClose(false); // Close screen after saving
|
widget.onClose(false); // Close screen after saving
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||||
@ -201,10 +206,11 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
Text("Accomodation Booking",
|
Text("Accomodation Booking",
|
||||||
style:
|
style: TextStyle(
|
||||||
TextStyle(fontSize: 18, fontWeight: FontWeight.bold,color: Color(0xFF575A74))),
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Color(0xFF575A74))),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 6,
|
height: 6,
|
||||||
),
|
),
|
||||||
@ -275,6 +281,9 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: _destinationFocused,
|
isFocused: _destinationFocused,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
|
width: isDesktop
|
||||||
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
@ -320,6 +329,9 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: _isHotelNameFocused,
|
isFocused: _isHotelNameFocused,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
|
width: isDesktop
|
||||||
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
@ -336,7 +348,6 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
if (errorMessages["hotel_name"] != null) ...[
|
if (errorMessages["hotel_name"] != null) ...[
|
||||||
SizedBox(height: 5), // Space before error message
|
SizedBox(height: 5), // Space before error message
|
||||||
Text(
|
Text(
|
||||||
@ -359,7 +370,8 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
|
|
||||||
DateTime? pickedDate = await showDatePicker(
|
DateTime? pickedDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
initialDate: _selectedCheckInDate != null && _selectedCheckInDate!.isAfter(today)
|
initialDate:
|
||||||
|
_selectedCheckInDate != null && _selectedCheckInDate!.isAfter(today)
|
||||||
? _selectedCheckInDate!
|
? _selectedCheckInDate!
|
||||||
: today,
|
: today,
|
||||||
firstDate: today,
|
firstDate: today,
|
||||||
@ -395,7 +407,6 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
}
|
}
|
||||||
//-------------------------------Check-In End
|
//-------------------------------Check-In End
|
||||||
|
|
||||||
|
|
||||||
DateTime? _selectedCheckOutDate;
|
DateTime? _selectedCheckOutDate;
|
||||||
TimeOfDay? _selectedCheckOutTime;
|
TimeOfDay? _selectedCheckOutTime;
|
||||||
|
|
||||||
@ -405,9 +416,8 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
|
|
||||||
DateTime? pickedDate = await showDatePicker(
|
DateTime? pickedDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
|
initialDate: _selectedCheckOutDate != null &&
|
||||||
|
_selectedCheckOutDate!.isAfter(today)
|
||||||
initialDate: _selectedCheckOutDate != null && _selectedCheckOutDate!.isAfter(today)
|
|
||||||
? _selectedCheckOutDate!
|
? _selectedCheckOutDate!
|
||||||
: today,
|
: today,
|
||||||
firstDate: today,
|
firstDate: today,
|
||||||
@ -417,7 +427,8 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
|
if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedCheckOutDate = pickedDate;
|
_selectedCheckOutDate = pickedDate;
|
||||||
_checkOutController.text = DateFormat('yyyy-MM-dd').format(pickedDate);
|
_checkOutController.text =
|
||||||
|
DateFormat('yyyy-MM-dd').format(pickedDate);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -442,9 +453,6 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -566,7 +574,6 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => _selectCheckOutDate(context),
|
onTap: () => _selectCheckOutDate(context),
|
||||||
child: AbsorbPointer(
|
child: AbsorbPointer(
|
||||||
@ -586,7 +593,6 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (errorMessages["checkout_date"] != null) ...[
|
if (errorMessages["checkout_date"] != null) ...[
|
||||||
@ -639,7 +645,6 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (errorMessages["checkout_time"] != null) ...[
|
if (errorMessages["checkout_time"] != null) ...[
|
||||||
@ -671,7 +676,7 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
|||||||
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
width: isDesktop
|
width: isDesktop
|
||||||
? MediaQuery.of(context).size.width * 0.4
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
: MediaQuery.of(context).size.width * 0.66,
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: _commentsFocusNode,
|
focusNode: _commentsFocusNode,
|
||||||
|
|||||||
@ -6,15 +6,18 @@ import '../../widgets/custom_text_field.dart';
|
|||||||
import '../../widgets/custom_text_itnerary_sub.dart';
|
import '../../widgets/custom_text_itnerary_sub.dart';
|
||||||
|
|
||||||
class BusScreen extends StatefulWidget {
|
class BusScreen extends StatefulWidget {
|
||||||
|
|
||||||
final Map<String, dynamic>? apiData;
|
final Map<String, dynamic>? apiData;
|
||||||
final Function(bool) onClose;
|
final Function(bool) onClose;
|
||||||
final Function(Map<String, dynamic>) onSaveBus;
|
final Function(Map<String, dynamic>) onSaveBus;
|
||||||
final Map<String, dynamic>? selectedItem;
|
final Map<String, dynamic>? selectedItem;
|
||||||
final String? loginUser;
|
final String? loginUser;
|
||||||
|
|
||||||
BusScreen({
|
BusScreen(
|
||||||
required this.onClose, this.apiData, required this.onSaveBus, required this.selectedItem, required this.loginUser});
|
{required this.onClose,
|
||||||
|
this.apiData,
|
||||||
|
required this.onSaveBus,
|
||||||
|
required this.selectedItem,
|
||||||
|
required this.loginUser});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_BusScreenState createState() => _BusScreenState();
|
_BusScreenState createState() => _BusScreenState();
|
||||||
@ -52,7 +55,6 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
bool _timeFocus = false;
|
bool _timeFocus = false;
|
||||||
bool _commentsFocus = false;
|
bool _commentsFocus = false;
|
||||||
|
|
||||||
|
|
||||||
Map<String, dynamic> get busData {
|
Map<String, dynamic> get busData {
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
"from": _fromController.text,
|
"from": _fromController.text,
|
||||||
@ -64,16 +66,16 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
"updated_by": widget.loginUser,
|
"updated_by": widget.loginUser,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
if (widget.selectedItem != null) {
|
if (widget.selectedItem != null) {
|
||||||
if (widget.selectedItem?["indx"] != null && widget.selectedItem?["indx"] != 0) {
|
if (widget.selectedItem?["indx"] != null &&
|
||||||
|
widget.selectedItem?["indx"] != 0) {
|
||||||
data["indx"] = widget.selectedItem!["indx"];
|
data["indx"] = widget.selectedItem!["indx"];
|
||||||
} else if (widget.selectedItem?["bus_id"] != null && widget.selectedItem?["bus_id"] != 0) {
|
} else if (widget.selectedItem?["bus_id"] != null &&
|
||||||
|
widget.selectedItem?["bus_id"] != 0) {
|
||||||
data["bus_id"] = widget.selectedItem!["bus_id"];
|
data["bus_id"] = widget.selectedItem!["bus_id"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,8 +127,6 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
_buscommentsController = initController("comments");
|
_buscommentsController = initController("comments");
|
||||||
_fromController = initController("from");
|
_fromController = initController("from");
|
||||||
_toController = initController("to");
|
_toController = initController("to");
|
||||||
@ -137,7 +137,6 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
_toController.addListener(() => _clearError("to"));
|
_toController.addListener(() => _clearError("to"));
|
||||||
_dateController.addListener(() => _clearError("date"));
|
_dateController.addListener(() => _clearError("date"));
|
||||||
_timeController.addListener(() => _clearError("time"));
|
_timeController.addListener(() => _clearError("time"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -153,7 +152,6 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _clearError(String field) {
|
void _clearError(String field) {
|
||||||
if (mounted && errorMessages.containsKey(field)) {
|
if (mounted && errorMessages.containsKey(field)) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -161,6 +159,7 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isValidData(Map<String, dynamic> data) {
|
bool isValidData(Map<String, dynamic> data) {
|
||||||
errorMessages.clear(); // Reset errors
|
errorMessages.clear(); // Reset errors
|
||||||
|
|
||||||
@ -177,9 +176,7 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
return errorMessages.isEmpty; // Valid if there are no errors
|
return errorMessages.isEmpty; // Valid if there are no errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void handleSave() {
|
void handleSave() {
|
||||||
|
|
||||||
print("Handle Save accomadationData $busData");
|
print("Handle Save accomadationData $busData");
|
||||||
|
|
||||||
Map<String, dynamic> data = busData;
|
Map<String, dynamic> data = busData;
|
||||||
@ -195,8 +192,6 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
widget.onClose(false); // Close screen after saving
|
widget.onClose(false); // Close screen after saving
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||||
@ -225,8 +220,10 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text("Bus Booking List",
|
Text("Bus Booking List",
|
||||||
style:
|
style: TextStyle(
|
||||||
TextStyle(fontSize: 18, fontWeight: FontWeight.bold,color: Color(0xFF575A74))),
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Color(0xFF575A74))),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 6,
|
height: 6,
|
||||||
),
|
),
|
||||||
@ -258,7 +255,6 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
// ...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
// ...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
||||||
|
|
||||||
// Iterate over rowBuilders and wrap each in a responsive container
|
// Iterate over rowBuilders and wrap each in a responsive container
|
||||||
@ -274,10 +270,7 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildFirstRow(isDesktop) {
|
List<Widget> _buildFirstRow(isDesktop) {
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -290,14 +283,9 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
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)
|
||||||
@ -306,34 +294,32 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildTripType(bool isDesktop) {
|
List<Widget> _buildTripType(bool isDesktop) {
|
||||||
|
|
||||||
List<dynamic> purposeList = widget.apiData?['flight_trip_type'] ?? [];
|
List<dynamic> purposeList = widget.apiData?['flight_trip_type'] ?? [];
|
||||||
|
|
||||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
||||||
.map((item) => DropdownMenuItem<String>(
|
.map((item) => DropdownMenuItem<String>(
|
||||||
value: item['dropdown_key'],
|
value: item['dropdown_key'],
|
||||||
child: Text(item['dropdown_value']),
|
child: Text(item['dropdown_value']),
|
||||||
)).toList();
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (dropdownItems.isEmpty) {
|
if (dropdownItems.isEmpty) {
|
||||||
dropdownItems.add(
|
dropdownItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
value: null,
|
value: null,
|
||||||
child: Text("No options available", style: TextStyle(color: Colors.grey)),
|
child: Text("No options available",
|
||||||
|
style: TextStyle(color: Colors.grey)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default selected value
|
// Default selected value
|
||||||
String? selectedPurpose = dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
String? selectedPurpose =
|
||||||
|
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
@ -341,37 +327,33 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: DropdownButtonFormField<String>(
|
child: DropdownButtonFormField<String>(
|
||||||
focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
||||||
value: selectedPurpose,
|
value: selectedPurpose,
|
||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(
|
contentPadding:
|
||||||
horizontal: 10), // Proper padding
|
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: purposeList.isNotEmpty
|
onChanged: purposeList.isNotEmpty
|
||||||
? (newValue) {
|
? (newValue) {
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedPurpose = newValue;
|
selectedPurpose = newValue;
|
||||||
});
|
});
|
||||||
print("Updating form data: Flight -> trip_type -> ${newValue ?? ""}");
|
print(
|
||||||
} : null,
|
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}");
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
|
||||||
items: dropdownItems,
|
items: dropdownItems,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildSecondRow(bool isDesktop) {
|
List<Widget> _buildSecondRow(bool isDesktop) {
|
||||||
|
|
||||||
|
|
||||||
DateTime? _selectedCheckOutDate;
|
DateTime? _selectedCheckOutDate;
|
||||||
TimeOfDay? _selectedCheckOutTime;
|
TimeOfDay? _selectedCheckOutTime;
|
||||||
|
|
||||||
@ -381,9 +363,8 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
|
|
||||||
DateTime? pickedDate = await showDatePicker(
|
DateTime? pickedDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
|
initialDate: _selectedCheckOutDate != null &&
|
||||||
|
_selectedCheckOutDate!.isAfter(today)
|
||||||
initialDate: _selectedCheckOutDate != null && _selectedCheckOutDate!.isAfter(today)
|
|
||||||
? _selectedCheckOutDate!
|
? _selectedCheckOutDate!
|
||||||
: today,
|
: today,
|
||||||
firstDate: today,
|
firstDate: today,
|
||||||
@ -419,7 +400,6 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -446,7 +426,6 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -482,7 +461,6 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: _toFocusNode,
|
focusNode: _toFocusNode,
|
||||||
controller: _toController,
|
controller: _toController,
|
||||||
@ -528,7 +506,6 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => _selectCheckOutDate(context),
|
onTap: () => _selectCheckOutDate(context),
|
||||||
child: AbsorbPointer(
|
child: AbsorbPointer(
|
||||||
@ -548,7 +525,6 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (errorMessages["date"] != null) ...[
|
if (errorMessages["date"] != null) ...[
|
||||||
@ -601,7 +577,6 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (errorMessages["time"] != null) ...[
|
if (errorMessages["time"] != null) ...[
|
||||||
@ -613,8 +588,6 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -635,7 +608,7 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
width: isDesktop
|
width: isDesktop
|
||||||
? MediaQuery.of(context).size.width * 0.4
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
: MediaQuery.of(context).size.width * 0.66,
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: _commentsFocusNode,
|
focusNode: _commentsFocusNode,
|
||||||
@ -644,7 +617,7 @@ class _BusScreenState extends State<BusScreen> {
|
|||||||
keyboardType: TextInputType.multiline,
|
keyboardType: TextInputType.multiline,
|
||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: "Description",
|
labelText: "Comments",
|
||||||
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,
|
||||||
|
|||||||
@ -7,23 +7,23 @@ import '../../widgets/custom_text_field.dart';
|
|||||||
import '../../widgets/custom_text_itnerary_sub.dart';
|
import '../../widgets/custom_text_itnerary_sub.dart';
|
||||||
|
|
||||||
class FlightScreen extends StatefulWidget {
|
class FlightScreen extends StatefulWidget {
|
||||||
|
|
||||||
final Map<String, dynamic>? apiData;
|
final Map<String, dynamic>? apiData;
|
||||||
final String? loginUser;
|
final String? loginUser;
|
||||||
final Function(bool) onClose;
|
final Function(bool) onClose;
|
||||||
final Function(Map<String, dynamic>) onSaveFlight;
|
final Function(Map<String, dynamic>) onSaveFlight;
|
||||||
final Map<String, dynamic>? selectedItem;
|
final Map<String, dynamic>? selectedItem;
|
||||||
|
|
||||||
FlightScreen({ required this.apiData,required this.loginUser,
|
FlightScreen(
|
||||||
required this.onClose, required this.onSaveFlight,required this.selectedItem});
|
{required this.apiData,
|
||||||
|
required this.loginUser,
|
||||||
|
required this.onClose,
|
||||||
|
required this.onSaveFlight,
|
||||||
|
required this.selectedItem});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_FlightScreenState createState() => _FlightScreenState();
|
_FlightScreenState createState() => _FlightScreenState();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class _FlightScreenState extends State<FlightScreen> {
|
class _FlightScreenState extends State<FlightScreen> {
|
||||||
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
@ -34,8 +34,16 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
String? selectedvisa_available;
|
String? selectedvisa_available;
|
||||||
int multiTripRowCount = 1;
|
int multiTripRowCount = 1;
|
||||||
|
|
||||||
|
List<String> dataHeader = [
|
||||||
List<String> dataHeader = ["_tripType", "_class", "_from", "_to", "_date","_visa", "_time", "_comments"];
|
"_tripType",
|
||||||
|
"_class",
|
||||||
|
"_from",
|
||||||
|
"_to",
|
||||||
|
"_date",
|
||||||
|
"_visa",
|
||||||
|
"_time",
|
||||||
|
"_comments"
|
||||||
|
];
|
||||||
|
|
||||||
Map<String, FocusNode> focusNodes = {};
|
Map<String, FocusNode> focusNodes = {};
|
||||||
Map<String, bool> focusStates = {};
|
Map<String, bool> focusStates = {};
|
||||||
@ -55,7 +63,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
// List<dynamic> purposeList = widget.apiData?['flight_trip_type'] ?? [];
|
// List<dynamic> purposeList = widget.apiData?['flight_trip_type'] ?? [];
|
||||||
// selectedTripType ??= purposeList.isNotEmpty ? purposeList.first['dropdown_value'] : null;
|
// selectedTripType ??= purposeList.isNotEmpty ? purposeList.first['dropdown_value'] : null;
|
||||||
|
|
||||||
|
|
||||||
// Get trip type from widget.selectedItem
|
// Get trip type from widget.selectedItem
|
||||||
selectedTripType = widget.selectedItem?["trip_type"] as String?;
|
selectedTripType = widget.selectedItem?["trip_type"] as String?;
|
||||||
|
|
||||||
@ -66,9 +73,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
selectedTripType = purposeList.first['dropdown_value'] as String?;
|
selectedTripType = purposeList.first['dropdown_value'] as String?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
_initializeFields();
|
_initializeFields();
|
||||||
getRowCount();
|
getRowCount();
|
||||||
|
|
||||||
@ -76,7 +80,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
print("Focus States Keys: ${focusStates.keys.toList()}");
|
print("Focus States Keys: ${focusStates.keys.toList()}");
|
||||||
print("Text Controllers Keys: ${textControllers.keys.toList()}");
|
print("Text Controllers Keys: ${textControllers.keys.toList()}");
|
||||||
|
|
||||||
|
|
||||||
for (var key in focusNodes.keys) {
|
for (var key in focusNodes.keys) {
|
||||||
_addFocusListener(focusNodes[key]!, (focus) {
|
_addFocusListener(focusNodes[key]!, (focus) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -87,7 +90,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
|
|
||||||
handleUpdateField();
|
handleUpdateField();
|
||||||
|
|
||||||
|
|
||||||
int rowCount = 1; // Default row count for One-way
|
int rowCount = 1; // Default row count for One-way
|
||||||
if (selectedTripType == "Roundtrip") {
|
if (selectedTripType == "Roundtrip") {
|
||||||
rowCount = 2; // Fixed for Roundtrip
|
rowCount = 2; // Fixed for Roundtrip
|
||||||
@ -97,12 +99,15 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
|
|
||||||
// Loop through each row and add listeners to clear errors
|
// Loop through each row and add listeners to clear errors
|
||||||
for (int i = 1; i <= rowCount; i++) {
|
for (int i = 1; i <= rowCount; i++) {
|
||||||
textControllers["_from${i}Controller"]?.addListener(() => _clearError("from_place_$i"));
|
textControllers["_from${i}Controller"]
|
||||||
textControllers["_to${i}Controller"]?.addListener(() => _clearError("to_place_$i"));
|
?.addListener(() => _clearError("from_place_$i"));
|
||||||
textControllers["_date${i}Controller"]?.addListener(() => _clearError("date_$i"));
|
textControllers["_to${i}Controller"]
|
||||||
textControllers["_time${i}Controller"]?.addListener(() => _clearError("time_$i"));
|
?.addListener(() => _clearError("to_place_$i"));
|
||||||
|
textControllers["_date${i}Controller"]
|
||||||
|
?.addListener(() => _clearError("date_$i"));
|
||||||
|
textControllers["_time${i}Controller"]
|
||||||
|
?.addListener(() => _clearError("time_$i"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int getRowCount() {
|
int getRowCount() {
|
||||||
@ -115,7 +120,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _initializeFields() {
|
void _initializeFields() {
|
||||||
|
|
||||||
print("_initializeFields-----------------");
|
print("_initializeFields-----------------");
|
||||||
|
|
||||||
// Dispose and clear previous controllers and focus nodes
|
// Dispose and clear previous controllers and focus nodes
|
||||||
@ -147,8 +151,7 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
// Initialize fields dynamically
|
// Initialize fields dynamically
|
||||||
for (var field in dataHeader) {
|
for (var field in dataHeader) {
|
||||||
for (int i = 1; i <= rowCount; i++) {
|
for (int i = 1; i <= rowCount; i++) {
|
||||||
textControllers["${field}${i}Controller"] =
|
textControllers["${field}${i}Controller"] = TextEditingController();
|
||||||
TextEditingController();
|
|
||||||
|
|
||||||
focusNodes["${field}${i}FocusNode"] = FocusNode();
|
focusNodes["${field}${i}FocusNode"] = FocusNode();
|
||||||
focusStates["${field}${i}Focused"] = false;
|
focusStates["${field}${i}Focused"] = false;
|
||||||
@ -165,8 +168,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setState(() {}); // Ensure UI updates
|
setState(() {}); // Ensure UI updates
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addMultiTripRow() {
|
void addMultiTripRow() {
|
||||||
@ -192,14 +193,10 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
// _tripTypeFocusNode.dispose();
|
// _tripTypeFocusNode.dispose();
|
||||||
|
|
||||||
|
|
||||||
// Dispose all dynamically created FocusNodes
|
// Dispose all dynamically created FocusNodes
|
||||||
for (var node in focusNodes.values) {
|
for (var node in focusNodes.values) {
|
||||||
node.dispose();
|
node.dispose();
|
||||||
@ -212,10 +209,7 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Map<String, dynamic> get flightsData {
|
Map<String, dynamic> get flightsData {
|
||||||
|
|
||||||
List<Map<String, dynamic>> trips = [];
|
List<Map<String, dynamic>> trips = [];
|
||||||
|
|
||||||
int rowCount = 1; // Default for One-way
|
int rowCount = 1; // Default for One-way
|
||||||
@ -226,7 +220,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
rowCount = multiTripRowCount; // Use dynamic count for Multitrip
|
rowCount = multiTripRowCount; // Use dynamic count for Multitrip
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (int i = 1; i <= rowCount; i++) {
|
for (int i = 1; i <= rowCount; i++) {
|
||||||
trips.add({
|
trips.add({
|
||||||
"class": selectedClasses[i],
|
"class": selectedClasses[i],
|
||||||
@ -239,7 +232,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
"trip_type": selectedTripType,
|
"trip_type": selectedTripType,
|
||||||
"comments": textControllers["_comments1Controller"]?.text ?? "",
|
"comments": textControllers["_comments1Controller"]?.text ?? "",
|
||||||
@ -249,11 +241,12 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
"trips": trips,
|
"trips": trips,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
if (widget.selectedItem != null) {
|
if (widget.selectedItem != null) {
|
||||||
if (widget.selectedItem?["indx"] != null && widget.selectedItem?["indx"] != 0) {
|
if (widget.selectedItem?["indx"] != null &&
|
||||||
|
widget.selectedItem?["indx"] != 0) {
|
||||||
data["indx"] = widget.selectedItem!["indx"];
|
data["indx"] = widget.selectedItem!["indx"];
|
||||||
} else if (widget.selectedItem?["flight_id"] != null && widget.selectedItem?["flight_id"] != 0) {
|
} else if (widget.selectedItem?["flight_id"] != null &&
|
||||||
|
widget.selectedItem?["flight_id"] != 0) {
|
||||||
data["flight_id"] = widget.selectedItem!["flight_id"];
|
data["flight_id"] = widget.selectedItem!["flight_id"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,7 +260,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
|
|
||||||
void handleUpdateField() {
|
void handleUpdateField() {
|
||||||
if (widget.selectedItem != null) {
|
if (widget.selectedItem != null) {
|
||||||
|
|
||||||
textControllers["_comments1Controller"] = initController("comments");
|
textControllers["_comments1Controller"] = initController("comments");
|
||||||
// selectedTripType = widget.selectedItem!["trip_type"] as String?;
|
// selectedTripType = widget.selectedItem!["trip_type"] as String?;
|
||||||
// selectedvisa_available = widget.selectedItem!["visa_available"].toString();
|
// selectedvisa_available = widget.selectedItem!["visa_available"].toString();
|
||||||
@ -277,7 +269,8 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (widget.selectedItem!["visa_available"] != null) {
|
if (widget.selectedItem!["visa_available"] != null) {
|
||||||
selectedvisa_available = widget.selectedItem!["visa_available"].toString();
|
selectedvisa_available =
|
||||||
|
widget.selectedItem!["visa_available"].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract trips from selectedItem
|
// Extract trips from selectedItem
|
||||||
@ -298,10 +291,14 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
int index = i + 1; // Use 1-based indexing to match the form
|
int index = i + 1; // Use 1-based indexing to match the form
|
||||||
|
|
||||||
selectedClasses[index] = trip["class"].toString();
|
selectedClasses[index] = trip["class"].toString();
|
||||||
textControllers["_from${index}Controller"] = TextEditingController(text: trip["from_place"]);
|
textControllers["_from${index}Controller"] =
|
||||||
textControllers["_to${index}Controller"] = TextEditingController(text: trip["to_place"]);
|
TextEditingController(text: trip["from_place"]);
|
||||||
textControllers["_date${index}Controller"] = TextEditingController(text: trip["date"]);
|
textControllers["_to${index}Controller"] =
|
||||||
textControllers["_time${index}Controller"] = TextEditingController(text: trip["time"]);
|
TextEditingController(text: trip["to_place"]);
|
||||||
|
textControllers["_date${index}Controller"] =
|
||||||
|
TextEditingController(text: trip["date"]);
|
||||||
|
textControllers["_time${index}Controller"] =
|
||||||
|
TextEditingController(text: trip["time"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Selected ITEM - ${widget.selectedItem}");
|
print("Selected ITEM - ${widget.selectedItem}");
|
||||||
@ -352,7 +349,8 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
|
|
||||||
setState(() {}); // Update UI to show error messages
|
setState(() {}); // Update UI to show error messages
|
||||||
|
|
||||||
return errorMessages.isEmpty; // Returns true if all required fields are filled
|
return errorMessages
|
||||||
|
.isEmpty; // Returns true if all required fields are filled
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeTrip(int index) {
|
void removeTrip(int index) {
|
||||||
@ -368,22 +366,23 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
textControllers.remove("_date${index}Controller");
|
textControllers.remove("_date${index}Controller");
|
||||||
textControllers.remove("_time${index}Controller");
|
textControllers.remove("_time${index}Controller");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Step 2: Shift remaining textControllers keys
|
// Step 2: Shift remaining textControllers keys
|
||||||
Map<String, TextEditingController> updatedTextControllers = {};
|
Map<String, TextEditingController> updatedTextControllers = {};
|
||||||
int newIndex = 1;
|
int newIndex = 1;
|
||||||
for (int i = 1; i <= multiTripRowCount + 1; i++) {
|
for (int i = 1; i <= multiTripRowCount + 1; i++) {
|
||||||
if (i == index) continue; // Skip the deleted one
|
if (i == index) continue; // Skip the deleted one
|
||||||
updatedTextControllers["_from${newIndex}Controller"] = textControllers["_from${i}Controller"]!;
|
updatedTextControllers["_from${newIndex}Controller"] =
|
||||||
updatedTextControllers["_to${newIndex}Controller"] = textControllers["_to${i}Controller"]!;
|
textControllers["_from${i}Controller"]!;
|
||||||
updatedTextControllers["_date${newIndex}Controller"] = textControllers["_date${i}Controller"]!;
|
updatedTextControllers["_to${newIndex}Controller"] =
|
||||||
updatedTextControllers["_time${newIndex}Controller"] = textControllers["_time${i}Controller"]!;
|
textControllers["_to${i}Controller"]!;
|
||||||
|
updatedTextControllers["_date${newIndex}Controller"] =
|
||||||
|
textControllers["_date${i}Controller"]!;
|
||||||
|
updatedTextControllers["_time${newIndex}Controller"] =
|
||||||
|
textControllers["_time${i}Controller"]!;
|
||||||
newIndex++;
|
newIndex++;
|
||||||
}
|
}
|
||||||
textControllers = updatedTextControllers;
|
textControllers = updatedTextControllers;
|
||||||
|
|
||||||
|
|
||||||
// Shift the selectedClasses map BEFORE removing the index
|
// Shift the selectedClasses map BEFORE removing the index
|
||||||
Map<int, String?> updatedClasses = {};
|
Map<int, String?> updatedClasses = {};
|
||||||
newIndex = 1;
|
newIndex = 1;
|
||||||
@ -402,7 +401,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||||
@ -431,8 +429,10 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text("Flight Booking",
|
Text("Flight Booking",
|
||||||
style:
|
style: TextStyle(
|
||||||
TextStyle(fontSize: 18, fontWeight: FontWeight.bold,color: Color(0xFF575A74))),
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Color(0xFF575A74))),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 6,
|
height: 6,
|
||||||
),
|
),
|
||||||
@ -457,7 +457,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildAccomadtionForm(bool isDesktop) {
|
List<Widget> _buildAccomadtionForm(bool isDesktop) {
|
||||||
List<Widget> buildResponsiveRow(List<Widget> children) {
|
List<Widget> buildResponsiveRow(List<Widget> children) {
|
||||||
return [
|
return [
|
||||||
@ -478,23 +477,18 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
_buildSecondRow(isDesktop, 2)
|
_buildSecondRow(isDesktop, 2)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
print("Trip Type Selected: $selectedTripType");
|
print("Trip Type Selected: $selectedTripType");
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
||||||
|
|
||||||
|
|
||||||
// Iterate over rowBuilders based on selectedTripType
|
// Iterate over rowBuilders based on selectedTripType
|
||||||
if (selectedTripType == "Oneway")
|
if (selectedTripType == "Oneway")
|
||||||
...rowBuilders.expand((row) => buildResponsiveRow(row)),
|
...rowBuilders.expand((row) => buildResponsiveRow(row)),
|
||||||
|
|
||||||
|
|
||||||
if (selectedTripType == "Roundtrip")
|
if (selectedTripType == "Roundtrip")
|
||||||
...rowRoundBuilders.expand((row) => buildResponsiveRow(row)),
|
...rowRoundBuilders.expand((row) => buildResponsiveRow(row)),
|
||||||
|
|
||||||
|
|
||||||
if (selectedTripType == "Multitrip")
|
if (selectedTripType == "Multitrip")
|
||||||
...List.generate(multiTripRowCount, (index) {
|
...List.generate(multiTripRowCount, (index) {
|
||||||
List<Widget> firstRow = _builClassType(isDesktop, index + 1);
|
List<Widget> firstRow = _builClassType(isDesktop, index + 1);
|
||||||
@ -506,15 +500,11 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
];
|
];
|
||||||
}).expand((row) => row),
|
}).expand((row) => row),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// if (selectedTripType == "Multitrip")
|
// if (selectedTripType == "Multitrip")
|
||||||
// ...List.generate(multiTripRowCount, (index) =>
|
// ...List.generate(multiTripRowCount, (index) =>
|
||||||
// buildResponsiveRow(_builClassType(isDesktop, index + 1) + _buildSecondRow(isDesktop, index + 1))
|
// buildResponsiveRow(_builClassType(isDesktop, index + 1) + _buildSecondRow(isDesktop, index + 1))
|
||||||
// ).expand((row) => row),
|
// ).expand((row) => row),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (selectedTripType == "Multitrip")
|
if (selectedTripType == "Multitrip")
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
@ -541,9 +531,7 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
|
|
||||||
// Create TextEditingController if it doesn't exist
|
// Create TextEditingController if it doesn't exist
|
||||||
if (!textControllers.containsKey(keyController)) {
|
if (!textControllers.containsKey(keyController)) {
|
||||||
textControllers[keyController] = TextEditingController(
|
textControllers[keyController] = TextEditingController();
|
||||||
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create FocusNode if it doesn't exist
|
// Create FocusNode if it doesn't exist
|
||||||
@ -553,7 +541,8 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
// Attach focus listener for dynamic fields
|
// Attach focus listener for dynamic fields
|
||||||
focusNodes[keyFocusNode]!.addListener(() {
|
focusNodes[keyFocusNode]!.addListener(() {
|
||||||
setState(() {
|
setState(() {
|
||||||
focusStates[keyFocusState] = focusNodes[keyFocusNode]!.hasFocus;
|
focusStates[keyFocusState] =
|
||||||
|
focusNodes[keyFocusNode]!.hasFocus;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -564,10 +553,12 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
|
|
||||||
// _initializeFields();
|
// _initializeFields();
|
||||||
},
|
},
|
||||||
child: Text("Add Trip",style: TextStyle(fontSize: 10,fontWeight:FontWeight.bold),),
|
child: Text(
|
||||||
|
"Add Trip",
|
||||||
|
style: TextStyle(fontSize: 10, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
...buildResponsiveRow(_buildvisa(isDesktop)),
|
...buildResponsiveRow(_buildvisa(isDesktop)),
|
||||||
...buildResponsiveRow(_buildThirdRow(isDesktop)),
|
...buildResponsiveRow(_buildThirdRow(isDesktop)),
|
||||||
@ -579,10 +570,7 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildFirstRow(isDesktop) {
|
List<Widget> _buildFirstRow(isDesktop) {
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -595,14 +583,9 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
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)
|
||||||
@ -611,41 +594,39 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildTripType(bool isDesktop) {
|
List<Widget> _buildTripType(bool isDesktop) {
|
||||||
|
|
||||||
List<dynamic> purposeList = widget.apiData?['flight_trip_type'] ?? [];
|
List<dynamic> purposeList = widget.apiData?['flight_trip_type'] ?? [];
|
||||||
|
|
||||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
||||||
.map((item) => DropdownMenuItem<String>(
|
.map((item) => DropdownMenuItem<String>(
|
||||||
value: item['dropdown_value'],
|
value: item['dropdown_value'],
|
||||||
child: Text(item['dropdown_value']),
|
child: Text(item['dropdown_value']),
|
||||||
)).toList();
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (dropdownItems.isEmpty) {
|
if (dropdownItems.isEmpty) {
|
||||||
dropdownItems.add(
|
dropdownItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
value: null,
|
value: null,
|
||||||
child: Text("No options available", style: TextStyle(color: Colors.grey)),
|
child: Text("No options available",
|
||||||
|
style: TextStyle(color: Colors.grey)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
// isFocused: _tripTypeFocused,
|
// isFocused: _tripTypeFocused,
|
||||||
isFocused: focusStates["_tripType1Focused"] ?? false,
|
isFocused: focusStates["_tripType1Focused"] ?? false,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
|
width: isDesktop
|
||||||
|
? 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>(
|
||||||
// focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
// focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
||||||
focusNode: focusNodes["_tripType1FocusNode"],
|
focusNode: focusNodes["_tripType1FocusNode"],
|
||||||
@ -653,8 +634,8 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(
|
contentPadding:
|
||||||
horizontal: 10), // Proper padding
|
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: purposeList.isNotEmpty
|
onChanged: purposeList.isNotEmpty
|
||||||
? (newValue) {
|
? (newValue) {
|
||||||
@ -667,98 +648,213 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
}
|
}
|
||||||
errorMessages.clear();
|
errorMessages.clear();
|
||||||
});
|
});
|
||||||
print("Updating form data: Flight -> trip_type -> $selectedTripType");
|
print(
|
||||||
|
"Updating form data: Flight -> trip_type -> $selectedTripType");
|
||||||
_initializeFields();
|
_initializeFields();
|
||||||
|
|
||||||
|
|
||||||
// _initializeRows();
|
// _initializeRows();
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
|
|
||||||
|
|
||||||
items: dropdownItems,
|
items: dropdownItems,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Widget _buildDelete(bool isDesktop, int index) {
|
||||||
|
// return Container(
|
||||||
|
// color: Colors.blueAccent,
|
||||||
|
// child: Row(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
// children: [
|
||||||
|
// Text(
|
||||||
|
// "Trip ${index}",
|
||||||
|
// style: TextStyle(
|
||||||
|
// fontSize: 14,
|
||||||
|
// fontWeight: FontWeight.w600,
|
||||||
|
// color: Color(0xFF575A74),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SizedBox(
|
||||||
|
// width: isDesktop
|
||||||
|
// ? MediaQuery.of(context).size.width * 0.38
|
||||||
|
// : MediaQuery.of(context).size.width * 0.3,
|
||||||
|
// child: Stack(
|
||||||
|
// alignment: Alignment.center, // Centers the icon
|
||||||
|
// children: [
|
||||||
|
// Divider(
|
||||||
|
// color: Color(0xFF8B8FB2),
|
||||||
|
// thickness: 0.5,
|
||||||
|
// height: 20,
|
||||||
|
// ),
|
||||||
|
// Container(
|
||||||
|
// // padding: EdgeInsets.all(4),
|
||||||
|
// color: Colors.white, // Background to avoid overlapping
|
||||||
|
// child: Row(
|
||||||
|
// mainAxisSize:
|
||||||
|
// MainAxisSize.min, // Prevents row from taking full width
|
||||||
|
// children: [
|
||||||
|
// Icon(Icons.add_circle_sharp,
|
||||||
|
// color: Colors.blue, size: 28),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// IconButton(
|
||||||
|
// onPressed: () {
|
||||||
|
// removeTrip(index);
|
||||||
|
// },
|
||||||
|
// icon: Icon(Icons.delete),
|
||||||
|
// color: Colors.red,
|
||||||
|
// iconSize: 20,
|
||||||
|
// )
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
List<Widget> _buildDelete(bool isDesktop, int index) {
|
List<Widget> _buildDelete(bool isDesktop, int index) {
|
||||||
return [
|
return [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(10),
|
||||||
|
// padding: const EdgeInsets.only(left: 10, right: 10),
|
||||||
|
// color: Colors.white,
|
||||||
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: Text(
|
child: Text(
|
||||||
"Trip ${index}",
|
"Trip ${index}",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
|
color: Colors.blueAccent,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF575A74),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
|
width: isDesktop
|
||||||
width: isDesktop? 1000 : 80, // Ensure full width
|
? MediaQuery.of(context).size.width * 0.58
|
||||||
child: Divider(
|
: 80, // Ensure full width
|
||||||
|
child: Stack(
|
||||||
thickness: 1, // Make it more visible
|
alignment: Alignment.center, // Centers the icon
|
||||||
|
children: [
|
||||||
|
Divider(
|
||||||
|
color: Color(0xFF8B8FB2),
|
||||||
|
thickness: 0.5,
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
// padding: EdgeInsets.all(4),
|
||||||
|
color: Colors.white, // Background to avoid overlapping
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize:
|
||||||
|
MainAxisSize.min, // Prevents row from taking full width
|
||||||
|
children: [
|
||||||
|
Icon(Icons.add_circle_sharp, color: Colors.blue, size: 28),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(onPressed: (){
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// SizedBox(
|
||||||
|
// width: isDesktop
|
||||||
|
// ? MediaQuery.of(context).size.width * 0.29
|
||||||
|
// : MediaQuery.of(context).size.width * 0.3,
|
||||||
|
// child: Stack(
|
||||||
|
// alignment: Alignment.center, // Centers the icon
|
||||||
|
// children: [
|
||||||
|
// Divider(
|
||||||
|
// color: Color(0xFF8B8FB2),
|
||||||
|
// thickness: 0.5,
|
||||||
|
// height: 20,
|
||||||
|
// ),
|
||||||
|
// Container(
|
||||||
|
// // padding: EdgeInsets.all(4),
|
||||||
|
// color: Colors.white, // Background to avoid overlapping
|
||||||
|
// child: Row(
|
||||||
|
// mainAxisSize:
|
||||||
|
// MainAxisSize.min, // Prevents row from taking full width
|
||||||
|
// children: [
|
||||||
|
// Icon(Icons.add_circle_sharp, color: Colors.blue, size: 28),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
|
||||||
|
Container(
|
||||||
|
// color: Colors.white,
|
||||||
|
// padding: const EdgeInsets.only(left: 10, right: 10),
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () {
|
||||||
removeTrip(index);
|
removeTrip(index);
|
||||||
},
|
},
|
||||||
icon: Icon(Icons.delete),color: Colors.red,iconSize: 20,)
|
icon: Icon(Icons.delete),
|
||||||
|
color: Colors.blueAccent,
|
||||||
|
iconSize: 20,
|
||||||
|
),
|
||||||
|
)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _builClassType(bool isDesktop, int index) {
|
List<Widget> _builClassType(bool isDesktop, int index) {
|
||||||
|
|
||||||
List<dynamic> purposeList = widget.apiData?['flight_class'] ?? [];
|
List<dynamic> purposeList = widget.apiData?['flight_class'] ?? [];
|
||||||
|
|
||||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
||||||
.map((item) => DropdownMenuItem<String>(
|
.map((item) => DropdownMenuItem<String>(
|
||||||
value: item['dropdown_key'],
|
value: item['dropdown_key'],
|
||||||
child: Text(item['dropdown_value']),
|
child: Text(item['dropdown_value']),
|
||||||
)).toList();
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (dropdownItems.isEmpty) {
|
if (dropdownItems.isEmpty) {
|
||||||
dropdownItems.add(
|
dropdownItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
value: null,
|
value: null,
|
||||||
child: Text("No options available", style: TextStyle(color: Colors.grey)),
|
child: Text("No options available",
|
||||||
|
style: TextStyle(color: Colors.grey)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default selected value
|
// Default selected value
|
||||||
selectedClasses[index] ??= dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
selectedClasses[index] ??=
|
||||||
|
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
if (selectedTripType == "Multitrip")
|
if (selectedTripType == "Multitrip")
|
||||||
isDesktop?
|
isDesktop
|
||||||
SizedBox(
|
?
|
||||||
width: MediaQuery.of(context).size.width * 0.89,
|
// SizedBox(
|
||||||
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
// width: MediaQuery.of(context).size.width * 0.89,
|
||||||
children: [..._buildDelete(isDesktop, index)]),
|
// child:
|
||||||
)
|
|
||||||
: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [..._buildDelete(isDesktop, index)]),
|
|
||||||
|
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
// Spacer(flex: 2),
|
||||||
|
|
||||||
|
// _buildDelete(isDesktop, index)
|
||||||
|
|
||||||
|
// Spacer(flex: 2),
|
||||||
|
|
||||||
|
..._buildDelete(isDesktop, index)
|
||||||
|
])
|
||||||
|
// )
|
||||||
|
: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||||
|
// _buildDelete(isDesktop, index)
|
||||||
|
..._buildDelete(isDesktop, index)
|
||||||
|
]),
|
||||||
SizedBox(height: 20),
|
SizedBox(height: 20),
|
||||||
|
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
"Class $index *",
|
"Class $index *",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
@ -767,13 +863,14 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74)),
|
||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
|
|
||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: focusStates["_class${index}Focused"] ?? false,
|
isFocused: focusStates["_class${index}Focused"] ?? false,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
|
width: isDesktop
|
||||||
|
? 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>(
|
||||||
focusNode: focusNodes["_class${index}FocusNode"],
|
focusNode: focusNodes["_class${index}FocusNode"],
|
||||||
// focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
// focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
||||||
@ -782,8 +879,8 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(
|
contentPadding:
|
||||||
horizontal: 10), // Proper padding
|
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: purposeList.isNotEmpty
|
onChanged: purposeList.isNotEmpty
|
||||||
? (newValue) {
|
? (newValue) {
|
||||||
@ -792,25 +889,18 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
print(selectedClasses[index]);
|
print(selectedClasses[index]);
|
||||||
|
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
items: dropdownItems,
|
items: dropdownItems,
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildSecondRow(bool isDesktop, int index) {
|
List<Widget> _buildSecondRow(bool isDesktop, int index) {
|
||||||
|
|
||||||
|
|
||||||
DateTime? _selectedCheckOutDate;
|
DateTime? _selectedCheckOutDate;
|
||||||
TimeOfDay? _selectedCheckOutTime;
|
TimeOfDay? _selectedCheckOutTime;
|
||||||
|
|
||||||
@ -820,9 +910,8 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
|
|
||||||
DateTime? pickedDate = await showDatePicker(
|
DateTime? pickedDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
|
initialDate: _selectedCheckOutDate != null &&
|
||||||
|
_selectedCheckOutDate!.isAfter(today)
|
||||||
initialDate: _selectedCheckOutDate != null && _selectedCheckOutDate!.isAfter(today)
|
|
||||||
? _selectedCheckOutDate!
|
? _selectedCheckOutDate!
|
||||||
: today,
|
: today,
|
||||||
firstDate: today,
|
firstDate: today,
|
||||||
@ -833,7 +922,8 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
_selectedCheckOutDate = pickedDate;
|
_selectedCheckOutDate = pickedDate;
|
||||||
// _dateController.text = DateFormat('yyyy-MM-dd').format(pickedDate);
|
// _dateController.text = DateFormat('yyyy-MM-dd').format(pickedDate);
|
||||||
textControllers["_date${index}Controller"]?.text = DateFormat('yyyy-MM-dd').format(pickedDate);
|
textControllers["_date${index}Controller"]?.text =
|
||||||
|
DateFormat('yyyy-MM-dd').format(pickedDate);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -860,7 +950,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -890,14 +979,10 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (errorMessages["from_place_$index"] != null) ...[
|
if (errorMessages["from_place_$index"] != null) ...[
|
||||||
SizedBox(height: 5), // Space before error message
|
SizedBox(height: 5), // Space before error message
|
||||||
Text(
|
Text(
|
||||||
@ -905,8 +990,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop)
|
||||||
@ -931,7 +1014,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: focusNodes["_to${index}FocusNode"],
|
focusNode: focusNodes["_to${index}FocusNode"],
|
||||||
controller: textControllers["_to${index}Controller"],
|
controller: textControllers["_to${index}Controller"],
|
||||||
@ -977,7 +1059,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => _selectCheckOutDate(context),
|
onTap: () => _selectCheckOutDate(context),
|
||||||
child: AbsorbPointer(
|
child: AbsorbPointer(
|
||||||
@ -998,10 +1079,8 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
if (errorMessages["date_$index"] != null) ...[
|
if (errorMessages["date_$index"] != null) ...[
|
||||||
SizedBox(height: 5), // Space before error message
|
SizedBox(height: 5), // Space before error message
|
||||||
Text(
|
Text(
|
||||||
@ -1009,10 +1088,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop)
|
||||||
@ -1057,7 +1132,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (errorMessages["time_$index"] != null) ...[
|
if (errorMessages["time_$index"] != null) ...[
|
||||||
@ -1067,14 +1141,11 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildThirdRow(bool isDesktop) {
|
List<Widget> _buildThirdRow(bool isDesktop) {
|
||||||
return [
|
return [
|
||||||
Column(
|
Column(
|
||||||
@ -1092,7 +1163,7 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
isFocused: focusStates["_comments1Focused"] ?? false,
|
isFocused: focusStates["_comments1Focused"] ?? false,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
width: isDesktop
|
width: isDesktop
|
||||||
? MediaQuery.of(context).size.width * 0.4
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
: MediaQuery.of(context).size.width * 0.66,
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: focusNodes["_comments1FocusNode"],
|
focusNode: focusNodes["_comments1FocusNode"],
|
||||||
@ -1115,33 +1186,31 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildvisa(bool isDesktop) {
|
List<Widget> _buildvisa(bool isDesktop) {
|
||||||
|
List<dynamic> visa_available =
|
||||||
List<dynamic> visa_available = widget.apiData?['flight_visa_available'] ?? [];
|
widget.apiData?['flight_visa_available'] ?? [];
|
||||||
// Default selected value
|
// Default selected value
|
||||||
|
|
||||||
|
|
||||||
List<DropdownMenuItem<String>> dropdownItems = visa_available
|
List<DropdownMenuItem<String>> dropdownItems = visa_available
|
||||||
.map((item) => DropdownMenuItem<String>(
|
.map((item) => DropdownMenuItem<String>(
|
||||||
value: item['dropdown_key'],
|
value: item['dropdown_key'],
|
||||||
child: Text(item['dropdown_value']),
|
child: Text(item['dropdown_value']),
|
||||||
)).toList();
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
selectedvisa_available ??= dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
selectedvisa_available ??=
|
||||||
|
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
||||||
|
|
||||||
if (dropdownItems.isEmpty) {
|
if (dropdownItems.isEmpty) {
|
||||||
dropdownItems.add(
|
dropdownItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
value: null,
|
value: null,
|
||||||
child: Text("No options available", style: TextStyle(color: Colors.grey)),
|
child: Text("No options available",
|
||||||
|
style: TextStyle(color: Colors.grey)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -1158,9 +1227,11 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
// isFocused: _tripTypeFocused,
|
// isFocused: _tripTypeFocused,
|
||||||
isFocused: focusStates["_visa1Focused"] ?? false,
|
isFocused: focusStates["_visa1Focused"] ?? false,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
|
width: isDesktop
|
||||||
|
? 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>(
|
||||||
// focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
// focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
||||||
focusNode: focusNodes["_visa1FocusNode"],
|
focusNode: focusNodes["_visa1FocusNode"],
|
||||||
@ -1168,8 +1239,8 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(
|
contentPadding:
|
||||||
horizontal: 10), // Proper padding
|
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: visa_available.isNotEmpty
|
onChanged: visa_available.isNotEmpty
|
||||||
? (newValue) {
|
? (newValue) {
|
||||||
@ -1178,18 +1249,15 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
// selectedTripType = "Oneway";
|
// selectedTripType = "Oneway";
|
||||||
// Reset `multiTripRowCount` when switching away from Multitrip
|
// Reset `multiTripRowCount` when switching away from Multitrip
|
||||||
});
|
});
|
||||||
print("Updating form data: Flight -> trip_type -> $selectedvisa_available");
|
print(
|
||||||
|
"Updating form data: Flight -> trip_type -> $selectedvisa_available");
|
||||||
|
|
||||||
// _initializeRows();
|
// _initializeRows();
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
|
|
||||||
|
|
||||||
items: dropdownItems,
|
items: dropdownItems,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -1197,7 +1265,6 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _handleAction(bool isDesktop) {
|
List<Widget> _handleAction(bool isDesktop) {
|
||||||
return [
|
return [
|
||||||
// Close Button
|
// Close Button
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import '../../widgets/custom_text_itnerary_sub.dart';
|
|||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
class ForexScreen extends StatefulWidget {
|
class ForexScreen extends StatefulWidget {
|
||||||
|
|
||||||
final Map<String, dynamic>? apiData;
|
final Map<String, dynamic>? apiData;
|
||||||
final Function(bool) onClose;
|
final Function(bool) onClose;
|
||||||
final Map<String, dynamic>? selectedItem;
|
final Map<String, dynamic>? selectedItem;
|
||||||
@ -22,11 +21,13 @@ class ForexScreen extends StatefulWidget {
|
|||||||
final Function(Map<String, dynamic>) onSaveForex;
|
final Function(Map<String, dynamic>) onSaveForex;
|
||||||
final String? loginUser;
|
final String? loginUser;
|
||||||
|
|
||||||
|
ForexScreen(
|
||||||
|
{required this.onClose,
|
||||||
ForexScreen({
|
this.apiData,
|
||||||
required this.onClose, this.apiData, required this.selectedItem, required this.apiCountryData,
|
required this.selectedItem,
|
||||||
required this.onSaveForex, required this.loginUser });
|
required this.apiCountryData,
|
||||||
|
required this.onSaveForex,
|
||||||
|
required this.loginUser});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_ForexScreenState createState() => _ForexScreenState();
|
_ForexScreenState createState() => _ForexScreenState();
|
||||||
@ -46,21 +47,39 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
Map<String, TextEditingController> textControllers = {};
|
Map<String, TextEditingController> textControllers = {};
|
||||||
List<dynamic> countryList = [];
|
List<dynamic> countryList = [];
|
||||||
|
|
||||||
|
List<String> dataHeader = [
|
||||||
List<String> dataHeader = ["_forexStartDate", "_forexEndDate", "_countries", "_duration",
|
"_forexStartDate",
|
||||||
"_currency","_perdiemAmount", "_transport", "_accomodation", "_telephone", "_otherExpenses",
|
"_forexEndDate",
|
||||||
"_cardNumber", "_currency","_card", "_cash","_checkForex", "_deliveryLocation","_comments"];
|
"_countries",
|
||||||
|
"_duration",
|
||||||
|
"_currency",
|
||||||
|
"_perdiemAmount",
|
||||||
|
"_transport",
|
||||||
|
"_accomodation",
|
||||||
|
"_telephone",
|
||||||
|
"_otherExpenses",
|
||||||
|
"_cardNumber",
|
||||||
|
"_currency",
|
||||||
|
"_card",
|
||||||
|
"_cash",
|
||||||
|
"_checkForex",
|
||||||
|
"_deliveryLocation",
|
||||||
|
"_comments"
|
||||||
|
];
|
||||||
|
|
||||||
String _formatDate(String? date) {
|
String _formatDate(String? date) {
|
||||||
if (date == null || date.isEmpty) return "";
|
if (date == null || date.isEmpty) return "";
|
||||||
try {
|
try {
|
||||||
DateTime parsedDate = DateTime.parse(date); // Assuming input is YYYY-MM-DD
|
DateTime parsedDate =
|
||||||
return DateFormat("dd-MM-yyyy").format(parsedDate); // Convert to DD-MM-YYYY
|
DateTime.parse(date); // Assuming input is YYYY-MM-DD
|
||||||
|
return DateFormat("dd-MM-yyyy")
|
||||||
|
.format(parsedDate); // Convert to DD-MM-YYYY
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Error formatting date: $e");
|
print("Error formatting date: $e");
|
||||||
return date; // Return as is if parsing fails
|
return date; // Return as is if parsing fails
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> errorMessages = {};
|
Map<String, String> errorMessages = {};
|
||||||
|
|
||||||
String? selectedCountry;
|
String? selectedCountry;
|
||||||
@ -70,7 +89,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
String? CalculatedOtherExpenses;
|
String? CalculatedOtherExpenses;
|
||||||
String? selectedQuotedAmount;
|
String? selectedQuotedAmount;
|
||||||
|
|
||||||
|
|
||||||
Map<String, dynamic> get forexData {
|
Map<String, dynamic> get forexData {
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
"start_date": textControllers["_forexStartDate"]?.text,
|
"start_date": textControllers["_forexStartDate"]?.text,
|
||||||
@ -93,9 +111,11 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (widget.selectedItem != null) {
|
if (widget.selectedItem != null) {
|
||||||
if (widget.selectedItem?["indx"] != null && widget.selectedItem?["indx"] != 0) {
|
if (widget.selectedItem?["indx"] != null &&
|
||||||
|
widget.selectedItem?["indx"] != 0) {
|
||||||
data["indx"] = widget.selectedItem!["indx"];
|
data["indx"] = widget.selectedItem!["indx"];
|
||||||
} else if (widget.selectedItem?["forex_id"] != null && widget.selectedItem?["forex_id"] != 0) {
|
} else if (widget.selectedItem?["forex_id"] != null &&
|
||||||
|
widget.selectedItem?["forex_id"] != 0) {
|
||||||
data["forex_id"] = widget.selectedItem!["forex_id"];
|
data["forex_id"] = widget.selectedItem!["forex_id"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,8 +132,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Future<String?> getToken() async {
|
Future<String?> getToken() async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
return prefs.getString('auth_token');
|
return prefs.getString('auth_token');
|
||||||
@ -150,19 +168,20 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
if (responseData.containsKey("currency") &&
|
if (responseData.containsKey("currency") &&
|
||||||
responseData.containsKey("perdiem_amount") &&
|
responseData.containsKey("perdiem_amount") &&
|
||||||
responseData.containsKey("duration")) {
|
responseData.containsKey("duration")) {
|
||||||
|
setState(() {
|
||||||
setState(() { // Update only if data is valid
|
// Update only if data is valid
|
||||||
selectedCurrency = responseData["currency"] ?? selectedCurrency;
|
selectedCurrency = responseData["currency"] ?? selectedCurrency;
|
||||||
selectedPerdiemAmount = responseData["perdiem_amount"]?.toString() ?? "";
|
selectedPerdiemAmount =
|
||||||
|
responseData["perdiem_amount"]?.toString() ?? "";
|
||||||
selectedDuration = responseData["duration"]?.toString() ?? "";
|
selectedDuration = responseData["duration"]?.toString() ?? "";
|
||||||
selectedQuotedAmount = responseData["perdiem_amount"]?.toString() ?? "";
|
selectedQuotedAmount =
|
||||||
|
responseData["perdiem_amount"]?.toString() ?? "";
|
||||||
});
|
});
|
||||||
_onFieldChangedForOthers();
|
_onFieldChangedForOthers();
|
||||||
_divideQuotedAmount();
|
_divideQuotedAmount();
|
||||||
} else {
|
} else {
|
||||||
print("Warning: Response does not contain expected fields.");
|
print("Warning: Response does not contain expected fields.");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
print("Failed to submit plan. Status: ${response.statusCode}");
|
print("Failed to submit plan. Status: ${response.statusCode}");
|
||||||
print("Error: ${response.body}");
|
print("Error: ${response.body}");
|
||||||
@ -176,7 +195,14 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
errorMessages.clear(); // Reset errors
|
errorMessages.clear(); // Reset errors
|
||||||
|
|
||||||
// Required fields that must not be empty
|
// Required fields that must not be empty
|
||||||
List<String> requiredFields = ["start_date", "end_date", "country_code", "deposit_on_card", "deposit_on_cash", "card_number"];
|
List<String> requiredFields = [
|
||||||
|
"start_date",
|
||||||
|
"end_date",
|
||||||
|
"country_code",
|
||||||
|
"deposit_on_card",
|
||||||
|
"deposit_on_cash",
|
||||||
|
"card_number"
|
||||||
|
];
|
||||||
|
|
||||||
// If have_card is "1", then delivery_location is required
|
// If have_card is "1", then delivery_location is required
|
||||||
bool isCardChecked = data["have_card"] == "1";
|
bool isCardChecked = data["have_card"] == "1";
|
||||||
@ -195,13 +221,10 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void handleSave() {
|
void handleSave() {
|
||||||
|
|
||||||
print("Handle Save forexData $forexData");
|
print("Handle Save forexData $forexData");
|
||||||
|
|
||||||
|
|
||||||
Map<String, dynamic> data = forexData;
|
Map<String, dynamic> data = forexData;
|
||||||
|
|
||||||
|
|
||||||
if (!isValidForexData(data)) {
|
if (!isValidForexData(data)) {
|
||||||
print("Validation Failed: Required fields are missing.");
|
print("Validation Failed: Required fields are missing.");
|
||||||
setState(() {});
|
setState(() {});
|
||||||
@ -211,10 +234,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
widget.onClose(false); // Close screen after saving
|
widget.onClose(false); // Close screen after saving
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DateTime? _parseDate(String date) {
|
DateTime? _parseDate(String date) {
|
||||||
try {
|
try {
|
||||||
return DateFormat("yyyy-MM-dd").parse(date); // Change format if needed
|
return DateFormat("yyyy-MM-dd").parse(date); // Change format if needed
|
||||||
@ -227,9 +248,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
return TextEditingController(text: widget.selectedItem?[key] ?? "");
|
return TextEditingController(text: widget.selectedItem?[key] ?? "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -257,8 +275,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Add listeners to text fields
|
// Add listeners to text fields
|
||||||
textControllers["_forexStartDate"]?.addListener(_onFieldChanged);
|
textControllers["_forexStartDate"]?.addListener(_onFieldChanged);
|
||||||
textControllers["_forexEndDate"]?.addListener(_onFieldChanged);
|
textControllers["_forexEndDate"]?.addListener(_onFieldChanged);
|
||||||
@ -267,7 +283,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void handleUpdatedField() {
|
void handleUpdatedField() {
|
||||||
|
|
||||||
// Set the selected value if available
|
// Set the selected value if available
|
||||||
if (widget.selectedItem != null) {
|
if (widget.selectedItem != null) {
|
||||||
print("UPDATAED SELECTION");
|
print("UPDATAED SELECTION");
|
||||||
@ -280,22 +295,22 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
textControllers["_cardNumber"] = initController("card_number");
|
textControllers["_cardNumber"] = initController("card_number");
|
||||||
textControllers["_card"] = initController("deposit_on_card");
|
textControllers["_card"] = initController("deposit_on_card");
|
||||||
textControllers["_cash"] = initController("deposit_on_cash");
|
textControllers["_cash"] = initController("deposit_on_cash");
|
||||||
textControllers["_deliveryLocation"]= initController("delivery_location");
|
textControllers["_deliveryLocation"] =
|
||||||
|
initController("delivery_location");
|
||||||
textControllers["_comments"] = initController("comments");
|
textControllers["_comments"] = initController("comments");
|
||||||
|
|
||||||
|
|
||||||
// Set dropdown values
|
// Set dropdown values
|
||||||
selectedCountry = widget.selectedItem!["country_code"] as String?;
|
selectedCountry = widget.selectedItem!["country_code"] as String?;
|
||||||
selectedCurrency = widget.selectedItem!["currency"] as String?;
|
selectedCurrency = widget.selectedItem!["currency"] as String?;
|
||||||
selectedDuration = widget.selectedItem!["duration"] as String?;
|
selectedDuration = widget.selectedItem!["duration"] as String?;
|
||||||
selectedPerdiemAmount = widget.selectedItem!["perdiem_amount"] as String?;
|
selectedPerdiemAmount = widget.selectedItem!["perdiem_amount"] as String?;
|
||||||
isChecked = widget.selectedItem!["have_card"] == "1"; // Convert string to bool
|
isChecked =
|
||||||
|
widget.selectedItem!["have_card"] == "1"; // Convert string to bool
|
||||||
_onFieldChangedForOthers();
|
_onFieldChangedForOthers();
|
||||||
setState(() {}); // Update the UI
|
setState(() {}); // Update the UI
|
||||||
|
|
||||||
// // Calculate other expenses (if applicable)
|
// // Calculate other expenses (if applicable)
|
||||||
// CalculatedOtherExpenses = calculateOtherExpenses();
|
// CalculatedOtherExpenses = calculateOtherExpenses();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,6 +338,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
postgetForexData(getForexData);
|
postgetForexData(getForexData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle dropdown change
|
// Handle dropdown change
|
||||||
void _onCountryChanged(String? newCountry) {
|
void _onCountryChanged(String? newCountry) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -338,9 +354,12 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
|
|
||||||
void _onFieldChangedForOthers() {
|
void _onFieldChangedForOthers() {
|
||||||
setState(() {
|
setState(() {
|
||||||
double transport = double.tryParse(textControllers["_transport"]?.text ?? "0") ?? 0;
|
double transport =
|
||||||
double accommodation = double.tryParse(textControllers["_accomodation"]?.text ?? "0") ?? 0;
|
double.tryParse(textControllers["_transport"]?.text ?? "0") ?? 0;
|
||||||
double telephone = double.tryParse(textControllers["_telephone"]?.text ?? "0") ?? 0;
|
double accommodation =
|
||||||
|
double.tryParse(textControllers["_accomodation"]?.text ?? "0") ?? 0;
|
||||||
|
double telephone =
|
||||||
|
double.tryParse(textControllers["_telephone"]?.text ?? "0") ?? 0;
|
||||||
double calclateVal = (transport + accommodation + telephone);
|
double calclateVal = (transport + accommodation + telephone);
|
||||||
|
|
||||||
CalculatedOtherExpenses = (calclateVal).toStringAsFixed(2);
|
CalculatedOtherExpenses = (calclateVal).toStringAsFixed(2);
|
||||||
@ -349,18 +368,19 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
double perdiemAmount = double.tryParse(selectedPerdiemAmount ?? "0") ?? 0;
|
double perdiemAmount = double.tryParse(selectedPerdiemAmount ?? "0") ?? 0;
|
||||||
print("calclateVal - $calclateVal");
|
print("calclateVal - $calclateVal");
|
||||||
|
|
||||||
selectedQuotedAmount = ((perdiemAmount + calclateVal).toString() ?? 0) as String?;
|
selectedQuotedAmount =
|
||||||
|
((perdiemAmount + calclateVal).toString() ?? 0) as String?;
|
||||||
});
|
});
|
||||||
_divideQuotedAmount();
|
_divideQuotedAmount();
|
||||||
errorMessages.clear();
|
errorMessages.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _divideQuotedAmount() {
|
void _divideQuotedAmount() {
|
||||||
|
|
||||||
int? quotedAmount = int.tryParse(selectedQuotedAmount!);
|
int? quotedAmount = int.tryParse(selectedQuotedAmount!);
|
||||||
print("DIVIDREFD - $selectedQuotedAmount -$quotedAmount");
|
print("DIVIDREFD - $selectedQuotedAmount -$quotedAmount");
|
||||||
if (quotedAmount != null) {
|
if (quotedAmount != null) {
|
||||||
fifteenPercent = (quotedAmount * 15) ~/ 100; // Calculate 15% (integer division)
|
fifteenPercent =
|
||||||
|
(quotedAmount * 15) ~/ 100; // Calculate 15% (integer division)
|
||||||
remainingAmount = quotedAmount - fifteenPercent; // Subtract from total
|
remainingAmount = quotedAmount - fifteenPercent; // Subtract from total
|
||||||
|
|
||||||
textControllers["_cash"]?.text = fifteenPercent.toString();
|
textControllers["_cash"]?.text = fifteenPercent.toString();
|
||||||
@ -370,21 +390,18 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
} else {
|
} else {
|
||||||
print("Invalid number format in selectedQuotedAmount");
|
print("Invalid number format in selectedQuotedAmount");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _validateCardAmount(String value) {
|
void _validateCardAmount(String value) {
|
||||||
|
|
||||||
print("_validateCardAmount - $value - $remainingAmount");
|
print("_validateCardAmount - $value - $remainingAmount");
|
||||||
|
|
||||||
|
|
||||||
int? enteredAmount = int.tryParse(value);
|
int? enteredAmount = int.tryParse(value);
|
||||||
int? cashAmount = int.tryParse(textControllers["_cash"]!.text ?? "0");
|
int? cashAmount = int.tryParse(textControllers["_cash"]!.text ?? "0");
|
||||||
int? qouteAmount = int.tryParse(selectedQuotedAmount ?? "0");
|
int? qouteAmount = int.tryParse(selectedQuotedAmount ?? "0");
|
||||||
int? calculateAmnt = cashAmount! + enteredAmount!;
|
int? calculateAmnt = cashAmount! + enteredAmount!;
|
||||||
|
|
||||||
print("CAsh - $cashAmount- CaRd- $enteredAmount - $calculateAmnt - selectedQuotedAmount - $qouteAmount");
|
print(
|
||||||
|
"CAsh - $cashAmount- CaRd- $enteredAmount - $calculateAmnt - selectedQuotedAmount - $qouteAmount");
|
||||||
|
|
||||||
if (enteredAmount == null || calculateAmnt > qouteAmount!) {
|
if (enteredAmount == null || calculateAmnt > qouteAmount!) {
|
||||||
errorMessages["deposit_on_card"] = "Amount cannot exceed $qouteAmount";
|
errorMessages["deposit_on_card"] = "Amount cannot exceed $qouteAmount";
|
||||||
@ -396,9 +413,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _validateCashAmount(String value) {
|
void _validateCashAmount(String value) {
|
||||||
|
|
||||||
print("_validateCashAmount - $value - $fifteenPercent");
|
print("_validateCashAmount - $value - $fifteenPercent");
|
||||||
|
|
||||||
int? enteredAmount = int.tryParse(value);
|
int? enteredAmount = int.tryParse(value);
|
||||||
@ -413,7 +428,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
for (var node in focusNodes.values) {
|
for (var node in focusNodes.values) {
|
||||||
@ -427,17 +441,18 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _validateDates() {
|
void _validateDates() {
|
||||||
|
|
||||||
print("VALiDATING DATES");
|
print("VALiDATING DATES");
|
||||||
|
|
||||||
DateTime? startDate = _parseDate(textControllers["_forexStartDate"]?.text ?? "");
|
DateTime? startDate =
|
||||||
DateTime? endDate = _parseDate(textControllers["_forexEndDate"]?.text ?? "");
|
_parseDate(textControllers["_forexStartDate"]?.text ?? "");
|
||||||
|
DateTime? endDate =
|
||||||
|
_parseDate(textControllers["_forexEndDate"]?.text ?? "");
|
||||||
|
|
||||||
if (startDate != null && endDate != null && endDate.isBefore(startDate)) {
|
if (startDate != null && endDate != null && endDate.isBefore(startDate)) {
|
||||||
setState(() {
|
setState(() {
|
||||||
errorMessages["end_date"] = "End date cannot be earlier than start date";
|
errorMessages["end_date"] =
|
||||||
|
"End date cannot be earlier than start date";
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -446,7 +461,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||||
@ -475,8 +489,10 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text("Forex List",
|
Text("Forex List",
|
||||||
style:
|
style: TextStyle(
|
||||||
TextStyle(fontSize: 18, fontWeight: FontWeight.bold,color: Color(0xFF575A74))),
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Color(0xFF575A74))),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 6,
|
height: 6,
|
||||||
),
|
),
|
||||||
@ -497,8 +513,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
List<Widget> _buildAccomadtionForm(bool isDesktop) {
|
List<Widget> _buildAccomadtionForm(bool isDesktop) {
|
||||||
List<Widget> buildResponsiveRow(List<Widget> children) {
|
List<Widget> buildResponsiveRow(List<Widget> children) {
|
||||||
return [
|
return [
|
||||||
|
|
||||||
|
|
||||||
isDesktop ? Row(children: children) : Column(children: children),
|
isDesktop ? Row(children: children) : Column(children: children),
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
];
|
];
|
||||||
@ -510,34 +524,41 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
// _buildSecondRow(isDesktop)
|
// _buildSecondRow(isDesktop)
|
||||||
// ];
|
// ];
|
||||||
|
|
||||||
|
|
||||||
List<Widget> rowBuilders = [
|
List<Widget> rowBuilders = [
|
||||||
..._builClassType(isDesktop), // Spread the List<Widget>
|
..._builClassType(isDesktop), // Spread the List<Widget>
|
||||||
Divider(),
|
Divider(),
|
||||||
..._buildSecondRow(isDesktop), // Spread the List<Widget>
|
..._buildSecondRow(isDesktop), // Spread the List<Widget>
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
||||||
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 28,
|
height: 28,
|
||||||
),
|
),
|
||||||
Text("Forex Details",style: TextStyle(
|
Text(
|
||||||
|
"Forex Details",
|
||||||
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Color(0xFF575A74)),),
|
color: Color(0xFF575A74)),
|
||||||
SizedBox(height: 8,),
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
Divider(),
|
Divider(),
|
||||||
SizedBox(height: 8,),
|
SizedBox(
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
|
|
||||||
...buildResponsiveRow(_builClassType(isDesktop)),
|
...buildResponsiveRow(_builClassType(isDesktop)),
|
||||||
SizedBox(height: 8,),
|
SizedBox(
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
Divider(),
|
Divider(),
|
||||||
SizedBox(height: 28,),
|
SizedBox(
|
||||||
|
height: 28,
|
||||||
|
),
|
||||||
...buildResponsiveRow(_buildSecondRow(isDesktop)),
|
...buildResponsiveRow(_buildSecondRow(isDesktop)),
|
||||||
|
|
||||||
...buildResponsiveRow(_buildCardDetailsRow(isDesktop)),
|
...buildResponsiveRow(_buildCardDetailsRow(isDesktop)),
|
||||||
@ -556,21 +577,18 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildFirstRow(isDesktop) {
|
List<Widget> _buildFirstRow(isDesktop) {
|
||||||
|
|
||||||
DateTime? _selectedCheckOutDate;
|
DateTime? _selectedCheckOutDate;
|
||||||
DateTime? _selectedEndDate;
|
DateTime? _selectedEndDate;
|
||||||
|
|
||||||
|
|
||||||
Future<void> _selectCheckOutDate(BuildContext context) async {
|
Future<void> _selectCheckOutDate(BuildContext context) async {
|
||||||
DateTime now = DateTime.now();
|
DateTime now = DateTime.now();
|
||||||
DateTime today = DateTime(now.year, now.month, now.day);
|
DateTime today = DateTime(now.year, now.month, now.day);
|
||||||
|
|
||||||
DateTime? pickedDate = await showDatePicker(
|
DateTime? pickedDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
initialDate: _selectedCheckOutDate != null && _selectedCheckOutDate!.isAfter(today)
|
initialDate: _selectedCheckOutDate != null &&
|
||||||
|
_selectedCheckOutDate!.isAfter(today)
|
||||||
? _selectedCheckOutDate!
|
? _selectedCheckOutDate!
|
||||||
: today,
|
: today,
|
||||||
firstDate: today,
|
firstDate: today,
|
||||||
@ -580,20 +598,22 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
|
if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedCheckOutDate = pickedDate;
|
_selectedCheckOutDate = pickedDate;
|
||||||
textControllers["_forexStartDate"]?.text = DateFormat('yyyy-MM-dd').format(pickedDate);
|
textControllers["_forexStartDate"]?.text =
|
||||||
|
DateFormat('yyyy-MM-dd').format(pickedDate);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
Future<void> _selectForexEndDate(BuildContext context) async {
|
Future<void> _selectForexEndDate(BuildContext context) async {
|
||||||
|
|
||||||
|
|
||||||
DateTime now = DateTime.now();
|
DateTime now = DateTime.now();
|
||||||
DateTime today = DateTime(now.year, now.month, now.day);
|
DateTime today = DateTime(now.year, now.month, now.day);
|
||||||
|
|
||||||
DateTime? pickedDate = await showDatePicker(
|
DateTime? pickedDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
initialDate: _selectedEndDate != null && _selectedEndDate!.isAfter(today)
|
initialDate:
|
||||||
|
_selectedEndDate != null && _selectedEndDate!.isAfter(today)
|
||||||
? _selectedEndDate!
|
? _selectedEndDate!
|
||||||
: today,
|
: today,
|
||||||
firstDate: today,
|
firstDate: today,
|
||||||
@ -603,21 +623,21 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
if (pickedDate != null && pickedDate != _selectedEndDate) {
|
if (pickedDate != null && pickedDate != _selectedEndDate) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedEndDate = pickedDate;
|
_selectedEndDate = pickedDate;
|
||||||
textControllers["_forexEndDate"]?.text = DateFormat('yyyy-MM-dd').format(pickedDate);
|
textControllers["_forexEndDate"]?.text =
|
||||||
|
DateFormat('yyyy-MM-dd').format(pickedDate);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
late Map<String, String> countryMap; // Mapping country_code -> country_name
|
late Map<String, String> countryMap; // Mapping country_code -> country_name
|
||||||
late List<String> countryCodes; // List of country codes
|
late List<String> countryCodes; // List of country codes
|
||||||
|
|
||||||
|
|
||||||
countryList = widget.apiCountryData ?? [];
|
countryList = widget.apiCountryData ?? [];
|
||||||
|
|
||||||
// Map country codes to country names
|
// Map country codes to country names
|
||||||
countryMap = {
|
countryMap = {
|
||||||
for (var item in countryList) item['country_code'] as String: item['country_name'] as String
|
for (var item in countryList)
|
||||||
|
item['country_code'] as String: item['country_name'] as String
|
||||||
};
|
};
|
||||||
|
|
||||||
// Extract only country codes for processing
|
// Extract only country codes for processing
|
||||||
@ -625,7 +645,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
|
|
||||||
selectedCountry ??= null;
|
selectedCountry ??= null;
|
||||||
|
|
||||||
|
|
||||||
// // Set default selected value
|
// // Set default selected value
|
||||||
// if (selectedCountry == null && countryCodes.isNotEmpty) {
|
// if (selectedCountry == null && countryCodes.isNotEmpty) {
|
||||||
// selectedCountry = countryCodes.first;
|
// selectedCountry = countryCodes.first;
|
||||||
@ -650,7 +669,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
// onTap: () async{
|
// onTap: () async{
|
||||||
// _selectCheckOutDate(context);
|
// _selectCheckOutDate(context);
|
||||||
@ -660,12 +678,17 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
await _selectCheckOutDate(context);
|
await _selectCheckOutDate(context);
|
||||||
|
|
||||||
if (textControllers["_forexEndDate"]!.text.isNotEmpty) {
|
if (textControllers["_forexEndDate"]!.text.isNotEmpty) {
|
||||||
DateTime? startDate = _parseDate(textControllers["_forexStartDate"]!.text);
|
DateTime? startDate =
|
||||||
DateTime? endDate = _parseDate(textControllers["_forexEndDate"]!.text);
|
_parseDate(textControllers["_forexStartDate"]!.text);
|
||||||
|
DateTime? endDate =
|
||||||
|
_parseDate(textControllers["_forexEndDate"]!.text);
|
||||||
|
|
||||||
if (startDate != null && endDate != null && endDate.isBefore(startDate)) {
|
if (startDate != null &&
|
||||||
|
endDate != null &&
|
||||||
|
endDate.isBefore(startDate)) {
|
||||||
setState(() {
|
setState(() {
|
||||||
errorMessages["end_date"] = "End date cannot be earlier than start date";
|
errorMessages["end_date"] =
|
||||||
|
"End date cannot be earlier than start date";
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -681,7 +704,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: "Select Date",
|
labelText: "Select Date",
|
||||||
labelStyle: const TextStyle(fontSize: 12, color: Colors.grey),
|
labelStyle:
|
||||||
|
const TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
@ -691,7 +715,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (errorMessages["start_date"] != null) ...[
|
if (errorMessages["start_date"] != null) ...[
|
||||||
@ -721,25 +744,27 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
CustomTextFieldForexWrapper(
|
CustomTextFieldForexWrapper(
|
||||||
|
|
||||||
isFocused: focusStates["_forexEndDate"] ?? false,
|
isFocused: focusStates["_forexEndDate"] ?? false,
|
||||||
|
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
// onTap: () => _selectForexEndDate(context),
|
// onTap: () => _selectForexEndDate(context),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await _selectForexEndDate(context);
|
await _selectForexEndDate(context);
|
||||||
|
|
||||||
if (textControllers["_forexEndDate"]!.text.isNotEmpty) {
|
if (textControllers["_forexEndDate"]!.text.isNotEmpty) {
|
||||||
DateTime? startDate = _parseDate(textControllers["_forexStartDate"]!.text);
|
DateTime? startDate =
|
||||||
DateTime? endDate = _parseDate(textControllers["_forexEndDate"]!.text);
|
_parseDate(textControllers["_forexStartDate"]!.text);
|
||||||
|
DateTime? endDate =
|
||||||
|
_parseDate(textControllers["_forexEndDate"]!.text);
|
||||||
|
|
||||||
if (startDate != null && endDate != null && endDate.isBefore(startDate)) {
|
if (startDate != null &&
|
||||||
|
endDate != null &&
|
||||||
|
endDate.isBefore(startDate)) {
|
||||||
setState(() {
|
setState(() {
|
||||||
errorMessages["end_date"] = "End date cannot be earlier than start date";
|
errorMessages["end_date"] =
|
||||||
|
"End date cannot be earlier than start date";
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -766,7 +791,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (errorMessages["end_date"] != null) ...[
|
if (errorMessages["end_date"] != null) ...[
|
||||||
@ -779,9 +803,12 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
if (isDesktop)
|
||||||
|
Spacer()
|
||||||
if (isDesktop)Spacer() else SizedBox(height: 8,),
|
else
|
||||||
|
SizedBox(
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -796,7 +823,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
CustomTextFieldForexWrapper(
|
CustomTextFieldForexWrapper(
|
||||||
isFocused: focusStates["_countries"] ?? false,
|
isFocused: focusStates["_countries"] ?? false,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
|
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: DropdownSearch<String>(
|
child: DropdownSearch<String>(
|
||||||
@ -811,14 +837,16 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
items: countryMap.values.toList(),
|
items: countryMap.values.toList(),
|
||||||
|
|
||||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
dropdownSearchDecoration: InputDecoration(
|
dropdownSearchDecoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 1,),
|
contentPadding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
dropdownBuilder: (context, selectedItem) => Align( // Center-align selected item
|
),
|
||||||
|
dropdownBuilder: (context, selectedItem) => Align(
|
||||||
|
// Center-align selected item
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Text(
|
child: Text(
|
||||||
selectedItem ?? "Select Country",
|
selectedItem ?? "Select Country",
|
||||||
@ -833,7 +861,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
.key;
|
.key;
|
||||||
_onCountryChanged(selectedCountry);
|
_onCountryChanged(selectedCountry);
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -847,19 +874,11 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _builClassType(bool isDesktop) {
|
List<Widget> _builClassType(bool isDesktop) {
|
||||||
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
|
|
||||||
// if (isDesktop) Spacer() else SizedBox(
|
// if (isDesktop) Spacer() else SizedBox(
|
||||||
// height: 8,
|
// height: 8,
|
||||||
// ),
|
// ),
|
||||||
@ -880,14 +899,16 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
// "dur",
|
// "dur",
|
||||||
// selectedDuration?.isNotEmpty == true ? selectedDuration! : "Duration",
|
// selectedDuration?.isNotEmpty == true ? selectedDuration! : "Duration",
|
||||||
selectedDuration ?? "Duration",
|
selectedDuration ?? "Duration",
|
||||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600,color: Color(0xFF575A74)),
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF575A74)),
|
||||||
// decoration: const InputDecoration(
|
// decoration: const InputDecoration(
|
||||||
// labelText: "To",
|
// labelText: "To",
|
||||||
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
@ -904,7 +925,12 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
// if (isDesktop)SizedBox(width: 8,) else SizedBox(
|
// if (isDesktop)SizedBox(width: 8,) else SizedBox(
|
||||||
// height: 8,
|
// height: 8,
|
||||||
// ),
|
// ),
|
||||||
if (isDesktop)Spacer() else SizedBox(height: 8,),
|
if (isDesktop)
|
||||||
|
Spacer()
|
||||||
|
else
|
||||||
|
SizedBox(
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -929,17 +955,23 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
// "${selectedCurrency}",
|
// "${selectedCurrency}",
|
||||||
selectedCurrency ?? "Currency",
|
selectedCurrency ?? "Currency",
|
||||||
// selectedCurrency?.isNotEmpty == true ? selectedCurrency! : "Currency",
|
// selectedCurrency?.isNotEmpty == true ? selectedCurrency! : "Currency",
|
||||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600,color: Color(0xFF575A74)),
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF575A74)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
// if (isDesktop)SizedBox(width: 8,) else SizedBox(height: 8,),
|
// if (isDesktop)SizedBox(width: 8,) else SizedBox(height: 8,),
|
||||||
if (isDesktop)Spacer() else SizedBox(height: 8,),
|
if (isDesktop)
|
||||||
|
Spacer()
|
||||||
|
else
|
||||||
|
SizedBox(
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -957,14 +989,16 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
// "amo",
|
// "amo",
|
||||||
selectedPerdiemAmount ?? "Amount",
|
selectedPerdiemAmount ?? "Amount",
|
||||||
// selectedPerdiemAmount?.isNotEmpty == true ? selectedPerdiemAmount! : "Amount",
|
// selectedPerdiemAmount?.isNotEmpty == true ? selectedPerdiemAmount! : "Amount",
|
||||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600,color: Color(0xFF575A74)),
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF575A74)),
|
||||||
// decoration: const InputDecoration(
|
// decoration: const InputDecoration(
|
||||||
// labelText: "To",
|
// labelText: "To",
|
||||||
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
@ -978,7 +1012,12 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)Spacer() else SizedBox(height: 8,),
|
if (isDesktop)
|
||||||
|
Spacer()
|
||||||
|
else
|
||||||
|
SizedBox(
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -997,15 +1036,16 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
// "amo",
|
// "amo",
|
||||||
selectedQuotedAmount ?? "0",
|
selectedQuotedAmount ?? "0",
|
||||||
// selectedPerdiemAmount?.isNotEmpty == true ? selectedPerdiemAmount! : "Amount",
|
// selectedPerdiemAmount?.isNotEmpty == true ? selectedPerdiemAmount! : "Amount",
|
||||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600,color: Color(0xFF575A74)),
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF575A74)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -1016,12 +1056,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildSecondRow(bool isDesktop) {
|
List<Widget> _buildSecondRow(bool isDesktop) {
|
||||||
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -1044,7 +1080,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
onChanged: (value) => _onFieldChangedForOthers(),
|
onChanged: (value) => _onFieldChangedForOthers(),
|
||||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||||
inputFormatters: [
|
inputFormatters: [
|
||||||
FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d*$')), // Allow only positive numbers with optional decimal
|
FilteringTextInputFormatter.allow(RegExp(
|
||||||
|
r'^\d*\.?\d*$')), // Allow only positive numbers with optional decimal
|
||||||
],
|
],
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
@ -1081,14 +1118,14 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: focusNodes["_accomodation"],
|
focusNode: focusNodes["_accomodation"],
|
||||||
controller: textControllers["_accomodation"],
|
controller: textControllers["_accomodation"],
|
||||||
onChanged: (value) => _onFieldChangedForOthers(),
|
onChanged: (value) => _onFieldChangedForOthers(),
|
||||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||||
inputFormatters: [
|
inputFormatters: [
|
||||||
FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d*$')), // Allow only positive numbers with optional decimal
|
FilteringTextInputFormatter.allow(RegExp(
|
||||||
|
r'^\d*\.?\d*$')), // Allow only positive numbers with optional decimal
|
||||||
],
|
],
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
@ -1131,7 +1168,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
onChanged: (value) => _onFieldChangedForOthers(),
|
onChanged: (value) => _onFieldChangedForOthers(),
|
||||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||||
inputFormatters: [
|
inputFormatters: [
|
||||||
FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d*$')), // Allow only positive numbers with optional decimal
|
FilteringTextInputFormatter.allow(RegExp(
|
||||||
|
r'^\d*\.?\d*$')), // Allow only positive numbers with optional decimal
|
||||||
],
|
],
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
@ -1140,7 +1178,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -1170,14 +1207,16 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
CalculatedOtherExpenses ?? "0",
|
CalculatedOtherExpenses ?? "0",
|
||||||
// focusNode: _toFocusNode,
|
// focusNode: _toFocusNode,
|
||||||
// controller: _toController,
|
// controller: _toController,
|
||||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600,color: Color(0xFF575A74)),
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF575A74)),
|
||||||
// decoration: const InputDecoration(
|
// decoration: const InputDecoration(
|
||||||
// labelText: "To",
|
// labelText: "To",
|
||||||
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
@ -1191,35 +1230,33 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _buildCardDetailsRow(bool isDesktop) {
|
List<Widget> _buildCardDetailsRow(bool isDesktop) {
|
||||||
|
|
||||||
List<dynamic> purposeList = widget.apiData?['flight_class'] ?? [];
|
List<dynamic> purposeList = widget.apiData?['flight_class'] ?? [];
|
||||||
|
|
||||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
||||||
.map((item) => DropdownMenuItem<String>(
|
.map((item) => DropdownMenuItem<String>(
|
||||||
value: item['dropdown_value'],
|
value: item['dropdown_value'],
|
||||||
child: Text(item['dropdown_value']),
|
child: Text(item['dropdown_value']),
|
||||||
)).toList();
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (dropdownItems.isEmpty) {
|
if (dropdownItems.isEmpty) {
|
||||||
dropdownItems.add(
|
dropdownItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
value: null,
|
value: null,
|
||||||
child: Text("No options available", style: TextStyle(color: Colors.grey)),
|
child: Text("No options available",
|
||||||
|
style: TextStyle(color: Colors.grey)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default selected value
|
// Default selected value
|
||||||
String? selectedPurpose = dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
String? selectedPurpose =
|
||||||
|
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
||||||
return [
|
return [
|
||||||
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -1239,11 +1276,11 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: focusNodes["_cash"],
|
focusNode: focusNodes["_cash"],
|
||||||
controller: textControllers["_cash"],
|
controller: textControllers["_cash"],
|
||||||
|
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
_validateCashAmount(value); // Call validation when text changes
|
_validateCashAmount(
|
||||||
|
value); // Call validation when text changes
|
||||||
},
|
},
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: "Cash",
|
labelText: "Cash",
|
||||||
@ -1251,7 +1288,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -1274,7 +1310,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -1291,14 +1326,14 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: focusNodes["_card"],
|
focusNode: focusNodes["_card"],
|
||||||
controller: textControllers["_card"],
|
controller: textControllers["_card"],
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
_validateCardAmount(value); // Call validation when text changes
|
_validateCardAmount(
|
||||||
|
value); // Call validation when text changes
|
||||||
},
|
},
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: "Card",
|
labelText: "Card",
|
||||||
@ -1317,15 +1352,9 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (isDesktop)
|
if (isDesktop)
|
||||||
Spacer()
|
Spacer()
|
||||||
else
|
else
|
||||||
@ -1399,7 +1428,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -1413,14 +1441,13 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _buildThirdRow(bool isDesktop) {
|
List<Widget> _buildThirdRow(bool isDesktop) {
|
||||||
return [
|
return [
|
||||||
isChecked?
|
isChecked
|
||||||
Column(
|
? Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
@ -1432,10 +1459,11 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: focusStates["_deliveryLocation"] ?? false, // Dropdown doesn't use focus
|
isFocused: focusStates["_deliveryLocation"] ??
|
||||||
|
false, // Dropdown doesn't use focus
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
width: isDesktop
|
width: isDesktop
|
||||||
? MediaQuery.of(context).size.width * 0.4
|
? MediaQuery.of(context).size.width * 0.464
|
||||||
: MediaQuery.of(context).size.width * 0.66,
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: focusNodes["_deliveryLocation"],
|
focusNode: focusNodes["_deliveryLocation"],
|
||||||
@ -1465,7 +1493,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildCommetsRow(bool isDesktop) {
|
List<Widget> _buildCommetsRow(bool isDesktop) {
|
||||||
return [
|
return [
|
||||||
Column(
|
Column(
|
||||||
@ -1480,10 +1507,11 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: focusStates["_comments"] ?? false, // Dropdown doesn't use focus
|
isFocused:
|
||||||
|
focusStates["_comments"] ?? false, // Dropdown doesn't use focus
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
width: isDesktop
|
width: isDesktop
|
||||||
? MediaQuery.of(context).size.width * 0.4
|
? MediaQuery.of(context).size.width * 0.464
|
||||||
: MediaQuery.of(context).size.width * 0.66,
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: focusNodes["_comments"],
|
focusNode: focusNodes["_comments"],
|
||||||
@ -1505,7 +1533,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildFprexCard(bool isDesktop) {
|
List<Widget> _buildFprexCard(bool isDesktop) {
|
||||||
return [
|
return [
|
||||||
Row(
|
Row(
|
||||||
@ -1525,7 +1552,10 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"Check If You Don't Have a forex Account",
|
"Check If You Don't Have a forex Account",
|
||||||
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74)),
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF575A74)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
@ -6,17 +6,18 @@ import '../../widgets/custom_text_field.dart';
|
|||||||
import '../../widgets/custom_text_itnerary_sub.dart';
|
import '../../widgets/custom_text_itnerary_sub.dart';
|
||||||
|
|
||||||
class InsuranceScreen extends StatefulWidget {
|
class InsuranceScreen extends StatefulWidget {
|
||||||
|
|
||||||
final Map<String, dynamic>? apiData;
|
final Map<String, dynamic>? apiData;
|
||||||
final Function(bool) onClose;
|
final Function(bool) onClose;
|
||||||
final Function(Map<String, dynamic>) onSaveInsurance;
|
final Function(Map<String, dynamic>) onSaveInsurance;
|
||||||
final Map<String, dynamic>? selectedItem;
|
final Map<String, dynamic>? selectedItem;
|
||||||
final String? loginUser;
|
final String? loginUser;
|
||||||
|
|
||||||
|
InsuranceScreen(
|
||||||
InsuranceScreen({
|
{required this.onClose,
|
||||||
required this.onClose, required this.apiData, required this.onSaveInsurance,
|
required this.apiData,
|
||||||
required this.selectedItem,required this.loginUser});
|
required this.onSaveInsurance,
|
||||||
|
required this.selectedItem,
|
||||||
|
required this.loginUser});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_InsuranceScreenState createState() => _InsuranceScreenState();
|
_InsuranceScreenState createState() => _InsuranceScreenState();
|
||||||
@ -33,17 +34,16 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
final FocusNode _dateFocusNode = FocusNode();
|
final FocusNode _dateFocusNode = FocusNode();
|
||||||
final FocusNode _commentsFocusNode = FocusNode();
|
final FocusNode _commentsFocusNode = FocusNode();
|
||||||
|
|
||||||
|
|
||||||
late TextEditingController _tripTypeController = TextEditingController();
|
late TextEditingController _tripTypeController = TextEditingController();
|
||||||
late TextEditingController _startdateController = TextEditingController();
|
late TextEditingController _startdateController = TextEditingController();
|
||||||
late TextEditingController _endDateController = TextEditingController();
|
late TextEditingController _endDateController = TextEditingController();
|
||||||
late TextEditingController _insuranceCommentsController = TextEditingController();
|
late TextEditingController _insuranceCommentsController =
|
||||||
|
TextEditingController();
|
||||||
|
|
||||||
bool _isHotelNameFocused = false;
|
bool _isHotelNameFocused = false;
|
||||||
bool _dateFocus = false;
|
bool _dateFocus = false;
|
||||||
bool _commentsFocus = false;
|
bool _commentsFocus = false;
|
||||||
|
|
||||||
|
|
||||||
String? selectedTripType;
|
String? selectedTripType;
|
||||||
String? selectedInsuranceType;
|
String? selectedInsuranceType;
|
||||||
|
|
||||||
@ -51,7 +51,6 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
|
|
||||||
Map<String, dynamic> get InsuranceData {
|
Map<String, dynamic> get InsuranceData {
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
|
|
||||||
"type_of_insurance": selectedInsuranceType,
|
"type_of_insurance": selectedInsuranceType,
|
||||||
"start_date": _startdateController.text,
|
"start_date": _startdateController.text,
|
||||||
"end_date": _endDateController.text,
|
"end_date": _endDateController.text,
|
||||||
@ -61,9 +60,11 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (widget.selectedItem != null) {
|
if (widget.selectedItem != null) {
|
||||||
if (widget.selectedItem?["indx"] != null && widget.selectedItem?["indx"] != 0) {
|
if (widget.selectedItem?["indx"] != null &&
|
||||||
|
widget.selectedItem?["indx"] != 0) {
|
||||||
data["indx"] = widget.selectedItem!["indx"];
|
data["indx"] = widget.selectedItem!["indx"];
|
||||||
} else if (widget.selectedItem?["insurance_id"] != null && widget.selectedItem?["insurance_id"] != 0) {
|
} else if (widget.selectedItem?["insurance_id"] != null &&
|
||||||
|
widget.selectedItem?["insurance_id"] != 0) {
|
||||||
data["insurance_id"] = widget.selectedItem!["insurance_id"];
|
data["insurance_id"] = widget.selectedItem!["insurance_id"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,18 +72,25 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
_hotelNameFocusNode.addListener(() {
|
_hotelNameFocusNode.addListener(() {
|
||||||
setState(() {_isHotelNameFocused = _hotelNameFocusNode.hasFocus;});});
|
setState(() {
|
||||||
|
_isHotelNameFocused = _hotelNameFocusNode.hasFocus;
|
||||||
|
});
|
||||||
|
});
|
||||||
_dateFocusNode.addListener(() {
|
_dateFocusNode.addListener(() {
|
||||||
setState(() {_dateFocus = _fromFocusNode.hasFocus;});});
|
setState(() {
|
||||||
|
_dateFocus = _fromFocusNode.hasFocus;
|
||||||
|
});
|
||||||
|
});
|
||||||
_commentsFocusNode.addListener(() {
|
_commentsFocusNode.addListener(() {
|
||||||
setState(() {_commentsFocus = _commentsFocusNode.hasFocus;});});
|
setState(() {
|
||||||
|
_commentsFocus = _commentsFocusNode.hasFocus;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
_insuranceCommentsController =
|
_insuranceCommentsController =
|
||||||
TextEditingController(text: widget.selectedItem?["comments"] ?? "");
|
TextEditingController(text: widget.selectedItem?["comments"] ?? "");
|
||||||
@ -92,13 +100,13 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
TextEditingController(text: widget.selectedItem?['end_date'] ?? "");
|
TextEditingController(text: widget.selectedItem?['end_date'] ?? "");
|
||||||
|
|
||||||
// Set the selected value if available
|
// Set the selected value if available
|
||||||
if (widget.selectedItem != null && widget.selectedItem!["type_of_insurance"] != null) {
|
if (widget.selectedItem != null &&
|
||||||
selectedInsuranceType = widget.selectedItem!["type_of_insurance"].toString();
|
widget.selectedItem!["type_of_insurance"] != null) {
|
||||||
|
selectedInsuranceType =
|
||||||
|
widget.selectedItem!["type_of_insurance"].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _addFocusListener(FocusNode node, Function(bool) updateState) {
|
void _addFocusListener(FocusNode node, Function(bool) updateState) {
|
||||||
node.addListener(() {
|
node.addListener(() {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -107,15 +115,15 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool isValidData(Map<String, dynamic> data) {
|
bool isValidData(Map<String, dynamic> data) {
|
||||||
errorMessages.clear(); // Reset errors
|
errorMessages.clear(); // Reset errors
|
||||||
|
|
||||||
// Required fields that must not be empty
|
// Required fields that must not be empty
|
||||||
List<String> requiredFields = ["type_of_insurance", "start_date","end_date"];
|
List<String> requiredFields = [
|
||||||
|
"type_of_insurance",
|
||||||
|
"start_date",
|
||||||
|
"end_date"
|
||||||
|
];
|
||||||
|
|
||||||
// Check validation for each field
|
// Check validation for each field
|
||||||
for (String field in requiredFields) {
|
for (String field in requiredFields) {
|
||||||
@ -127,9 +135,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
return errorMessages.isEmpty; // Valid if there are no errors
|
return errorMessages.isEmpty; // Valid if there are no errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void handleSave() {
|
void handleSave() {
|
||||||
|
|
||||||
print("Handle Save InsuranceData $InsuranceData");
|
print("Handle Save InsuranceData $InsuranceData");
|
||||||
|
|
||||||
Map<String, dynamic> data = InsuranceData;
|
Map<String, dynamic> data = InsuranceData;
|
||||||
@ -153,9 +159,6 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_tripTypeFocusNode.dispose();
|
_tripTypeFocusNode.dispose();
|
||||||
@ -165,8 +168,6 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||||
@ -195,8 +196,10 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text("Insurance Booking List",
|
Text("Insurance Booking List",
|
||||||
style:
|
style: TextStyle(
|
||||||
TextStyle(fontSize: 18, fontWeight: FontWeight.bold,color: Color(0xFF575A74))),
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Color(0xFF575A74))),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 6,
|
height: 6,
|
||||||
),
|
),
|
||||||
@ -228,7 +231,6 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
||||||
|
|
||||||
// Iterate over rowBuilders and wrap each in a responsive container
|
// Iterate over rowBuilders and wrap each in a responsive container
|
||||||
@ -244,10 +246,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildFirstRow(isDesktop) {
|
List<Widget> _buildFirstRow(isDesktop) {
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -260,14 +259,9 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
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)
|
||||||
@ -276,51 +270,52 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildTripType(bool isDesktop) {
|
List<Widget> _buildTripType(bool isDesktop) {
|
||||||
|
List<dynamic> purposeList =
|
||||||
List<dynamic> purposeList = widget.apiData?['insurance_type_of_insurance'] ?? [];
|
widget.apiData?['insurance_type_of_insurance'] ?? [];
|
||||||
// selectedInsuranceType = purposeList.isNotEmpty ? purposeList.first['dropdown_value'] : null;
|
// selectedInsuranceType = purposeList.isNotEmpty ? purposeList.first['dropdown_value'] : null;
|
||||||
|
|
||||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
||||||
.map((item) => DropdownMenuItem<String>(
|
.map((item) => DropdownMenuItem<String>(
|
||||||
value: item['dropdown_key'],
|
value: item['dropdown_key'],
|
||||||
child: Text(item['dropdown_value']),
|
child: Text(item['dropdown_value']),
|
||||||
)).toList();
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (dropdownItems.isEmpty) {
|
if (dropdownItems.isEmpty) {
|
||||||
dropdownItems.add(
|
dropdownItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
value: null,
|
value: null,
|
||||||
child: Text("No options available", style: TextStyle(color: Colors.grey)),
|
child: Text("No options available",
|
||||||
|
style: TextStyle(color: Colors.grey)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default selected value
|
// Default selected value
|
||||||
selectedInsuranceType ??= dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
selectedInsuranceType ??=
|
||||||
|
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: _isHotelNameFocused,
|
isFocused: _isHotelNameFocused,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
|
width: isDesktop
|
||||||
|
? 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>(
|
||||||
focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
||||||
value: selectedInsuranceType,
|
value: selectedInsuranceType,
|
||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(
|
contentPadding:
|
||||||
horizontal: 10), // Proper padding
|
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: purposeList.isNotEmpty
|
onChanged: purposeList.isNotEmpty
|
||||||
? (newValue) {
|
? (newValue) {
|
||||||
@ -329,28 +324,20 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
if (selectedInsuranceType!.isNotEmpty) {
|
if (selectedInsuranceType!.isNotEmpty) {
|
||||||
errorMessages.remove("type_of_insurance");
|
errorMessages.remove("type_of_insurance");
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
print(selectedInsuranceType);
|
print(selectedInsuranceType);
|
||||||
|
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
|
|
||||||
items: dropdownItems,
|
items: dropdownItems,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildSecondRow(bool isDesktop) {
|
List<Widget> _buildSecondRow(bool isDesktop) {
|
||||||
|
|
||||||
|
|
||||||
DateTime? _selectedCheckOutDate;
|
DateTime? _selectedCheckOutDate;
|
||||||
TimeOfDay? _selectedCheckOutTime;
|
TimeOfDay? _selectedCheckOutTime;
|
||||||
|
|
||||||
@ -360,9 +347,8 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
|
|
||||||
DateTime? pickedDate = await showDatePicker(
|
DateTime? pickedDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
|
initialDate: _selectedCheckOutDate != null &&
|
||||||
|
_selectedCheckOutDate!.isAfter(today)
|
||||||
initialDate: _selectedCheckOutDate != null && _selectedCheckOutDate!.isAfter(today)
|
|
||||||
? _selectedCheckOutDate!
|
? _selectedCheckOutDate!
|
||||||
: today,
|
: today,
|
||||||
firstDate: today,
|
firstDate: today,
|
||||||
@ -372,21 +358,20 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
|
if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedCheckOutDate = pickedDate;
|
_selectedCheckOutDate = pickedDate;
|
||||||
_startdateController.text = DateFormat('yyyy-MM-dd').format(pickedDate);
|
_startdateController.text =
|
||||||
|
DateFormat('yyyy-MM-dd').format(pickedDate);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<void> _selectEndCheckOutDate(BuildContext context) async {
|
Future<void> _selectEndCheckOutDate(BuildContext context) async {
|
||||||
DateTime now = DateTime.now();
|
DateTime now = DateTime.now();
|
||||||
DateTime today = DateTime(now.year, now.month, now.day);
|
DateTime today = DateTime(now.year, now.month, now.day);
|
||||||
|
|
||||||
DateTime? pickedDate = await showDatePicker(
|
DateTime? pickedDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
|
initialDate: _selectedCheckOutDate != null &&
|
||||||
|
_selectedCheckOutDate!.isAfter(today)
|
||||||
initialDate: _selectedCheckOutDate != null && _selectedCheckOutDate!.isAfter(today)
|
|
||||||
? _selectedCheckOutDate!
|
? _selectedCheckOutDate!
|
||||||
: today,
|
: today,
|
||||||
firstDate: today,
|
firstDate: today,
|
||||||
@ -402,7 +387,6 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -417,15 +401,18 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: _dateFocus,
|
isFocused: _dateFocus,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
|
width: isDesktop
|
||||||
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await _selectCheckOutDate(context);
|
await _selectCheckOutDate(context);
|
||||||
if (_startdateController.text.isNotEmpty) {
|
if (_startdateController.text.isNotEmpty) {
|
||||||
setState(() {
|
setState(() {
|
||||||
errorMessages.remove("start_date"); // Removes the key completely
|
errorMessages
|
||||||
|
.remove("start_date"); // Removes the key completely
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -446,11 +433,8 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
if (errorMessages["start_date"] != null) ...[
|
if (errorMessages["start_date"] != null) ...[
|
||||||
SizedBox(height: 5), // Space before error message
|
SizedBox(height: 5), // Space before error message
|
||||||
Text(
|
Text(
|
||||||
@ -466,7 +450,6 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -481,9 +464,11 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: _dateFocus,
|
isFocused: _dateFocus,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
|
width: isDesktop
|
||||||
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await _selectEndCheckOutDate(context);
|
await _selectEndCheckOutDate(context);
|
||||||
@ -492,9 +477,12 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
DateTime? startDate = _parseDate(_startdateController.text);
|
DateTime? startDate = _parseDate(_startdateController.text);
|
||||||
DateTime? endDate = _parseDate(_endDateController.text);
|
DateTime? endDate = _parseDate(_endDateController.text);
|
||||||
|
|
||||||
if (startDate != null && endDate != null && endDate.isBefore(startDate)) {
|
if (startDate != null &&
|
||||||
|
endDate != null &&
|
||||||
|
endDate.isBefore(startDate)) {
|
||||||
setState(() {
|
setState(() {
|
||||||
errorMessages["end_date"] = "End date cannot be earlier than start date";
|
errorMessages["end_date"] =
|
||||||
|
"End date cannot be earlier than start date";
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -503,7 +491,6 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
child: AbsorbPointer(
|
child: AbsorbPointer(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: _dateFocusNode,
|
focusNode: _dateFocusNode,
|
||||||
@ -521,7 +508,6 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (errorMessages["end_date"] != null) ...[
|
if (errorMessages["end_date"] != null) ...[
|
||||||
@ -532,7 +518,6 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop)
|
||||||
@ -541,8 +526,6 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -563,7 +546,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
|||||||
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
width: isDesktop
|
width: isDesktop
|
||||||
? MediaQuery.of(context).size.width * 0.4
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
: MediaQuery.of(context).size.width * 0.66,
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: _commentsFocusNode,
|
focusNode: _commentsFocusNode,
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import '../../widgets/custom_text_field.dart';
|
|||||||
import '../../widgets/custom_text_itnerary_sub.dart';
|
import '../../widgets/custom_text_itnerary_sub.dart';
|
||||||
|
|
||||||
class MiscellaneousScreen extends StatefulWidget {
|
class MiscellaneousScreen extends StatefulWidget {
|
||||||
|
|
||||||
final Map<String, dynamic>? apiData;
|
final Map<String, dynamic>? apiData;
|
||||||
final Function(bool) onClose;
|
final Function(bool) onClose;
|
||||||
final Function(Map<String, dynamic>) onSaveMiscellaneous;
|
final Function(Map<String, dynamic>) onSaveMiscellaneous;
|
||||||
@ -14,9 +13,13 @@ class MiscellaneousScreen extends StatefulWidget {
|
|||||||
final int? selectedIndex;
|
final int? selectedIndex;
|
||||||
final String? loginUser;
|
final String? loginUser;
|
||||||
|
|
||||||
MiscellaneousScreen({
|
MiscellaneousScreen(
|
||||||
required this.onClose, required this.apiData, required this.onSaveMiscellaneous,
|
{required this.onClose,
|
||||||
this.selectedItem, this.selectedIndex,required this.loginUser});
|
required this.apiData,
|
||||||
|
required this.onSaveMiscellaneous,
|
||||||
|
this.selectedItem,
|
||||||
|
this.selectedIndex,
|
||||||
|
required this.loginUser});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_MiscellaneousScreenState createState() => _MiscellaneousScreenState();
|
_MiscellaneousScreenState createState() => _MiscellaneousScreenState();
|
||||||
@ -49,14 +52,14 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
|||||||
"comments": _commentsController.text,
|
"comments": _commentsController.text,
|
||||||
"created_by": widget.loginUser,
|
"created_by": widget.loginUser,
|
||||||
"updated_by": widget.loginUser,
|
"updated_by": widget.loginUser,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (widget.selectedItem != null) {
|
if (widget.selectedItem != null) {
|
||||||
if (widget.selectedItem?["indx"] != null && widget.selectedItem?["indx"] != 0) {
|
if (widget.selectedItem?["indx"] != null &&
|
||||||
|
widget.selectedItem?["indx"] != 0) {
|
||||||
data["indx"] = widget.selectedItem!["indx"];
|
data["indx"] = widget.selectedItem!["indx"];
|
||||||
|
} else if (widget.selectedItem?["miscellaneous_id"] != null &&
|
||||||
} else if (widget.selectedItem?["miscellaneous_id"] != null && widget.selectedItem?["miscellaneous_id"] != 0) {
|
widget.selectedItem?["miscellaneous_id"] != 0) {
|
||||||
data["miscellaneous_id"] = widget.selectedItem!["miscellaneous_id"];
|
data["miscellaneous_id"] = widget.selectedItem!["miscellaneous_id"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,9 +67,6 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -90,13 +90,12 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
|||||||
TextEditingController(text: widget.selectedItem?["comments"] ?? "");
|
TextEditingController(text: widget.selectedItem?["comments"] ?? "");
|
||||||
|
|
||||||
// Set the selected value if available
|
// Set the selected value if available
|
||||||
if (widget.selectedItem != null && widget.selectedItem!["special_request"] != null) {
|
if (widget.selectedItem != null &&
|
||||||
|
widget.selectedItem!["special_request"] != null) {
|
||||||
selectedSpecialType = widget.selectedItem!["special_request"].toString();
|
selectedSpecialType = widget.selectedItem!["special_request"].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_tripTypeFocusNode.dispose();
|
_tripTypeFocusNode.dispose();
|
||||||
@ -105,16 +104,12 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool isValidData(Map<String, dynamic> data) {
|
bool isValidData(Map<String, dynamic> data) {
|
||||||
errorMessages.clear(); // Reset errors
|
errorMessages.clear(); // Reset errors
|
||||||
|
|
||||||
// Required fields that must not be empty
|
// Required fields that must not be empty
|
||||||
List<String> requiredFields = ["special_request", "comments"];
|
List<String> requiredFields = ["special_request", "comments"];
|
||||||
|
|
||||||
|
|
||||||
// Check validation for each field
|
// Check validation for each field
|
||||||
for (String field in requiredFields) {
|
for (String field in requiredFields) {
|
||||||
if (data[field] == null || data[field].toString().trim().isEmpty) {
|
if (data[field] == null || data[field].toString().trim().isEmpty) {
|
||||||
@ -125,10 +120,7 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
|||||||
return errorMessages.isEmpty; // Valid if there are no errors
|
return errorMessages.isEmpty; // Valid if there are no errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void handleSave() {
|
void handleSave() {
|
||||||
|
|
||||||
print("Handle Save miscellaneousData $miscellaneousData");
|
print("Handle Save miscellaneousData $miscellaneousData");
|
||||||
|
|
||||||
Map<String, dynamic> data = miscellaneousData;
|
Map<String, dynamic> data = miscellaneousData;
|
||||||
@ -148,7 +140,6 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||||
@ -178,8 +169,10 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text("Miscellaneous Booking List",
|
Text("Miscellaneous Booking List",
|
||||||
style:
|
style: TextStyle(
|
||||||
TextStyle(fontSize: 18, fontWeight: FontWeight.bold,color: Color(0xFF575A74))),
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Color(0xFF575A74))),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 6,
|
height: 6,
|
||||||
),
|
),
|
||||||
@ -205,9 +198,7 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
||||||
|
|
||||||
...buildResponsiveRow(_buildThirdRow(isDesktop)),
|
...buildResponsiveRow(_buildThirdRow(isDesktop)),
|
||||||
@ -220,10 +211,7 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildFirstRow(isDesktop) {
|
List<Widget> _buildFirstRow(isDesktop) {
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -236,14 +224,9 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
|||||||
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)
|
||||||
@ -252,51 +235,52 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildTripType(bool isDesktop) {
|
List<Widget> _buildTripType(bool isDesktop) {
|
||||||
|
List<dynamic> purposeList =
|
||||||
List<dynamic> purposeList = widget.apiData?['miscellaneous_special_request'] ?? [];
|
widget.apiData?['miscellaneous_special_request'] ?? [];
|
||||||
// selectedInsuranceType = purposeList.isNotEmpty ? purposeList.first['dropdown_value'] : null;
|
// selectedInsuranceType = purposeList.isNotEmpty ? purposeList.first['dropdown_value'] : null;
|
||||||
|
|
||||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
||||||
.map((item) => DropdownMenuItem<String>(
|
.map((item) => DropdownMenuItem<String>(
|
||||||
value: item['dropdown_key'],
|
value: item['dropdown_key'],
|
||||||
child: Text(item['dropdown_value']),
|
child: Text(item['dropdown_value']),
|
||||||
)).toList();
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (dropdownItems.isEmpty) {
|
if (dropdownItems.isEmpty) {
|
||||||
dropdownItems.add(
|
dropdownItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
value: null,
|
value: null,
|
||||||
child: Text("No options available", style: TextStyle(color: Colors.grey)),
|
child: Text("No options available",
|
||||||
|
style: TextStyle(color: Colors.grey)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default selected value
|
// Default selected value
|
||||||
selectedSpecialType ??= dropdownItems.isNotEmpty ? dropdownItems.first.value : "No options";
|
selectedSpecialType ??=
|
||||||
|
dropdownItems.isNotEmpty ? dropdownItems.first.value : "No options";
|
||||||
|
|
||||||
return [
|
return [
|
||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: _isHotelNameFocused,
|
isFocused: _isHotelNameFocused,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
|
width: isDesktop
|
||||||
|
? 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>(
|
||||||
focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
||||||
value: selectedSpecialType,
|
value: selectedSpecialType,
|
||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(
|
contentPadding:
|
||||||
horizontal: 10), // Proper padding
|
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: purposeList.isNotEmpty
|
onChanged: purposeList.isNotEmpty
|
||||||
? (newValue) {
|
? (newValue) {
|
||||||
@ -305,13 +289,10 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
print(selectedSpecialType);
|
print(selectedSpecialType);
|
||||||
|
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
items: dropdownItems,
|
items: dropdownItems,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (errorMessages["special_request"] != null) ...[
|
if (errorMessages["special_request"] != null) ...[
|
||||||
@ -324,8 +305,6 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildThirdRow(bool isDesktop) {
|
List<Widget> _buildThirdRow(bool isDesktop) {
|
||||||
return [
|
return [
|
||||||
Column(
|
Column(
|
||||||
@ -343,7 +322,7 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
|||||||
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
width: isDesktop
|
width: isDesktop
|
||||||
? MediaQuery.of(context).size.width * 0.4
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
: MediaQuery.of(context).size.width * 0.66,
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: _commentsFocusNode,
|
focusNode: _commentsFocusNode,
|
||||||
@ -352,7 +331,7 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
|||||||
keyboardType: TextInputType.multiline,
|
keyboardType: TextInputType.multiline,
|
||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: "Description",
|
labelText: "Comments",
|
||||||
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,
|
||||||
@ -377,7 +356,6 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
|||||||
// Close Button
|
// Close Button
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|
||||||
_commentsController.clear();
|
_commentsController.clear();
|
||||||
widget.onClose(false); // Close the dialog or screen
|
widget.onClose(false); // Close the dialog or screen
|
||||||
},
|
},
|
||||||
|
|||||||
@ -13,9 +13,12 @@ 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, this.apiData, required this.onSavetaxi,
|
{required this.onClose,
|
||||||
required this.selectedItem,required this.loginUser});
|
this.apiData,
|
||||||
|
required this.onSavetaxi,
|
||||||
|
required this.selectedItem,
|
||||||
|
required this.loginUser});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_TaxiScreenState createState() => _TaxiScreenState();
|
_TaxiScreenState createState() => _TaxiScreenState();
|
||||||
@ -55,11 +58,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
String? selectedReqTaxi;
|
String? selectedReqTaxi;
|
||||||
String? selectedCarType;
|
String? selectedCarType;
|
||||||
|
|
||||||
|
|
||||||
Map<String, dynamic> get taxiData {
|
Map<String, dynamic> get taxiData {
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
|
|
||||||
|
|
||||||
"destination_city": _destinationController.text,
|
"destination_city": _destinationController.text,
|
||||||
"date": _dateController.text,
|
"date": _dateController.text,
|
||||||
"time": _timeController.text,
|
"time": _timeController.text,
|
||||||
@ -72,13 +72,14 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
"updated_by": widget.loginUser,
|
"updated_by": widget.loginUser,
|
||||||
// "updated_on": ,
|
// "updated_on": ,
|
||||||
// "updated_by": ,
|
// "updated_by": ,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (widget.selectedItem != null) {
|
if (widget.selectedItem != null) {
|
||||||
if (widget.selectedItem?["indx"] != null && widget.selectedItem?["indx"] != 0) {
|
if (widget.selectedItem?["indx"] != null &&
|
||||||
|
widget.selectedItem?["indx"] != 0) {
|
||||||
data["indx"] = widget.selectedItem!["indx"];
|
data["indx"] = widget.selectedItem!["indx"];
|
||||||
} else if (widget.selectedItem?["taxi_id"] != null && widget.selectedItem?["taxi_id"] != 0) {
|
} else if (widget.selectedItem?["taxi_id"] != null &&
|
||||||
|
widget.selectedItem?["taxi_id"] != 0) {
|
||||||
data["taxi_id"] = widget.selectedItem!["taxi_id"];
|
data["taxi_id"] = widget.selectedItem!["taxi_id"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,17 +95,16 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
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(_numPassengerFocusNode, (focus) => _numPassengerFocus = focus);
|
_addFocusListener(
|
||||||
|
_numPassengerFocusNode, (focus) => _numPassengerFocus = focus);
|
||||||
_addFocusListener(_commentsFocusNode, (focus) => _commentsFocus = focus);
|
_addFocusListener(_commentsFocusNode, (focus) => _commentsFocus = focus);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
_destinationController = initController("destination_city");
|
_destinationController = initController("destination_city");
|
||||||
_dateController = initController("date");
|
_dateController = initController("date");
|
||||||
_timeController = initController("time");
|
_timeController = initController("time");
|
||||||
@ -112,14 +112,15 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
_numPassengerController = initController("no_of_passengers");
|
_numPassengerController = initController("no_of_passengers");
|
||||||
_taxiCommentsController = initController("comments");
|
_taxiCommentsController = initController("comments");
|
||||||
|
|
||||||
|
|
||||||
// Set the selected value if available
|
// Set the selected value if available
|
||||||
if (widget.selectedItem != null && widget.selectedItem!["car_required_for"] != null) {
|
if (widget.selectedItem != null &&
|
||||||
|
widget.selectedItem!["car_required_for"] != null) {
|
||||||
selectedReqTaxi = widget.selectedItem!["car_required_for"].toString();
|
selectedReqTaxi = widget.selectedItem!["car_required_for"].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the selected value if available
|
// Set the selected value if available
|
||||||
if (widget.selectedItem != null && widget.selectedItem!["car_type"] != null) {
|
if (widget.selectedItem != null &&
|
||||||
|
widget.selectedItem!["car_type"] != null) {
|
||||||
selectedCarType = widget.selectedItem!["car_type"].toString();
|
selectedCarType = widget.selectedItem!["car_type"].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,8 +129,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
_dateController.addListener(() => _clearError("date"));
|
_dateController.addListener(() => _clearError("date"));
|
||||||
_timeController.addListener(() => _clearError("time"));
|
_timeController.addListener(() => _clearError("time"));
|
||||||
_numPassengerController.addListener(() => _clearError("no_of_passengers"));
|
_numPassengerController.addListener(() => _clearError("no_of_passengers"));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _addFocusListener(FocusNode node, Function(bool) updateState) {
|
void _addFocusListener(FocusNode node, Function(bool) updateState) {
|
||||||
@ -140,8 +139,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_destinationFocusNode.dispose();
|
_destinationFocusNode.dispose();
|
||||||
@ -153,7 +150,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _clearError(String field) {
|
void _clearError(String field) {
|
||||||
if (mounted && errorMessages.containsKey(field)) {
|
if (mounted && errorMessages.containsKey(field)) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -162,12 +158,17 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool isValidData(Map<String, dynamic> data) {
|
bool isValidData(Map<String, dynamic> data) {
|
||||||
errorMessages.clear(); // Reset errors
|
errorMessages.clear(); // Reset errors
|
||||||
|
|
||||||
// Required fields that must not be empty
|
// Required fields that must not be empty
|
||||||
List<String> requiredFields = ["destination_city", "location_of_pickup","no_of_passengers","date","time"];
|
List<String> requiredFields = [
|
||||||
|
"destination_city",
|
||||||
|
"location_of_pickup",
|
||||||
|
"no_of_passengers",
|
||||||
|
"date",
|
||||||
|
"time"
|
||||||
|
];
|
||||||
|
|
||||||
// Check validation for each field
|
// Check validation for each field
|
||||||
for (String field in requiredFields) {
|
for (String field in requiredFields) {
|
||||||
@ -179,9 +180,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
return errorMessages.isEmpty; // Valid if there are no errors
|
return errorMessages.isEmpty; // Valid if there are no errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void handleSave() {
|
void handleSave() {
|
||||||
|
|
||||||
print("Handle Save taxiData $taxiData");
|
print("Handle Save taxiData $taxiData");
|
||||||
|
|
||||||
Map<String, dynamic> data = taxiData;
|
Map<String, dynamic> data = taxiData;
|
||||||
@ -197,9 +196,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
widget.onClose(false); // Close screen after saving
|
widget.onClose(false); // Close screen after saving
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||||
@ -228,8 +224,10 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text("Taxi Booking List",
|
Text("Taxi Booking List",
|
||||||
style:
|
style: TextStyle(
|
||||||
TextStyle(fontSize: 18, fontWeight: FontWeight.bold,color: Color(0xFF575A74))),
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Color(0xFF575A74))),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 6,
|
height: 6,
|
||||||
),
|
),
|
||||||
@ -261,7 +259,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
// Iterate over rowBuilders and wrap each in a responsive container
|
// Iterate over rowBuilders and wrap each in a responsive container
|
||||||
...rowBuilders.expand((row) => buildResponsiveRow(row)),
|
...rowBuilders.expand((row) => buildResponsiveRow(row)),
|
||||||
|
|
||||||
@ -277,30 +274,29 @@ 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 = purposeList
|
||||||
.map((item) => DropdownMenuItem<String>(
|
.map((item) => DropdownMenuItem<String>(
|
||||||
value: item['dropdown_key'],
|
value: item['dropdown_key'],
|
||||||
child: Text(item['dropdown_value']),
|
child: Text(item['dropdown_value']),
|
||||||
)).toList();
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (dropdownItems.isEmpty) {
|
if (dropdownItems.isEmpty) {
|
||||||
dropdownItems.add(
|
dropdownItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
value: null,
|
value: null,
|
||||||
child: Text("No options available", style: TextStyle(color: Colors.grey)),
|
child: Text("No options available",
|
||||||
|
style: TextStyle(color: Colors.grey)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default selected value
|
// Default selected value
|
||||||
selectedCarType ??= dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
selectedCarType ??=
|
||||||
|
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Column(
|
Column(
|
||||||
@ -314,12 +310,9 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
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)
|
||||||
@ -328,7 +321,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -351,7 +343,8 @@ 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(r'^\d*\.?\d*$')), // Allow only positive numbers with optional decimal
|
FilteringTextInputFormatter.allow(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",
|
||||||
@ -359,7 +352,6 @@ 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),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -371,7 +363,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop)
|
||||||
@ -396,23 +387,22 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: DropdownButtonFormField<String>(
|
child: DropdownButtonFormField<String>(
|
||||||
focusNode: _toFocusNode, // Assign the correct focus node
|
focusNode: _toFocusNode, // Assign the correct focus node
|
||||||
value: selectedCarType,
|
value: selectedCarType,
|
||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(
|
contentPadding:
|
||||||
horizontal: 10), // Proper padding
|
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: purposeList.isNotEmpty
|
onChanged: purposeList.isNotEmpty
|
||||||
? (newValue) {
|
? (newValue) {
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedCarType = newValue;
|
selectedCarType = newValue;
|
||||||
});
|
});
|
||||||
print("Updating form data: Flight -> trip_type -> ${newValue ?? ""}");
|
print(
|
||||||
|
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}");
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
|
|
||||||
@ -428,73 +418,69 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 8,
|
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 = purposeList
|
||||||
.map((item) => DropdownMenuItem<String>(
|
.map((item) => DropdownMenuItem<String>(
|
||||||
value: item['dropdown_key'],
|
value: item['dropdown_key'],
|
||||||
child: Text(item['dropdown_value']),
|
child: Text(item['dropdown_value']),
|
||||||
)).toList();
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (dropdownItems.isEmpty) {
|
if (dropdownItems.isEmpty) {
|
||||||
dropdownItems.add(
|
dropdownItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
value: null,
|
value: null,
|
||||||
child: Text("No options available", style: TextStyle(color: Colors.grey)),
|
child: Text("No options available",
|
||||||
|
style: TextStyle(color: Colors.grey)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default selected value
|
// Default selected value
|
||||||
selectedReqTaxi ??= dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
selectedReqTaxi ??=
|
||||||
|
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: _taxiReqFocused,
|
isFocused: _taxiReqFocused,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
|
width: isDesktop
|
||||||
|
? 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>(
|
||||||
focusNode: _taxiReqFocusNode, // Assign the correct focus node
|
focusNode: _taxiReqFocusNode, // Assign the correct focus node
|
||||||
value: selectedReqTaxi,
|
value: selectedReqTaxi,
|
||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(
|
contentPadding:
|
||||||
horizontal: 10), // Proper padding
|
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: purposeList.isNotEmpty
|
onChanged: purposeList.isNotEmpty
|
||||||
? (newValue) {
|
? (newValue) {
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedReqTaxi = newValue;
|
selectedReqTaxi = newValue;
|
||||||
});
|
});
|
||||||
print("Updating form data: Flight -> trip_type -> ${newValue ?? ""}");
|
print(
|
||||||
|
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}");
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
|
|
||||||
items: dropdownItems,
|
items: dropdownItems,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildSecondRow(bool isDesktop) {
|
List<Widget> _buildSecondRow(bool isDesktop) {
|
||||||
|
|
||||||
|
|
||||||
DateTime? _selectedCheckOutDate;
|
DateTime? _selectedCheckOutDate;
|
||||||
TimeOfDay? _selectedCheckOutTime;
|
TimeOfDay? _selectedCheckOutTime;
|
||||||
|
|
||||||
@ -504,9 +490,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
|
|
||||||
DateTime? pickedDate = await showDatePicker(
|
DateTime? pickedDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
|
initialDate: _selectedCheckOutDate != null &&
|
||||||
|
_selectedCheckOutDate!.isAfter(today)
|
||||||
initialDate: _selectedCheckOutDate != null && _selectedCheckOutDate!.isAfter(today)
|
|
||||||
? _selectedCheckOutDate!
|
? _selectedCheckOutDate!
|
||||||
: today,
|
: today,
|
||||||
firstDate: today,
|
firstDate: today,
|
||||||
@ -542,7 +527,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -569,7 +553,6 @@ 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),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -605,7 +588,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: _locationFocusNode,
|
focusNode: _locationFocusNode,
|
||||||
controller: _locationController,
|
controller: _locationController,
|
||||||
@ -651,7 +633,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => _selectCheckOutDate(context),
|
onTap: () => _selectCheckOutDate(context),
|
||||||
child: AbsorbPointer(
|
child: AbsorbPointer(
|
||||||
@ -671,7 +652,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (errorMessages["date"] != null) ...[
|
if (errorMessages["date"] != null) ...[
|
||||||
@ -724,7 +704,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (errorMessages["time"] != null) ...[
|
if (errorMessages["time"] != null) ...[
|
||||||
@ -756,8 +735,9 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
|||||||
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
width: isDesktop
|
width: isDesktop
|
||||||
? MediaQuery.of(context).size.width * 0.4
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
: MediaQuery.of(context).size.width * 0.66,
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
|
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: _commentsFocusNode,
|
focusNode: _commentsFocusNode,
|
||||||
controller: _taxiCommentsController,
|
controller: _taxiCommentsController,
|
||||||
|
|||||||
@ -6,15 +6,18 @@ import '../../widgets/custom_text_field.dart';
|
|||||||
import '../../widgets/custom_text_itnerary_sub.dart';
|
import '../../widgets/custom_text_itnerary_sub.dart';
|
||||||
|
|
||||||
class TrainScreen extends StatefulWidget {
|
class TrainScreen extends StatefulWidget {
|
||||||
|
|
||||||
final Map<String, dynamic>? apiData;
|
final Map<String, dynamic>? apiData;
|
||||||
final Function(Map<String, dynamic>) onSavetrain;
|
final Function(Map<String, dynamic>) onSavetrain;
|
||||||
final Function(bool) onClose;
|
final Function(bool) onClose;
|
||||||
final Map<String, dynamic>? selectedItem;
|
final Map<String, dynamic>? selectedItem;
|
||||||
final String? loginUser;
|
final String? loginUser;
|
||||||
|
|
||||||
TrainScreen({
|
TrainScreen(
|
||||||
required this.onClose, this.apiData, required this.onSavetrain, required this.selectedItem, required this.loginUser});
|
{required this.onClose,
|
||||||
|
this.apiData,
|
||||||
|
required this.onSavetrain,
|
||||||
|
required this.selectedItem,
|
||||||
|
required this.loginUser});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_TrainScreenState createState() => _TrainScreenState();
|
_TrainScreenState createState() => _TrainScreenState();
|
||||||
@ -33,7 +36,6 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
final FocusNode _timeFocusNode = FocusNode();
|
final FocusNode _timeFocusNode = FocusNode();
|
||||||
final FocusNode _commentsFocusNode = FocusNode();
|
final FocusNode _commentsFocusNode = FocusNode();
|
||||||
|
|
||||||
|
|
||||||
late TextEditingController _trainNoController = TextEditingController();
|
late TextEditingController _trainNoController = TextEditingController();
|
||||||
late TextEditingController _hotelNameController = TextEditingController();
|
late TextEditingController _hotelNameController = TextEditingController();
|
||||||
late TextEditingController _fromController = TextEditingController();
|
late TextEditingController _fromController = TextEditingController();
|
||||||
@ -56,7 +58,6 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
|
|
||||||
Map<String, dynamic> get trainData {
|
Map<String, dynamic> get trainData {
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
|
|
||||||
"train_no": _trainNoController.text,
|
"train_no": _trainNoController.text,
|
||||||
"class": selectedClass,
|
"class": selectedClass,
|
||||||
"from_station": _fromController.text,
|
"from_station": _fromController.text,
|
||||||
@ -69,9 +70,11 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (widget.selectedItem != null) {
|
if (widget.selectedItem != null) {
|
||||||
if (widget.selectedItem?["indx"] != null && widget.selectedItem?["indx"] != 0) {
|
if (widget.selectedItem?["indx"] != null &&
|
||||||
|
widget.selectedItem?["indx"] != 0) {
|
||||||
data["indx"] = widget.selectedItem!["indx"];
|
data["indx"] = widget.selectedItem!["indx"];
|
||||||
} else if (widget.selectedItem?["train_id"] != null && widget.selectedItem?["train_id"] != 0) {
|
} else if (widget.selectedItem?["train_id"] != null &&
|
||||||
|
widget.selectedItem?["train_id"] != 0) {
|
||||||
data["train_id"] = widget.selectedItem!["train_id"];
|
data["train_id"] = widget.selectedItem!["train_id"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,7 +86,6 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
return TextEditingController(text: widget.selectedItem?[key] ?? "");
|
return TextEditingController(text: widget.selectedItem?[key] ?? "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -124,7 +126,6 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
_trainCommentsController = initController("comments");
|
_trainCommentsController = initController("comments");
|
||||||
_trainNoController = initController("train_no");
|
_trainNoController = initController("train_no");
|
||||||
_fromController = initController("from_station");
|
_fromController = initController("from_station");
|
||||||
@ -142,10 +143,8 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
_toController.addListener(() => _clearError("to_station"));
|
_toController.addListener(() => _clearError("to_station"));
|
||||||
_dateController.addListener(() => _clearError("date"));
|
_dateController.addListener(() => _clearError("date"));
|
||||||
_timeController.addListener(() => _clearError("time"));
|
_timeController.addListener(() => _clearError("time"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_trainNoFocusNode.dispose();
|
_trainNoFocusNode.dispose();
|
||||||
@ -159,7 +158,6 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _clearError(String field) {
|
void _clearError(String field) {
|
||||||
if (mounted && errorMessages.containsKey(field)) {
|
if (mounted && errorMessages.containsKey(field)) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -168,12 +166,18 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool isValidData(Map<String, dynamic> data) {
|
bool isValidData(Map<String, dynamic> data) {
|
||||||
errorMessages.clear(); // Reset errors
|
errorMessages.clear(); // Reset errors
|
||||||
|
|
||||||
// Required fields that must not be empty
|
// Required fields that must not be empty
|
||||||
List<String> requiredFields = ["train_no", "class","from_station", "to_station","date","time"];
|
List<String> requiredFields = [
|
||||||
|
"train_no",
|
||||||
|
"class",
|
||||||
|
"from_station",
|
||||||
|
"to_station",
|
||||||
|
"date",
|
||||||
|
"time"
|
||||||
|
];
|
||||||
|
|
||||||
// Check validation for each field
|
// Check validation for each field
|
||||||
for (String field in requiredFields) {
|
for (String field in requiredFields) {
|
||||||
@ -185,9 +189,7 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
return errorMessages.isEmpty; // Valid if there are no errors
|
return errorMessages.isEmpty; // Valid if there are no errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void handleSave() {
|
void handleSave() {
|
||||||
|
|
||||||
print("Handle Save accomadationData $trainData");
|
print("Handle Save accomadationData $trainData");
|
||||||
|
|
||||||
Map<String, dynamic> data = trainData;
|
Map<String, dynamic> data = trainData;
|
||||||
@ -203,10 +205,6 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
widget.onClose(false); // Close screen after saving
|
widget.onClose(false); // Close screen after saving
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||||
@ -235,8 +233,10 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text("Train Booking List",
|
Text("Train Booking List",
|
||||||
style:
|
style: TextStyle(
|
||||||
TextStyle(fontSize: 18, fontWeight: FontWeight.bold,color: Color(0xFF575A74))),
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Color(0xFF575A74))),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 6,
|
height: 6,
|
||||||
),
|
),
|
||||||
@ -268,7 +268,6 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
||||||
|
|
||||||
// Iterate over rowBuilders and wrap each in a responsive container
|
// Iterate over rowBuilders and wrap each in a responsive container
|
||||||
@ -284,10 +283,7 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildFirstRow(isDesktop) {
|
List<Widget> _buildFirstRow(isDesktop) {
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -300,12 +296,9 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
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 (errorMessages["train_no"] != null) ...[
|
if (errorMessages["train_no"] != null) ...[
|
||||||
SizedBox(height: 5), // Space before error message
|
SizedBox(height: 5), // Space before error message
|
||||||
Text(
|
Text(
|
||||||
@ -313,7 +306,6 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop)
|
||||||
@ -322,39 +314,40 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildTripType(bool isDesktop) {
|
List<Widget> _buildTripType(bool isDesktop) {
|
||||||
|
|
||||||
List<dynamic> purposeList = widget.apiData?['flight_trip_type'] ?? [];
|
List<dynamic> purposeList = widget.apiData?['flight_trip_type'] ?? [];
|
||||||
|
|
||||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
||||||
.map((item) => DropdownMenuItem<String>(
|
.map((item) => DropdownMenuItem<String>(
|
||||||
value: item['dropdown_value'],
|
value: item['dropdown_value'],
|
||||||
child: Text(item['dropdown_value']),
|
child: Text(item['dropdown_value']),
|
||||||
)).toList();
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (dropdownItems.isEmpty) {
|
if (dropdownItems.isEmpty) {
|
||||||
dropdownItems.add(
|
dropdownItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
value: null,
|
value: null,
|
||||||
child: Text("No options available", style: TextStyle(color: Colors.grey)),
|
child: Text("No options available",
|
||||||
|
style: TextStyle(color: Colors.grey)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default selected value
|
// Default selected value
|
||||||
String? selectedPurpose = dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
String? selectedPurpose =
|
||||||
|
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: _trainNoFocused,
|
isFocused: _trainNoFocused,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
|
width: isDesktop
|
||||||
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
@ -369,36 +362,34 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _builClassType(bool isDesktop) {
|
List<Widget> _builClassType(bool isDesktop) {
|
||||||
|
|
||||||
List<dynamic> purposeList = widget.apiData?['train_class'] ?? [];
|
List<dynamic> purposeList = widget.apiData?['train_class'] ?? [];
|
||||||
|
|
||||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
||||||
.map((item) => DropdownMenuItem<String>(
|
.map((item) => DropdownMenuItem<String>(
|
||||||
value: item['dropdown_key'],
|
value: item['dropdown_key'],
|
||||||
child: Text(item['dropdown_value']),
|
child: Text(item['dropdown_value']),
|
||||||
)).toList();
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (dropdownItems.isEmpty) {
|
if (dropdownItems.isEmpty) {
|
||||||
dropdownItems.add(
|
dropdownItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
value: null,
|
value: null,
|
||||||
child: Text("No options available", style: TextStyle(color: Colors.grey)),
|
child: Text("No options available",
|
||||||
|
style: TextStyle(color: Colors.grey)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default selected value
|
// Default selected value
|
||||||
selectedClass ??= dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
selectedClass ??=
|
||||||
|
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Column(
|
Column(
|
||||||
@ -415,9 +406,11 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: _isHotelNameFocused,
|
isFocused: _isHotelNameFocused,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
|
width: isDesktop
|
||||||
|
? 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>(
|
||||||
focusNode: _hotelNameFocusNode, // Assign the correct focus node
|
focusNode: _hotelNameFocusNode, // Assign the correct focus node
|
||||||
// controller: _hotelNameController,
|
// controller: _hotelNameController,
|
||||||
@ -425,8 +418,8 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(
|
contentPadding:
|
||||||
horizontal: 10), // Proper padding
|
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: purposeList.isNotEmpty
|
onChanged: purposeList.isNotEmpty
|
||||||
? (newValue) {
|
? (newValue) {
|
||||||
@ -437,8 +430,6 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
: null,
|
: null,
|
||||||
items: dropdownItems,
|
items: dropdownItems,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (errorMessages["class"] != null) ...[
|
if (errorMessages["class"] != null) ...[
|
||||||
@ -453,10 +444,7 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildSecondRow(bool isDesktop) {
|
List<Widget> _buildSecondRow(bool isDesktop) {
|
||||||
|
|
||||||
|
|
||||||
DateTime? _selectedCheckOutDate;
|
DateTime? _selectedCheckOutDate;
|
||||||
TimeOfDay? _selectedCheckOutTime;
|
TimeOfDay? _selectedCheckOutTime;
|
||||||
|
|
||||||
@ -466,9 +454,8 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
|
|
||||||
DateTime? pickedDate = await showDatePicker(
|
DateTime? pickedDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
|
initialDate: _selectedCheckOutDate != null &&
|
||||||
|
_selectedCheckOutDate!.isAfter(today)
|
||||||
initialDate: _selectedCheckOutDate != null && _selectedCheckOutDate!.isAfter(today)
|
|
||||||
? _selectedCheckOutDate!
|
? _selectedCheckOutDate!
|
||||||
: today,
|
: today,
|
||||||
firstDate: today,
|
firstDate: today,
|
||||||
@ -504,7 +491,6 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -531,7 +517,6 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -567,7 +552,6 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: _toFocusNode,
|
focusNode: _toFocusNode,
|
||||||
controller: _toController,
|
controller: _toController,
|
||||||
@ -613,7 +597,6 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => _selectCheckOutDate(context),
|
onTap: () => _selectCheckOutDate(context),
|
||||||
child: AbsorbPointer(
|
child: AbsorbPointer(
|
||||||
@ -633,7 +616,6 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (errorMessages["date"] != null) ...[
|
if (errorMessages["date"] != null) ...[
|
||||||
@ -686,7 +668,6 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (errorMessages["time"] != null) ...[
|
if (errorMessages["time"] != null) ...[
|
||||||
@ -698,8 +679,6 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -720,7 +699,7 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
width: isDesktop
|
width: isDesktop
|
||||||
? MediaQuery.of(context).size.width * 0.4
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
: MediaQuery.of(context).size.width * 0.66,
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: _commentsFocusNode,
|
focusNode: _commentsFocusNode,
|
||||||
|
|||||||
@ -7,20 +7,21 @@ import '../../widgets/custom_text_field.dart';
|
|||||||
import '../../widgets/custom_text_itnerary_sub.dart';
|
import '../../widgets/custom_text_itnerary_sub.dart';
|
||||||
|
|
||||||
class VisaScreen extends StatefulWidget {
|
class VisaScreen extends StatefulWidget {
|
||||||
|
|
||||||
final Map<String, dynamic>? apiData;
|
final Map<String, dynamic>? apiData;
|
||||||
final List<dynamic>? apiCountryData;
|
final List<dynamic>? apiCountryData;
|
||||||
|
|
||||||
|
|
||||||
final Function(bool) onClose;
|
final Function(bool) onClose;
|
||||||
final Function(Map<String, dynamic>) onSaveVisa;
|
final Function(Map<String, dynamic>) onSaveVisa;
|
||||||
final Map<String, dynamic>? selectedItem;
|
final Map<String, dynamic>? selectedItem;
|
||||||
final String? loginUser;
|
final String? loginUser;
|
||||||
|
|
||||||
|
VisaScreen(
|
||||||
VisaScreen({
|
{required this.onClose,
|
||||||
required this.onClose,required this.onSaveVisa, this.apiData, required this.selectedItem,
|
required this.onSaveVisa,
|
||||||
required this.apiCountryData, required this.loginUser});
|
this.apiData,
|
||||||
|
required this.selectedItem,
|
||||||
|
required this.apiCountryData,
|
||||||
|
required this.loginUser});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_VisaScreenState createState() => _VisaScreenState();
|
_VisaScreenState createState() => _VisaScreenState();
|
||||||
@ -38,7 +39,6 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
final FocusNode _dateFocusNode = FocusNode();
|
final FocusNode _dateFocusNode = FocusNode();
|
||||||
final FocusNode _commentsFocusNode = FocusNode();
|
final FocusNode _commentsFocusNode = FocusNode();
|
||||||
|
|
||||||
|
|
||||||
late TextEditingController _tripTypeController = TextEditingController();
|
late TextEditingController _tripTypeController = TextEditingController();
|
||||||
late TextEditingController _hotelNameController = TextEditingController();
|
late TextEditingController _hotelNameController = TextEditingController();
|
||||||
late TextEditingController _fromController = TextEditingController();
|
late TextEditingController _fromController = TextEditingController();
|
||||||
@ -57,7 +57,6 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
|
|
||||||
Map<String, String> errorMessages = {};
|
Map<String, String> errorMessages = {};
|
||||||
|
|
||||||
|
|
||||||
Map<String, dynamic> get visaData {
|
Map<String, dynamic> get visaData {
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
"type_of_visa": selectedPurpose,
|
"type_of_visa": selectedPurpose,
|
||||||
@ -70,23 +69,24 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (widget.selectedItem != null) {
|
if (widget.selectedItem != null) {
|
||||||
if (widget.selectedItem?["indx"] != null && widget.selectedItem?["indx"] != 0) {
|
if (widget.selectedItem?["indx"] != null &&
|
||||||
|
widget.selectedItem?["indx"] != 0) {
|
||||||
data["indx"] = widget.selectedItem!["indx"];
|
data["indx"] = widget.selectedItem!["indx"];
|
||||||
} else if (widget.selectedItem?["visa_id"] != null && widget.selectedItem?["visa_id"] != 0) {
|
} else if (widget.selectedItem?["visa_id"] != null &&
|
||||||
|
widget.selectedItem?["visa_id"] != 0) {
|
||||||
data["visa_id"] = widget.selectedItem!["visa_id"];
|
data["visa_id"] = widget.selectedItem!["visa_id"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
_addFocusListener(_tripTypeFocusNode, (focus) => _tripTypeFocused = focus);
|
_addFocusListener(_tripTypeFocusNode, (focus) => _tripTypeFocused = focus);
|
||||||
_addFocusListener(_hotelNameFocusNode, (focus) => _isHotelNameFocused = focus);
|
_addFocusListener(
|
||||||
|
_hotelNameFocusNode, (focus) => _isHotelNameFocused = focus);
|
||||||
_addFocusListener(_dateFocusNode, (focus) => _dateFocus = focus);
|
_addFocusListener(_dateFocusNode, (focus) => _dateFocus = focus);
|
||||||
_addFocusListener(_commentsFocusNode, (focus) => _commentsFocus = focus);
|
_addFocusListener(_commentsFocusNode, (focus) => _commentsFocus = focus);
|
||||||
|
|
||||||
@ -96,20 +96,17 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
TextEditingController(text: widget.selectedItem?["start_date"] ?? "");
|
TextEditingController(text: widget.selectedItem?["start_date"] ?? "");
|
||||||
|
|
||||||
// Set the selected value if available
|
// Set the selected value if available
|
||||||
if (widget.selectedItem != null && widget.selectedItem!["type_of_visa"] != null) {
|
if (widget.selectedItem != null &&
|
||||||
|
widget.selectedItem!["type_of_visa"] != null) {
|
||||||
selectedPurpose = widget.selectedItem!["type_of_visa"].toString();
|
selectedPurpose = widget.selectedItem!["type_of_visa"].toString();
|
||||||
}
|
}
|
||||||
if (widget.selectedItem != null && widget.selectedItem!["country_code"] != null) {
|
if (widget.selectedItem != null &&
|
||||||
|
widget.selectedItem!["country_code"] != null) {
|
||||||
// selectedPurpose = widget.selectedItem!["selectedCountry"].toString();
|
// selectedPurpose = widget.selectedItem!["selectedCountry"].toString();
|
||||||
selectedCountry = widget.selectedItem!["country_code"] as String?;
|
selectedCountry = widget.selectedItem!["country_code"] as String?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _addFocusListener(FocusNode node, Function(bool) updateState) {
|
void _addFocusListener(FocusNode node, Function(bool) updateState) {
|
||||||
node.addListener(() {
|
node.addListener(() {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -131,12 +128,15 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool isValidData(Map<String, dynamic> data) {
|
bool isValidData(Map<String, dynamic> data) {
|
||||||
errorMessages.clear(); // Reset errors
|
errorMessages.clear(); // Reset errors
|
||||||
|
|
||||||
// Required fields that must not be empty
|
// Required fields that must not be empty
|
||||||
List<String> requiredFields = ["type_of_visa", "country_code","start_date"];
|
List<String> requiredFields = [
|
||||||
|
"type_of_visa",
|
||||||
|
"country_code",
|
||||||
|
"start_date"
|
||||||
|
];
|
||||||
|
|
||||||
// Check validation for each field
|
// Check validation for each field
|
||||||
for (String field in requiredFields) {
|
for (String field in requiredFields) {
|
||||||
@ -148,10 +148,7 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
return errorMessages.isEmpty; // Valid if there are no errors
|
return errorMessages.isEmpty; // Valid if there are no errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void handleSave() {
|
void handleSave() {
|
||||||
|
|
||||||
print("Handle Save visaData $visaData");
|
print("Handle Save visaData $visaData");
|
||||||
|
|
||||||
Map<String, dynamic> data = visaData;
|
Map<String, dynamic> data = visaData;
|
||||||
@ -167,10 +164,6 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
widget.onClose(false); // Close screen after saving
|
widget.onClose(false); // Close screen after saving
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||||
@ -199,8 +192,10 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text("Visa Registration",
|
Text("Visa Registration",
|
||||||
style:
|
style: TextStyle(
|
||||||
TextStyle(fontSize: 18, fontWeight: FontWeight.bold,color: Color(0xFF575A74))),
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Color(0xFF575A74))),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 6,
|
height: 6,
|
||||||
),
|
),
|
||||||
@ -226,12 +221,9 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
List<List<Widget>> rowBuilders = [
|
List<List<Widget>> rowBuilders = [_buildSecondRow(isDesktop)];
|
||||||
_buildSecondRow(isDesktop)
|
|
||||||
];
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
||||||
|
|
||||||
// Iterate over rowBuilders and wrap each in a responsive container
|
// Iterate over rowBuilders and wrap each in a responsive container
|
||||||
@ -247,10 +239,7 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildFirstRow(isDesktop) {
|
List<Widget> _buildFirstRow(isDesktop) {
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -263,12 +252,9 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
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 (errorMessages["type_of_visa"] != null) ...[
|
if (errorMessages["type_of_visa"] != null) ...[
|
||||||
SizedBox(height: 5), // Space before error message
|
SizedBox(height: 5), // Space before error message
|
||||||
Text(
|
Text(
|
||||||
@ -276,7 +262,6 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop)
|
||||||
@ -285,75 +270,69 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildTripType(bool isDesktop) {
|
List<Widget> _buildTripType(bool isDesktop) {
|
||||||
|
|
||||||
List<dynamic> purposeList = widget.apiData?['visa_type_of_visa'] ?? [];
|
List<dynamic> purposeList = widget.apiData?['visa_type_of_visa'] ?? [];
|
||||||
|
|
||||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
||||||
.map((item) => DropdownMenuItem<String>(
|
.map((item) => DropdownMenuItem<String>(
|
||||||
value: item['dropdown_key'],
|
value: item['dropdown_key'],
|
||||||
child: Text(item['dropdown_value']),
|
child: Text(item['dropdown_value']),
|
||||||
)).toList();
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (dropdownItems.isEmpty) {
|
if (dropdownItems.isEmpty) {
|
||||||
dropdownItems.add(
|
dropdownItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
value: null,
|
value: null,
|
||||||
child: Text("No options available", style: TextStyle(color: Colors.grey)),
|
child: Text("No options available",
|
||||||
|
style: TextStyle(color: Colors.grey)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default selected value
|
// Default selected value
|
||||||
selectedPurpose ??= dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
selectedPurpose ??=
|
||||||
|
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: _tripTypeFocused,
|
isFocused: _tripTypeFocused,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
|
width: isDesktop
|
||||||
|
? 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>(
|
||||||
focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
||||||
value: selectedPurpose,
|
value: selectedPurpose,
|
||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(
|
contentPadding:
|
||||||
horizontal: 10), // Proper padding
|
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: purposeList.isNotEmpty
|
onChanged: purposeList.isNotEmpty
|
||||||
? (newValue) {
|
? (newValue) {
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedPurpose = newValue;
|
selectedPurpose = newValue;
|
||||||
});
|
});
|
||||||
print("Updating form data: Flight -> trip_type -> ${newValue ?? ""}");
|
print(
|
||||||
|
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}");
|
||||||
|
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
|
|
||||||
items: dropdownItems,
|
items: dropdownItems,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildSecondRow(bool isDesktop) {
|
List<Widget> _buildSecondRow(bool isDesktop) {
|
||||||
|
|
||||||
// List<dynamic> countryList = widget.apiCountryData ?? [];
|
// List<dynamic> countryList = widget.apiCountryData ?? [];
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -380,12 +359,12 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
late Map<String, String> countryMap; // Mapping country_code -> country_name
|
late Map<String, String> countryMap; // Mapping country_code -> country_name
|
||||||
late List<String> countryCodes; // List of country codes
|
late List<String> countryCodes; // List of country codes
|
||||||
|
|
||||||
|
|
||||||
countryList = widget.apiCountryData ?? [];
|
countryList = widget.apiCountryData ?? [];
|
||||||
|
|
||||||
// Map country codes to country names
|
// Map country codes to country names
|
||||||
countryMap = {
|
countryMap = {
|
||||||
for (var item in countryList) item['country_code'] as String: item['country_name'] as String
|
for (var item in countryList)
|
||||||
|
item['country_code'] as String: item['country_name'] as String
|
||||||
};
|
};
|
||||||
|
|
||||||
// Extract only country codes for processing
|
// Extract only country codes for processing
|
||||||
@ -403,9 +382,8 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
|
|
||||||
DateTime? pickedDate = await showDatePicker(
|
DateTime? pickedDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
|
initialDate: _selectedCheckOutDate != null &&
|
||||||
|
_selectedCheckOutDate!.isAfter(today)
|
||||||
initialDate: _selectedCheckOutDate != null && _selectedCheckOutDate!.isAfter(today)
|
|
||||||
? _selectedCheckOutDate!
|
? _selectedCheckOutDate!
|
||||||
: today,
|
: today,
|
||||||
firstDate: today,
|
firstDate: today,
|
||||||
@ -420,9 +398,7 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -437,6 +413,9 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: _isHotelNameFocused,
|
isFocused: _isHotelNameFocused,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
|
width: isDesktop
|
||||||
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: DropdownSearch<String>(
|
child: DropdownSearch<String>(
|
||||||
@ -454,10 +433,13 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
dropdownSearchDecoration: InputDecoration(
|
dropdownSearchDecoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 1,),
|
contentPadding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
dropdownBuilder: (context, selectedItem) => Align( // Center-align selected item
|
),
|
||||||
|
dropdownBuilder: (context, selectedItem) => Align(
|
||||||
|
// Center-align selected item
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Text(
|
child: Text(
|
||||||
selectedItem ?? "Select Country",
|
selectedItem ?? "Select Country",
|
||||||
@ -474,7 +456,6 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
if (selectedCountry!.isNotEmpty) {
|
if (selectedCountry!.isNotEmpty) {
|
||||||
errorMessages.remove("country_code");
|
errorMessages.remove("country_code");
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -489,7 +470,6 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
if (isDesktop)
|
if (isDesktop)
|
||||||
Spacer()
|
Spacer()
|
||||||
else
|
else
|
||||||
@ -510,9 +490,11 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: _dateFocus,
|
isFocused: _dateFocus,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
|
width: isDesktop
|
||||||
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await _selectCheckOutDate(context);
|
await _selectCheckOutDate(context);
|
||||||
@ -521,7 +503,6 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
errorMessages.remove("start_date");
|
errorMessages.remove("start_date");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
child: AbsorbPointer(
|
child: AbsorbPointer(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
@ -540,7 +521,6 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (errorMessages["start_date"] != null) ...[
|
if (errorMessages["start_date"] != null) ...[
|
||||||
@ -552,9 +532,6 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,7 +552,7 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
width: isDesktop
|
width: isDesktop
|
||||||
? MediaQuery.of(context).size.width * 0.4
|
? MediaQuery.of(context).size.width * 0.34
|
||||||
: MediaQuery.of(context).size.width * 0.66,
|
: MediaQuery.of(context).size.width * 0.66,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: _commentsFocusNode,
|
focusNode: _commentsFocusNode,
|
||||||
@ -584,7 +561,7 @@ class _VisaScreenState extends State<VisaScreen> {
|
|||||||
keyboardType: TextInputType.multiline,
|
keyboardType: TextInputType.multiline,
|
||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: "Description",
|
labelText: "Comments",
|
||||||
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,
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:frontend/Screens/plans/dynamic_itinerary_stepper.dart';
|
import 'package:frontend/Screens/plans/dynamic_itinerary_stepper.dart';
|
||||||
|
import 'package:frontend/utils/auth_utils.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:responsive_builder/responsive_builder.dart';
|
import 'package:responsive_builder/responsive_builder.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
@ -28,26 +29,41 @@ class _CreatePlansState extends State<CreatePlan> {
|
|||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
body: Row(
|
||||||
|
children: [
|
||||||
|
if (isDesktop) CustomDrawer(isDesktop: true),
|
||||||
|
Expanded(child: buildUserTable(isDesktop, context)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildUserTable(bool isDesktop, context) {
|
||||||
final args = GoRouterState.of(context).extra as Map<String, dynamic>? ?? {};
|
final args = GoRouterState.of(context).extra as Map<String, dynamic>? ?? {};
|
||||||
// final planData = args?['planData'];
|
// final planData = args?['planData'];
|
||||||
final bool isViewMode = args?['isViewMode'] ?? false;
|
final bool isViewMode = args?['isViewMode'] ?? false;
|
||||||
|
|
||||||
final Map<String, dynamic> planData = args['planData'] as Map<String, dynamic>? ?? {};
|
final Map<String, dynamic> planData =
|
||||||
|
args['planData'] as Map<String, dynamic>? ?? {};
|
||||||
|
|
||||||
// print("isViewMode: $isViewMode");
|
// print("isViewMode: $isViewMode");
|
||||||
|
|
||||||
// final bool isViewMode = true;
|
// final bool isViewMode = true;
|
||||||
// final planData = GoRouterState.of(context).extra as Map<String, dynamic>? ?? {};
|
// final planData = GoRouterState.of(context).extra as Map<String, dynamic>? ?? {};
|
||||||
|
|
||||||
|
|
||||||
print("RECived palndata");
|
print("RECived palndata");
|
||||||
// print("RECived palndata - ${planData}");
|
// print("RECived palndata - ${planData}");
|
||||||
|
|
||||||
return Scaffold(
|
return Container(
|
||||||
backgroundColor: Colors.white,
|
margin:
|
||||||
body: Column(
|
const EdgeInsets.only(left: 10.0, right: 15.0, top: 10.0, bottom: 10.0),
|
||||||
|
decoration:
|
||||||
|
BoxDecoration(border: Border.all(color: Color(0xFFF7F7FB), width: 3.5)),
|
||||||
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
color: Color(0xFFF4F4FB),
|
color: Color(0xFFF4F4FB),
|
||||||
@ -67,21 +83,20 @@ class _CreatePlansState extends State<CreatePlan> {
|
|||||||
isViewMode
|
isViewMode
|
||||||
? "View Plan"
|
? "View Plan"
|
||||||
: (planData.isNotEmpty ? "Update Plan" : "New Plan"),
|
: (planData.isNotEmpty ? "Update Plan" : "New Plan"),
|
||||||
|
|
||||||
style: TextStyle(fontSize: 18),
|
style: TextStyle(fontSize: 18),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
Container(
|
// Container(
|
||||||
color: Color(0xFFE9EBF6),
|
// color: Color(0xFFE9EBF6),
|
||||||
child: IconButton(
|
// child: IconButton(
|
||||||
icon: Icon(Icons.close),
|
// icon: Icon(Icons.close),
|
||||||
onPressed: () {
|
// onPressed: () {
|
||||||
context.go('/listPlan');
|
// context.go('/listPlan');
|
||||||
},
|
// },
|
||||||
),
|
// ),
|
||||||
)
|
// )
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
@ -90,7 +105,10 @@ class _CreatePlansState extends State<CreatePlan> {
|
|||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.all(26.0),
|
padding: EdgeInsets.all(26.0),
|
||||||
child: CreateNewPlan(isDesktop: isDesktop, selectedPlanData: planData, isViewMode : isViewMode),
|
child: CreateNewPlan(
|
||||||
|
isDesktop: isDesktop,
|
||||||
|
selectedPlanData: planData,
|
||||||
|
isViewMode: isViewMode),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -98,22 +116,23 @@ class _CreatePlansState extends State<CreatePlan> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CreateNewPlan extends StatefulWidget {
|
class CreateNewPlan extends StatefulWidget {
|
||||||
final bool isDesktop;
|
final bool isDesktop;
|
||||||
final bool isViewMode;
|
final bool isViewMode;
|
||||||
final Map<String, dynamic> selectedPlanData;
|
final Map<String, dynamic> selectedPlanData;
|
||||||
const CreateNewPlan({super.key, required this.isDesktop, required this.selectedPlanData, required this.isViewMode});
|
const CreateNewPlan(
|
||||||
|
{super.key,
|
||||||
|
required this.isDesktop,
|
||||||
|
required this.selectedPlanData,
|
||||||
|
required this.isViewMode});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_CreateNewPlansState createState() => _CreateNewPlansState();
|
_CreateNewPlansState createState() => _CreateNewPlansState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _CreateNewPlansState extends State<CreateNewPlan> {
|
class _CreateNewPlansState extends State<CreateNewPlan> {
|
||||||
|
|
||||||
final TextEditingController _tripTitleController = TextEditingController();
|
final TextEditingController _tripTitleController = TextEditingController();
|
||||||
final TextEditingController _descriptionController = TextEditingController();
|
final TextEditingController _descriptionController = TextEditingController();
|
||||||
|
|
||||||
@ -134,13 +153,12 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
String? selectedplanUserId;
|
String? selectedplanUserId;
|
||||||
bool? selectedIstravelUser;
|
bool? selectedIstravelUser;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Map<String, dynamic>? apiData; // Store API response here
|
Map<String, dynamic>? apiData; // Store API response here
|
||||||
List<dynamic>? apiCountryData;
|
List<dynamic>? apiCountryData;
|
||||||
List<dynamic>? apiCostData; // Store API response here
|
List<dynamic>? apiCostData; // Store API response here
|
||||||
bool isLoading = true; // Track loading state
|
bool isLoading = true; // Track loading state
|
||||||
|
|
||||||
|
String? orgId;
|
||||||
String? planUsrId;
|
String? planUsrId;
|
||||||
String? planTravlrId;
|
String? planTravlrId;
|
||||||
String? _selectedTripType;
|
String? _selectedTripType;
|
||||||
@ -163,6 +181,7 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
|
|
||||||
//Getter Method
|
//Getter Method
|
||||||
Map<String, dynamic> get planData => {
|
Map<String, dynamic> get planData => {
|
||||||
|
"org_id": orgId,
|
||||||
"user_id": planUsrId,
|
"user_id": planUsrId,
|
||||||
"traveller_id": planTravlrId,
|
"traveller_id": planTravlrId,
|
||||||
"trip_title": _tripTitleController.text,
|
"trip_title": _tripTitleController.text,
|
||||||
@ -188,8 +207,6 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
"miscellaneous": miscellaneousList,
|
"miscellaneous": miscellaneousList,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// // Function to update miscellaneous list
|
// // Function to update miscellaneous list
|
||||||
// void updateMiscellaneousData(List<Map<String, dynamic>> newMiscellaneousList) {
|
// void updateMiscellaneousData(List<Map<String, dynamic>> newMiscellaneousList) {
|
||||||
// setState(() {
|
// setState(() {
|
||||||
@ -198,7 +215,6 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
// print("Updated Miscellaneous Data in CreateNewPlan: $miscellaneousList");
|
// print("Updated Miscellaneous Data in CreateNewPlan: $miscellaneousList");
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
void handleItineraryUpdate(String type, List<Map<String, dynamic>> newList) {
|
void handleItineraryUpdate(String type, List<Map<String, dynamic>> newList) {
|
||||||
setState(() {
|
setState(() {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -241,7 +257,6 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
fetchUserDetails();
|
fetchUserDetails();
|
||||||
|
|
||||||
|
|
||||||
fetchPlans();
|
fetchPlans();
|
||||||
fetchCostCenter();
|
fetchCostCenter();
|
||||||
fetchCountryList();
|
fetchCountryList();
|
||||||
@ -263,7 +278,6 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
handleUpdateData();
|
handleUpdateData();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -273,74 +287,76 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void handleUpdateData() {
|
void handleUpdateData() {
|
||||||
if (widget.selectedPlanData != null) {
|
if (widget.selectedPlanData != null) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|
||||||
|
|
||||||
planUsrId = widget.selectedPlanData['user_id'] ?? '';
|
planUsrId = widget.selectedPlanData['user_id'] ?? '';
|
||||||
_tripTitleController.text = widget.selectedPlanData['trip_title'] ?? '';
|
_tripTitleController.text = widget.selectedPlanData['trip_title'] ?? '';
|
||||||
_descriptionController.text = widget.selectedPlanData['description'] ?? '';
|
_descriptionController.text =
|
||||||
|
widget.selectedPlanData['description'] ?? '';
|
||||||
|
|
||||||
_selectedTripType = widget.selectedPlanData['trip_type'];
|
_selectedTripType = widget.selectedPlanData['trip_type'];
|
||||||
_selectedIsBillable = widget.selectedPlanData['is_billable'] == "1" ? "1" : "2";
|
_selectedIsBillable =
|
||||||
|
widget.selectedPlanData['is_billable'] == "1" ? "1" : "2";
|
||||||
|
|
||||||
// selectedCostCenterId = widget.selectedPlanData['cost_center_id']?.toString() ;
|
// selectedCostCenterId = widget.selectedPlanData['cost_center_id']?.toString() ;
|
||||||
// selectedPurpose = widget.selectedPlanData['purpose_of_travel']?.toString();
|
// selectedPurpose = widget.selectedPlanData['purpose_of_travel']?.toString();
|
||||||
// selectedFuncDept =widget.selectedPlanData['functional_department']?.toString();
|
// selectedFuncDept =widget.selectedPlanData['functional_department']?.toString();
|
||||||
|
|
||||||
if (widget.selectedPlanData!["cost_center_id"] != null) {
|
if (widget.selectedPlanData!["cost_center_id"] != null) {
|
||||||
selectedCostCenterId = widget.selectedPlanData!["cost_center_id"].toString();
|
selectedCostCenterId =
|
||||||
|
widget.selectedPlanData!["cost_center_id"].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
if (widget.selectedPlanData!["purpose_of_travel"] != null) {
|
if (widget.selectedPlanData!["purpose_of_travel"] != null) {
|
||||||
selectedPurpose = widget.selectedPlanData!["purpose_of_travel"].toString();
|
selectedPurpose =
|
||||||
|
widget.selectedPlanData!["purpose_of_travel"].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (widget.selectedPlanData!["functional_department"] != null) {
|
if (widget.selectedPlanData!["functional_department"] != null) {
|
||||||
// selectedFuncDept = widget.selectedPlanData!["functional_department"].toString();
|
// selectedFuncDept = widget.selectedPlanData!["functional_department"].toString();
|
||||||
selectedFuncDept = widget.selectedPlanData!["functional_department"];
|
selectedFuncDept = widget.selectedPlanData!["functional_department"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Assign lists from selectedPlanData, ensuring they are properly formatted
|
// Assign lists from selectedPlanData, ensuring they are properly formatted
|
||||||
flightList = List<Map<String, dynamic>>.from(widget.selectedPlanData['flight'] ?? []);
|
flightList = List<Map<String, dynamic>>.from(
|
||||||
accommodationList = List<Map<String, dynamic>>.from(widget.selectedPlanData['accomodation'] ?? []);
|
widget.selectedPlanData['flight'] ?? []);
|
||||||
busList = List<Map<String, dynamic>>.from(widget.selectedPlanData['bus'] ?? []);
|
accommodationList = List<Map<String, dynamic>>.from(
|
||||||
taxiList = List<Map<String, dynamic>>.from(widget.selectedPlanData['taxi'] ?? []);
|
widget.selectedPlanData['accomodation'] ?? []);
|
||||||
trainList = List<Map<String, dynamic>>.from(widget.selectedPlanData['train'] ?? []);
|
busList = List<Map<String, dynamic>>.from(
|
||||||
visaList = List<Map<String, dynamic>>.from(widget.selectedPlanData['visa'] ?? []);
|
widget.selectedPlanData['bus'] ?? []);
|
||||||
forexList = List<Map<String, dynamic>>.from(widget.selectedPlanData['forex'] ?? []);
|
taxiList = List<Map<String, dynamic>>.from(
|
||||||
insuranceList = List<Map<String, dynamic>>.from(widget.selectedPlanData['insurance'] ?? []);
|
widget.selectedPlanData['taxi'] ?? []);
|
||||||
miscellaneousList = List<Map<String, dynamic>>.from(widget.selectedPlanData['miscellaneous'] ?? []);
|
trainList = List<Map<String, dynamic>>.from(
|
||||||
|
widget.selectedPlanData['train'] ?? []);
|
||||||
|
visaList = List<Map<String, dynamic>>.from(
|
||||||
|
widget.selectedPlanData['visa'] ?? []);
|
||||||
|
forexList = List<Map<String, dynamic>>.from(
|
||||||
|
widget.selectedPlanData['forex'] ?? []);
|
||||||
|
insuranceList = List<Map<String, dynamic>>.from(
|
||||||
|
widget.selectedPlanData['insurance'] ?? []);
|
||||||
|
miscellaneousList = List<Map<String, dynamic>>.from(
|
||||||
|
widget.selectedPlanData['miscellaneous'] ?? []);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (widget.selectedPlanData.containsKey('plan_id') && widget.selectedPlanData['plan_id'] != null) {
|
if (widget.selectedPlanData.containsKey('plan_id') &&
|
||||||
|
widget.selectedPlanData['plan_id'] != null) {
|
||||||
print("Plan ID exists: ${widget.selectedPlanData['plan_id']}");
|
print("Plan ID exists: ${widget.selectedPlanData['plan_id']}");
|
||||||
selectedPlanId = widget.selectedPlanData['plan_id']?.toString();
|
selectedPlanId = widget.selectedPlanData['plan_id']?.toString();
|
||||||
} else {
|
} else {
|
||||||
print("Plan ID is missing or null");
|
print("Plan ID is missing or null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
print("updatedPlanDAta - $planData");
|
print("updatedPlanDAta - $planData");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void getSelectedPlanFor() {
|
void getSelectedPlanFor() {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
if (selectedplanUserId != null) {
|
if (selectedplanUserId != null) {
|
||||||
|
|
||||||
if (selectedIstravelUser!) {
|
if (selectedIstravelUser!) {
|
||||||
planUsrId = "";
|
planUsrId = "";
|
||||||
planTravlrId = selectedplanUserId;
|
planTravlrId = selectedplanUserId;
|
||||||
@ -348,9 +364,7 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
planUsrId = selectedplanUserId;
|
planUsrId = selectedplanUserId;
|
||||||
planTravlrId = "";
|
planTravlrId = "";
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
}
|
|
||||||
else {
|
|
||||||
planUsrId = selfId;
|
planUsrId = selfId;
|
||||||
planTravlrId = "";
|
planTravlrId = "";
|
||||||
}
|
}
|
||||||
@ -359,13 +373,11 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
print("USER ID - $planUsrId , TRAVELLER ID - $planTravlrId");
|
print("USER ID - $planUsrId , TRAVELLER ID - $planTravlrId");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fetchUserDetails() async {
|
void fetchUserDetails() async {
|
||||||
final details = await getUserDetails();
|
final details = await getUserDetails();
|
||||||
|
|
||||||
print("details- $details");
|
print("details- $details");
|
||||||
|
|
||||||
|
|
||||||
if (details != null) {
|
if (details != null) {
|
||||||
setState(() {
|
setState(() {
|
||||||
userDetails = details.toString(); // Store the full Map
|
userDetails = details.toString(); // Store the full Map
|
||||||
@ -373,7 +385,7 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
selfId = details['user_id'];
|
selfId = details['user_id'];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
orgId = await getOrgId();
|
||||||
print("userDetails - $selfId");
|
print("userDetails - $selfId");
|
||||||
getSelectedPlanFor();
|
getSelectedPlanFor();
|
||||||
}
|
}
|
||||||
@ -383,7 +395,6 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
return prefs.getString('auth_token');
|
return prefs.getString('auth_token');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<String?> getUserId() async {
|
Future<String?> getUserId() async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
return prefs.getString('userId');
|
return prefs.getString('userId');
|
||||||
@ -404,7 +415,6 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<void> fetchPlans() async {
|
Future<void> fetchPlans() async {
|
||||||
final String apiUrldata = '$apiUrl/api/getDropdownMaster';
|
final String apiUrldata = '$apiUrl/api/getDropdownMaster';
|
||||||
|
|
||||||
@ -428,16 +438,16 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
print(data);
|
print(data);
|
||||||
|
|
||||||
if (!data.containsKey('data') || data['data'] is! Map) {
|
if (!data.containsKey('data') || data['data'] is! Map) {
|
||||||
throw Exception("Invalid response format: 'data' field is missing or not a Map");
|
throw Exception(
|
||||||
|
"Invalid response format: 'data' field is missing or not a Map");
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
Map<String, dynamic> plansJson =
|
||||||
|
data['data']; // 'data' is a Map, not a List
|
||||||
setState(() {
|
setState(() {
|
||||||
apiData = plansJson; // Store API response in state
|
apiData = plansJson; // Store API response in state
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw Exception('Error parsing response: $e');
|
throw Exception('Error parsing response: $e');
|
||||||
}
|
}
|
||||||
@ -473,7 +483,8 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
print(data);
|
print(data);
|
||||||
|
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception("Invalid response format: 'data' field is missing or not a List");
|
throw Exception(
|
||||||
|
"Invalid response format: 'data' field is missing or not a List");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
List<dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
||||||
@ -484,11 +495,11 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
if (apiCostData != null && apiCostData!.isNotEmpty) {
|
if (apiCostData != null && apiCostData!.isNotEmpty) {
|
||||||
selectedCostCenterId ??= apiCostData!.first['department_id']?.toString();
|
selectedCostCenterId ??=
|
||||||
|
apiCostData!.first['department_id']?.toString();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
print('plansJSON');
|
print('plansJSON');
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw Exception('Error parsing response: $e');
|
throw Exception('Error parsing response: $e');
|
||||||
}
|
}
|
||||||
@ -497,7 +508,6 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<void> fetchCountryList() async {
|
Future<void> fetchCountryList() async {
|
||||||
final String apiUrldata = '$apiUrl/api/getcountryMaster';
|
final String apiUrldata = '$apiUrl/api/getcountryMaster';
|
||||||
|
|
||||||
@ -525,10 +535,10 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
print("Country - $data");
|
print("Country - $data");
|
||||||
|
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception("Invalid response format: 'data' field is missing or not a List");
|
throw Exception(
|
||||||
|
"Invalid response format: 'data' field is missing or not a List");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
List<dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
||||||
|
|
||||||
if (data['data'] is List) {
|
if (data['data'] is List) {
|
||||||
@ -540,10 +550,8 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
apiCountryData = plansJson; // Store API response in state
|
apiCountryData = plansJson; // Store API response in state
|
||||||
|
|
||||||
});
|
});
|
||||||
print('plansJSONContry - $plansJson');
|
print('plansJSONContry - $plansJson');
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw Exception('Error parsing response: $e');
|
throw Exception('Error parsing response: $e');
|
||||||
}
|
}
|
||||||
@ -558,9 +566,12 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
validationErrors.clear(); // Clear previous errors
|
validationErrors.clear(); // Clear previous errors
|
||||||
|
|
||||||
// Ensure either "user_id" or "traveller_id" is provided
|
// Ensure either "user_id" or "traveller_id" is provided
|
||||||
if ((planUsrId == null || planUsrId!.isEmpty) && (planTravlrId == null || planTravlrId!.isEmpty)) {
|
if ((planUsrId == null || planUsrId!.isEmpty) &&
|
||||||
validationErrors["user_id"] = "Either User ID or Traveller ID is required";
|
(planTravlrId == null || planTravlrId!.isEmpty)) {
|
||||||
validationErrors["traveller_id"] = "Either User ID or Traveller ID is required";
|
validationErrors["user_id"] =
|
||||||
|
"Either User ID or Traveller ID is required";
|
||||||
|
validationErrors["traveller_id"] =
|
||||||
|
"Either User ID or Traveller ID is required";
|
||||||
}
|
}
|
||||||
|
|
||||||
final requiredFields = {
|
final requiredFields = {
|
||||||
@ -572,7 +583,8 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
|
|
||||||
for (var entry in requiredFields.entries) {
|
for (var entry in requiredFields.entries) {
|
||||||
if (entry.value == null || entry.value!.isEmpty) {
|
if (entry.value == null || entry.value!.isEmpty) {
|
||||||
validationErrors[entry.key] = "${entry.key.replaceAll('_', ' ').toUpperCase()} is required";
|
validationErrors[entry.key] =
|
||||||
|
"${entry.key.replaceAll('_', ' ').toUpperCase()} is required";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -623,8 +635,6 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||||
bool isMobile = sizingInfo.isMobile;
|
bool isMobile = sizingInfo.isMobile;
|
||||||
@ -657,11 +667,14 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: otherUserName ?? userName ?? " ", // Dynamic username
|
text: otherUserName ??
|
||||||
|
userName ??
|
||||||
|
" ", // Dynamic username
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Colors.blueAccent, // Change this to any color
|
color:
|
||||||
|
Colors.blueAccent, // Change this to any color
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -716,7 +729,8 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
enabled: !widget.isViewMode,
|
enabled: !widget.isViewMode,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: "Trip Title",
|
labelText: "Trip Title",
|
||||||
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,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
@ -781,7 +795,6 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
|
|
||||||
isDesktop
|
isDesktop
|
||||||
? Row(
|
? Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -797,11 +810,8 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
_buildNonDescriptionColumn(),
|
_buildNonDescriptionColumn(),
|
||||||
SizedBox(height: 15),
|
SizedBox(height: 15),
|
||||||
_buildDescriptionColumn(isDesktop),
|
_buildDescriptionColumn(isDesktop),
|
||||||
|
|
||||||
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Divider(
|
child: Divider(
|
||||||
@ -809,11 +819,16 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
thickness: 0.5,
|
thickness: 0.5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(child: DynamicItinerary(apiData: apiData, apiCountryData: apiCountryData,
|
Expanded(
|
||||||
onItineraryUpdate: handleItineraryUpdate,loginUser: selfId,selectedPlanData: planData, isViewMode:widget.isViewMode ,
|
child: DynamicItinerary(
|
||||||
|
apiData: apiData,
|
||||||
|
apiCountryData: apiCountryData,
|
||||||
|
onItineraryUpdate: handleItineraryUpdate,
|
||||||
|
loginUser: selfId,
|
||||||
|
selectedPlanData: planData,
|
||||||
|
isViewMode: widget.isViewMode,
|
||||||
)), // Wrap with Expanded if needed
|
)), // Wrap with Expanded if needed
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -821,20 +836,19 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
isDesktop
|
isDesktop
|
||||||
? Row(
|
? Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: _buildSubmit(isDesktop),)
|
children: _buildSubmit(isDesktop),
|
||||||
|
)
|
||||||
: Row(
|
: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: _buildSubmit(isDesktop),)
|
children: _buildSubmit(isDesktop),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Extracted helper function
|
/// Extracted helper function
|
||||||
List<Widget> _buildCostIsBillable() {
|
List<Widget> _buildCostIsBillable() {
|
||||||
|
|
||||||
List<dynamic> purposeList = apiData?['plan_is_billable'] ?? [];
|
List<dynamic> purposeList = apiData?['plan_is_billable'] ?? [];
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@ -862,7 +876,9 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
contentPadding:
|
contentPadding:
|
||||||
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: widget.isViewMode ? null : (newValue) {
|
onChanged: widget.isViewMode
|
||||||
|
? null
|
||||||
|
: (newValue) {
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedCostCenterId = newValue;
|
selectedCostCenterId = newValue;
|
||||||
});
|
});
|
||||||
@ -873,18 +889,18 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
child: Text(item['name'] ?? "Unknown"),
|
child: Text(item['name'] ?? "Unknown"),
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
SizedBox(width: 25,height: 5,),
|
SizedBox(
|
||||||
|
width: 25,
|
||||||
|
height: 5,
|
||||||
|
),
|
||||||
|
|
||||||
Column(
|
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
Text(
|
||||||
"Is Billable ", // Your label
|
"Is Billable ", // Your label
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
@ -903,7 +919,9 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
value: item['dropdown_key'].toString(), // Convert to String
|
value: item['dropdown_key'].toString(), // Convert to String
|
||||||
groupValue: _selectedIsBillable,
|
groupValue: _selectedIsBillable,
|
||||||
activeColor: Colors.blueAccent,
|
activeColor: Colors.blueAccent,
|
||||||
onChanged: widget.isViewMode ? null :(value) {
|
onChanged: widget.isViewMode
|
||||||
|
? null
|
||||||
|
: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedIsBillable = value;
|
_selectedIsBillable = value;
|
||||||
});
|
});
|
||||||
@ -917,7 +935,6 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
|
|
||||||
])
|
])
|
||||||
// Column(
|
// Column(
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -970,7 +987,6 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildPlanTrip(bool isDesktop) {
|
List<Widget> _buildPlanTrip(bool isDesktop) {
|
||||||
List<Map<String, String>> options = [
|
List<Map<String, String>> options = [
|
||||||
{"title": "Self", "value": "Option 1"},
|
{"title": "Self", "value": "Option 1"},
|
||||||
@ -978,13 +994,14 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
{"title": "Others", "value": "Option 3"},
|
{"title": "Others", "value": "Option 3"},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
return options.map((option) {
|
return options.map((option) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 5),
|
padding: const EdgeInsets.symmetric(horizontal: 5),
|
||||||
child: CustomTextFieldWrapper(
|
child: CustomTextFieldWrapper(
|
||||||
color: Color(0xFFF4F4FB),
|
color: Color(0xFFF4F4FB),
|
||||||
width: option["value"] == "Option 2" ? 175 : 120, // Adjust width conditionally
|
width: option["value"] == "Option 2"
|
||||||
|
? 185
|
||||||
|
: 125, // Adjust width conditionally
|
||||||
isFocused: _selectedOption == option["value"],
|
isFocused: _selectedOption == option["value"],
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: RadioListTile<String>(
|
child: RadioListTile<String>(
|
||||||
@ -994,7 +1011,9 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
title: Text(option["title"]!),
|
title: Text(option["title"]!),
|
||||||
value: option["value"]!,
|
value: option["value"]!,
|
||||||
groupValue: _selectedOption,
|
groupValue: _selectedOption,
|
||||||
onChanged: widget.isViewMode ? null : (value) {
|
onChanged: widget.isViewMode
|
||||||
|
? null
|
||||||
|
: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedOption = value!;
|
_selectedOption = value!;
|
||||||
if (value == 'Option 2' || value == 'Option 3') {
|
if (value == 'Option 2' || value == 'Option 3') {
|
||||||
@ -1008,18 +1027,16 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildTripType(bool isMobile) {
|
List<Widget> _buildTripType(bool isMobile) {
|
||||||
return [
|
return [
|
||||||
|
|
||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
color: Color(0xFFF4F4FB),
|
color: Color(0xFFF4F4FB),
|
||||||
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||||
width: 120,
|
width: 130,
|
||||||
isFocused: _selectedTripType == "1",
|
isFocused: _selectedTripType == "1",
|
||||||
isDesktop: widget.isDesktop,
|
isDesktop: widget.isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 35,
|
height: 45,
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: RadioListTile<String>(
|
child: RadioListTile<String>(
|
||||||
@ -1030,7 +1047,9 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
title: Text("Domestic"),
|
title: Text("Domestic"),
|
||||||
value: "1",
|
value: "1",
|
||||||
groupValue: _selectedTripType,
|
groupValue: _selectedTripType,
|
||||||
onChanged: widget.isViewMode ? null : (value) {
|
onChanged: widget.isViewMode
|
||||||
|
? null
|
||||||
|
: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedTripType = value!;
|
_selectedTripType = value!;
|
||||||
});
|
});
|
||||||
@ -1053,19 +1072,18 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
title: Text("International"),
|
title: Text("International"),
|
||||||
value: "2",
|
value: "2",
|
||||||
groupValue: _selectedTripType,
|
groupValue: _selectedTripType,
|
||||||
onChanged: widget.isViewMode ? null :(value) {
|
onChanged: widget.isViewMode
|
||||||
|
? null
|
||||||
|
: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedTripType = value!;
|
_selectedTripType = value!;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Widget _buildNonDescriptionColumn() {
|
Widget _buildNonDescriptionColumn() {
|
||||||
// if (apiData == null) {
|
// if (apiData == null) {
|
||||||
// return Center(child: CircularProgressIndicator()); // Show loading indicator
|
// return Center(child: CircularProgressIndicator()); // Show loading indicator
|
||||||
@ -1081,32 +1099,32 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
value: item['dropdown_key']?.toString(),
|
value: item['dropdown_key']?.toString(),
|
||||||
// value: item['dropdown_key'].toString(),
|
// value: item['dropdown_key'].toString(),
|
||||||
child: Text(item['dropdown_value']),
|
child: Text(item['dropdown_value']),
|
||||||
)).toList();
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (dropdownItems.isEmpty) {
|
if (dropdownItems.isEmpty) {
|
||||||
dropdownItems.add(
|
dropdownItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
// value: null,
|
// value: null,
|
||||||
value: "1",
|
value: "1",
|
||||||
child: Text("No options available", style: TextStyle(color: Colors.grey)),
|
child: Text("No options available",
|
||||||
|
style: TextStyle(color: Colors.grey)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Ensure Selected Value Exists in the Dropdown List
|
// Ensure Selected Value Exists in the Dropdown List
|
||||||
List<String> dropdownKeys = dropdownItems.map((e) => e.value ?? "").toList();
|
List<String> dropdownKeys =
|
||||||
|
dropdownItems.map((e) => e.value ?? "").toList();
|
||||||
|
|
||||||
|
selectedPurpose ??= dropdownItems.isNotEmpty
|
||||||
|
? dropdownItems.first.value.toString()
|
||||||
|
: "No options";
|
||||||
|
|
||||||
|
print(
|
||||||
selectedPurpose ??= dropdownItems.isNotEmpty ? dropdownItems.first.value.toString() : "No options";
|
"Dropdown Purpose List: ${dropdownItems.map((e) => e.value).toList()}");
|
||||||
|
|
||||||
print("Dropdown Purpose List: ${dropdownItems.map((e) => e.value).toList()}");
|
|
||||||
print("Selected Purpose: $selectedPurpose");
|
print("Selected Purpose: $selectedPurpose");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 'plan_functional_department' Starts ---------------------------------------------
|
// 'plan_functional_department' Starts ---------------------------------------------
|
||||||
|
|
||||||
List<dynamic> funcDeptList = apiData?['plan_functional_department'] ?? [];
|
List<dynamic> funcDeptList = apiData?['plan_functional_department'] ?? [];
|
||||||
@ -1116,27 +1134,30 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
// value: item['dropdown_key'],
|
// value: item['dropdown_key'],
|
||||||
value: item['dropdown_key']?.toString(),
|
value: item['dropdown_key']?.toString(),
|
||||||
child: Text(item['dropdown_value']),
|
child: Text(item['dropdown_value']),
|
||||||
)).toList();
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (dropdownFuncDeptItems.isEmpty) {
|
if (dropdownFuncDeptItems.isEmpty) {
|
||||||
dropdownFuncDeptItems.add(
|
dropdownFuncDeptItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
// value: null,
|
// value: null,
|
||||||
value: "1",
|
value: "1",
|
||||||
child: Text("No options available", style: TextStyle(color: Colors.grey)),
|
child: Text("No options available",
|
||||||
|
style: TextStyle(color: Colors.grey)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// selectedFuncDept ??= dropdownFuncDeptItems.isNotEmpty ? dropdownFuncDeptItems.first.value.toString() : null;
|
// selectedFuncDept ??= dropdownFuncDeptItems.isNotEmpty ? dropdownFuncDeptItems.first.value.toString() : null;
|
||||||
selectedFuncDept ??= dropdownFuncDeptItems.isNotEmpty ? dropdownFuncDeptItems.first.value.toString() : "No options";
|
selectedFuncDept ??= dropdownFuncDeptItems.isNotEmpty
|
||||||
|
? dropdownFuncDeptItems.first.value.toString()
|
||||||
|
: "No options";
|
||||||
|
|
||||||
print("Dropdown Functional Department List: ${dropdownFuncDeptItems.map((e) => e.value).toList()}");
|
print(
|
||||||
|
"Dropdown Functional Department List: ${dropdownFuncDeptItems.map((e) => e.value).toList()}");
|
||||||
print("Selected Functional Department: $selectedFuncDept");
|
print("Selected Functional Department: $selectedFuncDept");
|
||||||
|
|
||||||
|
return Column(children: [
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Column(
|
||||||
@ -1156,9 +1177,10 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 45, // Set appropriate height
|
height: 45, // Set appropriate height
|
||||||
child: apiData == null
|
child: apiData == null
|
||||||
? Center(child: CircularProgressIndicator()) // Show loading inside dropdown
|
? Center(
|
||||||
:
|
child:
|
||||||
DropdownButtonFormField<String>(
|
CircularProgressIndicator()) // Show loading inside dropdown
|
||||||
|
: DropdownButtonFormField<String>(
|
||||||
value: selectedPurpose,
|
value: selectedPurpose,
|
||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@ -1166,12 +1188,15 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
contentPadding: EdgeInsets.symmetric(
|
contentPadding: EdgeInsets.symmetric(
|
||||||
horizontal: 10), // Proper padding
|
horizontal: 10), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: widget.isViewMode ? null : purposeList.isNotEmpty
|
onChanged: widget.isViewMode
|
||||||
|
? null
|
||||||
|
: purposeList.isNotEmpty
|
||||||
? (newValue) {
|
? (newValue) {
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedPurpose = newValue;
|
selectedPurpose = newValue;
|
||||||
});
|
});
|
||||||
print("selectedPurpose - $selectedPurpose");
|
print(
|
||||||
|
"selectedPurpose - $selectedPurpose");
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
items: dropdownItems,
|
items: dropdownItems,
|
||||||
@ -1203,9 +1228,10 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
isDesktop: widget.isDesktop,
|
isDesktop: widget.isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 45, // Set appropriate height
|
height: 45, // Set appropriate height
|
||||||
|
child: apiData == null
|
||||||
|
? Center(
|
||||||
child:
|
child:
|
||||||
apiData == null
|
CircularProgressIndicator()) // Show loading inside dropdown
|
||||||
? Center(child: CircularProgressIndicator()) // Show loading inside dropdown
|
|
||||||
: DropdownButtonFormField<String>(
|
: DropdownButtonFormField<String>(
|
||||||
value: selectedFuncDept,
|
value: selectedFuncDept,
|
||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
@ -1214,7 +1240,9 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
contentPadding: EdgeInsets.symmetric(
|
contentPadding: EdgeInsets.symmetric(
|
||||||
horizontal: 10), // Proper padding
|
horizontal: 10), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: widget.isViewMode ? null : funcDeptList.isNotEmpty
|
onChanged: widget.isViewMode
|
||||||
|
? null
|
||||||
|
: funcDeptList.isNotEmpty
|
||||||
? (newValue) {
|
? (newValue) {
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedFuncDept = newValue;
|
selectedFuncDept = newValue;
|
||||||
@ -1232,11 +1260,9 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 15,
|
height: 15,
|
||||||
),
|
),
|
||||||
]
|
]);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Widget _buildDescriptionColumn(isDesktop) {
|
Widget _buildDescriptionColumn(isDesktop) {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
@ -1255,8 +1281,9 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: _isdescriptionFocused,
|
isFocused: _isdescriptionFocused,
|
||||||
width: isDesktop? MediaQuery.of(context).size.width * 0.5 :
|
width: isDesktop
|
||||||
MediaQuery.of(context).size.width * 0.85 ,
|
? MediaQuery.of(context).size.width * 0.4
|
||||||
|
: MediaQuery.of(context).size.width * 0.85,
|
||||||
isDesktop: widget.isDesktop,
|
isDesktop: widget.isDesktop,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: _descriptionFocusNode,
|
focusNode: _descriptionFocusNode,
|
||||||
@ -1297,17 +1324,24 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.go('/listPlan');
|
context.go('/listPlan');
|
||||||
},
|
},
|
||||||
child: Text("Cancel")
|
child: Text("Cancel")),
|
||||||
|
SizedBox(
|
||||||
|
width: 20,
|
||||||
),
|
),
|
||||||
SizedBox(width: 20,),
|
|
||||||
MouseRegion(
|
MouseRegion(
|
||||||
cursor: widget.isViewMode ? SystemMouseCursors.forbidden : SystemMouseCursors.click,
|
cursor: widget.isViewMode
|
||||||
|
? SystemMouseCursors.forbidden
|
||||||
|
: SystemMouseCursors.click,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: widget.isViewMode ? Colors.blueAccent : Colors.blueAccent, // Keep original color
|
backgroundColor: widget.isViewMode
|
||||||
foregroundColor: widget.isViewMode ? Colors.white : Colors.white, // Keep original color
|
? Colors.blueAccent
|
||||||
disabledBackgroundColor: Colors.blueAccent, // Ensure color remains when disabled
|
: Colors.blueAccent, // Keep original color
|
||||||
|
foregroundColor: widget.isViewMode
|
||||||
|
? Colors.white
|
||||||
|
: Colors.white, // Keep original color
|
||||||
|
disabledBackgroundColor:
|
||||||
|
Colors.blueAccent, // Ensure color remains when disabled
|
||||||
disabledForegroundColor: Colors.white,
|
disabledForegroundColor: Colors.white,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
@ -1315,12 +1349,12 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
),
|
),
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
),
|
),
|
||||||
onPressed: widget.isViewMode ? null : handleSubmit, // Disable when in view mode
|
onPressed: widget.isViewMode
|
||||||
|
? null
|
||||||
|
: handleSubmit, // Disable when in view mode
|
||||||
child: Text("Submit"),
|
child: Text("Submit"),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1338,9 +1372,7 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
});
|
});
|
||||||
print("USer entered : $otherUserName $userId $isTraveller");
|
print("USer entered : $otherUserName $userId $isTraveller");
|
||||||
getSelectedPlanFor();
|
getSelectedPlanFor();
|
||||||
}
|
});
|
||||||
);
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import 'package:shared_preferences/shared_preferences.dart';
|
|||||||
import '../../routes/custom_appBar.dart';
|
import '../../routes/custom_appBar.dart';
|
||||||
import '../../routes/custom_drawer.dart';
|
import '../../routes/custom_drawer.dart';
|
||||||
|
|
||||||
|
|
||||||
class ListPlans extends StatefulWidget {
|
class ListPlans extends StatefulWidget {
|
||||||
const ListPlans({super.key});
|
const ListPlans({super.key});
|
||||||
|
|
||||||
@ -19,11 +18,10 @@ class ListPlans extends StatefulWidget{
|
|||||||
_ListPlansState createState() => _ListPlansState();
|
_ListPlansState createState() => _ListPlansState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class _ListPlansState extends State<ListPlans> {
|
class _ListPlansState extends State<ListPlans> {
|
||||||
|
|
||||||
late Future<List<Plan>> futurePlans;
|
late Future<List<Plan>> futurePlans;
|
||||||
String? userId;
|
String? userId;
|
||||||
|
String? orgId;
|
||||||
String? token;
|
String? token;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -32,28 +30,24 @@ class _ListPlansState extends State<ListPlans>{
|
|||||||
getToken();
|
getToken();
|
||||||
initializeData();
|
initializeData();
|
||||||
|
|
||||||
|
|
||||||
// futurePlans = fetchPlans();
|
// futurePlans = fetchPlans();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> initializeData() async {
|
Future<void> initializeData() async {
|
||||||
token = await getToken();
|
token = await getToken();
|
||||||
userId = await getUserId();
|
userId = await getUserId();
|
||||||
|
orgId = await getOrgId();
|
||||||
|
|
||||||
if (token == null || userId == null) {
|
if (token == null || userId == null) {
|
||||||
print("Token or USerId missing");
|
print("Token or USerId missing");
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
setState(() {
|
setState(() {
|
||||||
futurePlans = fetchPlans();
|
futurePlans = fetchPlans();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Future<String?> getUserId() async {
|
Future<String?> getUserId() async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
final String? userDataString = prefs.getString('user_data');
|
final String? userDataString = prefs.getString('user_data');
|
||||||
@ -69,22 +63,35 @@ class _ListPlansState extends State<ListPlans>{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<String?> getOrgId() async {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
final String? userDataString = prefs.getString('user_data');
|
||||||
|
|
||||||
|
if (userDataString != null) {
|
||||||
|
try {
|
||||||
|
final Map<String, dynamic> userData = jsonDecode(userDataString);
|
||||||
|
return userData["org_id"]?.toString();
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Future<String?> getToken() async {
|
Future<String?> getToken() async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
return prefs.getString('auth_token');
|
return prefs.getString('auth_token');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Fetch API Data
|
// Fetch API Data
|
||||||
Future<List<Plan>> fetchPlans() async {
|
Future<List<Plan>> fetchPlans() async {
|
||||||
// final String apiUrldata = '$apiUrl/api/plans';
|
// final String apiUrldata = '$apiUrl/api/plans';
|
||||||
final String apiUrldata = '$apiUrl/api/plans?user_id=$userId';
|
// final String apiUrldata = '$apiUrl/api/plans?user_id=$userId';
|
||||||
|
// final String apiUrldata = '$apiUrl/api/plans?user_id=$userId';
|
||||||
|
final String apiUrldata = '$apiUrl/api/plans?org_id=$orgId&user_id=$userId';
|
||||||
|
// api/plans?org_id=1&user_id=1
|
||||||
// final token = await getToken();
|
// final token = await getToken();
|
||||||
|
|
||||||
|
|
||||||
if (token == null) {
|
if (token == null) {
|
||||||
throw Exception('Token not found. Please log in.');
|
throw Exception('Token not found. Please log in.');
|
||||||
}
|
}
|
||||||
@ -106,7 +113,6 @@ class _ListPlansState extends State<ListPlans>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<Map<String, dynamic>> getViewPlan(String planId) async {
|
Future<Map<String, dynamic>> getViewPlan(String planId) async {
|
||||||
final String apiUrldata = '$apiUrl/api/plans/find/$planId';
|
final String apiUrldata = '$apiUrl/api/plans/find/$planId';
|
||||||
print("API URL: $apiUrldata");
|
print("API URL: $apiUrldata");
|
||||||
@ -128,27 +134,23 @@ class _ListPlansState extends State<ListPlans>{
|
|||||||
final Map<String, dynamic>? resData = json.decode(response.body);
|
final Map<String, dynamic>? resData = json.decode(response.body);
|
||||||
|
|
||||||
return resData?["data"];
|
return resData?["data"];
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw Exception('Failed to load plans');
|
throw Exception('Failed to load plans');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void viewPlan(String planId, {bool isViewMode = false}) async {
|
void viewPlan(String planId, {bool isViewMode = false}) async {
|
||||||
try {
|
try {
|
||||||
Map<String, dynamic> planData = await getViewPlan(planId);
|
Map<String, dynamic> planData = await getViewPlan(planId);
|
||||||
print("ViewAAA - $planData");
|
print("ViewAAA - $planData");
|
||||||
|
|
||||||
context.go('/createPlan',extra: {'planData': planData, 'isViewMode': isViewMode} );
|
context.go('/createPlan',
|
||||||
|
extra: {'planData': planData, 'isViewMode': isViewMode});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Error fetching plan: $e");
|
print("Error fetching plan: $e");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||||
@ -192,13 +194,22 @@ class _ListPlansState extends State<ListPlans>{
|
|||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
backgroundColor: Colors.blueAccent),
|
backgroundColor: Colors.blueAccent),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.go('/createPlan');
|
context.go('/createPlan', extra: {
|
||||||
|
// 'apiCountryData': apiCountryData,
|
||||||
|
'orgId': orgId,
|
||||||
|
});
|
||||||
|
|
||||||
if (!isDesktop) Navigator.pop(context);
|
if (!isDesktop) Navigator.pop(context);
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.add_circle,color: Colors.white,),
|
Icon(
|
||||||
SizedBox(width: 5,),
|
Icons.add_circle,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 5,
|
||||||
|
),
|
||||||
Text('NewPlan'),
|
Text('NewPlan'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -212,18 +223,69 @@ class _ListPlansState extends State<ListPlans>{
|
|||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
} else if (snapshot.hasError) {
|
} else if (snapshot.hasError) {
|
||||||
return Center(child: Text("Error: ${snapshot.error}"));
|
return Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.error_outline,
|
||||||
|
color: Colors.redAccent,
|
||||||
|
size: 60,
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
"Oops!",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.redAccent,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
"No Plans Available For This User",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
Text(
|
||||||
|
" Please Create Plan",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Colors.grey[700],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
// ElevatedButton.icon(
|
||||||
|
// onPressed: () {
|
||||||
|
// // Optional: retry logic or navigation
|
||||||
|
// },
|
||||||
|
// icon: Icon(Icons.refresh),
|
||||||
|
// label: Text("Try Again"),
|
||||||
|
// style: ElevatedButton.styleFrom(
|
||||||
|
// backgroundColor: Colors.blueAccent,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
||||||
return const Center(child: Text("No plans available"));
|
return const Center(child: Text("No plans available"));
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Plan> plans = snapshot.data!; // Extract the list of plans
|
List<Plan> plans = snapshot.data!; // Extract the list of plans
|
||||||
|
|
||||||
|
|
||||||
// Ensure planId is sorted in descending order
|
// Ensure planId is sorted in descending order
|
||||||
plans.sort((a, b) => int.parse(b.planId.toString()).compareTo(int.parse(a.planId.toString())));
|
plans.sort((a, b) => int.parse(b.planId.toString())
|
||||||
|
.compareTo(int.parse(a.planId.toString())));
|
||||||
|
|
||||||
|
|
||||||
// return ResponsiveBuilder(
|
// return ResponsiveBuilder(
|
||||||
// builder: (context, sizingInfo) {
|
// builder: (context, sizingInfo) {
|
||||||
@ -322,8 +384,8 @@ class _ListPlansState extends State<ListPlans>{
|
|||||||
|
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
// scrollDirection: Axis.vertical, // Inner wrapper for vertical scrolling
|
// scrollDirection: Axis.vertical, // Inner wrapper for vertical scrolling
|
||||||
scrollDirection: Axis.horizontal, // Inner wrapper for vertical scrolling
|
scrollDirection: Axis
|
||||||
|
.horizontal, // Inner wrapper for vertical scrolling
|
||||||
|
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: BoxConstraints(minWidth: 1300),
|
constraints: BoxConstraints(minWidth: 1300),
|
||||||
@ -332,55 +394,85 @@ class _ListPlansState extends State<ListPlans>{
|
|||||||
child: Container(
|
child: Container(
|
||||||
// color: Colors.amber,
|
// color: Colors.amber,
|
||||||
child: DataTable(
|
child: DataTable(
|
||||||
columnSpacing: 50.0, // Adjust spacing between columns
|
columnSpacing:
|
||||||
|
50.0, // Adjust spacing between columns
|
||||||
dividerThickness: 0.5,
|
dividerThickness: 0.5,
|
||||||
border: TableBorder(
|
border: TableBorder(
|
||||||
horizontalInside: BorderSide(width: 0.5, color: Colors.grey.shade200),
|
horizontalInside: BorderSide(
|
||||||
|
width: 0.5, color: Colors.grey.shade200),
|
||||||
),
|
),
|
||||||
columns: const [
|
columns: const [
|
||||||
DataColumn(label: Text('Plan ID', style: TextStyle(fontWeight: FontWeight.bold))),
|
DataColumn(
|
||||||
DataColumn(label: Text('Trip Title', style: TextStyle(fontWeight: FontWeight.bold))),
|
label: Text('Plan ID',
|
||||||
DataColumn(label: Text('Trip Type', style: TextStyle(fontWeight: FontWeight.bold))),
|
style: TextStyle(
|
||||||
DataColumn(label: Text('Cost Center', style: TextStyle(fontWeight: FontWeight.bold))),
|
fontWeight: FontWeight.bold))),
|
||||||
DataColumn(label: Text('Is Billable', style: TextStyle(fontWeight: FontWeight.bold))),
|
DataColumn(
|
||||||
DataColumn(label: Text('Status', style: TextStyle(fontWeight: FontWeight.bold))),
|
label: Text('Trip Title',
|
||||||
DataColumn(label: Text('Actions', style: TextStyle(fontWeight: FontWeight.bold))),
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold))),
|
||||||
|
DataColumn(
|
||||||
|
label: Text('Trip Type',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold))),
|
||||||
|
DataColumn(
|
||||||
|
label: Text('Cost Center',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold))),
|
||||||
|
DataColumn(
|
||||||
|
label: Text('Is Billable',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold))),
|
||||||
|
DataColumn(
|
||||||
|
label: Text('Status',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold))),
|
||||||
|
DataColumn(
|
||||||
|
label: Text('Actions',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold))),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
rows: plans.map((plan) {
|
rows: plans.map((plan) {
|
||||||
return DataRow(cells: [
|
return DataRow(cells: [
|
||||||
DataCell(Text(plan.planId)),
|
DataCell(Text(plan.planId)),
|
||||||
DataCell(Text(plan.tripTitle, softWrap: true, overflow: TextOverflow.ellipsis)),
|
DataCell(Text(plan.tripTitle,
|
||||||
|
softWrap: true,
|
||||||
|
overflow: TextOverflow.ellipsis)),
|
||||||
DataCell(Text(plan.tripType)),
|
DataCell(Text(plan.tripType)),
|
||||||
DataCell(Text(plan.costCenter)),
|
DataCell(Text(plan.costCenter)),
|
||||||
DataCell(Text(plan.isBillable)),
|
DataCell(Text(plan.isBillable)),
|
||||||
DataCell(
|
DataCell(
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), // Padding for better look
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 5,
|
||||||
|
horizontal:
|
||||||
|
10), // Padding for better look
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: plan.status == "Active" ? Colors.green.shade50 : Colors.grey.shade50, // Background color
|
color: plan.status == "Active"
|
||||||
borderRadius: BorderRadius.circular(10), // Rounded corners
|
? Colors.green.shade50
|
||||||
|
: Colors
|
||||||
|
.grey.shade50, // Background color
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
10), // Rounded corners
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
plan.status,
|
plan.status,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: plan.status == "Active" ? Colors.green : Colors.grey, // Text color
|
color: plan.status == "Active"
|
||||||
fontWeight: FontWeight.bold, // Optional: Make text bold
|
? Colors.green
|
||||||
|
: Colors.grey, // Text color
|
||||||
|
fontWeight: FontWeight
|
||||||
|
.bold, // Optional: Make text bold
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
DataCell(
|
DataCell(Row(children: [
|
||||||
Row(
|
|
||||||
children:[
|
|
||||||
|
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.remove_red_eye, color: Colors.blue),
|
icon: Icon(Icons.remove_red_eye,
|
||||||
|
color: Colors.blue),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
viewPlan(plan.planId, isViewMode: true);
|
viewPlan(plan.planId, isViewMode: true);
|
||||||
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
@ -395,12 +487,7 @@ class _ListPlansState extends State<ListPlans>{
|
|||||||
// deletePlan(plan.planId);
|
// deletePlan(plan.planId);
|
||||||
// },
|
// },
|
||||||
// ),
|
// ),
|
||||||
|
])),
|
||||||
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
),
|
|
||||||
]);
|
]);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
@ -410,16 +497,10 @@ class _ListPlansState extends State<ListPlans>{
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,8 @@ import 'package:responsive_builder/responsive_builder.dart';
|
|||||||
|
|
||||||
import '../../routes/custom_appBar.dart';
|
import '../../routes/custom_appBar.dart';
|
||||||
import '../../routes/custom_drawer.dart';
|
import '../../routes/custom_drawer.dart';
|
||||||
|
import '../../widgets/custom_text_field.dart';
|
||||||
|
import '../../widgets/custom_user_form.dart';
|
||||||
|
|
||||||
class Policy extends StatefulWidget {
|
class Policy extends StatefulWidget {
|
||||||
const Policy({super.key});
|
const Policy({super.key});
|
||||||
@ -18,6 +20,7 @@ class _PolicyState extends State<Policy> {
|
|||||||
late String policyType = "domestic";
|
late String policyType = "domestic";
|
||||||
int? selectedServiceIndex = 1;
|
int? selectedServiceIndex = 1;
|
||||||
late String selectedService = "Train";
|
late String selectedService = "Train";
|
||||||
|
String? _selectedTripType;
|
||||||
|
|
||||||
bool showClass = true;
|
bool showClass = true;
|
||||||
bool showCost = true;
|
bool showCost = true;
|
||||||
@ -42,7 +45,9 @@ class _PolicyState extends State<Policy> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget buildPolicyLayout(bool isDesktop) {
|
Widget buildPolicyLayout(bool isDesktop) {
|
||||||
return Container(
|
return SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.vertical,
|
||||||
|
child: Container(
|
||||||
margin: isDesktop
|
margin: isDesktop
|
||||||
? EdgeInsets.all(20.0)
|
? EdgeInsets.all(20.0)
|
||||||
: 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),
|
||||||
@ -50,16 +55,17 @@ class _PolicyState extends State<Policy> {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: isDesktop
|
border: isDesktop
|
||||||
? Border.all(
|
? Border.all(
|
||||||
width: 3,
|
width: 2,
|
||||||
color: Color(0xFFF7F7FB),
|
color: Color(0xFFF7F7FB),
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
|
color: Color(0xFFF7F7FB),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
color: Color(0xFFF7F7FB),
|
// color: Color(0xFFF7F7FB),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -151,6 +157,72 @@ class _PolicyState extends State<Policy> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
isDesktop ? SizedBox(height: 0) : SizedBox(height: 5),
|
||||||
|
Container(
|
||||||
|
// color: Colors.amber,
|
||||||
|
// color: isDesktop ? Color(0xFFF7F7FB) : Colors.white,
|
||||||
|
padding: isDesktop ? const EdgeInsets.only(left: 35) : null,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text("Policy Name",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w200,
|
||||||
|
color: Colors.black)),
|
||||||
|
SizedBox(height: 5),
|
||||||
|
CustomTextFieldUserWrapper(
|
||||||
|
isFocused: false,
|
||||||
|
isDesktop: isDesktop,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 40,
|
||||||
|
child: TextField(
|
||||||
|
style: TextStyle(fontSize: 12),
|
||||||
|
// controller: controllers["Fname"],
|
||||||
|
// enabled: !isViewMode,
|
||||||
|
onChanged: (value) {},
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: "Policy Name",
|
||||||
|
labelStyle: TextStyle(
|
||||||
|
fontSize: 12, color: Colors.grey),
|
||||||
|
floatingLabelBehavior:
|
||||||
|
FloatingLabelBehavior.never,
|
||||||
|
border: InputBorder.none,
|
||||||
|
contentPadding:
|
||||||
|
EdgeInsets.symmetric(vertical: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text("Policy Type",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w200,
|
||||||
|
color: Colors.black)),
|
||||||
|
SizedBox(height: 5),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: _buildTripType(isDesktop),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
),
|
),
|
||||||
@ -173,6 +245,7 @@ class _PolicyState extends State<Policy> {
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,8 +297,10 @@ class _PolicyState extends State<Policy> {
|
|||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: isDesktop ? 180 : null,
|
width: isDesktop ? 180 : null,
|
||||||
height: isDesktop
|
height: isDesktop
|
||||||
? max((MediaQuery.of(context).size.height * 0.09), 10)
|
? max((MediaQuery.of(context).size.height * 0.075), 10)
|
||||||
: 45,
|
: 45,
|
||||||
|
|
||||||
|
// max((MediaQuery.of(context).size.height * 0.09), 10)
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
print("Selected Services - $service - $index");
|
print("Selected Services - $service - $index");
|
||||||
@ -288,4 +363,64 @@ class _PolicyState extends State<Policy> {
|
|||||||
selectedTab: selectedService)),
|
selectedTab: selectedService)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Widget> _buildTripType(bool isDesktop) {
|
||||||
|
return [
|
||||||
|
CustomTextFieldWrapper(
|
||||||
|
color: Color(0xFFF4F4FB),
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||||
|
width: isDesktop ? 170 : 140,
|
||||||
|
isFocused: _selectedTripType == "1",
|
||||||
|
isDesktop: isDesktop,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 35,
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: RadioListTile<String>(
|
||||||
|
activeColor: Colors.blueAccent,
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
dense: true,
|
||||||
|
title: Text("Domestic"),
|
||||||
|
value: "1",
|
||||||
|
groupValue: _selectedTripType,
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_selectedTripType = value!;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
isDesktop ? SizedBox(width: 28) : SizedBox(width: 15),
|
||||||
|
CustomTextFieldWrapper(
|
||||||
|
color: Color(0xFFF4F4FB),
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||||
|
width: isDesktop ? 180 : 180,
|
||||||
|
isFocused: _selectedTripType == "2",
|
||||||
|
isDesktop: isDesktop,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 35,
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: RadioListTile<String>(
|
||||||
|
activeColor: Colors.blueAccent,
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
dense: true,
|
||||||
|
title: Text("International"),
|
||||||
|
value: "2",
|
||||||
|
groupValue: _selectedTripType,
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_selectedTripType = value!;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,6 +42,7 @@ class _PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
widget.isDesktop ? SizedBox(height: 10) : SizedBox(height: 5),
|
widget.isDesktop ? SizedBox(height: 10) : SizedBox(height: 5),
|
||||||
Row(
|
Row(
|
||||||
@ -56,15 +57,6 @@ class _PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
widget.isDesktop ? SizedBox(height: 15) : SizedBox(height: 5),
|
|
||||||
Padding(
|
|
||||||
padding: widget.isDesktop
|
|
||||||
? const EdgeInsets.all(8.0)
|
|
||||||
: const EdgeInsets.all(1.0),
|
|
||||||
child: Row(
|
|
||||||
children: _buildTripType(widget.isDesktop),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (widget.isClass!)
|
if (widget.isClass!)
|
||||||
widget.isDesktop ? SizedBox(height: 15) : SizedBox(height: 5),
|
widget.isDesktop ? SizedBox(height: 15) : SizedBox(height: 5),
|
||||||
Row(
|
Row(
|
||||||
@ -181,19 +173,20 @@ class _PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
|
color: Colors.grey.shade100,
|
||||||
width: widget.isDesktop
|
width: widget.isDesktop
|
||||||
? MediaQuery.of(context).size.width * 0.63
|
? MediaQuery.of(context).size.width * 0.63
|
||||||
: 600,
|
: 600,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.only(right: 20),
|
margin: const EdgeInsets.only(right: 0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.grey.shade50,
|
color: Colors.grey.shade100,
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Colors.grey.shade50,
|
color: Colors.grey.shade100,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(8)),
|
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
top: 10, bottom: 10, left: 35, right: 35),
|
top: 10, bottom: 10, left: 35, right: 35),
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -232,7 +225,7 @@ class _PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
child: Container(
|
child: Container(
|
||||||
// color: Colors.grey,
|
// color: Colors.grey,
|
||||||
margin: const EdgeInsets.only(right: 20),
|
margin: const EdgeInsets.only(right: 20),
|
||||||
color: Colors.grey.shade50,
|
color: Colors.grey.shade100,
|
||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
@ -511,57 +504,4 @@ class _PolicyCriteriaState extends State<PolicyCriteria> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _buildTripType(bool isMobile) {
|
|
||||||
return [
|
|
||||||
CustomTextFieldWrapper(
|
|
||||||
color: Color(0xFFF4F4FB),
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
|
||||||
width: 120,
|
|
||||||
isFocused: _selectedTripType == "1",
|
|
||||||
isDesktop: widget.isDesktop,
|
|
||||||
child: SizedBox(
|
|
||||||
height: 35,
|
|
||||||
child: Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: RadioListTile<String>(
|
|
||||||
activeColor: Colors.blueAccent,
|
|
||||||
contentPadding: EdgeInsets.zero,
|
|
||||||
visualDensity: VisualDensity.compact,
|
|
||||||
dense: true,
|
|
||||||
title: Text("Domestic"),
|
|
||||||
value: "1",
|
|
||||||
groupValue: _selectedTripType,
|
|
||||||
onChanged: (value) {
|
|
||||||
setState(() {
|
|
||||||
_selectedTripType = value!;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 20),
|
|
||||||
CustomTextFieldWrapper(
|
|
||||||
color: Color(0xFFF4F4FB),
|
|
||||||
width: 150,
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 5, vertical: 2),
|
|
||||||
isFocused: _selectedTripType == "2",
|
|
||||||
isDesktop: widget.isDesktop,
|
|
||||||
child: RadioListTile<String>(
|
|
||||||
activeColor: Colors.blueAccent,
|
|
||||||
contentPadding: EdgeInsets.zero,
|
|
||||||
dense: true,
|
|
||||||
title: Text("International"),
|
|
||||||
value: "2",
|
|
||||||
groupValue: _selectedTripType,
|
|
||||||
onChanged: (value) {
|
|
||||||
setState(() {
|
|
||||||
_selectedTripType = value!;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:html' as html;
|
import 'dart:html' as html;
|
||||||
import 'dart:typed_data'; // Import for Uint8List
|
import 'dart:typed_data'; // Import for Uint8List
|
||||||
@ -8,11 +9,14 @@ import 'package:file_picker/file_picker.dart';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:frontend/utils/auth_utils.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:http_parser/http_parser.dart' as http_parser;
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:responsive_builder/responsive_builder.dart';
|
import 'package:responsive_builder/responsive_builder.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:http_parser/http_parser.dart';
|
||||||
|
|
||||||
import '../../../config/apiUrl.dart';
|
import '../../../config/apiUrl.dart';
|
||||||
import '../../../routes/custom_appBar.dart';
|
import '../../../routes/custom_appBar.dart';
|
||||||
@ -31,6 +35,7 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
final ApiService apiService = ApiService();
|
final ApiService apiService = ApiService();
|
||||||
|
|
||||||
String? userId;
|
String? userId;
|
||||||
|
String? orgId;
|
||||||
|
|
||||||
String? token;
|
String? token;
|
||||||
|
|
||||||
@ -67,8 +72,11 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
|
|
||||||
String? selectedFileNames;
|
String? selectedFileNames;
|
||||||
Uint8List? passportDocumentBytes;
|
Uint8List? passportDocumentBytes;
|
||||||
|
String? passportFileUrlFromApi;
|
||||||
String? base64PDF;
|
String? base64PDF;
|
||||||
|
|
||||||
|
html.File? passportFile;
|
||||||
|
|
||||||
List<String> dataHeader = [
|
List<String> dataHeader = [
|
||||||
"Fname",
|
"Fname",
|
||||||
"Lname",
|
"Lname",
|
||||||
@ -109,12 +117,13 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
"address": controllers["address"]?.text,
|
"address": controllers["address"]?.text,
|
||||||
"gender": selectedGender,
|
"gender": selectedGender,
|
||||||
"postal_code": controllers["postalCode"]?.text,
|
"postal_code": controllers["postalCode"]?.text,
|
||||||
"country": selectedCountry,
|
"country_code": selectedCountry,
|
||||||
"employee_code": controllers["employeeCode"]?.text,
|
"employee_code": controllers["employeeCode"]?.text,
|
||||||
|
|
||||||
"user_type": selectedUserType,
|
"user_type": selectedUserType,
|
||||||
"role_id": selectedRole,
|
"role_id": selectedRole,
|
||||||
"department_id": selectedDepartment,
|
"department_id": selectedDepartment,
|
||||||
|
|
||||||
"group_id": selectedLevel,
|
"group_id": selectedLevel,
|
||||||
|
|
||||||
"first_approver": selectedFirstApprover,
|
"first_approver": selectedFirstApprover,
|
||||||
@ -122,21 +131,22 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
"third_approver": selectedThirdApprover,
|
"third_approver": selectedThirdApprover,
|
||||||
"passport_number": controllers["passportNumber"]?.text,
|
"passport_number": controllers["passportNumber"]?.text,
|
||||||
"place_of_issue": controllers["placeOfIssue"]?.text,
|
"place_of_issue": controllers["placeOfIssue"]?.text,
|
||||||
"passport_document": base64PDF,
|
"passport_document": passportFile,
|
||||||
|
|
||||||
"date_of_issue": controllers["dateOfIssue"]?.text,
|
"date_of_issue": controllers["dateOfIssue"]?.text,
|
||||||
"date_of_expiry": controllers["dateOfExpiry"]?.text,
|
"date_of_expiry": controllers["dateOfExpiry"]?.text,
|
||||||
"created_by": userId,
|
"created_by": userId,
|
||||||
"is_active": "1",
|
"is_active": "1",
|
||||||
// "passport_fileData": base64PDF,
|
"org_id": orgId,
|
||||||
|
// "passport_fileData": passportFile,
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateData() {
|
Future<void> updateData() async {
|
||||||
// Ensure apiselectedUser is not null before printing
|
// Ensure apiselectedUser is not null before printing
|
||||||
if (apiselectedUser != null) {
|
if (apiselectedUser != null) {
|
||||||
print("API Selected User Has Data - $apiselectedUser");
|
print("API Selected User Has Data - $widget.apiselectedUser");
|
||||||
setState(() {
|
setState(() {
|
||||||
// ✅ Wrap in setState to update the UI
|
// ✅ Wrap in setState to update the UI
|
||||||
|
|
||||||
@ -165,15 +175,22 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
apiselectedUser?["date_of_expiry"] ?? "";
|
apiselectedUser?["date_of_expiry"] ?? "";
|
||||||
|
|
||||||
selectedCountry = apiselectedUser?["country_code"]?.toString() ?? "";
|
selectedCountry = apiselectedUser?["country_code"]?.toString() ?? "";
|
||||||
|
|
||||||
selectedGender = apiselectedUser?["gender"]?.toString().trim() ?? "";
|
selectedGender = apiselectedUser?["gender"]?.toString().trim() ?? "";
|
||||||
|
|
||||||
base64PDF =
|
selectedUserType = selectedUserType =
|
||||||
apiselectedUser?["passport_document"]?.toString().trim() ?? "";
|
|
||||||
selectedUserType =
|
|
||||||
apiselectedUser?["user_type"]?.toString().trim() ?? "";
|
apiselectedUser?["user_type"]?.toString().trim() ?? "";
|
||||||
|
|
||||||
selectedRole = apiselectedUser?["role_id"]?.toString().trim() ?? "";
|
selectedRole = apiselectedUser?["role_id"]?.toString().trim() ?? "";
|
||||||
selectedDepartment =
|
// selectedDepartment =
|
||||||
apiselectedUser?["department_id"]?.toString().trim() ?? "";
|
// apiselectedUser?["department_id"]?.toString().trim() ?? "";
|
||||||
|
|
||||||
|
if (apiselectedUser?["department_id"] != null) {
|
||||||
|
selectedDepartment = apiselectedUser!["department_id"].toString();
|
||||||
|
}
|
||||||
|
// print(
|
||||||
|
// "selectedDepartment - $selectedDepartment - ${apiselectedUser?["department_id"]} ");
|
||||||
|
|
||||||
selectedLevel = apiselectedUser?["level_id"]?.toString().trim() ?? "";
|
selectedLevel = apiselectedUser?["level_id"]?.toString().trim() ?? "";
|
||||||
|
|
||||||
selectedFirstApprover =
|
selectedFirstApprover =
|
||||||
@ -184,6 +201,19 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
apiselectedUser?["third_approver"]?.toString() ?? "";
|
apiselectedUser?["third_approver"]?.toString() ?? "";
|
||||||
|
|
||||||
print("Updated selectedGender: $selectedGender"); // Debugging
|
print("Updated selectedGender: $selectedGender"); // Debugging
|
||||||
|
|
||||||
|
// ✅ Load passport document from API
|
||||||
|
String? apiDocPath = apiselectedUser?["passport_document"];
|
||||||
|
if (apiDocPath != null && apiDocPath.isNotEmpty) {
|
||||||
|
passportFileUrlFromApi = apiDocPath;
|
||||||
|
selectedFileNames =
|
||||||
|
apiDocPath.split('/').last; // Extract filename from path
|
||||||
|
passportFile = null; // No local file selected yet
|
||||||
|
} else {
|
||||||
|
passportFileUrlFromApi = null;
|
||||||
|
selectedFileNames = null;
|
||||||
|
passportFile = null;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
print("API Selected User Has Data - No data available yet");
|
print("API Selected User Has Data - No data available yet");
|
||||||
@ -195,37 +225,29 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
// Step 1: Set 'reloaded' flag before page unload
|
||||||
|
html.window.onBeforeUnload.listen((event) {
|
||||||
|
html.window.localStorage['reloaded'] = 'true';
|
||||||
|
});
|
||||||
|
|
||||||
// apiCountryData = extraData['apiCountryData']; // Extract apiCountryData
|
// apiCountryData = extraData['apiCountryData']; // Extract apiCountryData
|
||||||
// futureUsers = extraData['apiUserData']; // Extract futureUsers (Future<List<dynamic>>)
|
// futureUsers = extraData['apiUserData']; // Extract futureUsers (Future<List<dynamic>>)
|
||||||
apiCountryData = null;
|
apiCountryData = null;
|
||||||
apiUserData = null;
|
apiUserData = null;
|
||||||
apiselectedUser = null;
|
// apiselectedUser = null;
|
||||||
apiCostData = null;
|
apiCostData = null;
|
||||||
apiRoleData = null;
|
apiRoleData = null;
|
||||||
|
|
||||||
// Delay accessing context until the widget is fully initialized
|
|
||||||
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
// setState(() {
|
|
||||||
// apiCountryData = (GoRouterState.of(context).extra as Map<String, dynamic>)['apiCountryData'];
|
|
||||||
// apiUserData = (GoRouterState.of(context).extra as Map<String, dynamic>)['apiUserData'];
|
|
||||||
// apiselectedUser = (GoRouterState.of(context).extra as Map<String, dynamic>)['selectedUser'];
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// userList = apiUserData ?? [];
|
|
||||||
// userMap = {
|
|
||||||
// for (var user in userList)
|
|
||||||
// user['user_id'] as String: "${user['first_name']} ${user['last_name']}"
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// userIdsApi = userMap.keys.toList();
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// Initialize controllers for each field
|
// Initialize controllers for each field
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
|
// final wasReloaded = html.window.localStorage['reloaded'] == 'true';
|
||||||
|
//
|
||||||
|
// if (wasReloaded) {
|
||||||
|
// html.window.localStorage.remove('reloaded'); // Clear it
|
||||||
|
// context.go('/listUser'); // Navigate using go_router
|
||||||
|
// }
|
||||||
|
|
||||||
final extraData =
|
final extraData =
|
||||||
GoRouterState.of(context).extra as Map<String, dynamic>?;
|
GoRouterState.of(context).extra as Map<String, dynamic>?;
|
||||||
|
|
||||||
@ -250,6 +272,8 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
isEditProfile = extraData['isEditProfile'] ?? false;
|
isEditProfile = extraData['isEditProfile'] ?? false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
print("selectedUser: $apiselectedUser");
|
||||||
|
|
||||||
// Add another post-frame callback to check after setState
|
// Add another post-frame callback to check after setState
|
||||||
await Future.delayed(Duration(
|
await Future.delayed(Duration(
|
||||||
milliseconds: 100)); // Optional delay to ensure UI has updated
|
milliseconds: 100)); // Optional delay to ensure UI has updated
|
||||||
@ -296,7 +320,7 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
// apiUserData = users;
|
// apiUserData = users;
|
||||||
|
|
||||||
apiUserData = users.where((user) => user["role_id"] == "3").toList();
|
apiUserData = users.where((user) => user["role_id"] == "4").toList();
|
||||||
|
|
||||||
print("APIUSerDATa - $apiUserData");
|
print("APIUSerDATa - $apiUserData");
|
||||||
|
|
||||||
@ -383,7 +407,7 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleSubmit() {
|
void handleSubmit() async {
|
||||||
print("USR Detail Submit");
|
print("USR Detail Submit");
|
||||||
printFormData();
|
printFormData();
|
||||||
|
|
||||||
@ -396,6 +420,8 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
return; // Stop execution if validation fails
|
return; // Stop execution if validation fails
|
||||||
} else {
|
} else {
|
||||||
print("USERDETAILS : $userDetials");
|
print("USERDETAILS : $userDetials");
|
||||||
|
orgId = await getOrgId();
|
||||||
|
|
||||||
createUserData(userDetials);
|
createUserData(userDetials);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -464,12 +490,6 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
|
|
||||||
uploadInput.onChange.listen((e) {
|
uploadInput.onChange.listen((e) {
|
||||||
final file = uploadInput.files!.first;
|
final file = uploadInput.files!.first;
|
||||||
final reader = html.FileReader();
|
|
||||||
|
|
||||||
reader.readAsArrayBuffer(file);
|
|
||||||
reader.onLoadEnd.listen((event) {
|
|
||||||
print('File picked: ${file.name}');
|
|
||||||
print('File size: ${file.size} bytes');
|
|
||||||
|
|
||||||
// Ensure the file is a PDF
|
// Ensure the file is a PDF
|
||||||
if (!file.type.contains("pdf")) {
|
if (!file.type.contains("pdf")) {
|
||||||
@ -477,120 +497,95 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(() {
|
|
||||||
selectedFileNames = file.name; // Store file name
|
|
||||||
passportDocumentBytes = reader.result as Uint8List; // Store file data
|
|
||||||
|
|
||||||
// 🔹 Convert to Base64 properly
|
|
||||||
base64PDF = base64Encode(passportDocumentBytes!);
|
|
||||||
|
|
||||||
print('Base64 Length: ${base64PDF!.length}');
|
|
||||||
print('Base64 (first 50 chars): ${base64PDF!.substring(0, 50)}');
|
|
||||||
|
|
||||||
// Ensure Base64 starts with "JVBERi0x"
|
|
||||||
if (!base64PDF!.startsWith("JVBERi0x")) {
|
|
||||||
print("Error: Base64 does not start with 'JVBERi0x'");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 🔹 File size check: Ensure it does not exceed 3MB
|
// 🔹 File size check: Ensure it does not exceed 3MB
|
||||||
int maxFileSize = 3 * 1024 * 1024; // 3MB in bytes
|
int maxFileSize = 3 * 1024 * 1024; // 3MB in bytes
|
||||||
if (file.size > maxFileSize) {
|
if (file.size > maxFileSize) {
|
||||||
print('Error: File size exceeds 3MB');
|
print('Error: File size exceeds 3MB');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
selectedFileNames = file.name;
|
||||||
|
passportFile = file;
|
||||||
|
passportFileUrlFromApi = null;
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
print('PDF File selected: ${file.name}');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// void pickPDFWeb() {
|
|
||||||
// html.FileUploadInputElement uploadInput = html.FileUploadInputElement();
|
|
||||||
// uploadInput.accept = '.pdf';
|
|
||||||
// uploadInput.click();
|
|
||||||
//
|
|
||||||
// uploadInput.onChange.listen((e) {
|
|
||||||
// final file = uploadInput.files!.first;
|
|
||||||
// final reader = html.FileReader();
|
|
||||||
//
|
|
||||||
// reader.readAsArrayBuffer(file);
|
|
||||||
// reader.onLoadEnd.listen((event) {
|
|
||||||
// print('File picked: ${file.name}');
|
|
||||||
// print('File size: ${file.size} bytes');
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// // Update the state with the selected file name
|
|
||||||
// setState(() {
|
|
||||||
// selectedFileNames = file.name; // Store only one file name
|
|
||||||
// passportDocumentBytes = reader.result as Uint8List; // Store file data
|
|
||||||
//
|
|
||||||
// // 🔹 Convert file to Base64
|
|
||||||
// base64PDF = base64Encode(passportDocumentBytes! as List<int>);
|
|
||||||
// // File size check: Ensure the file size does not exceed 3MB
|
|
||||||
// int maxFileSize = 3 * 1024 * 1024; // 3MB in bytes
|
|
||||||
//
|
|
||||||
// if (file.size > maxFileSize) {
|
|
||||||
// print('Error: File size exceeds 3MB');
|
|
||||||
// // You can show an error message here if necessary
|
|
||||||
// // For example:
|
|
||||||
// // showError('File size cannot exceed 3MB');
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// print('File size: ${file.size} bytes');
|
|
||||||
// print('Base64 Data: $base64PDF'); // Debugging
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
Future<void> createUserData(Map<String, dynamic> userData) async {
|
Future<void> createUserData(Map<String, dynamic> userData) async {
|
||||||
bool isUpdating = apiselectedUser != null && apiselectedUser!.isNotEmpty;
|
final bool isUpdating =
|
||||||
final String apiUrldata = isUpdating
|
apiselectedUser != null && apiselectedUser!.isNotEmpty;
|
||||||
|
final uri = Uri.parse(
|
||||||
|
isUpdating
|
||||||
? '$apiUrl/api/users/update/${apiselectedUser?["user_id"]}'
|
? '$apiUrl/api/users/update/${apiselectedUser?["user_id"]}'
|
||||||
: '$apiUrl/api/users/create';
|
: '$apiUrl/api/users/create',
|
||||||
|
);
|
||||||
|
|
||||||
if (token == null) {
|
if (token == null) {
|
||||||
throw Exception('Token not found. Please log in.');
|
throw Exception('Token not found. Please log in.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add user_id only if updating
|
// Use MultipartRequest (POST only)
|
||||||
|
final request = http.MultipartRequest('POST', uri);
|
||||||
|
request.headers['Authorization'] = 'Bearer $token';
|
||||||
|
|
||||||
|
// If updating, spoof the method Laravel-style
|
||||||
if (isUpdating) {
|
if (isUpdating) {
|
||||||
userData['user_id'] = apiselectedUser?["user_id"];
|
request.fields['_method'] = 'PUT';
|
||||||
|
request.fields['user_id'] = apiselectedUser!["user_id"].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add all non-null and non-empty user data fields
|
||||||
|
userData.forEach((key, value) {
|
||||||
|
if (value != null && value.toString().trim().isNotEmpty) {
|
||||||
|
request.fields[key] = value.toString();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Attach file if selected
|
||||||
|
if (passportFile != null) {
|
||||||
try {
|
try {
|
||||||
final response = isUpdating
|
final reader = html.FileReader();
|
||||||
? await http.put(
|
reader.readAsArrayBuffer(passportFile!);
|
||||||
Uri.parse(apiUrldata),
|
await reader.onLoad.first;
|
||||||
headers: {
|
|
||||||
'Authorization': 'Bearer $token',
|
final data = reader.result as Uint8List;
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
final multipartFile = http.MultipartFile.fromBytes(
|
||||||
body: jsonEncode(userData),
|
'passport_document',
|
||||||
)
|
data,
|
||||||
: await http.post(
|
filename: passportFile!.name,
|
||||||
Uri.parse(apiUrldata),
|
|
||||||
headers: {
|
|
||||||
'Authorization': 'Bearer $token',
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: jsonEncode(userData),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
request.files.add(multipartFile);
|
||||||
|
print("📎 File attached: ${passportFile!.name}");
|
||||||
|
} catch (e) {
|
||||||
|
print("❌ Failed to read file: $e");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print("⚠️ No passport file selected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
print("🚀 Sending request with fields: ${request.fields}");
|
||||||
|
|
||||||
|
try {
|
||||||
|
final streamedResponse = await request.send();
|
||||||
|
final response = await http.Response.fromStream(streamedResponse);
|
||||||
|
print("Response status: ${response.statusCode}");
|
||||||
|
print("Response body: ${response.body}");
|
||||||
|
|
||||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||||
print("Plan submitted successfully!");
|
print("✅ User submitted successfully!");
|
||||||
print("Response: ${response.body}");
|
print("📨 Response: ${response.body}");
|
||||||
context.go('/listUser');
|
context.go('/listUser');
|
||||||
} else {
|
} else {
|
||||||
print("Failed to submit plan. Status: ${response.statusCode}");
|
print("❌ Submission failed. Status: ${response.statusCode}");
|
||||||
print("Error: ${response.body}");
|
print("📨 Body: ${response.body}");
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(" Error submitting plan: $e");
|
print("🔥 Error submitting user: $e");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -755,6 +750,7 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
child: isDesktop
|
child: isDesktop
|
||||||
? Row(
|
? Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// Expanded(child: _buildFirstRowLeftColumn(isDesktop)),
|
// Expanded(child: _buildFirstRowLeftColumn(isDesktop)),
|
||||||
// SizedBox(width: 20),
|
// SizedBox(width: 20),
|
||||||
@ -1136,7 +1132,7 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
_selectedDateOfBirth != null && _selectedDateOfBirth!.isAfter(today)
|
_selectedDateOfBirth != null && _selectedDateOfBirth!.isAfter(today)
|
||||||
? _selectedDateOfBirth!
|
? _selectedDateOfBirth!
|
||||||
: today,
|
: today,
|
||||||
firstDate: today,
|
firstDate: DateTime(1900),
|
||||||
lastDate: DateTime(2100),
|
lastDate: DateTime(2100),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1436,21 +1432,7 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
),
|
),
|
||||||
SizedBox(height: 3),
|
SizedBox(height: 3),
|
||||||
apiselectedUser != null
|
apiselectedUser != null
|
||||||
? Row(
|
? SizedBox()
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text("Change Password",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 15,
|
|
||||||
fontWeight: FontWeight.w200,
|
|
||||||
color: Colors.black)),
|
|
||||||
SizedBox(height: 5),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
: Row(
|
: Row(
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Column(
|
||||||
@ -1876,7 +1858,7 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
if (base64PDF != null)
|
if (passportFile != null || passportFileUrlFromApi != null)
|
||||||
|
|
||||||
// Centers the text
|
// Centers the text
|
||||||
Container(
|
Container(
|
||||||
@ -1890,57 +1872,46 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
|||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
print('DOWLOAS- $base64PDF ');
|
print('DOWNLOAD - $passportFile');
|
||||||
|
|
||||||
if (base64PDF != null && base64PDF!.isNotEmpty) {
|
if (passportFile != null) {
|
||||||
try {
|
try {
|
||||||
// ✅ Step 1: Clean the Base64 string
|
// ✅ Step 1: Create a Blob directly from the file
|
||||||
String cleanedBase64 = base64PDF!
|
final blob = html.Blob(
|
||||||
.replaceAll("\n", "") // Remove newlines
|
[passportFile!], 'application/pdf');
|
||||||
.replaceAll(
|
|
||||||
"\r", "") // Remove carriage returns
|
|
||||||
.replaceAll(" ", "") // Remove spaces
|
|
||||||
.trim(); // Trim any whitespace
|
|
||||||
|
|
||||||
// ✅ Step 2: Ensure valid Base64 length (multiple of 4)
|
// ✅ Step 2: Generate a download URL from the Blob
|
||||||
while (cleanedBase64.length % 4 != 0) {
|
|
||||||
cleanedBase64 += "_"; // Add '=' padding
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ Step 3: Decode the cleaned Base64
|
|
||||||
Uint8List bytes;
|
|
||||||
try {
|
|
||||||
bytes = base64Decode(cleanedBase64);
|
|
||||||
} catch (e) {
|
|
||||||
print("Base64 decoding failed: $e");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ Step 4: Create a Blob for download
|
|
||||||
final blob =
|
|
||||||
html.Blob([bytes], 'application/pdf');
|
|
||||||
final url =
|
final url =
|
||||||
html.Url.createObjectUrlFromBlob(blob);
|
html.Url.createObjectUrlFromBlob(blob);
|
||||||
|
|
||||||
// ✅ Step 5: Trigger the file download
|
// ✅ Step 3: Create an invisible anchor to trigger download
|
||||||
final anchor = html.AnchorElement(href: url)
|
final anchor = html.AnchorElement(href: url)
|
||||||
..setAttribute("download",
|
..setAttribute("download",
|
||||||
selectedFileNames ?? "document.pdf")
|
selectedFileNames ?? "document.pdf")
|
||||||
..style.display = "none";
|
..style.display = "none";
|
||||||
|
|
||||||
|
// ✅ Step 4: Add anchor to DOM and click it
|
||||||
html.document.body!.append(anchor);
|
html.document.body!.append(anchor);
|
||||||
anchor.click();
|
anchor.click();
|
||||||
|
|
||||||
// ✅ Step 6: Clean up
|
// ✅ Step 5: Clean up
|
||||||
anchor.remove();
|
anchor.remove();
|
||||||
html.Url.revokeObjectUrl(url);
|
html.Url.revokeObjectUrl(url);
|
||||||
|
|
||||||
print("Download successful!");
|
print("Download triggered successfully!");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Error downloading file: $e");
|
print("Error during download: $e");
|
||||||
}
|
}
|
||||||
|
} else if (passportFileUrlFromApi != null) {
|
||||||
|
// Trigger file download from the server path
|
||||||
|
final anchor = html.AnchorElement(
|
||||||
|
href: passportFileUrlFromApi!)
|
||||||
|
..target = 'blank'
|
||||||
|
..download =
|
||||||
|
selectedFileNames ?? "document.pdf"
|
||||||
|
..click();
|
||||||
} else {
|
} else {
|
||||||
print("No file to download.");
|
print("No file available to download.");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:frontend/utils/auth_utils.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:responsive_builder/responsive_builder.dart';
|
import 'package:responsive_builder/responsive_builder.dart';
|
||||||
@ -18,6 +19,7 @@ class _UserListScreenState extends State<UserListScreen> {
|
|||||||
late Future<List<dynamic>> futureUsers;
|
late Future<List<dynamic>> futureUsers;
|
||||||
List<dynamic>? apiCountryData;
|
List<dynamic>? apiCountryData;
|
||||||
String? selectedUserId;
|
String? selectedUserId;
|
||||||
|
String? orgId;
|
||||||
|
|
||||||
Future<String?> getToken() async {
|
Future<String?> getToken() async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
@ -25,7 +27,8 @@ class _UserListScreenState extends State<UserListScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<List<dynamic>> fetchUsers() async {
|
Future<List<dynamic>> fetchUsers() async {
|
||||||
final String apiUrlData = '$apiUrl/api/users';
|
orgId = await getOrgId();
|
||||||
|
final String apiUrlData = '$apiUrl/api/users?org_id=$orgId';
|
||||||
final String? token = await getToken();
|
final String? token = await getToken();
|
||||||
|
|
||||||
print("Fetch Users");
|
print("Fetch Users");
|
||||||
@ -110,7 +113,59 @@ class _UserListScreenState extends State<UserListScreen> {
|
|||||||
print("handDel - $userId");
|
print("handDel - $userId");
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleToggleUserStatus(String userId, String currentStatus) async {
|
Future<void> createUserData(
|
||||||
|
Map<String, dynamic> userData, String userId, String newStatus) async {
|
||||||
|
final uri = Uri.parse('$apiUrl/api/users/update/$userId');
|
||||||
|
|
||||||
|
final String? token = await getToken();
|
||||||
|
if (token == null) {
|
||||||
|
throw Exception('Token not found. Please log in.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use MultipartRequest (POST only)
|
||||||
|
final request = http.MultipartRequest('POST', uri);
|
||||||
|
request.headers['Authorization'] = 'Bearer $token';
|
||||||
|
|
||||||
|
// If updating, spoof the method Laravel-style
|
||||||
|
|
||||||
|
request.fields['_method'] = 'PUT';
|
||||||
|
request.fields['user_id'] = userId;
|
||||||
|
|
||||||
|
print("STatus 2 - $newStatus");
|
||||||
|
|
||||||
|
// Add all non-null and non-empty user data fields
|
||||||
|
userData.forEach((key, value) {
|
||||||
|
if (value != null && value.toString().trim().isNotEmpty) {
|
||||||
|
request.fields[key] = value.toString();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
request.fields['is_active'] = newStatus;
|
||||||
|
|
||||||
|
print("🚀 Sending request with fields: ${request.fields}");
|
||||||
|
|
||||||
|
try {
|
||||||
|
final streamedResponse = await request.send();
|
||||||
|
final response = await http.Response.fromStream(streamedResponse);
|
||||||
|
print("Response status: ${response.statusCode}");
|
||||||
|
print("Response body: ${response.body}");
|
||||||
|
|
||||||
|
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||||
|
print("✅ User Status submitted successfully! ");
|
||||||
|
print("📨 Response: ${response.body}");
|
||||||
|
|
||||||
|
refreshUserList();
|
||||||
|
} else {
|
||||||
|
print("❌ Submission failed. Status: ${response.statusCode}");
|
||||||
|
print("📨 Body: ${response.body}");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("🔥 Error submitting user: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleToggleUserStatus(String userId, String currentStatus,
|
||||||
|
Map<String, dynamic> userData) async {
|
||||||
print("Toggling user status - $userId (Current: $currentStatus)");
|
print("Toggling user status - $userId (Current: $currentStatus)");
|
||||||
|
|
||||||
final String apiUrlData =
|
final String apiUrlData =
|
||||||
@ -125,28 +180,32 @@ class _UserListScreenState extends State<UserListScreen> {
|
|||||||
// Toggle status: If active ("1"), set to inactive ("0"); otherwise, activate ("1")
|
// Toggle status: If active ("1"), set to inactive ("0"); otherwise, activate ("1")
|
||||||
String newStatus = (currentStatus == "1") ? "0" : "1";
|
String newStatus = (currentStatus == "1") ? "0" : "1";
|
||||||
|
|
||||||
try {
|
print("STatus 1 - $newStatus");
|
||||||
final response = await http.put(
|
|
||||||
Uri.parse(apiUrlData),
|
|
||||||
headers: {
|
|
||||||
'Authorization': 'Bearer $token',
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: jsonEncode({
|
|
||||||
"is_active": newStatus // Set new status dynamically
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
createUserData(userData, userId, newStatus);
|
||||||
print("User status updated successfully to $newStatus!");
|
|
||||||
refreshUserList(); // Refresh users list after update
|
// try {
|
||||||
} else {
|
// final response = await http.put(
|
||||||
print("Failed to update user status. Status: ${response.statusCode}");
|
// Uri.parse(apiUrlData),
|
||||||
print("Error: ${response.body}");
|
// headers: {
|
||||||
}
|
// 'Authorization': 'Bearer $token',
|
||||||
} catch (e) {
|
// 'Content-Type': 'application/json',
|
||||||
print("Error updating user status: $e");
|
// },
|
||||||
}
|
// body: jsonEncode({
|
||||||
|
// "is_active": newStatus // Set new status dynamically
|
||||||
|
// }),
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// if (response.statusCode == 200) {
|
||||||
|
// print("User status updated successfully to $newStatus!");
|
||||||
|
// refreshUserList(); // Refresh users list after update
|
||||||
|
// } else {
|
||||||
|
// print("Failed to update user status. Status: ${response.statusCode}");
|
||||||
|
// print("Error: ${response.body}");
|
||||||
|
// }
|
||||||
|
// } catch (e) {
|
||||||
|
// print("Error updating user status: $e");
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh user list after update
|
// Refresh user list after update
|
||||||
@ -207,10 +266,12 @@ class _UserListScreenState extends State<UserListScreen> {
|
|||||||
// Print the resolved value
|
// Print the resolved value
|
||||||
print("CREATELIAS - $users");
|
print("CREATELIAS - $users");
|
||||||
|
|
||||||
context.go("/CreateUserDetails", extra: {
|
context.go("/CreateUserDetails"
|
||||||
// 'apiCountryData': apiCountryData,
|
// extra: {
|
||||||
'apiUserData': users,
|
// // 'apiCountryData': apiCountryData,
|
||||||
});
|
// 'apiUserData': users,
|
||||||
|
// }
|
||||||
|
);
|
||||||
if (!isDesktop) Navigator.pop(context);
|
if (!isDesktop) Navigator.pop(context);
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -235,7 +296,60 @@ class _UserListScreenState extends State<UserListScreen> {
|
|||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
return Center(child: CircularProgressIndicator());
|
return Center(child: CircularProgressIndicator());
|
||||||
} else if (snapshot.hasError) {
|
} else if (snapshot.hasError) {
|
||||||
return Center(child: Text("Error: ${snapshot.error}"));
|
return Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.error_outline,
|
||||||
|
color: Colors.redAccent,
|
||||||
|
size: 60,
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
"Oops!",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.redAccent,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
"No User Available",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
Text(
|
||||||
|
" Please Create NewUser",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Colors.grey[700],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
// ElevatedButton.icon(
|
||||||
|
// onPressed: () {
|
||||||
|
// // Optional: retry logic or navigation
|
||||||
|
// },
|
||||||
|
// icon: Icon(Icons.refresh),
|
||||||
|
// label: Text("Try Again"),
|
||||||
|
// style: ElevatedButton.styleFrom(
|
||||||
|
// backgroundColor: Colors.blueAccent,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
||||||
return Center(child: Text("No users found"));
|
return Center(child: Text("No users found"));
|
||||||
}
|
}
|
||||||
@ -467,8 +581,8 @@ class _UserListScreenState extends State<UserListScreen> {
|
|||||||
)),
|
)),
|
||||||
DataCell(GestureDetector(
|
DataCell(GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
handleToggleUserStatus(
|
handleToggleUserStatus(user['user_id'],
|
||||||
user['user_id'], user['is_active']);
|
user['is_active'], user);
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
user['is_active'] == "1"
|
user['is_active'] == "1"
|
||||||
@ -519,6 +633,13 @@ class _UserListScreenState extends State<UserListScreen> {
|
|||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
print("USER: $user");
|
print("USER: $user");
|
||||||
|
|
||||||
|
// final userJson = jsonEncode(
|
||||||
|
// user); // Convert user map to string
|
||||||
|
// final encodedUser =
|
||||||
|
// Uri.encodeComponent(
|
||||||
|
// userJson);
|
||||||
|
|
||||||
context.go(
|
context.go(
|
||||||
"/CreateUserDetails",
|
"/CreateUserDetails",
|
||||||
extra: {
|
extra: {
|
||||||
@ -529,25 +650,6 @@ class _UserListScreenState extends State<UserListScreen> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
MouseRegion(
|
|
||||||
cursor: user['is_active'] == "0"
|
|
||||||
? SystemMouseCursors.forbidden
|
|
||||||
: SystemMouseCursors.click,
|
|
||||||
child: IconButton(
|
|
||||||
icon: Icon(Icons.delete,
|
|
||||||
color: user['is_active'] == "0"
|
|
||||||
? Colors.grey
|
|
||||||
: Colors.redAccent),
|
|
||||||
onPressed: user['is_active'] == "0"
|
|
||||||
? null
|
|
||||||
: () {
|
|
||||||
print(
|
|
||||||
"USER ID: ${user['user_id']}");
|
|
||||||
var userId = user['user_id'];
|
|
||||||
handleDelete(userId);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -5,19 +5,15 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:responsive_builder/responsive_builder.dart';
|
import 'package:responsive_builder/responsive_builder.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
|
||||||
class CustomDrawer extends StatefulWidget {
|
class CustomDrawer extends StatefulWidget {
|
||||||
|
|
||||||
final bool isDesktop;
|
final bool isDesktop;
|
||||||
const CustomDrawer({super.key, required this.isDesktop});
|
const CustomDrawer({super.key, required this.isDesktop});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_CustomDrawerState createState() => _CustomDrawerState();
|
_CustomDrawerState createState() => _CustomDrawerState();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _CustomDrawerState extends State<CustomDrawer> {
|
class _CustomDrawerState extends State<CustomDrawer> {
|
||||||
|
|
||||||
String? token;
|
String? token;
|
||||||
Map<String, dynamic>? userData;
|
Map<String, dynamic>? userData;
|
||||||
Map<String, dynamic>? fetchedUserData;
|
Map<String, dynamic>? fetchedUserData;
|
||||||
@ -30,13 +26,11 @@ class _CustomDrawerState extends State<CustomDrawer>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> initializeData() async {
|
Future<void> initializeData() async {
|
||||||
|
|
||||||
print("initializeDatainitializeData");
|
print("initializeDatainitializeData");
|
||||||
token = await getToken();
|
token = await getToken();
|
||||||
fetchedUserData = await getUserData();
|
fetchedUserData = await getUserData();
|
||||||
|
|
||||||
if(token == null || fetchedUserData == null)
|
if (token == null || fetchedUserData == null) {
|
||||||
{
|
|
||||||
print("Token or USerId missing");
|
print("Token or USerId missing");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -44,10 +38,8 @@ class _CustomDrawerState extends State<CustomDrawer>{
|
|||||||
setState(() {
|
setState(() {
|
||||||
userData = fetchedUserData;
|
userData = fetchedUserData;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<String?> getToken() async {
|
Future<String?> getToken() async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
return prefs.getString("auth_token");
|
return prefs.getString("auth_token");
|
||||||
@ -74,8 +66,6 @@ class _CustomDrawerState extends State<CustomDrawer>{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget drawerContent = Container(
|
Widget drawerContent = Container(
|
||||||
@ -85,6 +75,7 @@ class _CustomDrawerState extends State<CustomDrawer>{
|
|||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
print("ONTAP Custom");
|
print("ONTAP Custom");
|
||||||
|
print("ONTAP Custom- $userDetails ");
|
||||||
context.go(
|
context.go(
|
||||||
"/CreateUserDetails",
|
"/CreateUserDetails",
|
||||||
extra: {
|
extra: {
|
||||||
@ -101,7 +92,6 @@ class _CustomDrawerState extends State<CustomDrawer>{
|
|||||||
padding: EdgeInsets.all(16),
|
padding: EdgeInsets.all(16),
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(2.0),
|
padding: const EdgeInsets.all(2.0),
|
||||||
@ -109,36 +99,39 @@ class _CustomDrawerState extends State<CustomDrawer>{
|
|||||||
height: 50,
|
height: 50,
|
||||||
width: 50,
|
width: 50,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.blueAccent,
|
color: Colors.blueAccent, shape: BoxShape.circle),
|
||||||
shape: BoxShape.circle
|
|
||||||
) ,
|
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [ Text(
|
children: [
|
||||||
|
Text(
|
||||||
userData?["name"]?.isNotEmpty == true
|
userData?["name"]?.isNotEmpty == true
|
||||||
? userData!["name"]![0].toUpperCase()
|
? userData!["name"]![0].toUpperCase()
|
||||||
: "N/A",
|
: "N/A",
|
||||||
style: TextStyle(color: Colors.white, fontSize: 25),
|
style: TextStyle(
|
||||||
),],),
|
color: Colors.white, fontSize: 25),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
userData?["name"] ?? "N/A",
|
userData?["name"] ?? "N/A",
|
||||||
style: TextStyle(color: Colors.black87, fontSize: 11),
|
style:
|
||||||
|
TextStyle(color: Colors.black87, fontSize: 11),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
userData?["email"] ?? "N/A",
|
userData?["email"] ?? "N/A",
|
||||||
style: TextStyle(color: Colors.black45, fontSize: 10),
|
style:
|
||||||
),
|
TextStyle(color: Colors.black45, fontSize: 10),
|
||||||
|
|
||||||
],)
|
|
||||||
],)
|
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
_buildDrawerItem(context, Icons.home, 'Home', '/home'),
|
_buildDrawerItem(context, Icons.home, 'Home', '/home'),
|
||||||
@ -146,11 +139,11 @@ class _CustomDrawerState extends State<CustomDrawer>{
|
|||||||
_buildSubDrawerItem(context, 'My Travel Request', '/listPlan'),
|
_buildSubDrawerItem(context, 'My Travel Request', '/listPlan'),
|
||||||
// _buildSubDrawerItem(context,'PlanB','/PlanB')
|
// _buildSubDrawerItem(context,'PlanB','/PlanB')
|
||||||
]),
|
]),
|
||||||
_buildExpandableItem(context,Icons.account_circle_outlined,'User ',[
|
_buildExpandableItem(
|
||||||
|
context, Icons.account_circle_outlined, 'User ', [
|
||||||
_buildSubDrawerItem(context, 'User List', '/listUser'),
|
_buildSubDrawerItem(context, 'User List', '/listUser'),
|
||||||
// _buildSubDrawerItem(context,'PlanB','/PlanB')
|
// _buildSubDrawerItem(context,'PlanB','/PlanB')
|
||||||
]),
|
]),
|
||||||
|
|
||||||
_buildExpandableItem(context, Icons.policy, 'Policy ', [
|
_buildExpandableItem(context, Icons.policy, 'Policy ', [
|
||||||
_buildSubDrawerItem(context, 'Policy', '/Policy'),
|
_buildSubDrawerItem(context, 'Policy', '/Policy'),
|
||||||
// _buildSubDrawerItem(context,'PlanB','/PlanB')
|
// _buildSubDrawerItem(context,'PlanB','/PlanB')
|
||||||
@ -169,14 +162,14 @@ class _CustomDrawerState extends State<CustomDrawer>{
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Drawer for Mobile & Tablet**
|
// Drawer for Mobile & Tablet**
|
||||||
return Drawer(child: ListView(padding: EdgeInsets.zero, children: [drawerContent]));
|
return Drawer(
|
||||||
|
child: ListView(padding: EdgeInsets.zero, children: [drawerContent]));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// **Reusable Drawer Item**
|
/// **Reusable Drawer Item**
|
||||||
Widget _buildDrawerItem(BuildContext context, IconData icon, String title, String route)
|
Widget _buildDrawerItem(
|
||||||
{
|
BuildContext context, IconData icon, String title, String route) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: Icon(icon),
|
leading: Icon(icon),
|
||||||
title: Text(title),
|
title: Text(title),
|
||||||
@ -189,11 +182,11 @@ class _CustomDrawerState extends State<CustomDrawer>{
|
|||||||
} else {
|
} else {
|
||||||
context.go(route);
|
context.go(route);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildExpandableItem(BuildContext context, IconData icon, String title, List<Widget>children){
|
Widget _buildExpandableItem(BuildContext context, IconData icon, String title,
|
||||||
|
List<Widget> children) {
|
||||||
return ExpansionTile(
|
return ExpansionTile(
|
||||||
leading: Icon(icon),
|
leading: Icon(icon),
|
||||||
title: Text(title),
|
title: Text(title),
|
||||||
@ -203,8 +196,7 @@ class _CustomDrawerState extends State<CustomDrawer>{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSubDrawerItem(BuildContext context, String title, String route)
|
Widget _buildSubDrawerItem(BuildContext context, String title, String route) {
|
||||||
{
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(title),
|
title: Text(title),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@ -213,6 +205,4 @@ class _CustomDrawerState extends State<CustomDrawer>{
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:frontend/Screens/authentication/login/login_page.dart';
|
import 'package:frontend/Screens/authentication/login/login_page.dart';
|
||||||
import 'package:frontend/Screens/authentication/loginPage1.dart';
|
import 'package:frontend/Screens/authentication/loginPage1.dart';
|
||||||
@ -11,7 +12,6 @@ import 'package:go_router/go_router.dart';
|
|||||||
|
|
||||||
final GoRouter router = GoRouter(
|
final GoRouter router = GoRouter(
|
||||||
routes: [
|
routes: [
|
||||||
|
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/',
|
path: '/',
|
||||||
builder: (context, state) => LoginPage(),
|
builder: (context, state) => LoginPage(),
|
||||||
@ -35,11 +35,27 @@ final GoRouter router = GoRouter(
|
|||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/CreateUserDetails',
|
path: '/CreateUserDetails',
|
||||||
builder: (context, state) => CreateUserForm(),
|
builder: (context, state) => CreateUserForm(),
|
||||||
|
// builder: (context, state) {
|
||||||
|
// final userParam = state.uri.queryParameters['user'];
|
||||||
|
//
|
||||||
|
// final isEditProfile =
|
||||||
|
// state.uri.queryParameters['isEditProfile'] == 'true';
|
||||||
|
// final isViewMode = state.uri.queryParameters['isViewMode'] == 'true';
|
||||||
|
//
|
||||||
|
// final user = userParam != null
|
||||||
|
// ? jsonDecode(Uri.decodeComponent(userParam))
|
||||||
|
// : null;
|
||||||
|
//
|
||||||
|
// return CreateUserForm(
|
||||||
|
// apiselectedUser: user,
|
||||||
|
// isEditProfile: isEditProfile,
|
||||||
|
// isViewMode: isViewMode,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/Policy',
|
path: '/Policy',
|
||||||
builder: (context, state) => Policy(),
|
builder: (context, state) => Policy(),
|
||||||
),
|
),
|
||||||
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -3,11 +3,8 @@ import 'package:frontend/utils/auth_utils.dart';
|
|||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import '../../config/apiUrl.dart';
|
import '../../config/apiUrl.dart';
|
||||||
|
|
||||||
|
|
||||||
class ApiService {
|
class ApiService {
|
||||||
|
|
||||||
Future<List<dynamic>> fetchCountryList() async {
|
Future<List<dynamic>> fetchCountryList() async {
|
||||||
|
|
||||||
final String apiUrldata = '$apiUrl/api/getcountryMaster';
|
final String apiUrldata = '$apiUrl/api/getcountryMaster';
|
||||||
final token = await getToken();
|
final token = await getToken();
|
||||||
|
|
||||||
@ -29,7 +26,8 @@ class ApiService {
|
|||||||
print("Country - $data");
|
print("Country - $data");
|
||||||
|
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception("Invalid response format: 'data' field is missing or not a List");
|
throw Exception(
|
||||||
|
"Invalid response format: 'data' field is missing or not a List");
|
||||||
}
|
}
|
||||||
|
|
||||||
return data['data'];
|
return data['data'];
|
||||||
@ -42,7 +40,8 @@ class ApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<List<dynamic>> fetchUsers() async {
|
Future<List<dynamic>> fetchUsers() async {
|
||||||
final String apiUrlData = '$apiUrl/api/users';
|
String? ordId = await getOrgId();
|
||||||
|
final String apiUrlData = '$apiUrl/api/users?org_id=$ordId';
|
||||||
final String? token = await getToken();
|
final String? token = await getToken();
|
||||||
|
|
||||||
print("Fetch Users");
|
print("Fetch Users");
|
||||||
@ -68,7 +67,6 @@ class ApiService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<List> fetchCostCenter() async {
|
Future<List> fetchCostCenter() async {
|
||||||
final String apiUrldata = '$apiUrl/api/getCostCenterMaster';
|
final String apiUrldata = '$apiUrl/api/getCostCenterMaster';
|
||||||
|
|
||||||
@ -96,7 +94,8 @@ class ApiService {
|
|||||||
print(data);
|
print(data);
|
||||||
|
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception("Invalid response format: 'data' field is missing or not a List");
|
throw Exception(
|
||||||
|
"Invalid response format: 'data' field is missing or not a List");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
List<dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
||||||
@ -114,8 +113,6 @@ class ApiService {
|
|||||||
print('plansJSON');
|
print('plansJSON');
|
||||||
|
|
||||||
return plansJson;
|
return plansJson;
|
||||||
|
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw Exception('Error parsing response: $e');
|
throw Exception('Error parsing response: $e');
|
||||||
}
|
}
|
||||||
@ -137,20 +134,23 @@ class ApiService {
|
|||||||
Uri.parse(apiUrldata),
|
Uri.parse(apiUrldata),
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': 'Bearer $token',
|
'Authorization': 'Bearer $token',
|
||||||
'Content-Type': 'application/json',},);
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
try {
|
try {
|
||||||
final data = json.decode(response.body);
|
final data = json.decode(response.body);
|
||||||
print(data);
|
print(data);
|
||||||
if (!data.containsKey('data') || data['data'] is! Map) {
|
if (!data.containsKey('data') || data['data'] is! Map) {
|
||||||
throw Exception("Invalid response format: 'data' field is missing or not a Map");
|
throw Exception(
|
||||||
|
"Invalid response format: 'data' field is missing or not a Map");
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
Map<String, dynamic> plansJson =
|
||||||
|
data['data']; // 'data' is a Map, not a List
|
||||||
|
|
||||||
return plansJson;
|
return plansJson;
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw Exception('Error parsing response: $e');
|
throw Exception('Error parsing response: $e');
|
||||||
}
|
}
|
||||||
@ -158,6 +158,4 @@ class ApiService {
|
|||||||
throw Exception('Failed to load plans');
|
throw Exception('Failed to load plans');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
Future<String?> getToken() async {
|
Future<String?> getToken() async {
|
||||||
@ -9,3 +11,18 @@ Future<String?> getUserId() async {
|
|||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
return prefs.getString('userId');
|
return prefs.getString('userId');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<String?> getOrgId() async {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
final String? userDataString = prefs.getString('user_data');
|
||||||
|
|
||||||
|
if (userDataString != null) {
|
||||||
|
try {
|
||||||
|
final Map<String, dynamic> userData = jsonDecode(userDataString);
|
||||||
|
return userData["org_id"]?.toString();
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ class _CustomTextFieldWrapperState extends State<CustomTextFieldWrapper> {
|
|||||||
return Container(
|
return Container(
|
||||||
width: widget.width ?? // Use custom width if provided, else default
|
width: widget.width ?? // Use custom width if provided, else default
|
||||||
(widget.isDesktop
|
(widget.isDesktop
|
||||||
? MediaQuery.of(context).size.width * 0.4
|
? MediaQuery.of(context).size.width * 0.3
|
||||||
: MediaQuery.of(context).size.width * 0.85),
|
: MediaQuery.of(context).size.width * 0.85),
|
||||||
padding: widget.padding,
|
padding: widget.padding,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -47,7 +47,6 @@ class _CustomTextFieldWrapperState extends State<CustomTextFieldWrapper> {
|
|||||||
blurRadius: 10,
|
blurRadius: 10,
|
||||||
spreadRadius: 2,
|
spreadRadius: 2,
|
||||||
offset: Offset(0, 4),
|
offset: Offset(0, 4),
|
||||||
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
: [],
|
: [],
|
||||||
|
|||||||
@ -21,16 +21,18 @@ class CustomTextFieldForexWrapper extends StatefulWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_CustomTextFieldForexWrapperState createState() => _CustomTextFieldForexWrapperState();
|
_CustomTextFieldForexWrapperState createState() =>
|
||||||
|
_CustomTextFieldForexWrapperState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _CustomTextFieldForexWrapperState extends State<CustomTextFieldForexWrapper> {
|
class _CustomTextFieldForexWrapperState
|
||||||
|
extends State<CustomTextFieldForexWrapper> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
width: widget.width ?? // Use custom width if provided, else default
|
width: widget.width ?? // Use custom width if provided, else default
|
||||||
(widget.isDesktop
|
(widget.isDesktop
|
||||||
? MediaQuery.of(context).size.width * 0.25
|
? MediaQuery.of(context).size.width * 0.2
|
||||||
: MediaQuery.of(context).size.width * 0.8),
|
: MediaQuery.of(context).size.width * 0.8),
|
||||||
padding: widget.padding,
|
padding: widget.padding,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -48,7 +50,6 @@ class _CustomTextFieldForexWrapperState extends State<CustomTextFieldForexWrappe
|
|||||||
blurRadius: 10,
|
blurRadius: 10,
|
||||||
spreadRadius: 2,
|
spreadRadius: 2,
|
||||||
offset: Offset(0, 4),
|
offset: Offset(0, 4),
|
||||||
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
: [],
|
: [],
|
||||||
|
|||||||
44
pubspec.lock
44
pubspec.lock
@ -17,6 +17,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.12.0"
|
version: "2.12.0"
|
||||||
|
bcrypt:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: bcrypt
|
||||||
|
sha256: "9dc3f234d5935a76917a6056613e1a6d9b53f7fa56f98e24cd49b8969307764b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.3"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -49,6 +57,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.19.1"
|
version: "1.19.1"
|
||||||
|
cross_file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cross_file
|
||||||
|
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.4+2"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -105,6 +121,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.1"
|
version: "7.0.1"
|
||||||
|
file_picker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: file_picker
|
||||||
|
sha256: "36a1652d99cb6bf8ccc8b9f43aded1fd60b234d23ce78af422c07f950a436ef7"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.0.0"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -118,6 +142,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.0"
|
version: "5.0.0"
|
||||||
|
flutter_plugin_android_lifecycle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_plugin_android_lifecycle
|
||||||
|
sha256: "5a1e6fb2c0561958d7e4c33574674bda7b77caaca7a33b758876956f2902eea3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.27"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -145,7 +177,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.3.0"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: http_parser
|
name: http_parser
|
||||||
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
||||||
@ -453,6 +485,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.1"
|
||||||
|
win32:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: win32
|
||||||
|
sha256: dc6ecaa00a7c708e5b4d10ee7bec8c270e9276dfcab1783f57e9962d7884305f
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.12.0"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -462,5 +502,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.7.0-0 <4.0.0"
|
dart: ">=3.7.0 <4.0.0"
|
||||||
flutter: ">=3.27.0"
|
flutter: ">=3.27.0"
|
||||||
|
|||||||
@ -43,6 +43,7 @@ dependencies:
|
|||||||
dropdown_search: ^5.0.6
|
dropdown_search: ^5.0.6
|
||||||
file_picker: ^10.0.0
|
file_picker: ^10.0.0
|
||||||
bcrypt: ^1.1.3
|
bcrypt: ^1.1.3
|
||||||
|
http_parser: ^4.1.2
|
||||||
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user