user management functionalities
This commit is contained in:
parent
c8f2d798ea
commit
41308b2590
@ -335,7 +335,6 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void getSelectedPlanFor(){
|
void getSelectedPlanFor(){
|
||||||
if (!mounted) return;
|
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 String apiUrldata = '$apiUrl/api/plans/createOrEditPlan';
|
||||||
final token = await getToken(); // Fetch token
|
final token = await getToken(); // Fetch token
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:frontend/Screens/policy/policyCriteria.dart';
|
||||||
import 'package:responsive_builder/responsive_builder.dart';
|
import 'package:responsive_builder/responsive_builder.dart';
|
||||||
|
|
||||||
import '../../routes/custom_appBar.dart';
|
import '../../routes/custom_appBar.dart';
|
||||||
@ -203,7 +204,8 @@ class _PolicyState extends State<Policy>{
|
|||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 180,
|
width: 180,
|
||||||
height: isDesktop? 65 : 50,
|
height: isDesktop ? MediaQuery.of(context).size.height * 0.1 : 50,
|
||||||
|
|
||||||
child:GestureDetector(
|
child:GestureDetector(
|
||||||
onTap :(){
|
onTap :(){
|
||||||
print("Selected Services - $service - $index");
|
print("Selected Services - $service - $index");
|
||||||
@ -242,45 +244,10 @@ class _PolicyState extends State<Policy>{
|
|||||||
Widget _buildPolicyCategory(bool isDesktop){
|
Widget _buildPolicyCategory(bool isDesktop){
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.brown.shade100,
|
// color: Colors.brown.shade100,
|
||||||
// color: Colors.white60,
|
color: Colors.white60,
|
||||||
|
|
||||||
|
child: PolicyCriteria(isDesktop: isDesktop)
|
||||||
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"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
|
|
||||||
),
|
),
|
||||||
|
|||||||
@ -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 final List<dynamic>? apiCountryData ;
|
||||||
|
|
||||||
late List<dynamic>? apiCountryData;
|
late List<dynamic>? apiCountryData;
|
||||||
|
late List<dynamic>? apiCostData;
|
||||||
|
late List<dynamic>? apiRoleData;
|
||||||
late List<dynamic>? apiUserData;
|
late List<dynamic>? apiUserData;
|
||||||
Map<String, dynamic>? apiselectedUser;
|
Map<String, dynamic>? apiselectedUser;
|
||||||
|
|
||||||
@ -102,20 +102,20 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
|||||||
"user_type" : selectedUserType,
|
"user_type" : selectedUserType,
|
||||||
"role_id" : selectedRole,
|
"role_id" : selectedRole,
|
||||||
"department_id": selectedDepartment,
|
"department_id": selectedDepartment,
|
||||||
"level_id" : selectedLevel,
|
"group_id" : selectedLevel,
|
||||||
|
|
||||||
"first_approver": selectedFirstApprover,
|
"first_approver": selectedFirstApprover,
|
||||||
"second_approver": selectedSecondApprover,
|
"second_approver": selectedSecondApprover,
|
||||||
"third_approver": selectedThirdApprover,
|
"third_approver": selectedThirdApprover,
|
||||||
"passport_number": controllers["passportNumber"]?.text,
|
"passport_number": controllers["passportNumber"]?.text,
|
||||||
"place_of_issue": controllers["placeOfIssue"]?.text,
|
"place_of_issue": controllers["placeOfIssue"]?.text,
|
||||||
"passport_document": selectedFileNames,
|
"passport_document": base64PDF,
|
||||||
|
|
||||||
"date_of_issue": controllers["dateOfIssue"]?.text,
|
"date_of_issue": controllers["dateOfIssue"]?.text,
|
||||||
"date_of_expiry": controllers["dateOfExpiry"]?.text,
|
"date_of_expiry": controllers["dateOfExpiry"]?.text,
|
||||||
"created_by": userId,
|
"created_by": userId,
|
||||||
"is_active": "1",
|
"is_active": "1",
|
||||||
"passport_fileData": base64PDF,
|
// "passport_fileData": base64PDF,
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@ -145,10 +145,10 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
|||||||
controllers["dateOfExpiry"]?.text = apiselectedUser?["date_of_expiry"] ?? "";
|
controllers["dateOfExpiry"]?.text = apiselectedUser?["date_of_expiry"] ?? "";
|
||||||
|
|
||||||
|
|
||||||
selectedCountry = apiselectedUser?["country"]?.toString() ?? "";
|
selectedCountry = apiselectedUser?["country_code"]?.toString() ?? "";
|
||||||
selectedGender = apiselectedUser?["gender"]?.toString().trim() ?? "";
|
selectedGender = apiselectedUser?["gender"]?.toString().trim() ?? "";
|
||||||
|
|
||||||
selectedFileNames = apiselectedUser?["passport_document"]?.toString().trim() ?? "";
|
base64PDF = apiselectedUser?["passport_document"]?.toString().trim() ?? "";
|
||||||
selectedUserType = apiselectedUser?["user_type"]?.toString().trim() ?? "";
|
selectedUserType = apiselectedUser?["user_type"]?.toString().trim() ?? "";
|
||||||
selectedRole = apiselectedUser?["role_id"]?.toString().trim() ?? "";
|
selectedRole = apiselectedUser?["role_id"]?.toString().trim() ?? "";
|
||||||
selectedDepartment = apiselectedUser?["department_id"]?.toString().trim() ?? "";
|
selectedDepartment = apiselectedUser?["department_id"]?.toString().trim() ?? "";
|
||||||
@ -178,6 +178,8 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
|||||||
apiCountryData = null;
|
apiCountryData = null;
|
||||||
apiUserData = null;
|
apiUserData = null;
|
||||||
apiselectedUser = null;
|
apiselectedUser = null;
|
||||||
|
apiCostData = null;
|
||||||
|
apiRoleData = null;
|
||||||
|
|
||||||
// Delay accessing context until the widget is fully initialized
|
// Delay accessing context until the widget is fully initialized
|
||||||
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
@ -246,7 +248,9 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
|||||||
|
|
||||||
initializeData();
|
initializeData();
|
||||||
fetchCountries();
|
fetchCountries();
|
||||||
|
fetchDepartment();
|
||||||
fetchUsers();
|
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 {
|
Future<void> fetchUsers() async {
|
||||||
try {
|
try {
|
||||||
List<dynamic> users = await apiService.fetchUsers();
|
List<dynamic> users = await apiService.fetchUsers();
|
||||||
setState(() {
|
setState(() {
|
||||||
apiUserData = users;
|
// apiUserData = users;
|
||||||
|
|
||||||
|
apiUserData = users.where((user) => user["role_id"] == "3").toList();
|
||||||
|
|
||||||
|
print("APIUSerDATa - $apiUserData");
|
||||||
|
|
||||||
userList = apiUserData ?? [];
|
userList = apiUserData ?? [];
|
||||||
userMap = {
|
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() {
|
void printFormData() {
|
||||||
for (var field in dataHeader) {
|
for (var field in dataHeader) {
|
||||||
@ -346,6 +384,7 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
|||||||
Map<String,dynamic> data = userDetials;
|
Map<String,dynamic> data = userDetials;
|
||||||
|
|
||||||
if (!isValidData(data)) {
|
if (!isValidData(data)) {
|
||||||
|
print("USERDETAILS : $userDetials");
|
||||||
print("Validation Failed: Required fields are missing.");
|
print("Validation Failed: Required fields are missing.");
|
||||||
setState(() {});
|
setState(() {});
|
||||||
return; // Stop execution if validation fails
|
return; // Stop execution if validation fails
|
||||||
@ -362,7 +401,11 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
|||||||
errorMessages.clear(); // Reset errors
|
errorMessages.clear(); // Reset errors
|
||||||
|
|
||||||
// Required fields that must not be empty
|
// 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
|
// Check validation for each field
|
||||||
for (String field in requiredFields) {
|
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
|
// Mobile number validation for both mobile_no and alternate_mobile_no
|
||||||
if (data["mobile_no"] != null && data["mobile_no"].toString().isNotEmpty) {
|
if (data["mobile_no"] != null && data["mobile_no"].toString().isNotEmpty) {
|
||||||
if (!RegExp(r"^\d{10}$").hasMatch(data["mobile_no"].toString())) {
|
if (!RegExp(r"^\d{10}$").hasMatch(data["mobile_no"].toString())) {
|
||||||
@ -402,6 +446,8 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void pickPDFWeb() {
|
void pickPDFWeb() {
|
||||||
html.FileUploadInputElement uploadInput = html.FileUploadInputElement();
|
html.FileUploadInputElement uploadInput = html.FileUploadInputElement();
|
||||||
uploadInput.accept = '.pdf';
|
uploadInput.accept = '.pdf';
|
||||||
@ -416,35 +462,87 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
|||||||
print('File picked: ${file.name}');
|
print('File picked: ${file.name}');
|
||||||
print('File size: ${file.size} bytes');
|
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(() {
|
setState(() {
|
||||||
selectedFileNames = file.name; // Store only one file name
|
selectedFileNames = file.name; // Store file name
|
||||||
passportDocumentBytes = reader.result as Uint8List; // Store file data
|
passportDocumentBytes = reader.result as Uint8List; // Store file data
|
||||||
|
|
||||||
// 🔹 Convert file to Base64
|
// 🔹 Convert to Base64 properly
|
||||||
base64PDF = base64Encode(passportDocumentBytes! as List<int>);
|
base64PDF = base64Encode(passportDocumentBytes!);
|
||||||
// File size check: Ensure the file size does not exceed 3MB
|
|
||||||
int maxFileSize = 3 * 1024 * 1024; // 3MB in bytes
|
|
||||||
|
|
||||||
if (file.size > maxFileSize) {
|
print('Base64 Length: ${base64PDF!.length}');
|
||||||
print('Error: File size exceeds 3MB');
|
print('Base64 (first 50 chars): ${base64PDF!.substring(0, 50)}');
|
||||||
// You can show an error message here if necessary
|
|
||||||
// For example:
|
// Ensure Base64 starts with "JVBERi0x"
|
||||||
// showError('File size cannot exceed 3MB');
|
if (!base64PDF!.startsWith("JVBERi0x")) {
|
||||||
|
print("Error: Base64 does not start with 'JVBERi0x'");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
print('File size: ${file.size} bytes');
|
// 🔹 File size check: Ensure it does not exceed 3MB
|
||||||
print('Base64 Data: $base64PDF'); // Debugging
|
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 {
|
Future<void> createUserData(Map<String, dynamic> userData) async {
|
||||||
|
|
||||||
bool isUpdating = apiselectedUser != null && apiselectedUser!.isNotEmpty;
|
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,
|
Text("Personal Details", style: TextStyle(fontSize: 18,fontWeight: FontWeight.bold,
|
||||||
// color: Colors.black,
|
// color: Colors.black,
|
||||||
color: Color(0xFF8B8FB2)
|
color: Color(0xFF8B8FB2)
|
||||||
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],),
|
],),
|
||||||
@ -1238,36 +1335,7 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
|||||||
children: [
|
children: [
|
||||||
Text("Change Password", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200, color: Colors.black)),
|
Text("Change Password", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200, color: Colors.black)),
|
||||||
SizedBox(height: 5),
|
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: [
|
children: [
|
||||||
Text("Passport Document", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200, color: Colors.black)),
|
Text("Passport Document", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200, color: Colors.black)),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
|
|
||||||
CustomTextFieldUserWrapper(
|
CustomTextFieldUserWrapper(
|
||||||
isFocused: false,
|
isFocused: false,
|
||||||
isDesktop: isDesktop,
|
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),
|
constraints: BoxConstraints(maxHeight: 250),
|
||||||
|
|
||||||
),
|
),
|
||||||
items: ["Admin", "Manager", "HR"],
|
items: ["Normal", "Privilege",],
|
||||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
dropdownSearchDecoration: InputDecoration(
|
dropdownSearchDecoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
@ -1952,6 +2116,8 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
|||||||
// Find the country_code based on selected country_name
|
// Find the country_code based on selected country_name
|
||||||
selectedUserType = newValue;
|
selectedUserType = newValue;
|
||||||
|
|
||||||
|
// print("selectedUserType - $selectedUserType");
|
||||||
|
|
||||||
// if (selectedCountry!.isNotEmpty) {
|
// if (selectedCountry!.isNotEmpty) {
|
||||||
// errorMessages.remove("country_code");
|
// 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)),
|
Text("Role ", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200, color: Colors.black)),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
CustomTextFieldUserWrapper(
|
CustomTextFieldUserWrapper(
|
||||||
isFocused: false,
|
isFocused: false, // Dropdown doesn't use focus
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 45, // Set appropriate height
|
||||||
child: DropdownSearch<String>(
|
child: DropdownButtonFormField<String>(
|
||||||
selectedItem: selectedRole,
|
value: selectedRole,
|
||||||
enabled: !isViewMode,
|
style: TextStyle(fontSize: 12),
|
||||||
popupProps: PopupProps.menu(
|
decoration: InputDecoration(
|
||||||
// showSearchBox: true,
|
border: InputBorder.none,
|
||||||
fit: FlexFit.loose, // Allows flexible height
|
contentPadding:
|
||||||
constraints: BoxConstraints(maxHeight: 250),
|
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||||
),
|
),
|
||||||
items: ["Role 1", "Role 2", "Role 3"],
|
onChanged: isViewMode ? null : (newValue) {
|
||||||
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) {
|
|
||||||
setState(() {
|
setState(() {
|
||||||
// Find the country_code based on selected country_name
|
selectedRole = newValue;
|
||||||
selectedRole = newValue;
|
|
||||||
|
|
||||||
// if (selectedCountry!.isNotEmpty) {
|
|
||||||
// errorMessages.remove("country_code");
|
|
||||||
// }
|
|
||||||
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
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(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
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),
|
SizedBox(height: 5),
|
||||||
CustomTextFieldUserWrapper(
|
CustomTextFieldUserWrapper(
|
||||||
isFocused: false,
|
isFocused: false,
|
||||||
@ -2097,44 +2252,30 @@ class _CreateUserFormState extends State<CreateUserForm>{
|
|||||||
Text("Department", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200, color: Colors.black)),
|
Text("Department", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200, color: Colors.black)),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
CustomTextFieldUserWrapper(
|
CustomTextFieldUserWrapper(
|
||||||
isFocused: false,
|
isFocused: false, // Dropdown doesn't use focus
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 45, // Set appropriate height
|
||||||
child: DropdownSearch<String>(
|
child: DropdownButtonFormField<String>(
|
||||||
selectedItem: selectedDepartment,
|
value: selectedDepartment,
|
||||||
enabled: !isViewMode,
|
style: TextStyle(fontSize: 12),
|
||||||
popupProps: PopupProps.menu(
|
decoration: InputDecoration(
|
||||||
// showSearchBox: true,
|
border: InputBorder.none,
|
||||||
fit: FlexFit.loose, // Allows flexible height
|
contentPadding:
|
||||||
constraints: BoxConstraints(maxHeight: 250),
|
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||||
|
|
||||||
),
|
),
|
||||||
items: ["Dep1", "Dep2", "Dep3"],
|
onChanged: isViewMode ? null : (newValue) {
|
||||||
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) {
|
|
||||||
setState(() {
|
setState(() {
|
||||||
// Find the country_code based on selected country_name
|
selectedDepartment = newValue;
|
||||||
selectedDepartment = newValue;
|
|
||||||
|
|
||||||
// if (selectedCountry!.isNotEmpty) {
|
|
||||||
// errorMessages.remove("country_code");
|
|
||||||
// }
|
|
||||||
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
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,),
|
SizedBox(width: 10,),
|
||||||
Text(user['user_type'] ?? '') ],),
|
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();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
return prefs.getString("auth_token");
|
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