ts-tat/lib/Screens/userManagement/create_user/create_user.dart
2025-05-21 11:25:31 +05:30

1226 lines
38 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:html' as html;
import 'dart:typed_data'; // Import for Uint8List
import 'package:bcrypt/bcrypt.dart';
import 'package:dropdown_search/dropdown_search.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:frontend/Screens/userManagement/create_user/personal_details.dart';
import 'package:frontend/Screens/userManagement/create_user/traveller_details.dart';
import 'package:frontend/utils/auth_utils.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
import 'package:http_parser/http_parser.dart' as http_parser;
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:http_parser/http_parser.dart';
import '../../../config/apiUrl.dart';
import '../../../routes/custom_appBar.dart';
import '../../../routes/custom_drawer.dart';
import '../../../services/apiService.dart';
import '../../../widgets/custom_text_field.dart';
import '../../../widgets/custom_text_forex.dart';
import '../../../widgets/custom_user_form.dart';
import 'office_details.dart';
import 'package:universal_html/html.dart' as html;
class CreateUserFormDetials extends StatefulWidget {
@override
_CreateUserFormDetialsState createState() => _CreateUserFormDetialsState();
}
class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
final ApiService apiService = ApiService();
final GlobalKey<PersonalDetailsState> personalDetailsKey =
GlobalKey<PersonalDetailsState>();
final GlobalKey<TravellerDetailsState> travellerDetailsKey =
GlobalKey<TravellerDetailsState>();
// late List<Map<String, dynamic>?> travelDetailsData;
Map<String, dynamic>? travelDetailsData;
Map<String, dynamic>? travelDetailsDataFromAPI;
late TabController _tabController;
String? userId;
String? orgId;
String? token;
late bool isapiselectedUser = false;
// Map to store controllers dynamically
final Map<String, TextEditingController> controllers = {};
bool isViewMode = false;
bool isEditProfile = false;
// late final List<dynamic>? apiCountryData ;
late List<dynamic>? apiCountryData;
late List<dynamic>? apiCostData;
late List<dynamic>? apiRoleData;
late List<dynamic>? apiUserData;
Map<String, dynamic>? apiselectedUser;
List<Map<String, dynamic>> selectedServiceIds = [];
late List<dynamic> userList;
late Future<List<dynamic>> futureUsers;
List<dynamic>? resolvedUserData;
late List<String> userIdsApi;
late Map<String, String> userMap;
Map<String, String> errorMessages = {};
String? selectedTab;
String? selectedCountry;
String? selectedGender;
// String? selectedGender = personalDetailsKey.currentState?.selectedGender;
String? selectedUserType;
String? selectedRole;
String? selectedLevel;
String? selectedDepartment;
String? selectedFirstApprover;
String? selectedSecondApprover;
String? selectedThirdApprover;
String? selectedSubstituteApprover;
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",
"delegationStartDate",
"delegationEndDate",
"dateOfIssue",
"dateOfExpiry",
"changePassword"
];
Color? layoutColor;
Color? bodyColor;
bool setSelectesUserType = false;
Map<String, dynamic> get userDetials {
Map<String, dynamic> data = {
"first_name": controllers["Fname"]?.text,
"last_name": controllers["Lname"]?.text,
"email": controllers["email"]?.text,
"password": controllers["password"]?.text,
"mobile_no": controllers["mobileNumber"]?.text,
"alternate_mobile_no": controllers["alternateMobile"]?.text,
"date_of_birth": controllers["dob"]?.text,
"address": controllers["address"]?.text,
"gender": selectedGender,
// "gender": personalDetailsKey.currentState?.selectedGender,
"agent_supported_service_ids": selectedServiceIds,
"postal_code": controllers["postalCode"]?.text,
"country_code": selectedCountry,
"employee_code": controllers["employeeCode"]?.text,
"delegation_start_date": controllers["delegationStartDate"]?.text,
"delegation_end_date": controllers["delegationEndDate"]?.text,
"user_type": selectedUserType,
"role_id": selectedRole,
"department_id": selectedDepartment,
"group_id": selectedLevel,
"first_approver": selectedFirstApprover,
"second_approver": selectedSecondApprover,
"third_approver": selectedThirdApprover,
"delegated_to_user_id": selectedSubstituteApprover,
"passport_number": controllers["passportNumber"]?.text,
"place_of_issue": controllers["placeOfIssue"]?.text,
"passport_document": passportFile,
"date_of_issue": controllers["dateOfIssue"]?.text,
"date_of_expiry": controllers["dateOfExpiry"]?.text,
"created_by": userId,
"is_active": "1",
"org_id": orgId,
"travel_details": travelDetailsData ?? {},
// "passport_fileData": passportFile,
};
return data;
}
void handleUserTypeChange(bool isTravelAgent) {
print("handleUserTypeChange- $isTravelAgent");
setState(() {
setSelectesUserType = isTravelAgent;
});
}
Future<void> updateData() async {
// Ensure apiselectedUser is not null before printing
if (apiselectedUser != null) {
print("API Selected User Has Data - $widget.apiselectedUser");
setState(() {
// ✅ Wrap in setState to update the UI
if (apiselectedUser != null && apiselectedUser!.isNotEmpty) {
isapiselectedUser = true;
print("API Selected User Has Data - $apiselectedUser");
}
controllers["Fname"]?.text = apiselectedUser?["first_name"] ?? "";
controllers["Lname"]?.text = apiselectedUser?["last_name"] ?? "";
controllers["email"]?.text = apiselectedUser?["email"] ?? "";
controllers["password"]?.text = "";
// controllers["password"]?.text = apiselectedUser?["password"] ?? "";
controllers["mobileNumber"]?.text = apiselectedUser?["mobile_no"] ?? "";
controllers["alternateMobile"]?.text =
apiselectedUser?["alternate_mobile_no"] ?? "";
controllers["dob"]?.text = apiselectedUser?["date_of_birth"] ?? "";
controllers["address"]?.text = apiselectedUser?["address"] ?? "";
controllers["postalCode"]?.text = apiselectedUser?["postal_code"] ?? "";
controllers["employeeCode"]?.text =
apiselectedUser?["employee_code"] ?? "";
controllers["delegationStartDate"]?.text =
apiselectedUser?["delegation_start_date"] ?? "";
controllers["delegationEndDate"]?.text =
apiselectedUser?["delegation_end_date"] ?? "";
controllers["passportNumber"]?.text =
apiselectedUser?["passport_number"] ?? "";
controllers["placeOfIssue"]?.text =
apiselectedUser?["place_of_issue"] ?? "";
if (apiselectedUser?["date_of_issue"] != null) {
controllers["dateOfIssue"]?.text =
apiselectedUser?["date_of_issue"] ?? "";
}
if (apiselectedUser?["date_of_expiry"] != null) {
controllers["dateOfExpiry"]?.text =
apiselectedUser?["date_of_expiry"] ?? "";
}
if (apiselectedUser?["country_code"] != null) {
selectedCountry = apiselectedUser?["country_code"]?.toString() ?? "";
}
if (apiselectedUser?["gender"] != null) {
selectedGender = apiselectedUser?["gender"]?.toString().trim() ?? "";
}
if (apiselectedUser?["user_type"] != null) {
selectedUserType =
apiselectedUser?["user_type"]?.toString().trim() ?? "";
}
if (apiselectedUser?["role_id"] != null) {
selectedRole = apiselectedUser?["role_id"]?.toString().trim() ?? "";
}
if (apiselectedUser?["group_id"] != null) {
selectedLevel = apiselectedUser?["group_id"]?.toString().trim() ?? "";
}
// selectedDepartment =
// apiselectedUser?["department_id"]?.toString().trim() ?? "";
if (apiselectedUser?["department_id"] != null) {
selectedDepartment = apiselectedUser!["department_id"].toString();
}
// print(
// "selectedDepartment - $selectedDepartment - ${apiselectedUser?["department_id"]} ");
if (apiselectedUser?["level_id"] != null) {
selectedLevel = apiselectedUser?["level_id"]?.toString().trim() ?? "";
}
if (apiselectedUser?["first_approver"] != null) {
selectedFirstApprover =
apiselectedUser?["first_approver"]?.toString() ?? "";
}
if (apiselectedUser?["second_approver"] != null) {
selectedSecondApprover =
apiselectedUser?["second_approver"]?.toString() ?? "";
}
if (apiselectedUser?["third_approver"] != null) {
selectedThirdApprover =
apiselectedUser?["third_approver"]?.toString() ?? "";
}
if (apiselectedUser?["delegated_to_user_id"] != null) {
print(
"UPDADele- ${apiselectedUser?["delegated_to_user_id"]?.toString()}");
selectedSubstituteApprover =
apiselectedUser?["delegated_to_user_id"]?.toString() ?? "";
print("UPDADele1- $selectedSubstituteApprover");
}
try {
final raw = apiselectedUser!["agent_supported_service_ids"];
// Fix the invalid JSON (dangerous if the format changes)
final fixedJson = raw.replaceAllMapped(
RegExp(r'(\w+):'), // matches `service_id:`
(match) => '"${match.group(1)}":',
);
List<dynamic> decodedList = jsonDecode(fixedJson);
selectedServiceIds = decodedList.map<Map<String, dynamic>>((item) {
final map = Map<String, dynamic>.from(item);
return {
"service_id": map['service_id'].toString(),
};
}).toList();
} catch (e) {
print("❌ Error decoding fixed agent_supported_service_ids: $e");
selectedServiceIds = [];
}
print("Updated selectedGender: $selectedGender"); // Debugging
travelDetailsDataFromAPI = apiselectedUser?["travel_details"];
print("travelDetailsDataFromAPI00 - $travelDetailsDataFromAPI");
// if (travelDetails != null) {
// WidgetsBinding.instance.addPostFrameCallback((_) {
// // Safe to call updateTravel now
// travellerDetailsKey.currentState?.updateTravel();
// });
// }
// Optionally load other travel-related fields like meal/seat preferences, etc.
});
} else {
print("API Selected User Has Data - No data available yet");
}
}
@override
void initState() {
super.initState();
prepareForNewEntry();
selectedTab = "personal";
// WidgetsFlutterBinding.ensureInitialized();
// Step 1: Set 'reloaded' flag before page unload
// html.window.onBeforeUnload.listen((event) {
// html.window.localStorage['reloaded'] = 'true';
// });
apiCountryData = null;
apiUserData = null;
// apiselectedUser = null;
apiCostData = null;
apiRoleData = null;
// Initialize controllers for each field
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 =
GoRouterState.of(context).extra as Map<String, dynamic>?;
if (extraData != null) {
print("extraData: ${extraData['selectedUser']}");
setState(() {
// apiCountryData = extraData['apiCountryData'];
// apiUserData = extraData['apiUserData'];
//
// userList = apiUserData ?? [];
// userMap = {
// for (var user in userList)
// user['user_id'].toString(): "${user['first_name']} ${user['last_name']}"
// };
// userIdsApi = userMap.keys.toList();
// Handle selectedUser as a Map (not a List)
apiselectedUser = extraData['selectedUser']
as Map<String, dynamic>?; // Cast it as a Map
isViewMode = extraData['isViewMode'] ?? false;
isEditProfile = extraData['isEditProfile'] ?? false;
});
print("selectedUser: $apiselectedUser");
// Add another post-frame callback to check after setState
// await Future.delayed(Duration(
// milliseconds: 100)); // Optional delay to ensure UI has updated
updateData();
}
initializeData();
fetchCountries();
fetchDepartment();
fetchUsers();
fetchRoles();
loadInitialData();
});
for (var field in dataHeader) {
controllers[field] = TextEditingController();
}
}
Future<void> fetchCountries() async {
try {
List<dynamic> countries = await apiService.fetchCountryList();
setState(() {
apiCountryData = countries;
});
} catch (e) {
print('Error fetching country list: $e');
}
}
Future<void> fetchDepartment() async {
try {
List<dynamic> department = await apiService.fetchCostCenter();
setState(() {
apiCostData = department;
});
} catch (e) {
print('Error fetching department list: $e');
}
}
Future<void> fetchUsers() async {
try {
List<dynamic> users = await apiService.fetchUsers();
setState(() {
// apiUserData = users;
apiUserData = users.where((user) => user["role_id"] == "4").toList();
print("APIUSerDATa - $apiUserData");
userList = apiUserData ?? [];
userMap = {
for (var user in userList)
user['user_id'].toString():
"${user['first_name']} ${user['last_name']}"
};
userIdsApi = userMap.keys.toList();
});
} catch (e) {
print('Error fetching country list: $e');
}
}
Future<void> fetchRoles() async {
try {
final response = await apiService.fetchMasterDropdown();
if (response is Map<String, dynamic> && response.containsKey("role")) {
List<dynamic> roleList = response["role"]; // Extract the list
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');
}
}
void printFormData() {
for (var field in dataHeader) {
print("$field: ${controllers[field]?.text}");
}
}
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> initializeData() async {
token = await getToken();
userId = await getUserId();
if (token == null || userId == null) {
print("Token or USerId missing");
print("Retrieved Token: $token");
print("Retrieved UserId: $userId");
return;
} else {
setState(() {});
}
}
Future<String?> getToken() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('auth_token');
}
Future<String?> getUserId() async {
final prefs = await SharedPreferences.getInstance();
final userData = prefs.getString('user_data');
if (userData != null) {
final decodedData = jsonDecode(userData);
// Return the user_id from the decoded data
return decodedData['user_id']?.toString();
}
return null;
}
@override
void dispose() {
// Dispose all controllers to prevent memory leaks
for (var controller in controllers.values) {
controller.dispose();
}
super.dispose();
}
void prepareForNewEntry() {
for (var controller in controllers.values) {
controller.clear();
}
}
void handleNext() async {
print("USR Detail Next");
printFormData();
// travelDetailsData = [travellerDetailsKey.currentState?.travel_Detials];
travelDetailsData = travellerDetailsKey.currentState?.travel_Detials;
print("TRAVEL DETAILS FROM CHILD: $travelDetailsData");
Map<String, dynamic> data = userDetials;
print("USERDETAILS : $data");
if (!isValidData(data)) {
print("USERDETAILS : $userDetials");
print("Validation Failed: Required fields are missing.");
setState(() {});
return; // Stop execution if validation fails
} else {
print("USERDETAILS : $userDetials");
final tabs = {
"personal": "Personal Details",
"office": "Office Details",
"travel": "Travel Details",
};
final tabKeys = tabs.keys.toList(); // ["personal", "office", "travel"]
final currentIndex = tabKeys.indexOf(selectedTab ?? "personal");
if (currentIndex < tabKeys.length - 1) {
// Move to next tab
setState(() {
selectedTab = tabKeys[currentIndex + 1];
});
} else {
// Already at last tab (travel), maybe submit form or show done message
print("All tabs completed!");
// You can trigger full form submit here
}
}
}
void handleSubmit() async {
print("USR Detail Submit");
// printFormData();
travelDetailsData = travellerDetailsKey.currentState?.travel_Detials;
print("TRAVEL DETAILS FROM CHILD");
// print("TRAVEL DETAILS FROM CHILD: $travelDetailsData");
passportFile = travellerDetailsKey.currentState?.passportFile;
print("passportFile : $passportFile");
Map<String, dynamic> data = userDetials;
print("USERDETAILS : $data");
// Map<String, dynamic> data = userDetials;
if (!isValidData(data)) {
print("USERDETAILS : $userDetials");
print("Validation Failed: Required fields are missing.");
setState(() {});
return; // Stop execution if validation fails
} else {
print("USERDETAILS : $userDetials");
orgId = await getOrgId();
createUserData(userDetials);
}
}
bool isValidData(Map<String, dynamic> data) {
errorMessages.clear(); // Reset errors
// Required fields that must not be empty
List<String> requiredFields = [
"first_name",
"last_name",
"email",
"mobile_no",
// "employeeCode"
];
if (apiselectedUser == null) {
requiredFields.add("password");
}
// Check validation for each field
for (String field in requiredFields) {
if (data[field] == null || data[field].toString().trim().isEmpty) {
errorMessages[field] = "Required";
}
}
// Mobile number validation for both mobile_no and alternate_mobile_no
if (data["mobile_no"] != null && data["mobile_no"].toString().isNotEmpty) {
if (!RegExp(r"^\d{10}$").hasMatch(data["mobile_no"].toString())) {
errorMessages["mobile_no"] =
"Enter 10 digits"; // Invalid mobile number format
}
}
if (data["alternate_mobile_no"] != null &&
data["alternate_mobile_no"].toString().isNotEmpty) {
if (!RegExp(r"^\d{10}$")
.hasMatch(data["alternate_mobile_no"].toString())) {
errorMessages["alternate_mobile_no"] =
"Enter 10 digits"; // Invalid mobile number format
}
}
// Email validation
if (data["email"] != null && data["email"].toString().isNotEmpty) {
if (!RegExp(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")
.hasMatch(data["email"].toString())) {
errorMessages["email"] = "Invalid email format"; // Invalid email format
}
}
return errorMessages.isEmpty; // Valid if there are no errors
}
void _clearError(String field) {
if (mounted && errorMessages.containsKey(field)) {
setState(() {
errorMessages.remove(field);
});
}
}
void pickPDFWeb() {
html.FileUploadInputElement uploadInput = html.FileUploadInputElement();
uploadInput.accept = '.pdf';
uploadInput.click();
uploadInput.onChange.listen((e) {
final file = uploadInput.files!.first;
// Ensure the file is a PDF
if (!file.type.contains("pdf")) {
print("Error: Not a PDF file");
return;
}
// 🔹 File size check: Ensure it does not exceed 3MB
int maxFileSize = 3 * 1024 * 1024; // 3MB in bytes
if (file.size > maxFileSize) {
print('Error: File size exceeds 3MB');
return;
}
setState(() {
selectedFileNames = file.name;
passportFile = file;
passportFileUrlFromApi = null;
});
print('PDF File selected: ${file.name}');
});
}
Future<void> createUserData(Map<String, dynamic> userData) async {
final bool isUpdating =
apiselectedUser != null && apiselectedUser!.isNotEmpty;
final uri = Uri.parse(
isUpdating
? '$apiUrl/api/users/update/${apiselectedUser?["user_id"]}'
: '$apiUrl/api/users/create',
);
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
if (isUpdating) {
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();
// }
// });
userData.forEach((key, value) {
if (value != null && value.toString().trim().isNotEmpty) {
if (key == 'travel_details' && value is Map<String, dynamic>) {
// ✅ Encode travel_details as a proper JSON string
request.fields[key] = jsonEncode(value);
print("✅ Encoded travel_details: ${request.fields[key]}");
} else {
request.fields[key] = value.toString();
}
}
});
// Attach file if selected
if (passportFile != null) {
try {
final reader = html.FileReader();
reader.readAsArrayBuffer(passportFile!);
await reader.onLoad.first;
final data = reader.result as Uint8List;
final multipartFile = http.MultipartFile.fromBytes(
'passport_document',
data,
filename: passportFile!.name,
);
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) {
dispose();
print("✅ User submitted successfully!");
print("📨 Response: ${response.body}");
context.go('/listUser');
} else {
print("❌ Submission failed. Status: ${response.statusCode}");
print("📨 Body: ${response.body}");
}
} catch (e) {
print("🔥 Error submitting user: $e");
}
}
void handleChangePassword(String enteredPassword) {
var hashedPassword = apiselectedUser?["password"]; // Get stored bcrypt hash
print("HAshPAssword - $hashedPassword ");
print("enteredPassword - $enteredPassword ");
if (hashedPassword != null && hashedPassword.isNotEmpty) {
bool isMatch =
BCrypt.checkpw(enteredPassword, hashedPassword); // Compare passwords
setState(() {
// ✅ Ensure UI updates
if (isMatch) {
errorMessages["password"] =
"New password is not similar to old password";
print(" Password match!");
} else {
print(" Password NOT match!");
errorMessages
.remove("password"); // Clear error if password is different
}
});
} else {
print("No stored password found.");
}
}
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) {
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold(
backgroundColor: Color(0xFFf5f5f5),
// appBar: isDesktop ? null : const CustomAppBar(title: 'Create User '),
// drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false),
body: Padding(
padding: isDesktop
? EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width *
0.1, // 30% of screen width as horizontal padding
vertical: MediaQuery.of(context).size.height *
0, // 5% of screen height as vertical padding
)
: EdgeInsets.all(0),
child: Row(
children: [
Expanded(child: buildData(isDesktop, context)),
],
),
),
);
});
}
Widget buildData(bool isDesktop, context) {
return Container(
margin: isDesktop ? const EdgeInsets.only(top: 10.0, bottom: 10.0) : null,
padding: const EdgeInsets.only(left: 10, right: 10, top: 8),
decoration: BoxDecoration(
color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
),
child: Column(
children: [
Expanded(
child: Container(
height: isDesktop
? MediaQuery.of(context).size.height * 0.98
: MediaQuery.of(context).size.height,
child: Padding(
padding: EdgeInsets.all(0.0),
child: _buildUserDetails(isDesktop),
),
),
),
Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: isDesktop
? Row(
mainAxisAlignment: MainAxisAlignment.end,
children: (selectedTab == "travel" ||
selectedRole == "5" ||
setSelectesUserType == true)
? _buildSubmit(isDesktop, layoutColor!)
: _buildNext(isDesktop, layoutColor!),
)
: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: (selectedTab == "travel" ||
selectedRole == "5" ||
setSelectesUserType == true)
? _buildSubmit(isDesktop, layoutColor!)
: _buildNext(isDesktop, layoutColor!),
)),
)
],
),
);
}
Widget _buildUserDetails(bool isDesktop) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
apiselectedUser != null ? "Profile" : "Create New User",
style: GoogleFonts.poppins(
fontSize: isDesktop ? 15 : 12,
fontWeight: FontWeight.w600,
color: Colors.black,
),
),
// if (isEditProfile)
// IconButton(
// icon: Icon(
// Icons.edit,
// color: Color(0xFF114D8B),
// size: 14,
// ),
// onPressed: () {
// setState(() {
// isViewMode = !isViewMode;
// });
// })
],
),
SizedBox(
height: 18,
),
isDesktop
? buildTabsForUser()
: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: buildTabsForUser(),
),
Container(
// color: Colors.yellow.shade50,
height: MediaQuery.of(context).size.height * 0.64,
child: Row(
children: [
Expanded(child: buildTabContents(isDesktop, isViewMode)),
],
),
)
],
),
),
],
);
}
Widget buildTabContents(isDesktop, isViewMode) {
switch (selectedTab) {
case "personal":
return PersonalDetails(
personalDetailsKey: personalDetailsKey,
isDesktop: isDesktop, // pass isDesktop as a named argument
isViewMode: isViewMode,
controllers: controllers,
errorMessages: errorMessages,
selectedGender: selectedGender,
selectedCountry: selectedCountry,
selectedRole: selectedRole,
apiselectedUser: isapiselectedUser,
onUserTypeChanged: handleUserTypeChange,
onGenderChanged: (gender) {
setState(() {
selectedGender = gender;
});
},
onCountryChanged: (country) {
setState(() {
selectedCountry = country;
});
},
onRoleChanged: (role) {
setState(() {
selectedRole = role;
});
},
onServiceIdsChanged: (List<Map<String, dynamic>> updatedList) {
setState(() {
selectedServiceIds = updatedList;
});
},
initialSelectedServices: selectedServiceIds,
);
case "office":
return OfficeDetails(
isDesktop: isDesktop, // pass isDesktop as a named argument
isViewMode: isViewMode,
controllers: controllers,
errorMessages: errorMessages,
selectedLevel: selectedLevel,
selectedDepartment: selectedDepartment,
selectedFirstApprover: selectedFirstApprover,
selectedSecondApprover: selectedSecondApprover,
selectedThirdApprover: selectedThirdApprover,
selectedSubstituteApprover: selectedSubstituteApprover,
onLevelChanged: (gender) {
setState(() {
selectedLevel = gender;
});
},
onDepartmentChanged: (country) {
setState(() {
selectedDepartment = country;
});
},
onFirstApproverChanged: (role) {
setState(() {
selectedFirstApprover = role;
});
},
onSecondApproverChanged: (role) {
setState(() {
selectedSecondApprover = role;
});
},
onThirdApproverChanged: (role) {
setState(() {
selectedThirdApprover = role;
});
},
onFirstSubsApproverChanged: (role) {
setState(() {
selectedSubstituteApprover = role;
});
},
);
case "travel":
return TravellerDetails(
key: travellerDetailsKey,
isDesktop: isDesktop,
isViewMode: isViewMode,
controllers: controllers,
errorMessages: errorMessages,
travelDetails: travelDetailsDataFromAPI, // 👈 Pass this down
passportFileUrlFromApi: passportFileUrlFromApi,
);
default:
return PersonalDetails(
personalDetailsKey: personalDetailsKey,
isDesktop: isDesktop, // pass isDesktop as a named argument
isViewMode: isViewMode,
controllers: controllers,
errorMessages: errorMessages,
selectedGender: selectedGender,
selectedCountry: selectedCountry,
apiselectedUser: isapiselectedUser,
onUserTypeChanged: handleUserTypeChange,
onServiceIdsChanged: (List<Map<String, dynamic>> updatedList) {
setState(() {
selectedServiceIds = updatedList;
});
},
);
}
}
Widget buildTabsForUser() {
// final tabs = {
// "personal": "Personal Details",
// "office": "Office Details",
// "travel": "Travel Details",
// };
final Map<String, String> allTabs = {
"personal": "Personal Details",
"office": "Office Details",
"travel": "Travel Details",
};
Map<String, String> getTabs(bool setSelectesUserType) {
if (setSelectesUserType || selectedRole == "5") {
return {
"personal": "Personal Details",
};
} else {
return allTabs;
}
}
final tabs = getTabs(setSelectesUserType);
return Row(
crossAxisAlignment: CrossAxisAlignment.end, // important
children: tabs.entries.map((entry) {
final isSelected = selectedTab == entry.key;
return GestureDetector(
onTap: () {
setState(() {
selectedTab = entry.key;
});
},
child: Padding(
padding: const EdgeInsets.only(right: 24.0), // space between tabs
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
entry.value,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: isSelected ? Color(0xFF114D8B) : Color(0xFF475569),
),
),
const SizedBox(height: 8),
AnimatedContainer(
duration: Duration(milliseconds: 300),
height: 2,
width: isSelected ? 50 : 0, // small line
color: Color(0xFF114D8B),
),
],
),
),
);
}).toList(),
);
}
// ---- Submit ---------------------------------------
List<Widget> _buildNext(isDesktop, Color layoutColor) {
return [
MouseRegion(
cursor: isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:
isViewMode ? layoutColor : layoutColor, // Keep original color
foregroundColor:
isViewMode ? Colors.white : Colors.white, // Keep original color
disabledBackgroundColor:
layoutColor, // Ensure color remains when disabled
disabledForegroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: BorderSide(color: layoutColor, width: 2),
),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
onPressed: handleNext,
// onPressed:
// isViewMode ? null : handleNext, // Disable when in view mode
child: Text("Next"),
),
)
];
}
List<Widget> _buildSubmit(isDesktop, Color layoutColor) {
return [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: layoutColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: BorderSide(color: layoutColor, width: 2),
),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
onPressed: () {
isEditProfile ? context.go('/listPlan') : context.go('/listUser');
},
child: Text("Cancel")),
SizedBox(
width: 20,
),
if (!isViewMode)
MouseRegion(
cursor: isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:
isViewMode ? layoutColor : layoutColor, // Keep original color
foregroundColor: isViewMode
? Colors.white
: Colors.white, // Keep original color
disabledBackgroundColor:
layoutColor, // Ensure color remains when disabled
disabledForegroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: BorderSide(color: layoutColor, width: 2),
),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
onPressed:
isViewMode ? null : handleSubmit, // Disable when in view mode
child: Text("Submit"),
),
)
];
}
}
class DatabaseHelper {
// Example: Singleton pattern to ensure only one instance of the class exists
static final DatabaseHelper _instance = DatabaseHelper._internal();
// Private constructor to prevent external instantiation
DatabaseHelper._internal();
// Public method to access the instance
static DatabaseHelper get instance => _instance;
// Add your database methods here
Future<void> fetchData() async {
// Implement data fetching logic
}
}