ts-tat/lib/Screens/userManagement/create_user/personal_details.dart
2025-10-30 16:31:33 +05:30

2053 lines
70 KiB
Dart

import 'dart:convert';
import 'dart:io' as html;
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';
import '../../../services/apiService.dart';
import '../../../utils/auth_utils.dart';
import '../../../widgets/custom_user_form.dart';
import '../../../config/apiUrl.dart';
import 'change_password.dart';
class PersonalDetails extends StatefulWidget {
final GlobalKey<PersonalDetailsState> personalDetailsKey;
final Map<String, TextEditingController> controllers;
final Map<String, String> errorMessages;
final bool isDesktop;
final bool isViewMode;
final bool apiselectedUser;
final bool isEditProfile;
final Function(List<Map<String, dynamic>>)? onServiceIdsChanged;
final ValueChanged<String?>? onGenderChanged;
final ValueChanged<String?>? onCountryChanged;
final ValueChanged<String?>? onRoleChanged;
final void Function(bool)? onUserTypeChanged;
final List<Map<String, dynamic>>? initialSelectedServices;
final String? selectedGender;
final String? selectedCountry;
final String? selectedRole;
final String? userIdApi;
final dynamic focusNodes;
// const PersonalDetails(this.isDesktop, this.isViewMode, {super.key},);
const PersonalDetails({
Key? key,
this.selectedGender,
this.selectedCountry,
this.selectedRole,
this.onServiceIdsChanged,
required this.personalDetailsKey,
this.initialSelectedServices,
required this.controllers,
required this.errorMessages,
required this.isDesktop,
required this.isViewMode,
required this.apiselectedUser,
this.focusNodes,
this.onGenderChanged,
this.onCountryChanged,
this.onRoleChanged,
this.onUserTypeChanged,
this.userIdApi,
required this.isEditProfile,
}) : super(key: key);
@override
PersonalDetailsState createState() => PersonalDetailsState();
}
class PersonalDetailsState extends State<PersonalDetails> {
final ApiService apiService = ApiService();
late Map<String, String> countryMap; // Mapping country_code -> country_name
late List<String> countryCodes; // List of country codes
late List<dynamic>? apiCountryData;
late List<dynamic>? apiRoleData;
List<dynamic>? apiAllServices;
Map<String, dynamic>? selectedOrg;
List<Map<String, dynamic>> selectedServiceIds = [];
String? get selectedGenderValue => selectedGender;
String? get selectedCountryValue => selectedCountry;
String? get selectedRoleValue => selectedRole;
final FocusNode _fnameFocusNode = FocusNode();
final FocusNode _lnameFocusNode = FocusNode();
final FocusNode _emailFocusNode = FocusNode();
final FocusNode _passwordFocusNode = FocusNode();
final FocusNode _dobFocusNode = FocusNode();
final FocusNode _genderFocusNode = FocusNode();
final FocusNode _mobileNumberFocusNode = FocusNode();
final FocusNode _alternateMobileFocusNode = FocusNode();
final FocusNode _addressFocusNode = FocusNode();
final FocusNode _countryFocusNode = FocusNode();
final FocusNode _postalCodeFocusNode = FocusNode();
final FocusNode _roleIdFocusNode = FocusNode();
bool _fnameFocus = false;
bool _lnameFocus = false;
bool _emailFocus = false;
bool _passwordFocus = false;
bool _dobFocus = false;
bool _genderFocus = false;
bool _mobileNumberFocus = false;
bool _alternateMobileFocus = false;
bool _addressFocus = false;
bool _countryFocus = false;
bool _postalCodeFocus = false;
bool _roleIdFocus = false;
late bool isTravelAgent = false;
String? selectedTab;
String? selectedCountry;
String? selectedGender;
String? selectedUserType;
String? selectedRole;
String? selectedLevel;
String? selectedDepartment;
String? selectedFirstApprover;
String? selectedSecondApprover;
String? selectedThirdApprover;
String? selectedFileNames;
Uint8List? passportDocumentBytes;
String? passportFileUrlFromApi;
String? base64PDF;
html.File? passportFile;
List<String> dataHeader = [
"Fname",
"Lname",
"email",
"password",
"dob",
"gender",
"mobileNumber",
"alternateMobile",
"address",
"postalCode",
"country",
"passportNumber",
"placeOfIssue",
"passportDoc",
"userType",
"roleId",
"deptId",
"levelId",
"firstApproval",
"secondApproval",
"thirdApproval",
"employeeCode",
"dateOfIssue",
"dateOfExpiry",
"changePassword",
];
Color? layoutColor;
Color? bodyColor;
final Map<String, TextEditingController> controllers = {};
Map<String, String> errorMessages = {};
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
});
apiCountryData = null;
apiRoleData = null;
selectedGender = widget.selectedGender;
selectedCountry = widget.selectedCountry;
selectedRole = widget.selectedRole;
fetchRoles();
fetchCountries();
selectedServiceIds = List<Map<String, dynamic>>.from(
widget.initialSelectedServices ?? [],
);
print("selectedServiceIdsAPI - $selectedServiceIds");
_addFocusListener(_fnameFocusNode, (focus) => _fnameFocus = focus);
_addFocusListener(_lnameFocusNode, (focus) => _lnameFocus = focus);
_addFocusListener(_emailFocusNode, (focus) => _emailFocus = focus);
_addFocusListener(_passwordFocusNode, (focus) => _passwordFocus = focus);
_addFocusListener(_dobFocusNode, (focus) => _dobFocus = focus);
_addFocusListener(_genderFocusNode, (focus) => _genderFocus = focus);
_addFocusListener(
_mobileNumberFocusNode,
(focus) => _mobileNumberFocus = focus,
);
_addFocusListener(
_alternateMobileFocusNode,
(focus) => _alternateMobileFocus = focus,
);
_addFocusListener(_addressFocusNode, (focus) => _addressFocus = focus);
_addFocusListener(_countryFocusNode, (focus) => _countryFocus = focus);
_addFocusListener(
_postalCodeFocusNode,
(focus) => _postalCodeFocus = focus,
);
_addFocusListener(_roleIdFocusNode, (focus) => _roleIdFocus = focus);
WidgetsBinding.instance.addPostFrameCallback((_) {
loadAllServices();
getOrganizationData();
loadInitialData();
_fnameFocusNode.requestFocus();
});
}
void _addFocusListener(FocusNode node, Function(bool) updateState) {
node.addListener(() {
setState(() {
updateState(node.hasFocus);
});
});
}
Future<void> apiCheckDuplicate(
String label,
String field,
String value,
String? userId,
) async {
try {
// Basic validation: Check mobile number length
if (field == "mobile_no" && value.length != 10) {
_clearError(field);
widget.errorMessages[field] = "$label is invalid";
print("Validation failed: $label is too short.");
// widget.controllers["mobileNumber"]?.clear();
final controller = widget.controllers["mobileNumber"];
if (controller != null) {
print("Before clear: ${controller.text}");
// controller.clear();
print("After clear: ${controller.text}");
}
// Make sure this setState rebuilds the widget that owns the TextField!
if (mounted) setState(() {});
// setState(() {});
return; // Skip the API call if input is invalid
}
final response = await apiService.CheckDuplicate(
context,
label,
field,
value,
userId,
);
if (response.isNotEmpty) {
// _clearError(field);
widget.errorMessages[field] =
response['message'] ?? "$label already exists";
print("Duplicate found: ${response['message']}");
return;
} else {
_clearError(field);
print("No duplicates found.");
}
} catch (e) {
print("Error in checkDuplicate: $e");
}
}
void _clearError(String field) {
setState(() {
widget.errorMessages.remove(field);
});
}
void loadInitialData() async {
String? layoutString = await getLayoutColor();
String? bodyStringColor = await getBodyColor();
setState(() {
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
bodyColor =
bodyStringColor != null
? Color(int.parse(bodyStringColor))
: Colors.white;
});
}
Future<void> fetchRoles() async {
try {
final response = await apiService.fetchMasterDropdown(context);
if (response is Map<String, dynamic> && response.containsKey("role")) {
List<dynamic> roleList = response["role"]; // Extract the list
if (!mounted) return;
setState(() {
apiRoleData = roleList;
});
print("APIROLEData - $apiRoleData");
} else {
print("Error: 'role' key not found or response is not a Map.");
}
} catch (e) {
print('Error fetching role list: $e');
}
}
Future<void> fetchCountries() async {
try {
List<dynamic> countries = await apiService.fetchCountryList(context);
setState(() {
apiCountryData = countries;
});
} catch (e) {
print('Error fetching country list: $e');
}
}
Future<void> getOrganizationData() async {
try {
print("getUpdatedServices");
final result = await apiService.fetchOrganization(context);
print("UUPdatedServices - $result");
setState(() {
final servicesRaw = selectedOrg?['services_ids'];
List<dynamic> services;
if (servicesRaw is String) {
try {
services = jsonDecode(servicesRaw);
} catch (e) {
print('❌ Failed to decode services_ids: $e');
services = [];
}
} else if (servicesRaw is List) {
services = servicesRaw;
} else {
services = [];
}
if (selectedServiceIds.isEmpty && services.isNotEmpty) {
selectedServiceIds =
services.map<Map<String, dynamic>>((item) {
final map = Map<String, dynamic>.from(item);
return {"service_id": map['service_id'].toString()};
}).toList();
}
// selectedServiceIds = services.map<Map<String, dynamic>>((item) {
// // force cast or copy to a regular map
// final map = Map<String, dynamic>.from(item);
// return {
// "service_id": map['service_id'].toString(),
// };
// }).toList();
});
// orgId = await getOrgId();
print("selectedOrg - $selectedOrg");
} catch (e) {
print('Error fetching updatedServices list: $e');
}
}
@override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: Colors.blueGrey.shade300, // Set your desired color
width: 0.09, // Set border thickness
),
),
),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 20),
// _buildPassportDataRow1(widget.isDesktop),
// SizedBox(height: 10),
_buildFirstRow(widget.isDesktop),
SizedBox(height: 10),
_buildSecondRow(widget.isDesktop),
SizedBox(height: 10),
_buildThirdRow(widget.isDesktop),
SizedBox(height: 10),
_buildForthRow(widget.isDesktop),
SizedBox(height: 10),
if (selectedRole == "5") _buildServices(widget.isDesktop),
],
),
),
);
}
Widget _buildPassportDataRow1(bool isDesktop) {
return Container(
color: Colors.white,
child: Row(
children: [
Text(
"* Please fill name details as per in passport *",
style: GoogleFonts.poppins(
fontSize: 10,
color: Colors.black87,
fontStyle: FontStyle.italic,
letterSpacing: 0.5,
),
),
],
),
);
}
Future<void> loadAllServices() async {
try {
final result = await apiService.fetchAllServices(context);
setState(() {
// apiAllServices = result;
setState(() {
apiAllServices =
result
..sort((a, b) => (a['order'] ?? 0).compareTo(b['order'] ?? 0));
});
});
print("Fetched services: $apiAllServices");
} catch (e) {
print('Error fetching role list: $e');
}
}
Widget _buildServices(bool isDesktop) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Services",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Colors.black,
),
// style: TextStyle(
// fontFamily: "Archivo",
// fontSize: 14,
// fontWeight: FontWeight.w600,
// color: Color(0xFF212121)),
),
SizedBox(height: 10),
Container(
decoration: BoxDecoration(
border: Border.all(color: Color(0xFFF4F4FB)),
borderRadius: BorderRadius.circular(1),
// color: bodyColor,
// color: Color(0xFFF5F5F5),
color: Colors.white,
),
padding: EdgeInsets.only(left: 5, right: 5, top: 15, bottom: 5),
child:
isDesktop
? Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
// mainAxisSize: MainAxisSize.min,
children: _buildOptions(),
)
: Expanded(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(children: _buildOptions()),
),
),
),
],
);
}
List<Widget> _buildOptions() {
if (apiAllServices == null) return [];
return apiAllServices!.map((service) {
return Padding(
padding: const EdgeInsets.only(right: 20.0),
child: _buildOption(service),
);
}).toList();
}
Widget _buildOption(Map<String, dynamic> service) {
String name = service['name'];
String iconUrl = service['icon']; // Can be empty string
IconData fallbackIcon = _getLocalIconForService(name);
String serviceId = service['service_id'].toString();
// bool isSelected = selectedServiceIds.contains(serviceId);
bool isSelected = selectedServiceIds.any(
(item) => item["service_id"] == serviceId,
);
return GestureDetector(
onTap: () {
setState(() {
String serviceId = service['service_id'].toString();
// Check if already selected
int existingIndex = selectedServiceIds.indexWhere(
(item) => item["service_id"] == serviceId,
);
if (existingIndex != -1) {
selectedServiceIds.removeAt(existingIndex);
} else {
selectedServiceIds.add({"service_id": serviceId});
}
print("selectedServiceIdsUser --- $selectedServiceIds");
print(
"selectedServiceIdsUser1 --- ${json.encode(selectedServiceIds)}",
);
// Call the parent's callback
widget.onServiceIdsChanged!(selectedServiceIds);
// widget.onServiceIdsChanged!(selectedServiceIds);
});
},
child: Row(
children: [
iconUrl.isNotEmpty
? Image.network(
iconUrl,
width: 18,
height: 18,
errorBuilder: (context, error, stackTrace) {
return Icon(
fallbackIcon,
size: 18,
color:
isSelected == name
? Color(0xFF114D8B)
: Color(0xFF475569),
);
},
)
: Icon(
fallbackIcon,
size: 18,
color:
isSelected == name ? Color(0xFF114D8B) : Color(0xFF475569),
),
SizedBox(width: 5),
SizedBox(width: 5),
Text(
name,
style: GoogleFonts.poppins(
fontSize: 12,
color: isSelected == name ? Color(0xFF114D8B) : Color(0xFF475569),
fontWeight:
isSelected == name ? FontWeight.bold : FontWeight.w500,
),
// style: TextStyle(
// fontSize: 13,
// color: isSelected == name ? Color(0xFF114D8B) : Color(0xFF475569),
// fontFamily: "Archivo",
// fontWeight:
// isSelected == name ? FontWeight.bold : FontWeight.w500),
// fontWeight: selectedListOption == title ? FontWeight.bold : FontWeight.normal,)),
),
SizedBox(width: 5),
// if (selectedListOption == title && widget.isViewMode == false)
Container(
height: 15,
width: 15,
decoration: BoxDecoration(
shape: BoxShape.rectangle,
border: Border.all(
color: isSelected ? Colors.green : Colors.grey.shade400,
width: isSelected ? 2 : 1,
),
),
child: Icon(
Icons.check,
size: 10,
color: isSelected ? Colors.green : Colors.white10,
// color: Colors.grey,
),
),
],
),
);
}
IconData _getLocalIconForService(String name) {
switch (name.toLowerCase()) {
case 'flight':
return Icons.flight_takeoff_outlined;
case 'train':
return Icons.train_outlined;
case 'bus':
return Icons.directions_bus;
case 'taxi':
return Icons.local_taxi_outlined;
case 'accomodation':
return Icons.local_hotel_outlined;
case 'forex':
return Icons.attach_money_outlined;
case 'insurance':
return Icons.list_alt_outlined;
case 'visa':
return Icons.badge_outlined;
case 'miscellaneous':
return Icons.card_giftcard_outlined;
default:
return Icons.circle_notifications;
}
}
Widget _buildFirstRow(bool isDesktop) {
return Container(
color: Colors.white,
child:
widget.isDesktop
? Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildFirstNameField(),
Spacer(),
buildLastNameField(),
Spacer(), // Space after Last Name
buildGenderField(),
SizedBox(width: 15),
buildDobField(),
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildFirstNameField(),
SizedBox(height: 8), // Vertical space
buildLastNameField(),
SizedBox(height: 8),
buildGenderField(),
SizedBox(height: 8),
buildDobField(),
],
),
);
}
Widget _buildSecondRow(bool isDesktop) {
return Container(
color: Colors.white,
child:
widget.isDesktop
? Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildEmailField(),
Spacer(),
buildMobileField(),
Spacer(), // Space after Last Name
buildAlternateMobileField(),
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildMobileField(),
SizedBox(height: 8), // Vertical space
buildAlternateMobileField(),
SizedBox(height: 8),
buildEmailField(),
],
),
);
}
Widget _buildThirdRow(bool isDesktop) {
void _openPopup() {
final emailValue = widget.controllers["email"]?.text ?? "";
final updaterUserId = widget.userIdApi ?? "";
showDialog(
context: context,
builder: (context) {
return ChangePasswordDialogData(
updaterEmail: emailValue,
updaterUserId: updaterUserId,
layoutColor: layoutColor,
isDesktop: widget.isDesktop,
);
},
);
}
return Container(
color: Colors.white,
child:
isDesktop
? !widget.apiselectedUser
? Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (!widget.apiselectedUser) ...[
buildPassword(),
SizedBox(
width: MediaQuery.of(context).size.width * 0.015,
),
buildRole(),
] else ...[
// TextButton(
// onPressed: () => _openPopup(),
// style: TextButton.styleFrom(
// foregroundColor: Colors.black,
// textStyle: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w400,
// ),
// ),
// child: Text("Change Password"),
// ),
//
// SizedBox(height: 8, width: 15),
// buildRole(),
],
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width:
isDesktop
? MediaQuery.of(context).size.width * 0.25
: MediaQuery.of(context).size.width * 0.8,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () => _openPopup(),
style: TextButton.styleFrom(
foregroundColor: Color(0xFF114D8B),
textStyle: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
child: Text("Change Password"),
),
],
),
),
SizedBox(height: 1),
buildRole(),
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (!widget.apiselectedUser) ...[
buildPassword(),
SizedBox(height: 8),
buildRole(),
] else ...[
Container(
width:
isDesktop
? MediaQuery.of(context).size.width * 0.25
: MediaQuery.of(context).size.width * 0.8,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () => _openPopup(),
style: TextButton.styleFrom(
foregroundColor: Color(0xFF114D8B),
textStyle: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
child: Text("Change Password"),
),
],
),
),
SizedBox(height: 1),
buildRole(),
],
],
),
);
}
Widget _buildForthRow(bool isDesktop) {
return Container(
color: Colors.white,
child:
isDesktop
? Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildAddress(),
Spacer(),
// SizedBox(width: 15),
buildCountryField(),
Spacer(),
// SizedBox(width: 15),
buildPostalCodeField(),
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildAddress(),
SizedBox(height: 8), //
buildCountryField(),
SizedBox(height: 8), // Vertical space
buildPostalCodeField(),
],
),
);
}
Widget buildFirstNameField() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"First Name *",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldUserWrapper(
isFocused: _fnameFocus,
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// focusNode: focusNodes["FnameFocusNode"],
focusNode: _fnameFocusNode, // 👈 Use it here
controller: widget.controllers["Fname"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
autofocus: true,
enabled: !widget.isViewMode,
onChanged: (value) {
_clearError("first_name");
},
decoration: InputDecoration(
labelText: "FirstName",
labelStyle: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w400,
color: Colors.grey,
),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
),
if (widget.errorMessages["first_name"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
widget.errorMessages["first_name"]!,
style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
),
],
],
);
}
Widget buildLastNameField() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Last Name*",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldUserWrapper(
isFocused: _lnameFocus,
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
style: TextStyle(fontSize: 12, color: Colors.black),
focusNode: _lnameFocusNode,
autofocus: true,
controller: widget.controllers["Lname"],
enabled: !widget.isViewMode,
onChanged: (value) {
_clearError("last_name");
},
decoration: InputDecoration(
labelText: "LastName",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
),
if (widget.errorMessages["last_name"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
widget.errorMessages["last_name"]!,
style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
),
],
],
);
}
// Widget buildGenderFieldOld() {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// "Gender",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Color(0xFF575A74),
// ),
// ),
// SizedBox(height: 5),
// CustomTextFieldUserWrapper(
// width:
// widget.isDesktop
// ? MediaQuery.of(context).size.width * 0.12
// : null,
// isFocused: false,
// isDesktop: widget.isDesktop,
// child: SizedBox(
// height: 40,
// child: DropdownButtonFormField<String>(
// // value: selectedGender,
// value: widget.isViewMode ? null : selectedGender,
// onChanged:
// widget.isViewMode
// ? null
// : (String? newValue) {
// setState(() {
// selectedGender = newValue;
// print("selectedGender - $selectedGender");
// });
//
// widget.onGenderChanged?.call(newValue);
// },
// decoration: InputDecoration(
// border: InputBorder.none,
// enabled: !widget.isViewMode, // Disables input when in view mode
// ),
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// items: [
// DropdownMenuItem(value: "Male", child: Text("Male")),
// DropdownMenuItem(value: "Female", child: Text("Female")),
// ],
// hint: Text(
// selectedGender ?? "Select Gender",
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// ),
// disabledHint: Text(
// selectedGender ?? "Select Gender",
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// ),
// ),
//
// // child: DropdownSearch<String>(
// // selectedItem: selectedGender,
// // // key: ValueKey(selectedGender),
// // popupProps: PopupProps.menu(
// // fit: FlexFit.loose, // Allows flexible height
// // constraints: BoxConstraints(maxHeight: 250),
// //
// // ),
// // items: ["Male", "Female", "Others"],
// // dropdownDecoratorProps: DropDownDecoratorProps(
// // dropdownSearchDecoration: InputDecoration(
// // border: InputBorder.none,
// // contentPadding: EdgeInsets.symmetric(horizontal: 1,),
// // ),
// // ),
// // dropdownBuilder: (context, selectedItem) => Align( // Center-align selected item
// // alignment: Alignment.centerLeft,
// // child: Text(
// // selectedItem ?? "Select",
// // style: TextStyle(fontSize: 12),
// // ),
// // ),
// // onChanged: isViewMode
// // ? null
// // : (String? newValue) {
// // setState(() {
// // // Find the country_code based on selected country_name
// // selectedGender = newValue;
// // print("selectedGender - $selectedGender");
// // // if (selectedCountry!.isNotEmpty) {
// // // errorMessages.remove("country_code");
// // // }
// // });
// // },
// //
// //
// // ),
// ),
// ),
// ],
// );
// }
Widget buildGenderField() {
List<String> genderOptions = ["Male", "Female"];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Gender",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldUserWrapper(
width:
widget.isDesktop
? MediaQuery.of(context).size.width * 0.12
: null,
isFocused: _genderFocus,
padding: const EdgeInsets.symmetric(horizontal: 0),
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
child: Focus(
focusNode: _genderFocusNode,
onFocusChange: (hasFocus) {
setState(() {
_genderFocus = hasFocus;
});
},
child: GestureDetector(
onTap: () {
_genderFocusNode?.requestFocus();
},
child: DropdownSearch<String>(
selectedItem: selectedGender,
enabled: !widget.isViewMode,
popupProps: PopupProps.menu(
showSearchBox: false, // Set true if you want search
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 200),
itemBuilder:
(context, item, isSelected) => Container(
color: Colors.white,
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(fontSize: 11.5),
),
),
),
items: genderOptions,
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: BorderSide(
color:
(_genderFocus)
? (layoutColor ?? Colors.blue)
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_genderFocus)
? (layoutColor ?? Colors.blue)
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: (layoutColor ?? Colors.grey),
width: 0.5,
),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
// vertical: 1,
),
// contentPadding: EdgeInsets.symmetric(horizontal: 1),
),
),
dropdownBuilder:
(context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select Gender",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
),
onChanged:
widget.isViewMode
? null
: (String? newValue) {
setState(() {
selectedGender = newValue;
print("selectedGender - $selectedGender");
});
widget.onGenderChanged?.call(newValue);
},
),
),
),
),
),
],
);
}
Widget buildDobField() {
DateTime? _selectedDateOfBirth;
Future<void> _selectCheckDateOfBirth(BuildContext context) async {
DateTime now = DateTime.now();
DateTime today = DateTime(now.year, now.month, now.day);
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate:
_selectedDateOfBirth != null && _selectedDateOfBirth!.isAfter(today)
? _selectedDateOfBirth!
: today,
firstDate: DateTime(1900),
// lastDate: DateTime(2100),
lastDate: today,
initialEntryMode: DatePickerEntryMode.calendarOnly,
);
if (pickedDate != null && pickedDate != _selectedDateOfBirth) {
setState(() {
_selectedDateOfBirth = pickedDate;
widget.controllers["dob"]?.text = DateFormat(
'dd-MM-yyyy',
).format(pickedDate);
});
}
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Date of Birth",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldUserWrapper(
width:
widget.isDesktop
? MediaQuery.of(context).size.width * 0.12
: null,
isFocused: _dobFocus,
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
child: Focus(
focusNode: _dobFocusNode,
onKeyEvent: (FocusNode node, KeyEvent event) {
// Only act on KeyDown and when Enter is pressed
if (event is KeyDownEvent &&
(event.logicalKey == LogicalKeyboardKey.enter ||
event.logicalKey == LogicalKeyboardKey.numpadEnter)) {
if (!widget.isViewMode) {
_selectCheckDateOfBirth(context).then((_) {
if (widget.controllers["dob"]!.text.isNotEmpty) {
Future.delayed(Duration(milliseconds: 100), () {
_dobFocusNode?.requestFocus();
});
}
});
}
return KeyEventResult.handled; // Stop default behavior
}
return KeyEventResult.ignored; // Allow normal handling
},
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTapDown: (details) {
if (!widget.isViewMode) {
_selectCheckDateOfBirth(context).then((_) {
if (widget.controllers["dob"]!.text.isNotEmpty) {
Future.delayed(Duration(milliseconds: 100), () {
_dobFocusNode?.requestFocus();
});
}
});
}
},
child: AbsorbPointer(
child: TextField(
controller: widget.controllers["dob"],
readOnly: true,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
decoration: InputDecoration(
labelText: "Select Date",
labelStyle: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w400,
color: Colors.grey,
),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
suffixIcon: Icon(
Icons.calendar_today,
size: 16,
color: Color(0xFF8B8FB2),
),
),
),
),
),
),
// GestureDetector(
// onTap:
// widget.isViewMode
// ? null
// : () async {
// await _selectCheckDateOfBirth(context);
// if (widget.controllers["dob"]!.text.isNotEmpty) {
// setState(() {
// // errorMessages.remove("start_date");
// });
// // Delay re-focusing the DOB field slightly
// Future.delayed(Duration(milliseconds: 100), () {
// _dobFocusNode?.requestFocus();
// });
// }
// },
// child: AbsorbPointer(
// child: TextField(
// controller: widget.controllers["dob"],
// focusNode:_dobFocusNode,
// readOnly: true,
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// decoration: InputDecoration(
// labelText: "Select Date",
// labelStyle: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w400,
// color: Colors.grey,
// ),
// floatingLabelBehavior: FloatingLabelBehavior.never,
// border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(vertical: 16),
// suffixIcon: Icon(
// Icons.calendar_today,
// size: 16,
// color: Color(0xFF8B8FB2),
// ),
// ),
// ),
// ),
// ),
),
),
],
);
}
Widget buildEmailField() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Email *",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldUserWrapper(
isFocused: _emailFocus,
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
focusNode: _emailFocusNode,
autofocus: true,
controller: widget.controllers["email"],
onChanged: (value) {
_clearError("email");
apiCheckDuplicate("Email", "email", value, widget.userIdApi);
},
enabled: !widget.isViewMode,
decoration: InputDecoration(
labelText: "Email",
labelStyle: GoogleFonts.poppins(
fontSize: 12,
color: Colors.grey,
),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
),
if (widget.errorMessages["email"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
widget.errorMessages["email"]!,
style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
),
],
],
);
}
Widget buildMobileField() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Mobile Number *",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldUserWrapper(
isFocused: _mobileNumberFocus,
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
focusNode: _mobileNumberFocusNode,
autofocus: true,
controller: widget.controllers["mobileNumber"],
enabled: !widget.isViewMode,
onChanged: (value) {
_clearError("mobile_no");
apiCheckDuplicate(
"Mobile Number",
"mobile_no",
value,
widget.userIdApi,
);
},
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'^\d*\.?\d*$'),
), // Allow only positive numbers with optional decimal
],
decoration: InputDecoration(
labelText: "Mobile Number",
labelStyle: GoogleFonts.poppins(
fontSize: 12,
color: Colors.grey,
),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
),
if (widget.errorMessages["mobile_no"] != null) ...[
// Builder(
// builder: (context) {
// WidgetsBinding.instance.addPostFrameCallback((_) {
// widget.controllers["mobileNumber"]?.clear();
// });
// return const SizedBox.shrink();
// },
// ),
SizedBox(height: 5), // Space before error message
Text(
widget.errorMessages["mobile_no"]!,
style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
),
],
],
);
}
Widget buildAlternateMobileField() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Alternate Mobile Number",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldUserWrapper(
isFocused: _alternateMobileFocus,
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
focusNode: _alternateMobileFocusNode,
autofocus: true,
controller: widget.controllers["alternateMobile"],
enabled: !widget.isViewMode,
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'^\d*\.?\d*$'),
), // Allow only positive numbers with optional decimal
],
decoration: InputDecoration(
labelText: "Alternate Number",
labelStyle: GoogleFonts.poppins(
fontSize: 12,
color: Colors.grey,
),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
),
if (widget.errorMessages["alternate_mobile_no"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
widget.errorMessages["alternate_mobile_no"]!,
style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
),
],
],
);
}
Widget buildCountryField() {
late Map<String, String> countryMap; // Mapping country_code -> country_name
late List<String> countryCodes; // List of country codes
List<dynamic> countryList = apiCountryData ?? [];
countryList = apiCountryData ?? [];
// Map country codes to country names
// countryMap = {
// for (var item in countryList)
// item['country_code'] as String: item['country_name'] as String,
// };
countryMap = {
for (var country in countryList)
(country['country_code'] ?? ''):
'${country['country_name'] ?? ''} (${country['country_code'] ?? ''})',
};
// Extract only country codes for processing
countryCodes = countryMap.keys.toList();
selectedCountry ??= null;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Country",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldUserWrapper(
isFocused: _countryFocus,
padding: const EdgeInsets.symmetric(horizontal: 0),
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
width: double.infinity,
child: Focus(
focusNode: _countryFocusNode,
onFocusChange: (hasFocus) {
setState(() {
_countryFocus = hasFocus;
});
},
child: GestureDetector(
onTap: () {
// Request focus when user taps
_countryFocusNode?.requestFocus();
},
child: DropdownSearch<String>(
selectedItem: countryMap[selectedCountry],
enabled: !widget.isViewMode,
popupProps: PopupProps.menu(
showSearchBox: true, // Enables search functionality
fit: FlexFit.loose, // Allows flexible height
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder:
(context, item, isSelected) => Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(fontSize: 11.5),
),
),
constraints: BoxConstraints(maxHeight: 180),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search Country...",
contentPadding: EdgeInsets.symmetric(
horizontal: 3,
vertical: 3,
),
),
),
),
items: countryMap.values.toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(horizontal: 1),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(
color:
(_countryFocus)
? (layoutColor ?? Colors.blue)
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_countryFocus)
? (layoutColor ?? Colors.blue)
: Colors.white,
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: (layoutColor ?? Colors.grey),
width: 0.5,
),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 8.0,
),
),
),
dropdownBuilder:
(context, selectedItem) => Align(
// Center-align selected item
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select Country",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
),
// onChanged: widget.isViewMode
// ? null
// : (String? newValue) {
// setState(() {
// // Find the country_code based on selected country_name
// selectedCountry = countryMap.entries
// .firstWhere((entry) => entry.value == newValue)
// .key;
//
// // if (selectedCountry!.isNotEmpty) {
// // errorMessages.remove("country_code");
// // }
// });
// widget.onCountryChanged?.call(newValue);
// },
onChanged:
widget.isViewMode
? null
: (String? newValue) {
if (newValue == null) return;
final countryCode =
countryMap.entries
.firstWhere(
(entry) => entry.value == newValue,
)
.key;
setState(() {
selectedCountry = countryCode;
});
widget.onCountryChanged?.call(
countryCode,
); // ✅ send code not name
},
),
),
),
),
),
],
);
}
Widget buildPostalCodeField() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Postal Code",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldUserWrapper(
isFocused: _postalCodeFocus,
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
child: TextField(
autofocus: true,
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
focusNode: _postalCodeFocusNode,
controller: widget.controllers["postalCode"],
enabled: !widget.isViewMode,
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'^\d*\.?\d*$'),
), // Allow only positive numbers with optional decimal
],
decoration: InputDecoration(
labelText: "Postal Code",
labelStyle: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w400,
color: Colors.grey,
),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
),
],
);
}
// Widget buildRoleOld() {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// "Role ",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Color(0xFF575A74),
// ),
// ),
// SizedBox(height: 5),
// CustomTextFieldUserWrapper(
// isFocused: false, // Dropdown doesn't use focus
// isDesktop: widget.isDesktop,
// child: SizedBox(
// height: 45, // Set appropriate height
// child: DropdownButtonFormField<String>(
// // value: widget.isViewMode ? null : selectedRole,
// value: selectedRole,
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// decoration: InputDecoration(
// border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(
// horizontal: 10,
// ), // Proper padding
// ),
// onChanged:
// widget.isViewMode
// ? null
// : (newValue) {
// setState(() {
// selectedRole = newValue;
// isTravelAgent = selectedRole == "5";
// // Pass the result back to parent
// widget.onUserTypeChanged?.call(isTravelAgent);
// });
// widget.onRoleChanged?.call(newValue);
// },
// items:
// apiRoleData?.map<DropdownMenuItem<String>>((item) {
// return DropdownMenuItem(
// value: item['dropdown_key'], // ID as value
// child: Text(item['dropdown_value'] ?? "Select Role"),
// );
// }).toList(),
// hint: Text("Select Role"),
// disabledHint: Text(
// selectedRole ?? "Select Role",
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// ),
// ),
// ),
// ),
// ],
// );
// }
Widget buildRole() {
// Map dropdown_key (ID) -> dropdown_value (Name)
// Map<String, String> roleMap = {
// for (var item in apiRoleData ?? [])
// item['dropdown_key'] as String: item['dropdown_value'] as String,
// };
Map<String, String> roleMap = {
for (var item in apiRoleData ?? [])
if (item['dropdown_key'] != '5')
item['dropdown_key'].toString(): item['dropdown_value'].toString(),
};
List<String> roleNames = roleMap.values.toList();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Role*",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldUserWrapper(
// isFocused: false,
isFocused: _roleIdFocus,
padding: const EdgeInsets.symmetric(horizontal: 0),
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
child: Focus(
focusNode: _roleIdFocusNode,
onFocusChange: (hasFocus) {
setState(() {
_roleIdFocus = hasFocus;
});
},
child: GestureDetector(
onTap: () {
// Request focus when user taps
_roleIdFocusNode?.requestFocus();
},
child: DropdownSearch<String>(
selectedItem:
selectedRole != null ? roleMap[selectedRole] : null,
enabled: !widget.isEditProfile,
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 250),
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder:
(context, item, isSelected) => Container(
color: Colors.white,
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(fontSize: 11.5),
),
),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search Role...",
contentPadding: EdgeInsets.symmetric(horizontal: 10),
),
),
),
items: roleNames,
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(horizontal: 1),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: BorderSide(
color:
(_roleIdFocus)
? (layoutColor ?? Colors.blue)
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_roleIdFocus)
? (layoutColor ?? Colors.blue)
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: (layoutColor ?? Colors.grey),
width: 0.5,
),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 8,
vertical: 1,
),
),
),
dropdownBuilder:
(context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select Role",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
),
onChanged:
widget.isViewMode
? null
: (String? newValue) {
widget.errorMessages.remove("role_id");
if (newValue == null) return;
final selectedKey =
roleMap.entries
.firstWhere(
(entry) => entry.value == newValue,
)
.key;
setState(() {
selectedRole = selectedKey;
isTravelAgent = selectedKey == "5";
});
widget.onUserTypeChanged?.call(isTravelAgent);
widget.onRoleChanged?.call(selectedKey);
},
),
),
),
),
),
if (widget.errorMessages["role_id"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
widget.errorMessages["role_id"]!,
style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
),
],
],
);
}
Widget buildAddress() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Address",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldUserWrapper(
isFocused: _addressFocus,
isDesktop: widget.isDesktop,
child: SizedBox(
height: 80,
child: TextField(
autofocus: true,
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
focusNode: _addressFocusNode,
controller: widget.controllers["address"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r"[a-zA-Z0-9\s,.\-/#']"),
),
],
enabled: !widget.isViewMode,
maxLines: 2,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
labelText: "Address",
labelStyle: GoogleFonts.poppins(
fontSize: 12,
color: Colors.grey,
),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(vertical: 16),
contentPadding: EdgeInsets.symmetric(vertical: 4),
),
),
),
),
],
);
}
Widget buildPassword() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Password *",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldUserWrapper(
isFocused: _passwordFocus,
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
focusNode: _passwordFocusNode,
autofocus: true,
controller: widget.controllers["password"],
enabled: !widget.isViewMode,
onChanged: (value) {
_clearError("password");
},
decoration: InputDecoration(
labelText: "Password",
labelStyle: GoogleFonts.poppins(
fontSize: 12,
color: Colors.grey,
),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
),
if (widget.errorMessages["password"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
widget.errorMessages["password"]!,
style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
),
],
],
);
}
// apiselectedUser != null
// ? SizedBox()
}