user management functionalities
This commit is contained in:
parent
c8f2d798ea
commit
41308b2590
@ -335,7 +335,6 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
||||
}
|
||||
|
||||
|
||||
|
||||
void getSelectedPlanFor(){
|
||||
if (!mounted) return;
|
||||
|
||||
@ -590,7 +589,7 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> postPlanData(Map<String, dynamic> planData) async {
|
||||
Future<void> postPlanData(Map<String, dynamic> planData) async {
|
||||
final String apiUrldata = '$apiUrl/api/plans/createOrEditPlan';
|
||||
final token = await getToken(); // Fetch token
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:frontend/Screens/policy/policyCriteria.dart';
|
||||
import 'package:responsive_builder/responsive_builder.dart';
|
||||
|
||||
import '../../routes/custom_appBar.dart';
|
||||
@ -203,7 +204,8 @@ class _PolicyState extends State<Policy>{
|
||||
|
||||
return SizedBox(
|
||||
width: 180,
|
||||
height: isDesktop? 65 : 50,
|
||||
height: isDesktop ? MediaQuery.of(context).size.height * 0.1 : 50,
|
||||
|
||||
child:GestureDetector(
|
||||
onTap :(){
|
||||
print("Selected Services - $service - $index");
|
||||
@ -242,45 +244,10 @@ class _PolicyState extends State<Policy>{
|
||||
Widget _buildPolicyCategory(bool isDesktop){
|
||||
return Expanded(
|
||||
child: Container(
|
||||
color: Colors.brown.shade100,
|
||||
// color: Colors.white60,
|
||||
// color: Colors.brown.shade100,
|
||||
color: Colors.white60,
|
||||
|
||||
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
child: Text(
|
||||
"policy Data 1"
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
|
||||
Expanded(
|
||||
child: Container(
|
||||
color: Colors.brown.shade200,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
child: Text(
|
||||
"policy Data 2"
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: PolicyCriteria(isDesktop: isDesktop)
|
||||
|
||||
|
||||
),
|
||||
|
||||
@ -0,0 +1,157 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../widgets/custom_text_field.dart';
|
||||
import '../../widgets/custom_user_form.dart';
|
||||
|
||||
class PolicyCriteria extends StatefulWidget{
|
||||
|
||||
bool isDesktop;
|
||||
|
||||
PolicyCriteria({super.key, required this.isDesktop});
|
||||
@override
|
||||
_PolicyCriteriaState createState() => _PolicyCriteriaState();
|
||||
|
||||
}
|
||||
|
||||
class _PolicyCriteriaState extends State<PolicyCriteria>{
|
||||
|
||||
Widget build(BuildContext context){
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
|
||||
SizedBox(height: 15),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text("Selected Policy Criteria For Flight",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color:Colors.grey,
|
||||
fontWeight: FontWeight.bold
|
||||
)
|
||||
,)
|
||||
],),
|
||||
|
||||
|
||||
SizedBox(height: 15),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
// color:Colors.grey,
|
||||
padding: const EdgeInsets.only(top:5,bottom: 5,left:5, right: 5),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
||||
Row(
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Class", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200, color: Colors.black)),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldUserWrapper(
|
||||
isFocused: false,
|
||||
isDesktop: widget.isDesktop,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
style: TextStyle(fontSize: 12),
|
||||
// controller: controllers["Fname"],
|
||||
// enabled: !isViewMode,
|
||||
onChanged: (value) { },
|
||||
decoration: InputDecoration(
|
||||
labelText: "Class",
|
||||
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
SizedBox(height: 10),
|
||||
|
||||
Row(
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Cost", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200, color: Colors.black)),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldUserWrapper(
|
||||
isFocused: false,
|
||||
isDesktop: widget.isDesktop,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
style: TextStyle(fontSize: 12),
|
||||
// controller: controllers["Fname"],
|
||||
// enabled: !isViewMode,
|
||||
onChanged: (value) { },
|
||||
decoration: InputDecoration(
|
||||
labelText: "Cost",
|
||||
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
|
||||
],
|
||||
),
|
||||
|
||||
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
|
||||
Expanded(
|
||||
child: Container(
|
||||
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Color(0xFFEBEBF7),
|
||||
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
// color: Colors.brown.shade200,
|
||||
),
|
||||
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
child: Text(
|
||||
"policy Data 2"
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -44,8 +44,8 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
// 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;
|
||||
|
||||
@ -102,20 +102,20 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
"user_type" : selectedUserType,
|
||||
"role_id" : selectedRole,
|
||||
"department_id": selectedDepartment,
|
||||
"level_id" : selectedLevel,
|
||||
"group_id" : selectedLevel,
|
||||
|
||||
"first_approver": selectedFirstApprover,
|
||||
"second_approver": selectedSecondApprover,
|
||||
"third_approver": selectedThirdApprover,
|
||||
"passport_number": controllers["passportNumber"]?.text,
|
||||
"place_of_issue": controllers["placeOfIssue"]?.text,
|
||||
"passport_document": selectedFileNames,
|
||||
"passport_document": base64PDF,
|
||||
|
||||
"date_of_issue": controllers["dateOfIssue"]?.text,
|
||||
"date_of_expiry": controllers["dateOfExpiry"]?.text,
|
||||
"created_by": userId,
|
||||
"is_active": "1",
|
||||
"passport_fileData": base64PDF,
|
||||
// "passport_fileData": base64PDF,
|
||||
};
|
||||
return data;
|
||||
}
|
||||
@ -145,10 +145,10 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
controllers["dateOfExpiry"]?.text = apiselectedUser?["date_of_expiry"] ?? "";
|
||||
|
||||
|
||||
selectedCountry = apiselectedUser?["country"]?.toString() ?? "";
|
||||
selectedCountry = apiselectedUser?["country_code"]?.toString() ?? "";
|
||||
selectedGender = apiselectedUser?["gender"]?.toString().trim() ?? "";
|
||||
|
||||
selectedFileNames = apiselectedUser?["passport_document"]?.toString().trim() ?? "";
|
||||
base64PDF = apiselectedUser?["passport_document"]?.toString().trim() ?? "";
|
||||
selectedUserType = apiselectedUser?["user_type"]?.toString().trim() ?? "";
|
||||
selectedRole = apiselectedUser?["role_id"]?.toString().trim() ?? "";
|
||||
selectedDepartment = apiselectedUser?["department_id"]?.toString().trim() ?? "";
|
||||
@ -178,6 +178,8 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
apiCountryData = null;
|
||||
apiUserData = null;
|
||||
apiselectedUser = null;
|
||||
apiCostData = null;
|
||||
apiRoleData = null;
|
||||
|
||||
// Delay accessing context until the widget is fully initialized
|
||||
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
@ -246,7 +248,9 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
|
||||
initializeData();
|
||||
fetchCountries();
|
||||
fetchDepartment();
|
||||
fetchUsers();
|
||||
fetchRoles();
|
||||
|
||||
}
|
||||
|
||||
@ -261,11 +265,27 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
apiUserData = users.where((user) => user["role_id"] == "3").toList();
|
||||
|
||||
print("APIUSerDATa - $apiUserData");
|
||||
|
||||
userList = apiUserData ?? [];
|
||||
userMap = {
|
||||
@ -280,6 +300,24 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
@ -346,6 +384,7 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
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
|
||||
@ -362,7 +401,11 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
errorMessages.clear(); // Reset errors
|
||||
|
||||
// Required fields that must not be empty
|
||||
List<String> requiredFields = ["first_name", "last_name","email","password","mobile_no"];
|
||||
List<String> requiredFields = ["first_name", "last_name","email","mobile_no"];
|
||||
|
||||
if (apiselectedUser == null) {
|
||||
requiredFields.add("password");
|
||||
}
|
||||
|
||||
// Check validation for each field
|
||||
for (String field in requiredFields) {
|
||||
@ -371,6 +414,7 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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())) {
|
||||
@ -402,6 +446,8 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void pickPDFWeb() {
|
||||
html.FileUploadInputElement uploadInput = html.FileUploadInputElement();
|
||||
uploadInput.accept = '.pdf';
|
||||
@ -416,35 +462,87 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
print('File picked: ${file.name}');
|
||||
print('File size: ${file.size} bytes');
|
||||
|
||||
// Ensure the file is a PDF
|
||||
if (!file.type.contains("pdf")) {
|
||||
print("Error: Not a PDF file");
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the state with the selected file name
|
||||
setState(() {
|
||||
selectedFileNames = file.name; // Store only one file name
|
||||
selectedFileNames = file.name; // Store file name
|
||||
passportDocumentBytes = reader.result as Uint8List; // Store file data
|
||||
|
||||
// 🔹 Convert file to Base64
|
||||
base64PDF = base64Encode(passportDocumentBytes! as List<int>);
|
||||
// File size check: Ensure the file size does not exceed 3MB
|
||||
int maxFileSize = 3 * 1024 * 1024; // 3MB in bytes
|
||||
// 🔹 Convert to Base64 properly
|
||||
base64PDF = base64Encode(passportDocumentBytes!);
|
||||
|
||||
if (file.size > maxFileSize) {
|
||||
print('Error: File size exceeds 3MB');
|
||||
// You can show an error message here if necessary
|
||||
// For example:
|
||||
// showError('File size cannot exceed 3MB');
|
||||
print('Base64 Length: ${base64PDF!.length}');
|
||||
print('Base64 (first 50 chars): ${base64PDF!.substring(0, 50)}');
|
||||
|
||||
// Ensure Base64 starts with "JVBERi0x"
|
||||
if (!base64PDF!.startsWith("JVBERi0x")) {
|
||||
print("Error: Base64 does not start with 'JVBERi0x'");
|
||||
return;
|
||||
}
|
||||
|
||||
print('File size: ${file.size} bytes');
|
||||
print('Base64 Data: $base64PDF'); // Debugging
|
||||
// 🔹 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;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// void pickPDFWeb() {
|
||||
// html.FileUploadInputElement uploadInput = html.FileUploadInputElement();
|
||||
// uploadInput.accept = '.pdf';
|
||||
// uploadInput.click();
|
||||
//
|
||||
// uploadInput.onChange.listen((e) {
|
||||
// final file = uploadInput.files!.first;
|
||||
// final reader = html.FileReader();
|
||||
//
|
||||
// reader.readAsArrayBuffer(file);
|
||||
// reader.onLoadEnd.listen((event) {
|
||||
// print('File picked: ${file.name}');
|
||||
// print('File size: ${file.size} bytes');
|
||||
//
|
||||
//
|
||||
// // Update the state with the selected file name
|
||||
// setState(() {
|
||||
// selectedFileNames = file.name; // Store only one file name
|
||||
// passportDocumentBytes = reader.result as Uint8List; // Store file data
|
||||
//
|
||||
// // 🔹 Convert file to Base64
|
||||
// base64PDF = base64Encode(passportDocumentBytes! as List<int>);
|
||||
// // File size check: Ensure the file size does not exceed 3MB
|
||||
// int maxFileSize = 3 * 1024 * 1024; // 3MB in bytes
|
||||
//
|
||||
// if (file.size > maxFileSize) {
|
||||
// print('Error: File size exceeds 3MB');
|
||||
// // You can show an error message here if necessary
|
||||
// // For example:
|
||||
// // showError('File size cannot exceed 3MB');
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// print('File size: ${file.size} bytes');
|
||||
// print('Base64 Data: $base64PDF'); // Debugging
|
||||
// });
|
||||
//
|
||||
//
|
||||
//
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Future<void> createUserData(Map<String, dynamic> userData) async {
|
||||
|
||||
bool isUpdating = apiselectedUser != null && apiselectedUser!.isNotEmpty;
|
||||
@ -624,7 +722,6 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
Text("Personal Details", style: TextStyle(fontSize: 18,fontWeight: FontWeight.bold,
|
||||
// color: Colors.black,
|
||||
color: Color(0xFF8B8FB2)
|
||||
|
||||
),
|
||||
)
|
||||
],),
|
||||
@ -1238,36 +1335,7 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
children: [
|
||||
Text("Change Password", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200, color: Colors.black)),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldUserWrapper(
|
||||
isFocused: false,
|
||||
isDesktop: isDesktop,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
style: TextStyle(fontSize: 12),
|
||||
controller: controllers["password"],
|
||||
enabled: !isViewMode,
|
||||
onChanged: (value) {
|
||||
_clearError("changePassword");
|
||||
handleChangePassword(value);
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
labelText: "Change Password",
|
||||
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (errorMessages["password"] != null) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
Text(
|
||||
errorMessages["password"]!,
|
||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||
),
|
||||
],
|
||||
|
||||
],
|
||||
),
|
||||
],
|
||||
@ -1621,6 +1689,7 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
children: [
|
||||
Text("Passport Document", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200, color: Colors.black)),
|
||||
SizedBox(height: 5),
|
||||
|
||||
CustomTextFieldUserWrapper(
|
||||
isFocused: false,
|
||||
isDesktop: isDesktop,
|
||||
@ -1641,6 +1710,101 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
if(base64PDF != null)
|
||||
|
||||
// Centers the text
|
||||
Container(
|
||||
color: Colors.white,
|
||||
width : isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.25
|
||||
: MediaQuery.of(context).size.width * 0.8,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
GestureDetector(onTap: (){
|
||||
print('DOWLOAS- $base64PDF ');
|
||||
|
||||
if (base64PDF != null && base64PDF!.isNotEmpty) {
|
||||
try {
|
||||
// ✅ Step 1: Clean the Base64 string
|
||||
String cleanedBase64 = base64PDF!
|
||||
.replaceAll("\n", "") // Remove newlines
|
||||
.replaceAll("\r", "") // Remove carriage returns
|
||||
.replaceAll(" ", "") // Remove spaces
|
||||
.trim(); // Trim any whitespace
|
||||
|
||||
// ✅ Step 2: Ensure valid Base64 length (multiple of 4)
|
||||
while (cleanedBase64.length % 4 != 0) {
|
||||
cleanedBase64 += "_"; // Add '=' padding
|
||||
}
|
||||
|
||||
// ✅ Step 3: Decode the cleaned Base64
|
||||
Uint8List bytes;
|
||||
try {
|
||||
bytes = base64Decode(cleanedBase64);
|
||||
} catch (e) {
|
||||
print("Base64 decoding failed: $e");
|
||||
return;
|
||||
}
|
||||
|
||||
// ✅ Step 4: Create a Blob for download
|
||||
final blob = html.Blob([bytes], 'application/pdf');
|
||||
final url = html.Url.createObjectUrlFromBlob(blob);
|
||||
|
||||
// ✅ Step 5: Trigger the file download
|
||||
final anchor = html.AnchorElement(href: url)
|
||||
..setAttribute("download", selectedFileNames ?? "document.pdf")
|
||||
..style.display = "none";
|
||||
|
||||
html.document.body!.append(anchor);
|
||||
anchor.click();
|
||||
|
||||
// ✅ Step 6: Clean up
|
||||
anchor.remove();
|
||||
html.Url.revokeObjectUrl(url);
|
||||
|
||||
print("Download successful!");
|
||||
} catch (e) {
|
||||
print("Error downloading file: $e");
|
||||
}
|
||||
} else {
|
||||
print("No file to download.");
|
||||
}
|
||||
|
||||
} ,
|
||||
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
color: Colors.green.shade300,
|
||||
),
|
||||
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
"Download",
|
||||
style: TextStyle(fontSize: 12, color: Colors.white,fontWeight: FontWeight.bold),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.end, // Ensures text is centered within the Text widget
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
Icon(Icons.download ,size: 13, color: Colors.white,)
|
||||
],
|
||||
),
|
||||
|
||||
|
||||
),
|
||||
)
|
||||
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1933,7 +2097,7 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
constraints: BoxConstraints(maxHeight: 250),
|
||||
|
||||
),
|
||||
items: ["Admin", "Manager", "HR"],
|
||||
items: ["Normal", "Privilege",],
|
||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||
dropdownSearchDecoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
@ -1952,6 +2116,8 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
// Find the country_code based on selected country_name
|
||||
selectedUserType = newValue;
|
||||
|
||||
// print("selectedUserType - $selectedUserType");
|
||||
|
||||
// if (selectedCountry!.isNotEmpty) {
|
||||
// errorMessages.remove("country_code");
|
||||
// }
|
||||
@ -1989,43 +2155,32 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
Text("Role ", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200, color: Colors.black)),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldUserWrapper(
|
||||
isFocused: false,
|
||||
isFocused: false, // Dropdown doesn't use focus
|
||||
isDesktop: isDesktop,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: DropdownSearch<String>(
|
||||
selectedItem: selectedRole,
|
||||
enabled: !isViewMode,
|
||||
popupProps: PopupProps.menu(
|
||||
// showSearchBox: true,
|
||||
fit: FlexFit.loose, // Allows flexible height
|
||||
constraints: BoxConstraints(maxHeight: 250),
|
||||
height: 45, // Set appropriate height
|
||||
child: DropdownButtonFormField<String>(
|
||||
value: selectedRole,
|
||||
style: TextStyle(fontSize: 12),
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding:
|
||||
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||
),
|
||||
items: ["Role 1", "Role 2", "Role 3"],
|
||||
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: (String? newValue) {
|
||||
onChanged: isViewMode ? null : (newValue) {
|
||||
setState(() {
|
||||
// Find the country_code based on selected country_name
|
||||
selectedRole = newValue;
|
||||
|
||||
// if (selectedCountry!.isNotEmpty) {
|
||||
// errorMessages.remove("country_code");
|
||||
// }
|
||||
|
||||
selectedRole = newValue;
|
||||
});
|
||||
},
|
||||
|
||||
items:apiRoleData?.map<DropdownMenuItem<String>>((item){
|
||||
return DropdownMenuItem(
|
||||
value: item['dropdown_key'], // ID as value
|
||||
child:Text(item['dropdown_value'] ?? "Select")
|
||||
|
||||
);
|
||||
}).toList(),
|
||||
hint: Text("Select"),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2039,7 +2194,7 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Level", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200, color: Colors.black)),
|
||||
Text("Group", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200, color: Colors.black)),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldUserWrapper(
|
||||
isFocused: false,
|
||||
@ -2097,44 +2252,30 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
||||
Text("Department", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200, color: Colors.black)),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldUserWrapper(
|
||||
isFocused: false,
|
||||
isFocused: false, // Dropdown doesn't use focus
|
||||
isDesktop: isDesktop,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: DropdownSearch<String>(
|
||||
selectedItem: selectedDepartment,
|
||||
enabled: !isViewMode,
|
||||
popupProps: PopupProps.menu(
|
||||
// showSearchBox: true,
|
||||
fit: FlexFit.loose, // Allows flexible height
|
||||
constraints: BoxConstraints(maxHeight: 250),
|
||||
|
||||
height: 45, // Set appropriate height
|
||||
child: DropdownButtonFormField<String>(
|
||||
value: selectedDepartment,
|
||||
style: TextStyle(fontSize: 12),
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding:
|
||||
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||
),
|
||||
items: ["Dep1", "Dep2", "Dep3"],
|
||||
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: (String? newValue) {
|
||||
onChanged: isViewMode ? null : (newValue) {
|
||||
setState(() {
|
||||
// Find the country_code based on selected country_name
|
||||
selectedDepartment = newValue;
|
||||
|
||||
// if (selectedCountry!.isNotEmpty) {
|
||||
// errorMessages.remove("country_code");
|
||||
// }
|
||||
|
||||
selectedDepartment = newValue;
|
||||
});
|
||||
},
|
||||
items:apiCostData?.map<DropdownMenuItem<String>>((item){
|
||||
return DropdownMenuItem(
|
||||
value: item['department_id'], // ID as value
|
||||
child: Text(item['name'] ?? "Unknown"),
|
||||
);
|
||||
}).toList(),
|
||||
hint: Text("Select"),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@ -388,8 +388,6 @@ class _UserListScreenState extends State<UserListScreen> {
|
||||
SizedBox(width: 10,),
|
||||
Text(user['user_type'] ?? '') ],),
|
||||
],),
|
||||
|
||||
|
||||
],
|
||||
)
|
||||
),
|
||||
|
||||
@ -69,4 +69,95 @@ class ApiService {
|
||||
}
|
||||
|
||||
|
||||
Future<List> fetchCostCenter() async {
|
||||
final String apiUrldata = '$apiUrl/api/getCostCenterMaster';
|
||||
|
||||
final token = await getToken();
|
||||
|
||||
final userId = await getUserId();
|
||||
|
||||
// print("SUSRTRT- $userId");
|
||||
//
|
||||
if (token == null) {
|
||||
throw Exception('Token not found. Please log in.');
|
||||
}
|
||||
|
||||
final response = await http.get(
|
||||
Uri.parse(apiUrldata),
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
try {
|
||||
final data = json.decode(response.body);
|
||||
print(data);
|
||||
|
||||
if (!data.containsKey('data') || data['data'] is!List) {
|
||||
throw Exception("Invalid response format: 'data' field is missing or not a List");
|
||||
}
|
||||
|
||||
List <dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
||||
// setState(() {
|
||||
// apiCostData = plansJson; // Store API response in state
|
||||
// if(apiCostData!.isNotEmpty){
|
||||
// selectedCostCenterId =apiCostData?.first['department_id'];
|
||||
// }
|
||||
|
||||
// if (apiCostData != null && apiCostData!.isNotEmpty) {
|
||||
// selectedCostCenterId ??= apiCostData!.first['department_id']?.toString();
|
||||
// }
|
||||
// });
|
||||
|
||||
print('plansJSON');
|
||||
|
||||
return plansJson;
|
||||
|
||||
|
||||
} catch (e) {
|
||||
throw Exception('Error parsing response: $e');
|
||||
}
|
||||
} else {
|
||||
throw Exception('Failed to load plans');
|
||||
}
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> fetchMasterDropdown() async {
|
||||
final String apiUrldata = '$apiUrl/api/getDropdownMaster';
|
||||
|
||||
final token = await getToken();
|
||||
|
||||
if (token == null) {
|
||||
throw Exception('Token not found. Please log in.');
|
||||
}
|
||||
|
||||
final response = await http.get(
|
||||
Uri.parse(apiUrldata),
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',},);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
try {
|
||||
final data = json.decode(response.body);
|
||||
print(data);
|
||||
if (!data.containsKey('data') || data['data'] is! Map) {
|
||||
throw Exception("Invalid response format: 'data' field is missing or not a Map");
|
||||
}
|
||||
|
||||
Map<String, dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
||||
|
||||
return plansJson;
|
||||
|
||||
} catch (e) {
|
||||
throw Exception('Error parsing response: $e');
|
||||
}
|
||||
} else {
|
||||
throw Exception('Failed to load plans');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -4,3 +4,9 @@ Future<String?> getToken() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return prefs.getString("auth_token");
|
||||
}
|
||||
|
||||
|
||||
Future<String?> getUserId() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return prefs.getString('userId');
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user