feat: Update employee creation process and API endpoints for improved functionality
This commit is contained in:
parent
943c7c7b50
commit
69e64ec789
@ -110,7 +110,8 @@ class AddEmployeeController extends MyController {
|
|||||||
logSafe("Failed to fetch roles: null result", level: LogLevel.error);
|
logSafe("Failed to fetch roles: null result", level: LogLevel.error);
|
||||||
}
|
}
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
logSafe("Error fetching roles", level: LogLevel.error, error: e, stackTrace: st);
|
logSafe("Error fetching roles",
|
||||||
|
level: LogLevel.error, error: e, stackTrace: st);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +121,7 @@ class AddEmployeeController extends MyController {
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> createEmployees() async {
|
Future<Map<String, dynamic>?> createEmployees() async {
|
||||||
logSafe("Starting employee creation...");
|
logSafe("Starting employee creation...");
|
||||||
if (selectedGender == null || selectedRoleId == null) {
|
if (selectedGender == null || selectedRoleId == null) {
|
||||||
logSafe("Missing gender or role.", level: LogLevel.warning);
|
logSafe("Missing gender or role.", level: LogLevel.warning);
|
||||||
@ -129,14 +130,13 @@ class AddEmployeeController extends MyController {
|
|||||||
message: "Please select both Gender and Role.",
|
message: "Please select both Gender and Role.",
|
||||||
type: SnackbarType.warning,
|
type: SnackbarType.warning,
|
||||||
);
|
);
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final firstName = basicValidator.getController("first_name")?.text.trim();
|
final firstName = basicValidator.getController("first_name")?.text.trim();
|
||||||
final lastName = basicValidator.getController("last_name")?.text.trim();
|
final lastName = basicValidator.getController("last_name")?.text.trim();
|
||||||
final phoneNumber = basicValidator.getController("phone_number")?.text.trim();
|
final phoneNumber =
|
||||||
|
basicValidator.getController("phone_number")?.text.trim();
|
||||||
logSafe("Creating employee", level: LogLevel.info);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final response = await ApiService.createEmployee(
|
final response = await ApiService.createEmployee(
|
||||||
@ -146,20 +146,24 @@ class AddEmployeeController extends MyController {
|
|||||||
gender: selectedGender!.name,
|
gender: selectedGender!.name,
|
||||||
jobRoleId: selectedRoleId!,
|
jobRoleId: selectedRoleId!,
|
||||||
);
|
);
|
||||||
logSafe("Response: $response");
|
|
||||||
if (response == true) {
|
logSafe("Response: $response");
|
||||||
|
|
||||||
|
if (response != null && response['success'] == true) {
|
||||||
logSafe("Employee created successfully.");
|
logSafe("Employee created successfully.");
|
||||||
showAppSnackbar(
|
showAppSnackbar(
|
||||||
title: "Success",
|
title: "Success",
|
||||||
message: "Employee created successfully!",
|
message: "Employee created successfully!",
|
||||||
type: SnackbarType.success,
|
type: SnackbarType.success,
|
||||||
);
|
);
|
||||||
return true;
|
return response;
|
||||||
} else {
|
} else {
|
||||||
logSafe("Failed to create employee (response false)", level: LogLevel.error);
|
logSafe("Failed to create employee (response false)",
|
||||||
|
level: LogLevel.error);
|
||||||
}
|
}
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
logSafe("Error creating employee", level: LogLevel.error, error: e, stackTrace: st);
|
logSafe("Error creating employee",
|
||||||
|
level: LogLevel.error, error: e, stackTrace: st);
|
||||||
}
|
}
|
||||||
|
|
||||||
showAppSnackbar(
|
showAppSnackbar(
|
||||||
@ -167,7 +171,7 @@ logSafe("Response: $response");
|
|||||||
message: "Failed to create employee.",
|
message: "Failed to create employee.",
|
||||||
type: SnackbarType.error,
|
type: SnackbarType.error,
|
||||||
);
|
);
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> _checkAndRequestContactsPermission() async {
|
Future<bool> _checkAndRequestContactsPermission() async {
|
||||||
@ -181,7 +185,8 @@ logSafe("Response: $response");
|
|||||||
|
|
||||||
showAppSnackbar(
|
showAppSnackbar(
|
||||||
title: "Permission Required",
|
title: "Permission Required",
|
||||||
message: "Please allow Contacts permission from settings to pick a contact.",
|
message:
|
||||||
|
"Please allow Contacts permission from settings to pick a contact.",
|
||||||
type: SnackbarType.warning,
|
type: SnackbarType.warning,
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
@ -195,7 +200,8 @@ logSafe("Response: $response");
|
|||||||
final picked = await FlutterContacts.openExternalPick();
|
final picked = await FlutterContacts.openExternalPick();
|
||||||
if (picked == null) return;
|
if (picked == null) return;
|
||||||
|
|
||||||
final contact = await FlutterContacts.getContact(picked.id, withProperties: true);
|
final contact =
|
||||||
|
await FlutterContacts.getContact(picked.id, withProperties: true);
|
||||||
if (contact == null) {
|
if (contact == null) {
|
||||||
showAppSnackbar(
|
showAppSnackbar(
|
||||||
title: "Error",
|
title: "Error",
|
||||||
@ -216,7 +222,8 @@ logSafe("Response: $response");
|
|||||||
|
|
||||||
final indiaPhones = contact.phones.where((p) {
|
final indiaPhones = contact.phones.where((p) {
|
||||||
final normalized = p.number.replaceAll(RegExp(r'[^0-9+]'), '');
|
final normalized = p.number.replaceAll(RegExp(r'[^0-9+]'), '');
|
||||||
return normalized.startsWith('+91') || RegExp(r'^\d{10}$').hasMatch(normalized);
|
return normalized.startsWith('+91') ||
|
||||||
|
RegExp(r'^\d{10}$').hasMatch(normalized);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
if (indiaPhones.isEmpty) {
|
if (indiaPhones.isEmpty) {
|
||||||
@ -256,10 +263,12 @@ logSafe("Response: $response");
|
|||||||
? normalizedPhone.substring(normalizedPhone.length - 10)
|
? normalizedPhone.substring(normalizedPhone.length - 10)
|
||||||
: normalizedPhone;
|
: normalizedPhone;
|
||||||
|
|
||||||
basicValidator.getController('phone_number')?.text = phoneWithoutCountryCode;
|
basicValidator.getController('phone_number')?.text =
|
||||||
|
phoneWithoutCountryCode;
|
||||||
update();
|
update();
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
logSafe("Error fetching contacts", level: LogLevel.error, error: e, stackTrace: st);
|
logSafe("Error fetching contacts",
|
||||||
|
level: LogLevel.error, error: e, stackTrace: st);
|
||||||
showAppSnackbar(
|
showAppSnackbar(
|
||||||
title: "Error",
|
title: "Error",
|
||||||
message: "Failed to fetch contacts.",
|
message: "Failed to fetch contacts.",
|
||||||
|
|||||||
@ -18,7 +18,7 @@ class ApiEndpoints {
|
|||||||
static const String getAllEmployeesByProject = "/employee/list";
|
static const String getAllEmployeesByProject = "/employee/list";
|
||||||
static const String getAllEmployees = "/employee/list";
|
static const String getAllEmployees = "/employee/list";
|
||||||
static const String getRoles = "/roles/jobrole";
|
static const String getRoles = "/roles/jobrole";
|
||||||
static const String createEmployee = "/employee/manage";
|
static const String createEmployee = "/employee/manage-mobile";
|
||||||
static const String getEmployeeInfo = "/employee/profile/get";
|
static const String getEmployeeInfo = "/employee/profile/get";
|
||||||
static const String assignEmployee = "/employee/profile/get";
|
static const String assignEmployee = "/employee/profile/get";
|
||||||
static const String getAssignedProjects = "/project/assigned-projects";
|
static const String getAssignedProjects = "/project/assigned-projects";
|
||||||
|
|||||||
@ -479,37 +479,37 @@ class ApiService {
|
|||||||
|
|
||||||
/// Get list of assigned projects for a specific employee
|
/// Get list of assigned projects for a specific employee
|
||||||
/// Get list of assigned projects for a specific employee
|
/// Get list of assigned projects for a specific employee
|
||||||
static Future<List<dynamic>?> getAssignedProjects(String employeeId) async {
|
static Future<List<dynamic>?> getAssignedProjects(String employeeId) async {
|
||||||
if (employeeId.isEmpty) {
|
if (employeeId.isEmpty) {
|
||||||
throw ArgumentError("employeeId must not be empty");
|
throw ArgumentError("employeeId must not be empty");
|
||||||
}
|
|
||||||
|
|
||||||
final endpoint = "${ApiEndpoints.getAssignedProjects}/$employeeId";
|
|
||||||
|
|
||||||
try {
|
|
||||||
final response = await _getRequest(endpoint);
|
|
||||||
|
|
||||||
if (response == null) {
|
|
||||||
logSafe("Failed to fetch assigned projects: null response",
|
|
||||||
level: LogLevel.error);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final parsed = _parseResponse(response, label: "Assigned Projects");
|
final endpoint = "${ApiEndpoints.getAssignedProjects}/$employeeId";
|
||||||
if (parsed is List) {
|
|
||||||
return parsed;
|
try {
|
||||||
} else {
|
final response = await _getRequest(endpoint);
|
||||||
logSafe("Unexpected response format for assigned projects.",
|
|
||||||
|
if (response == null) {
|
||||||
|
logSafe("Failed to fetch assigned projects: null response",
|
||||||
|
level: LogLevel.error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final parsed = _parseResponse(response, label: "Assigned Projects");
|
||||||
|
if (parsed is List) {
|
||||||
|
return parsed;
|
||||||
|
} else {
|
||||||
|
logSafe("Unexpected response format for assigned projects.",
|
||||||
|
level: LogLevel.error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (e, stack) {
|
||||||
|
logSafe("Exception during getAssignedProjects API: $e",
|
||||||
level: LogLevel.error);
|
level: LogLevel.error);
|
||||||
|
logSafe("StackTrace: $stack", level: LogLevel.debug);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} catch (e, stack) {
|
|
||||||
logSafe("Exception during getAssignedProjects API: $e",
|
|
||||||
level: LogLevel.error);
|
|
||||||
logSafe("StackTrace: $stack", level: LogLevel.debug);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Assign projects to a specific employee
|
/// Assign projects to a specific employee
|
||||||
static Future<bool> assignProjects({
|
static Future<bool> assignProjects({
|
||||||
@ -839,8 +839,7 @@ static Future<List<dynamic>?> getAssignedProjects(String employeeId) async {
|
|||||||
static Future<List<dynamic>?> getRoles() async =>
|
static Future<List<dynamic>?> getRoles() async =>
|
||||||
_getRequest(ApiEndpoints.getRoles).then(
|
_getRequest(ApiEndpoints.getRoles).then(
|
||||||
(res) => res != null ? _parseResponse(res, label: 'Roles') : null);
|
(res) => res != null ? _parseResponse(res, label: 'Roles') : null);
|
||||||
|
static Future<Map<String, dynamic>?> createEmployee({
|
||||||
static Future<bool> createEmployee({
|
|
||||||
required String firstName,
|
required String firstName,
|
||||||
required String lastName,
|
required String lastName,
|
||||||
required String phoneNumber,
|
required String phoneNumber,
|
||||||
@ -854,15 +853,20 @@ static Future<List<dynamic>?> getAssignedProjects(String employeeId) async {
|
|||||||
"gender": gender,
|
"gender": gender,
|
||||||
"jobRoleId": jobRoleId,
|
"jobRoleId": jobRoleId,
|
||||||
};
|
};
|
||||||
|
|
||||||
final response = await _postRequest(
|
final response = await _postRequest(
|
||||||
ApiEndpoints.createEmployee,
|
ApiEndpoints.createEmployee,
|
||||||
body,
|
body,
|
||||||
customTimeout: extendedTimeout,
|
customTimeout: extendedTimeout,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response == null) return false;
|
if (response == null) return null;
|
||||||
|
|
||||||
final json = jsonDecode(response.body);
|
final json = jsonDecode(response.body);
|
||||||
return response.statusCode == 200 && json['success'] == true;
|
return {
|
||||||
|
"success": response.statusCode == 200 && json['success'] == true,
|
||||||
|
"data": json
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<Map<String, dynamic>?> getEmployeeDetails(
|
static Future<Map<String, dynamic>?> getEmployeeDetails(
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
import 'package:marco/controller/dashboard/add_employee_controller.dart';
|
import 'package:marco/controller/dashboard/add_employee_controller.dart';
|
||||||
import 'package:marco/controller/dashboard/employees_screen_controller.dart';
|
import 'package:marco/controller/dashboard/employees_screen_controller.dart';
|
||||||
@ -274,6 +275,12 @@ class _AddEmployeeBottomSheetState extends State<AddEmployeeBottomSheet>
|
|||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
keyboardType: TextInputType.phone,
|
keyboardType: TextInputType.phone,
|
||||||
|
inputFormatters: [
|
||||||
|
// Allow only digits
|
||||||
|
FilteringTextInputFormatter.digitsOnly,
|
||||||
|
// Limit to 10 digits
|
||||||
|
LengthLimitingTextInputFormatter(10),
|
||||||
|
],
|
||||||
decoration: _inputDecoration("e.g., 9876543210")
|
decoration: _inputDecoration("e.g., 9876543210")
|
||||||
.copyWith(
|
.copyWith(
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
@ -355,9 +362,12 @@ class _AddEmployeeBottomSheetState extends State<AddEmployeeBottomSheet>
|
|||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
if (_controller.basicValidator
|
if (_controller.basicValidator
|
||||||
.validateForm()) {
|
.validateForm()) {
|
||||||
final success =
|
final result =
|
||||||
await _controller.createEmployees();
|
await _controller.createEmployees();
|
||||||
if (success) {
|
|
||||||
|
if (result != null &&
|
||||||
|
result['success'] == true) {
|
||||||
|
final employeeData = result['data'];
|
||||||
final employeeController =
|
final employeeController =
|
||||||
Get.find<EmployeesScreenController>();
|
Get.find<EmployeesScreenController>();
|
||||||
final projectId =
|
final projectId =
|
||||||
@ -387,7 +397,7 @@ class _AddEmployeeBottomSheetState extends State<AddEmployeeBottomSheet>
|
|||||||
_controller.selectedRoleId = null;
|
_controller.selectedRoleId = null;
|
||||||
_controller.update();
|
_controller.update();
|
||||||
|
|
||||||
Navigator.pop(context);
|
Navigator.pop(context, employeeData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import 'package:marco/helpers/widgets/my_custom_skeleton.dart';
|
|||||||
import 'package:marco/view/employees/employee_detail_screen.dart';
|
import 'package:marco/view/employees/employee_detail_screen.dart';
|
||||||
import 'package:marco/model/employee_model.dart';
|
import 'package:marco/model/employee_model.dart';
|
||||||
import 'package:marco/helpers/utils/launcher_utils.dart';
|
import 'package:marco/helpers/utils/launcher_utils.dart';
|
||||||
|
import 'package:marco/view/employees/assign_employee_bottom_sheet.dart';
|
||||||
|
|
||||||
class EmployeesScreen extends StatefulWidget {
|
class EmployeesScreen extends StatefulWidget {
|
||||||
const EmployeesScreen({super.key});
|
const EmployeesScreen({super.key});
|
||||||
@ -162,7 +163,8 @@ class _EmployeesScreenState extends State<EmployeesScreen> with UIMixin {
|
|||||||
),
|
),
|
||||||
floatingActionButton: InkWell(
|
floatingActionButton: InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final result = await showModalBottomSheet<bool>(
|
// Step 1: Open AddEmployeeBottomSheet
|
||||||
|
final result = await showModalBottomSheet<Map<String, dynamic>>(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
@ -172,7 +174,29 @@ class _EmployeesScreenState extends State<EmployeesScreen> with UIMixin {
|
|||||||
builder: (context) => AddEmployeeBottomSheet(),
|
builder: (context) => AddEmployeeBottomSheet(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (result == true) {
|
// Step 2: Check if employee creation was successful
|
||||||
|
if (result != null && result['success'] == true) {
|
||||||
|
print("Employee data from bottom sheet: $result");
|
||||||
|
|
||||||
|
final employeeData = result['data'];
|
||||||
|
final employeeId = employeeData['id'] as String;
|
||||||
|
final jobRoleId = employeeData['jobRoleId'] as String?;
|
||||||
|
|
||||||
|
// Step 3: Open AssignProjectBottomSheet for the new employee
|
||||||
|
await showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
builder: (context) => AssignProjectBottomSheet(
|
||||||
|
employeeId: employeeId,
|
||||||
|
jobRoleId: jobRoleId ?? '',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Step 4: Refresh employee list after project assignment
|
||||||
await _refreshEmployees();
|
await _refreshEmployees();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user