import 'dart:convert'; import 'package:google_fonts/google_fonts.dart'; 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 '../../services/apiService.dart'; import '../../utils/auth_utils.dart'; import '../../widgets/custom_text_traveller.dart'; class UserSelectionDialog extends StatefulWidget { final String title; final String? currentUser; final Color layoutColorForUser; final void Function(String, String, bool) onSubmit; final void Function() onClose; UserSelectionDialog({ Key? key, required this.title, required this.layoutColorForUser, required this.onSubmit, required this.onClose, required this.currentUser, }) : super(key: key); @override _UserSelectionDialogState createState() => _UserSelectionDialogState(); } class _UserSelectionDialogState extends State { final ApiService apiService = ApiService(); 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; String? orgId; final _formKey = GlobalKey(); Future getToken() async { final prefs = await SharedPreferences.getInstance(); return prefs.getString('auth_token'); } Future fetchUsers() async { orgId = await getOrgId(); // final String apiUrlData = '$apiUrl/api/users?org_id=$orgId'; final String apiUrldata = '$apiUrl/api/users?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', 'app-signature': 'ts-traveltool-2025-signature-123456', }, ); 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); _filterUsers(""); }); print("filtered user === ${_filteredUsers.length}"); print("Users fetched: ${_users.length}"); for (var user in _users) { print("${user.firstName} ${user.lastName} ${user.empCode}"); } } else { throw Exception( "Unexpected response format: Expected a List but got ${responseBody.runtimeType}", ); } } else if (response.statusCode == 403) { print("403-FORB"); await apiService.logout(context); return null; // throw Exception('Failed to load users'); } else { throw Exception( 'Failed to load users. Status Code: ${response.statusCode}', ); } } catch (e) { print("Error fetching users: $e"); } } Future 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', 'app-signature': 'ts-traveltool-2025-signature-123456', }, ); if (response.statusCode == 200) { final Map responseBody = json.decode(response.body); print("API Traveller 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); _filterTravellers(""); }); print("Users fetched: ${_users.length}"); for (var travvelr in _traveller) { print( "${travvelr.firstName} ${travvelr.lastName} ${travvelr.mobileNo}", ); } } else { throw Exception( "Unexpected response format: Expected a List but got ${responseBody.runtimeType}", ); } } else if (response.statusCode == 403) { print("403-FORB"); await apiService.logout(context); return null; // throw Exception('Failed to load users'); } else { throw Exception( 'Failed to load users. Status Code: ${response.statusCode}', ); } } catch (e) { print("Error fetching traveller: $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.empCode?.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 _filterUsers... ${_filteredUsers.length}"); setState(() { _filteredList.clear(); // Reset the list before filtering final excludedUserId = widget.currentUser.toString(); if (query.isEmpty) { // ✅ Return all users excluding self and roleId == 5 _filteredList = _users .where( (user) => user.userId.toString() != excludedUserId && user.roleId.toString() != "5", ) .map((user) => {"type": "user", "data": user}) .toList(); // _filteredList = [ // // ..._users.map((user) => {"type": "user", "data": user}), // ..._users // .where( // (user) => // (user.userId.toString() == excludedUserId && // user.roleId.toString() == "5"), // ) // ⛔ Exclude user ID 4 // .map((user) => {"type": "user", "data": user}), // ]; } else { _filteredList = [ ..._users .where((user) { print("usersLLL : ${user}"); if (user.userId.toString() == excludedUserId || user.roleId.toString() == "5") return false; List searchFields = [ "${user.firstName} ${user.lastName}".toLowerCase(), user.email.toLowerCase() ?? "", user.userId.toLowerCase() ?? "", user.mobileNo ?? "", user.alternateMobileNo ?? "", user.empCode?.toLowerCase() ?? "", ]; return searchFields.any( (field) => field.contains(query.toLowerCase()), ); }) .map((user) => {"type": "user", "data": user}), ]; } }); // setState(() { // print("Called 2.1"); // print("h1 - ${_filteredUsers}"); // if (query.isEmpty) { // _filteredList = _filteredUsers // .map((user) => {"type": "user", "data": user}) // .toList(); // } // // }); for (var item in _filteredList) { var user = item["data"]; print( "${item["type"].toUpperCase()} - ${user.firstName} ${user.lastName}", ); } } void _filterTravellers(String query) { print("Filtering _filterTravellers..."); setState(() { _filteredList.clear(); // Reset the list before filtering if (query.isEmpty) { _filteredList = _traveller .map((traveller) => {"type": "traveller", "data": traveller}) .toList(); // _filteredList = [ // ..._users.map((user) => {"type": "user", "data": user}), // ]; } else { _filteredList = [ ..._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}", ); } } void _filterByTitle(String query) { print("filtered by title"); if (widget.title == "Others (Non Employee)") { _filterTravellers(query); } else { _filterUsers(query); } } 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}", ); } } @override void initState() { super.initState(); if (widget.title == "Others (Non Employee)") { fetchTraveller(); } else { fetchUsers(); } print("SelffsdfcurrentUser - ${widget.currentUser}"); _filterByTitle(""); } @override Widget build(BuildContext context) { final isValid = _searchController.text.trim().isNotEmpty && userIdSelected.trim().isNotEmpty; 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: [ widget.title == "Others (Non Employee)" ? Text( "Please Select Other User", style: GoogleFonts.poppins(fontSize: 14), ) : Text( "Please Select Other Employee", style: GoogleFonts.poppins(fontSize: 14), ), SizedBox(height: 10), // Search Field TextField( controller: _searchController, onChanged: (query) { setState(() { _showTravellerForm = false; }); widget.title == "Others (Non Employee)" ? _filterTravellers(query) : _filterUsers(query); }, style: GoogleFonts.poppins(fontSize: 12), decoration: InputDecoration( hintText: "Search for a user", hintStyle: GoogleFonts.poppins( fontSize: 14, color: Colors.grey, ), prefixIcon: Icon(Icons.search), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), enabledBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.grey.shade200, width: 1), // borderSide: BorderSide(color: Color(0xFFF5F5F5), width: 2), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide(color: Colors.grey.shade200, width: 1), ), ), ), SizedBox(height: 10), if (widget.title == "Others (Non Employee)") ...[ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "or create a new traveller", style: GoogleFonts.poppins( fontSize: 14, color: Color(0xFF575A74), ), ), TextButton( onPressed: () { setState(() { _showTravellerForm = true; _searchController.clear(); }); }, child: Text( "Create", style: GoogleFonts.poppins( fontSize: 14, color: widget.layoutColorForUser, ), ), ), ], ), ], SizedBox(height: 5), // User List or Message // _searchController.text.isNotEmpty // ? if (!_showTravellerForm) SizedBox( height: 300, // Limit height to avoid overflow // child: _filteredUsers.isEmpty child: _filteredList.isEmpty ? Center( child: Text( "No users found", style: GoogleFonts.poppins( 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" if (user is Map) { print( "userLsirer - ${jsonEncode(user)}", ); // pretty JSON-like string } else { print("userLsirer - $user"); // fallback } final isSelected = userIdSelected == (userType == "user" ? user.userId : user.travellerId); return ListTile( // hoverColor: , title: Text( "${user.firstName ?? "Unknown"}" "${(user.lastName?.isNotEmpty ?? false) ? " ${user.lastName}" : ""}", style: GoogleFonts.poppins( fontSize: 11, color: isSelected ? widget.layoutColorForUser : Colors.black, ), ), subtitle: userType == "user" ? Text( "Employee ID: ${user.empCode ?? "-"} ", // "Employee ID: ${userType == "user" ? user.userId : user.travellerId}", style: GoogleFonts.poppins( fontSize: 10, color: isSelected ? widget.layoutColorForUser : Colors.black, ), ) : Text( "Mobile : ${user.mobileNo ?? "-"} ", // "Employee ID: ${userType == "user" ? user.userId : user.travellerId}", style: GoogleFonts.poppins( fontSize: 10, color: isSelected ? widget.layoutColorForUser : Colors.black, ), ), 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(), orgId: orgId, ), ), ), // Actions Row( mainAxisAlignment: MainAxisAlignment.end, children: [ ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.white, foregroundColor: widget.layoutColorForUser, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide( color: widget.layoutColorForUser, width: 2, ), ), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), ), onPressed: () { widget.onClose(); Navigator.pop(context); }, child: Text( "Cancel", style: GoogleFonts.poppins(fontSize: 11), ), ), SizedBox(width: 10), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: isValid ? widget.layoutColorForUser : Colors.grey, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide( // color: widget.layoutColorForUser, color: isValid ? widget.layoutColorForUser : Colors.grey, width: isValid ? 2 : 0, ), ), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), ), onPressed: isValid ? () { print( "Submitting: ${_searchController.text}, ID: $userIdSelected", ); widget.onSubmit( _searchController.text, userIdSelected, isTraveller, ); Navigator.pop(context); } : null, child: Text("Save", style: GoogleFonts.poppins(fontSize: 11)), ), ], ), ], ), ), ); } } class TravelerForm extends StatefulWidget { final TextEditingController firstNameController; final TextEditingController lastNameController; final TextEditingController emailController; final TextEditingController mobileController; final String? orgId; final GlobalKey formKey; final void Function(String, String, bool) onSubmit; TravelerForm({ required this.formKey, required this.orgId, required this.firstNameController, required this.lastNameController, required this.emailController, required this.mobileController, required this.onSubmit, }); @override _TravelerFormState createState() => _TravelerFormState(); } class _TravelerFormState extends State { final ApiService apiService = ApiService(); 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; } Future _onSubmit(BuildContext context) async { 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 = { "org_id": widget.orgId!, "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', 'app-signature': 'ts-traveltool-2025-signature-123456', }, body: jsonEncode(requestBody), ); if (response.statusCode == 200 || response.statusCode == 201) { final Map responseData = jsonDecode(response.body); if (responseData.containsKey("data")) { // Parse response print("responseData- $responseData "); 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); String fullName = "${firstName.trim()} ${lastName.trim()}"; widget.onSubmit(fullName, travellerId, true); // Close the dialog Navigator.pop(context); } ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( "Traveller added successfully!", style: GoogleFonts.poppins( color: Colors.white, ), // ✅ Set text color ), backgroundColor: Colors.green, ), ); } else if (response.statusCode == 403) { print("403-FORB"); await apiService.logout(context); return null; // throw Exception('Failed to load users'); } 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 Traveller", style: GoogleFonts.poppins(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: GoogleFonts.poppins(color: Colors.grey), ), ), TextButton( onPressed: () => _onSubmit(context), child: Text( "Add", style: GoogleFonts.poppins(color: Color(0xFF114D8B)), ), ), ], ), ], ), ); }, ); } 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, ), ]; } }