OrgLevel Data, UserDetails

This commit is contained in:
venbaittech 2025-04-08 16:14:01 +05:30
parent 1f28816021
commit 886bef2baa
24 changed files with 3302 additions and 2972 deletions

View File

@ -4,23 +4,27 @@ 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();
} }
class _UserSelectionDialogState extends State<UserSelectionDialog>{ class _UserSelectionDialogState extends State<UserSelectionDialog> {
TextEditingController _controller = TextEditingController(); TextEditingController _controller = TextEditingController();
TextEditingController _searchController = TextEditingController(); TextEditingController _searchController = TextEditingController();
// List<String> _filteredUsers = []; // List<String> _filteredUsers = [];
@ -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();
@ -62,8 +68,7 @@ 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
@ -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)),
), ),
], ],
), ),

View File

@ -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,11 +59,10 @@ 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,
"checkin_date": _checkInController.text , "checkin_date": _checkInController.text,
"checkin_time": _checkInTimeController.text, "checkin_time": _checkInTimeController.text,
"checkout_date": _checkOutController.text, "checkout_date": _checkOutController.text,
"checkout_time": _checkOutTimeController.text, "checkout_time": _checkOutTimeController.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,25 +162,22 @@ 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() {
print("Handle Save accomadationData $accomadationData");
void handleSave(){ Map<String, dynamic> data = accomadationData;
print( "Handle Save accomadationData $accomadationData");
Map<String,dynamic> data = accomadationData;
if (!isValidData(data)) { if (!isValidData(data)) {
print("Validation Failed: Required fields are missing."); print("Validation Failed: Required fields are missing.");
setState(() {}); setState(() {});
return; // Stop execution if validation fails return; // Stop execution if validation fails
}else { } else {
widget.onSaveAccomadation(accomadationData); widget.onSaveAccomadation(accomadationData);
} }
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,

View File

@ -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,9 +55,8 @@ 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,
"to": _toController.text, "to": _toController.text,
"date": _dateController.text, "date": _dateController.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,11 +159,12 @@ 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
// Required fields that must not be empty // Required fields that must not be empty
List<String> requiredFields = ["from", "to","date","time"]; List<String> requiredFields = ["from", "to", "date", "time"];
// Check validation for each field // Check validation for each field
for (String field in requiredFields) { for (String field in requiredFields) {
@ -177,26 +176,22 @@ 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() {
print("Handle Save accomadationData $busData");
void handleSave(){ Map<String, dynamic> data = busData;
print( "Handle Save accomadationData $busData");
Map<String,dynamic> data = busData;
if (!isValidData(data)) { if (!isValidData(data)) {
print("Validation Failed: Required fields are missing."); print("Validation Failed: Required fields are missing.");
setState(() {}); setState(() {});
return; // Stop execution if validation fails return; // Stop execution if validation fails
}else { } else {
widget.onSaveBus(busData); widget.onSaveBus(busData);
} }
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,
), ),
@ -244,7 +241,7 @@ class _BusScreenState extends State<BusScreen> {
}); });
} }
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),
@ -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,
@ -662,7 +635,7 @@ class _BusScreenState extends State<BusScreen> {
// Close Button // Close Button
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
widget.onClose(false);// Close the dialog or screen widget.onClose(false); // Close the dialog or screen
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color backgroundColor: Colors.grey[400], // Light grey color

View File

@ -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,10 +220,9 @@ 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],
"from_place": textControllers["_from${i}Controller"]?.text ?? "", "from_place": textControllers["_from${i}Controller"]?.text ?? "",
"to_place": textControllers["_to${i}Controller"]?.text ?? "", "to_place": textControllers["_to${i}Controller"]?.text ?? "",
"date": textControllers["_date${i}Controller"]?.text ?? "", "date": textControllers["_date${i}Controller"]?.text ?? "",
@ -239,8 +232,7 @@ 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 ?? "",
"visa_available": selectedvisa_available, "visa_available": selectedvisa_available,
@ -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,17 +260,17 @@ 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();
if ( widget.selectedItem!["trip_type"] != null) { if (widget.selectedItem!["trip_type"] != null) {
selectedTripType = widget.selectedItem!["trip_type"].toString(); selectedTripType = widget.selectedItem!["trip_type"].toString();
} }
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,8 +457,7 @@ 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 [
isDesktop ? Row(children: children) : Column(children: children), isDesktop ? Row(children: children) : Column(children: children),
@ -467,34 +466,29 @@ class _FlightScreenState extends State<FlightScreen> {
} }
List<List<Widget>> rowBuilders = [ List<List<Widget>> rowBuilders = [
_builClassType(isDesktop,1), _builClassType(isDesktop, 1),
_buildSecondRow(isDesktop,1) _buildSecondRow(isDesktop, 1)
]; ];
List<List<Widget>> rowRoundBuilders = [ List<List<Widget>> rowRoundBuilders = [
_builClassType(isDesktop,1), _builClassType(isDesktop, 1),
_buildSecondRow(isDesktop,1), _buildSecondRow(isDesktop, 1),
_builClassType(isDesktop,2), _builClassType(isDesktop, 2),
_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,
@ -527,7 +517,7 @@ class _FlightScreenState extends State<FlightScreen> {
side: BorderSide(color: Colors.blueAccent, width: 2), side: BorderSide(color: Colors.blueAccent, width: 2),
), ),
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 2), padding: EdgeInsets.symmetric(horizontal: 8, vertical: 2),
) , ),
onPressed: () { onPressed: () {
setState(() { setState(() {
multiTripRowCount++; // Increase the row count multiTripRowCount++; // Increase the row count
@ -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,
), ),
), ),
), ),
]; ];
} }
List<Widget> _buildDelete(bool isDesktop, int index){ // Widget _buildDelete(bool isDesktop, int index) {
return [ // 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) {
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")
isDesktop
?
// SizedBox(
// width: MediaQuery.of(context).size.width * 0.89,
// child:
if (selectedTripType == "Multitrip" ) Row(
isDesktop? mainAxisAlignment: MainAxisAlignment.spaceBetween,
SizedBox( // crossAxisAlignment: CrossAxisAlignment.center,
width: MediaQuery.of(context).size.width * 0.89, children: [
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, // Spacer(flex: 2),
children: [..._buildDelete(isDesktop, index)]),
)
: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [..._buildDelete(isDesktop, index)]),
// _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,23 +863,24 @@ 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
// controller: _hotelNameController, // controller: _hotelNameController,
value: selectedClasses[index] , value: selectedClasses[index],
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) {
@ -791,26 +888,19 @@ class _FlightScreenState extends State<FlightScreen> {
selectedClasses[index] = newValue; selectedClasses[index] = newValue;
}); });
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<dynamic> visa_available =
List<Widget> _buildvisa(bool isDesktop){ widget.apiData?['flight_visa_available'] ?? [];
List<dynamic> 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,13 +1265,12 @@ class _FlightScreenState extends State<FlightScreen> {
]; ];
} }
List<Widget> _handleAction(bool isDesktop) { List<Widget> _handleAction(bool isDesktop) {
return [ return [
// Close Button // Close Button
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
widget.onClose(false);// Close the dialog or screen widget.onClose(false); // Close the dialog or screen
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color backgroundColor: Colors.grey[400], // Light grey color

File diff suppressed because it is too large Load Diff

View File

@ -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,25 +34,23 @@ 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;
Map<String, String> errorMessages = {}; Map<String, String> errorMessages = {};
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,22 +135,20 @@ 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() {
print("Handle Save InsuranceData $InsuranceData");
void handleSave(){ Map<String, dynamic> data = InsuranceData;
print( "Handle Save InsuranceData $InsuranceData");
Map<String,dynamic> data = InsuranceData;
if (!isValidData(data)) { if (!isValidData(data)) {
print("Validation Failed: Required fields are missing."); print("Validation Failed: Required fields are missing.");
setState(() {}); setState(() {});
return; // Stop execution if validation fails return; // Stop execution if validation fails
}else { } else {
widget.onSaveInsurance(InsuranceData); widget.onSaveInsurance(InsuranceData);
} }
widget.onClose(false);// Close screen after saving widget.onClose(false); // Close screen after saving
} }
DateTime? _parseDate(String date) { DateTime? _parseDate(String date) {
@ -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,
), ),
@ -214,7 +217,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
}); });
} }
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),
@ -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<dynamic> purposeList =
List<Widget> _buildTripType(bool isDesktop){ widget.apiData?['insurance_type_of_insurance'] ?? [];
List<dynamic> purposeList = 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,

View File

@ -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,30 +120,26 @@ 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() {
print("Handle Save miscellaneousData $miscellaneousData");
Map<String, dynamic> data = miscellaneousData;
void handleSave(){
print( "Handle Save miscellaneousData $miscellaneousData");
Map<String,dynamic> data = miscellaneousData;
if (!isValidData(data)) { if (!isValidData(data)) {
print("Validation Failed: Required fields are missing."); print("Validation Failed: Required fields are missing.");
setState(() {}); setState(() {});
return; // Stop execution if validation fails return; // Stop execution if validation fails
}else { } else {
widget.onSaveMiscellaneous(miscellaneousData); // Send object to parent widget.onSaveMiscellaneous(miscellaneousData); // Send object to parent
} }
widget.onClose(false);// Close screen after saving widget.onClose(false); // Close screen after saving
// Clear only if this is a new entry // Clear only if this is a new entry
// if (widget.selectedItem == null) { // if (widget.selectedItem == null) {
// _commentsController.clear(); // _commentsController.clear();
// } // }
} }
@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,
), ),
@ -197,7 +190,7 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
}); });
} }
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),
@ -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<dynamic> purposeList =
List<Widget> _buildTripType(bool isDesktop){ widget.apiData?['miscellaneous_special_request'] ?? [];
List<dynamic> purposeList = 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,9 +356,8 @@ 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
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color backgroundColor: Colors.grey[400], // Light grey color

View File

@ -9,13 +9,16 @@ import '../../widgets/custom_text_itnerary_sub.dart';
class TaxiScreen extends StatefulWidget { class TaxiScreen 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>) onSavetaxi; final Function(Map<String, dynamic>) onSavetaxi;
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,27 +180,22 @@ 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() {
print("Handle Save taxiData $taxiData");
void handleSave(){ Map<String, dynamic> data = taxiData;
print( "Handle Save taxiData $taxiData");
Map<String,dynamic> data = taxiData;
if (!isValidData(data)) { if (!isValidData(data)) {
print("Validation Failed: Required fields are missing."); print("Validation Failed: Required fields are missing.");
setState(() {}); setState(() {});
return; // Stop execution if validation fails return; // Stop execution if validation fails
}else { } else {
widget.onSavetaxi(taxiData); widget.onSavetaxi(taxiData);
} }
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,
), ),
@ -247,7 +245,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
}); });
} }
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),
@ -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,
@ -783,7 +763,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
// Close Button // Close Button
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
widget.onClose(false);// Close the dialog or screen widget.onClose(false); // Close the dialog or screen
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color backgroundColor: Colors.grey[400], // Light grey color

View File

@ -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();
@ -54,9 +56,8 @@ class _TrainScreenState extends State<TrainScreen> {
Map<String, String> errorMessages = {}; Map<String, String> errorMessages = {};
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,28 +189,22 @@ 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() {
print("Handle Save accomadationData $trainData");
void handleSave(){ Map<String, dynamic> data = trainData;
print( "Handle Save accomadationData $trainData");
Map<String,dynamic> data = trainData;
if (!isValidData(data)) { if (!isValidData(data)) {
print("Validation Failed: Required fields are missing."); print("Validation Failed: Required fields are missing.");
setState(() {}); setState(() {});
return; // Stop execution if validation fails return; // Stop execution if validation fails
}else { } else {
widget.onSavetrain(trainData); widget.onSavetrain(trainData);
} }
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,
), ),
@ -254,7 +254,7 @@ class _TrainScreenState extends State<TrainScreen> {
}); });
} }
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),
@ -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,

View File

@ -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,36 +57,36 @@ 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,
// "country": selectedCountry, // "country": selectedCountry,
"country_code": selectedCountry, "country_code": selectedCountry,
"start_date": _dateController.text, "start_date": _dateController.text,
"comments":_visaCommentsController.text, "comments": _visaCommentsController.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?["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,29 +148,22 @@ 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() {
print("Handle Save visaData $visaData");
Map<String, dynamic> data = visaData;
void handleSave(){
print( "Handle Save visaData $visaData");
Map<String,dynamic> data = visaData;
if (!isValidData(data)) { if (!isValidData(data)) {
print("Validation Failed: Required fields are missing."); print("Validation Failed: Required fields are missing.");
setState(() {}); setState(() {});
return; // Stop execution if validation fails return; // Stop execution if validation fails
}else { } else {
widget.onSaveVisa(visaData); widget.onSaveVisa(visaData);
} }
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,
), ),
@ -218,7 +213,7 @@ class _VisaScreenState extends State<VisaScreen> {
}); });
} }
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),
@ -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,18 +490,19 @@ 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);
if (_dateController.text.isNotEmpty) { if (_dateController.text.isNotEmpty) {
setState(() { setState(() {
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,

View File

@ -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,18 +153,17 @@ 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;
String? selectedCostCenterId; String? selectedCostCenterId;
String? _selectedIsBillable ; String? _selectedIsBillable;
String? selectedFuncDept; String? selectedFuncDept;
String? selectedPurpose; String? selectedPurpose;
@ -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,
@ -177,7 +196,7 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
"created_by": selfId, "created_by": selfId,
"updated_by": selfId, "updated_by": selfId,
"is_active": "1", "is_active": "1",
"flight":flightList, "flight": flightList,
"accomodation": accommodationList, "accomodation": accommodationList,
"bus": busList, "bus": busList,
"taxi": taxiList, "taxi": taxiList,
@ -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) {
@ -237,11 +253,10 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
} }
@override @override
void initState(){ void initState() {
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,84 +287,84 @@ 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;
}else { } else {
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,17 +395,16 @@ 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');
} }
Future <Map<String,String>?> getUserDetails() async{ Future<Map<String, String>?> getUserDetails() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
final userData = prefs.getString('user_data'); final userData = prefs.getString('user_data');
if(userData!= null){ if (userData != null) {
final decodedData = jsonDecode(userData); final decodedData = jsonDecode(userData);
return { return {
@ -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');
} }
@ -472,11 +482,12 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
final data = json.decode(response.body); final data = json.decode(response.body);
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
setState(() { setState(() {
apiCostData = plansJson; // Store API response in state apiCostData = plansJson; // Store API response in state
// if(apiCostData!.isNotEmpty){ // if(apiCostData!.isNotEmpty){
@ -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';
@ -524,12 +534,12 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
final data = json.decode(response.body); final data = json.decode(response.body);
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) {
List<dynamic> plansJson = data['data']; List<dynamic> plansJson = data['data'];
@ -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');
} }
@ -554,13 +562,16 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
// Handle Submit // Handle Submit
bool validateForm(){ bool validateForm() {
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";
} }
} }
@ -581,7 +593,7 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
void handleSubmit() { void handleSubmit() {
setState(() { setState(() {
if(validateForm()){ if (validateForm()) {
print("Form submitted successfully: $planData"); print("Form submitted successfully: $planData");
postPlanData(planData); postPlanData(planData);
context.go('/listPlan'); context.go('/listPlan');
@ -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,29 +876,31 @@ 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;
}); });
}, },
items:apiCostData?.map<DropdownMenuItem<String>>((item){ items: apiCostData?.map<DropdownMenuItem<String>>((item) {
return DropdownMenuItem( return DropdownMenuItem(
value: item['department_id'], // ID as value value: item['department_id'], // ID as value
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(
@ -900,10 +916,12 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
Radio<String>( Radio<String>(
// value: item['dropdown_key'], // Use dropdown_value as value // value: item['dropdown_key'], // Use dropdown_value as value
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,10 +1011,12 @@ 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') {
_showInputDialog(option["title"]!); _showInputDialog(option["title"]!);
} }
}); });
@ -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,20 +1072,19 @@ 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
// } // }
@ -1076,67 +1094,70 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
List<dynamic> purposeList = apiData?['plan_purpose_of_travel'] ?? []; List<dynamic> purposeList = apiData?['plan_purpose_of_travel'] ?? [];
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'],
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'] ?? [];
List<DropdownMenuItem<String>> dropdownFuncDeptItems = funcDeptList List<DropdownMenuItem<String>> dropdownFuncDeptItems = funcDeptList
.map((item)=>DropdownMenuItem<String>( .map((item) => DropdownMenuItem<String>(
// 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,10 +1228,11 @@ 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),
decoration: InputDecoration( decoration: InputDecoration(
@ -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,12 +1260,10 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
SizedBox( SizedBox(
height: 15, height: 15,
), ),
] ]);
);
} }
Widget _buildDescriptionColumn(isDesktop) {
Widget _buildDescriptionColumn(isDesktop){
return Column( return Column(
children: [ children: [
Row( Row(
@ -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,
@ -1282,8 +1309,8 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
); );
} }
List<Widget> _buildSubmit(isDesktop){ List<Widget> _buildSubmit(isDesktop) {
return[ return [
ElevatedButton( ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.white, backgroundColor: Colors.white,
@ -1294,20 +1321,27 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
), ),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
), ),
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,22 +1349,22 @@ 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"),
), ),
) )
]; ];
} }
void _showInputDialog(String title){ void _showInputDialog(String title) {
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context){ builder: (BuildContext context) {
return UserSelectionDialog( return UserSelectionDialog(
title:title, title: title,
onSubmit: (input,userId,isTraveller){ onSubmit: (input, userId, isTraveller) {
setState(() { setState(() {
otherUserName = input; otherUserName = input;
selectedplanUserId = userId; selectedplanUserId = userId;
@ -1338,9 +1372,7 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
}); });
print("USer entered : $otherUserName $userId $isTraveller"); print("USer entered : $otherUserName $userId $isTraveller");
getSelectedPlanFor(); getSelectedPlanFor();
} });
); });
}
);
} }
} }

View File

@ -11,80 +11,87 @@ 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});
@override @override
_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
void initState(){ void initState() {
super.initState(); super.initState();
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');
if(userDataString != null){ if (userDataString != null) {
try{ try {
final Map<String,dynamic> userData = jsonDecode(userDataString); final Map<String, dynamic> userData = jsonDecode(userDataString);
return userData["user_id"]?.toString(); return userData["user_id"]?.toString();
}catch(e){ } catch (e) {
return null; return null;
} }
} }
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,8 +113,7 @@ 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");
// final token = await getToken(); // final token = await getToken();
@ -125,30 +131,26 @@ class _ListPlansState extends State<ListPlans>{
); );
if (response.statusCode == 200) { if (response.statusCode == 200) {
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>{
), ),
), ),
); );
}, },
), ),
], ],
), ),
); );
} }
} }

View File

@ -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!;
});
},
),
),
),
),
];
}
} }

View File

@ -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,22 +57,13 @@ 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(
children: [ children: [
Expanded( Expanded(
child: Container( child: Container(
// color:Colors.grey, // color: Colors.grey,
padding: padding:
const EdgeInsets.only(top: 5, bottom: 5, left: 5, right: 5), const EdgeInsets.only(top: 5, bottom: 5, left: 5, right: 5),
child: Column( child: Column(
@ -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!;
});
},
),
),
];
}
} }

View File

@ -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(

View File

@ -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);
},
),
),
], ],
), ),
), ),

View File

@ -5,21 +5,17 @@ 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;
Map<String, dynamic> userDetails = {}; Map<String, dynamic> userDetails = {};
@ -29,14 +25,12 @@ class _CustomDrawerState extends State<CustomDrawer>{
initializeData(); initializeData();
} }
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,29 +38,27 @@ 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");
} }
Future <Map<String,dynamic>?> getUserData() async { Future<Map<String, dynamic>?> getUserData() 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');
if(userDataString != null){ if (userDataString != null) {
try{ try {
userDetails = jsonDecode(userDataString); userDetails = jsonDecode(userDataString);
return{ return {
"user_id" : userDetails["user_id"].toString(), "user_id": userDetails["user_id"].toString(),
"name" : "${userDetails["first_name"]} ${userDetails["last_name"]}", "name": "${userDetails["first_name"]} ${userDetails["last_name"]}",
"email" : userDetails["email"] ?? "", "email": userDetails["email"] ?? "",
}; };
}catch (e) { } catch (e) {
print("Error decoding user data: $e"); print("Error decoding user data: $e");
return null; return null;
} }
@ -74,17 +66,16 @@ 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(
color: Color(0xFFF3F3FA), color: Color(0xFFF3F3FA),
child: Column( child: Column(
children: [ children: [
GestureDetector( GestureDetector(
onTap:(){ onTap: () {
print("ONTAP Custom"); print("ONTAP Custom");
print("ONTAP Custom- $userDetails ");
context.go( context.go(
"/CreateUserDetails", "/CreateUserDetails",
extra: { extra: {
@ -94,68 +85,70 @@ class _CustomDrawerState extends State<CustomDrawer>{
}, },
); );
}, },
child :SizedBox( child: SizedBox(
height: 80, height: 80,
child: Container( child: Container(
color: Color(0xFFF3F3FA), color: Color(0xFFF3F3FA),
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),
child: Container( child: Container(
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'), _buildExpandableItem(context, Icons.assessment, 'Plans', [
_buildExpandableItem(context,Icons.assessment,'Plans',[ _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(
_buildSubDrawerItem(context,'User List','/listUser'), context, Icons.account_circle_outlined, 'User ', [
_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')
]), ]),
_buildDrawerItem(context,Icons.logout,'Logout','/') _buildDrawerItem(context, Icons.logout, 'Logout', '/')
], ],
), ),
); );
@ -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,16 +196,13 @@ 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: () {
context.go(route); context.go(route);
if (!widget.isDesktop) Navigator.pop(context); if (!widget.isDesktop) Navigator.pop(context);
}, },
); );
} }
} }

View File

@ -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(),
), ),
], ],
); );

View File

@ -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';
@ -95,11 +93,12 @@ class ApiService {
final data = json.decode(response.body); final data = json.decode(response.body);
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
// setState(() { // setState(() {
// apiCostData = plansJson; // Store API response in state // apiCostData = plansJson; // Store API response in state
// if(apiCostData!.isNotEmpty){ // if(apiCostData!.isNotEmpty){
@ -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');
} }
} }
} }

View File

@ -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;
}

View File

@ -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),
), ),
] ]
: [], : [],

View File

@ -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),
), ),
] ]
: [], : [],

View File

@ -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"

View File

@ -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: