import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; import 'package:responsive_builder/responsive_builder.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../config/apiUrl.dart'; import '../../data/models/Searchtraveller.dart'; import '../../data/models/searchUser.dart'; import '../../widgets/custom_text_traveller.dart'; class UserSelectionDialog extends StatefulWidget{ final String title; final void Function(String,String, bool) onSubmit; UserSelectionDialog({Key? key, required this.title, required this.onSubmit,}) : super(key: key); @override _UserSelectionDialogState createState() => _UserSelectionDialogState(); } class _UserSelectionDialogState extends State{ TextEditingController _controller = TextEditingController(); TextEditingController _searchController = TextEditingController(); // List _filteredUsers = []; // List _users = []; List _users = []; List _traveller = []; List _filteredUsers = []; List> _filteredList = []; List _filteredTraveller = []; String userIdSelected = " "; bool isTraveller = false; bool _showTravellerForm = false; final _formKey = GlobalKey(); Future getToken() async { final prefs = await SharedPreferences.getInstance(); return prefs.getString('auth_token'); } Future fetchUsers() async { final String apiUrldata = '$apiUrl/api/users'; 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 responseBody = json.decode(response.body); print("API Response: $responseBody"); // Debugging if (responseBody.containsKey('data') && responseBody['data'] is List) { List userList = responseBody['data']; // Extract first name and last name correctly // setState(() { // _users = userList // .where((user) => user['first_name'] != null && user['last_name'] != null) // .map((user) => "${user['first_name']} ${user['last_name']}") // .toList(); // _filteredUsers = List.from(_users); // }); setState(() { _users = userList.map((user) => SearchUser.fromJson(user)).toList(); _filteredUsers = List.from(_users); }); print("Users fetched: ${_users.length}"); for (var user in _users) { print("${user.firstName} ${user.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 users: $e"); } } void _filterUsers1(String query) { print("Filtering users..."); setState(() { if (query.isEmpty) { _filteredUsers = List.from(_users); } else { _filteredUsers = _users.where((user) { List searchFields = [ "${user.firstName} ${user.lastName}".toLowerCase(), user.email.toLowerCase() ?? "", user.userId.toLowerCase() ?? "", user.mobileNo ?? "", user.alternateMobileNo ?? "" ]; return searchFields.any((field) => field.contains(query.toLowerCase())); }).toList(); } }); print("Filtered Users:"); for (var user in _filteredUsers) { print("${user.firstName} ${user.lastName}"); } } void _filterUsers(String query) { print("Filtering _filterUsersTravellers..."); setState(() { _filteredList.clear(); // Reset the list before filtering if (query.isEmpty) { _filteredList = [ ..._users.map((user) => {"type": "user", "data": user}), ]; } else { _filteredList = [ ..._users.where((user) { List searchFields = [ "${user.firstName} ${user.lastName}".toLowerCase(), user.email.toLowerCase() ?? "", user.userId.toLowerCase() ?? "", user.mobileNo ?? "", user.alternateMobileNo ?? "" ]; return searchFields.any((field) => field.contains(query.toLowerCase())); }).map((user) => {"type": "user", "data": user}), ]; } }); print("Filtered List:"); for (var item in _filteredList) { var user = item["data"]; print("${item["type"].toUpperCase()} - ${user.firstName} ${user.lastName}"); } } void _filterUsersTravellers(String query) { print("Filtering _filterUsersTravellers..."); setState(() { _filteredList.clear(); // Reset the list before filtering if (query.isEmpty) { _filteredList = [ ..._users.map((user) => {"type": "user", "data": user}), ..._traveller.map((traveller) => {"type": "traveller", "data": traveller}), ]; } else { _filteredList = [ ..._users.where((user) { List searchFields = [ "${user.firstName} ${user.lastName}".toLowerCase(), user.email.toLowerCase() ?? "", user.userId.toLowerCase() ?? "", user.mobileNo ?? "", user.alternateMobileNo ?? "" ]; return searchFields.any((field) => field.contains(query.toLowerCase())); }).map((user) => {"type": "user", "data": user}), ..._traveller.where((traveller) { List searchFields = [ "${traveller.firstName} ${traveller.lastName}".toLowerCase(), traveller.email.toLowerCase() ?? "", traveller.travellerId.toLowerCase() ?? "", traveller.mobileNo ?? "", ]; return searchFields.any((field) => field.contains(query.toLowerCase())); }).map((traveller) => {"type": "traveller", "data": traveller}), ]; } }); print("Filtered List:"); for (var item in _filteredList) { var user = item["data"]; print("${item["type"].toUpperCase()} - ${user.firstName} ${user.lastName}"); } } Future 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 responseBody = json.decode(response.body); print("API Response: $responseBody"); // Debugging if (responseBody.containsKey('data') && responseBody['data'] is List) { List 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 void initState() { super.initState(); fetchUsers(); fetchTraveller(); } @override Widget build(BuildContext context) { return Dialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), child: Container( color: Colors.white, width: 400, // Adjust width as needed padding: EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, // Ensures content doesn't expand unnecessarily children: [ Text("Please Select User", style: TextStyle(fontSize: 14)), SizedBox(height: 10), // Search Field TextField( controller: _searchController, onChanged: (query) { setState(() { _showTravellerForm = false; }); widget.title == "Others"? _filterUsersTravellers(query): _filterUsers(query); }, decoration: InputDecoration( hintText: "Search for a user", hintStyle: TextStyle(fontSize: 14), prefixIcon: Icon(Icons.search), border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide(color: Colors.blueAccent, width: 2), ), ), ), if (widget.title == "Others") ...[ SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text("or create a new traveler", style: TextStyle(fontSize: 14, color: Color(0xFF575A74))), TextButton( onPressed: () { setState(() { _showTravellerForm = true; _searchController.clear(); }); }, child: Text("Create", style: TextStyle(fontSize: 14, color: Colors.blueAccent)), ), ], ), ], SizedBox(height: 5), // User List or Message _searchController.text.isNotEmpty ? SizedBox( height: 300, // Limit height to avoid overflow // child: _filteredUsers.isEmpty child: _filteredList.isEmpty ? Center( child: Text( "No users found", style: TextStyle(fontSize: 14, color: Colors.grey), ), ) : ListView.builder( // itemCount: _filteredUsers.length, itemCount: _filteredList.length, itemBuilder: (context, index) { // final user = _filteredUsers[index]; final item = _filteredList[index]; final user = item["data"]; // Extract user object final userType = item["type"]; // "user" or "traveller" return ListTile( title: Text("${user.firstName ?? "Unknown"} ${user.lastName ?? ""}"), subtitle: Text("ID: ${userType == "user" ? user.userId : user.travellerId}"), onTap: () { String selectedUser = "${user.firstName ?? "Unknown"} ${user.lastName ?? ""}"; setState(() { _searchController.text = selectedUser; userIdSelected = userType == "user" ? user.userId : user.travellerId; isTraveller = userType == "traveller"; }); print("Selected: $selectedUser, ID: ${userType == "user" ? user.userId : user.travellerId}," " isTraveller: $userIdSelected"); }, ); }, ), ) : SizedBox.shrink(), // Traveler Form if (_showTravellerForm) Container( height: 300, // Set a defined height color: Color(0xFFF4F4FB), child: Padding( padding: const EdgeInsets.all(16.0), child: TravelerForm( formKey: _formKey, onSubmit: (String fullName, String travellerId, bool isTraveller) { widget.onSubmit(fullName, travellerId,isTraveller); // Pass the data up }, firstNameController: TextEditingController(), lastNameController: TextEditingController(), emailController: TextEditingController(), mobileController: TextEditingController(), ), ), ), // Actions Row( mainAxisAlignment: MainAxisAlignment.end, children: [ ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.white, foregroundColor: Colors.blueAccent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide(color: Colors.blueAccent, width: 2), ), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), ), onPressed: () => Navigator.pop(context), child: Text("Cancel",), ), SizedBox(width: 10), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.blueAccent, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide(color: Colors.blueAccent, width: 2), ), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), ), onPressed: () { print("Submitting: ${_searchController.text}, ID: $userIdSelected"); widget.onSubmit(_searchController.text,userIdSelected,isTraveller); Navigator.pop(context); }, child: Text("Submit"), ), ], ), ], ), ), ); } } class TravelerForm extends StatefulWidget { final TextEditingController firstNameController; final TextEditingController lastNameController; final TextEditingController emailController; final TextEditingController mobileController; final GlobalKey formKey; final void Function(String, String, bool) onSubmit; TravelerForm({ required this.formKey, required this.firstNameController, required this.lastNameController, required this.emailController, required this.mobileController, required this.onSubmit }); @override _TravelerFormState createState() => _TravelerFormState(); } class _TravelerFormState extends State { Future getToken() async { final prefs = await SharedPreferences.getInstance(); return prefs.getString('auth_token'); } bool _validateForm() { if (widget.formKey.currentState != null) { return widget.formKey.currentState!.validate(); } return false; // Return false when form is not initialized } String? validateMobile(String? value) { if (value == null || value.isEmpty) { return 'Mobile number is required'; } if (!RegExp(r'^[0-9]{10}$').hasMatch(value)) { return 'Enter a valid 10-digit mobile number'; } return null; } String? validateEmail(String? value) { if (value == null || value.isEmpty) { return 'Email is required'; } if (!RegExp(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$').hasMatch(value)) { return 'Enter a valid email address'; } return null; } void _onSubmit(BuildContext context) { bool isValid = _validateForm(); print("Form Validation Result: $isValid"); if (isValid) { print("Validation Success"); _submitForm(context); } else { print("Validation Failed"); // This should now print if validation fails } } Future _submitForm(BuildContext context) async { Map requestBody = { "first_name": widget.firstNameController.text, "last_name": widget.lastNameController.text, "email": widget.emailController.text, "mobile": widget.mobileController.text, }; String apiUrlData = '$apiUrl/api/travellers/create'; try { final token = await getToken(); if (token == null) { throw Exception('Token not found. Please log in.'); } print("response1"); var response = await http.post( Uri.parse(apiUrlData), headers: { 'Authorization': 'Bearer $token', 'Content-Type': 'application/json', }, body: jsonEncode(requestBody), ); if (response.statusCode == 200 || response.statusCode == 201) { if (response.statusCode == 200 || response.statusCode == 201) { final Map responseData = jsonDecode(response.body); // Parse response if (responseData["success"] == true && responseData.containsKey("data")) { final travellerData = responseData["data"]; String travellerId = travellerData["traveller_id"]; String firstName = travellerData["first_name"]; String lastName = travellerData["last_name"]; print("Traveller Added: ID: $travellerId, Name: $firstName $lastName"); // Pass data to callback widget.onSubmit("$firstName $lastName", travellerId, true); // Close the dialog Navigator.pop(context); } } ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( "Traveller added successfully!", style: TextStyle(color: Colors.white), // ✅ Set text color ), backgroundColor: Colors.green,), ); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("Error: ${response.body}")), ); } } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("Failed to connect to server.")), ); } } @override Widget build(BuildContext context) { return ResponsiveBuilder( builder: (context, sizingInfo) { double widthFactor; bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; if (sizingInfo.deviceScreenType == DeviceScreenType.desktop) { widthFactor = 0.23; } else if (sizingInfo.deviceScreenType == DeviceScreenType.tablet) { widthFactor = 0.8; } else { widthFactor = 1.0; } return Form( key: widget.formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Text("Create Traveler", style: TextStyle(color: Colors.black54)), SizedBox(height: 7), Expanded( child: SingleChildScrollView( scrollDirection: Axis.vertical, child: Column(children: _buildFormFirstRow(isDesktop)), ), ), SizedBox(height: 4), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ TextButton( onPressed: () { widget.formKey.currentState?.reset(); }, child: Text("Clear", style: TextStyle(color: Colors.grey)), ), TextButton( onPressed: () => _onSubmit(context), child: Text("Add", style: TextStyle(color: Colors.blueAccent)), ), ], ), ], ), ); }, ); } List _buildFormFirstRow(bool isDesktop) { return [ CustomTextField( controller: widget.firstNameController, labelText: "First Name", validator: (value) => value!.isEmpty ? "Enter first name" : null, ), SizedBox(height: 15), CustomTextField( controller: widget.lastNameController, labelText: "Last Name", validator: (value) => value!.isEmpty ? "Enter last name" : null, ), SizedBox(height: 15), CustomTextField( controller: widget.emailController, labelText: "Email", keyboardType: TextInputType.emailAddress, validator: validateEmail, ), SizedBox(height: 15), CustomTextField( controller: widget.mobileController, labelText: "Mobile Number", keyboardType: TextInputType.phone, validator: validateMobile, ), ]; } }