2025-07-16 10:31:09 +05:30

971 lines
30 KiB
Dart

import 'dart:convert';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart';
import 'package:marco/helpers/services/auth_service.dart';
import 'package:marco/helpers/services/api_endpoints.dart';
import 'package:marco/helpers/services/storage/local_storage.dart';
import 'package:jwt_decoder/jwt_decoder.dart';
import 'package:marco/helpers/services/app_logger.dart';
class ApiService {
static const Duration timeout = Duration(seconds: 30);
static const bool enableLogs = true;
static const Duration extendedTimeout = Duration(seconds: 60);
static Future<String?> _getToken() async {
final token = await LocalStorage.getJwtToken();
if (token == null) {
logSafe("No JWT token found.");
return null;
}
try {
if (JwtDecoder.isExpired(token)) {
logSafe("Access token is expired. Attempting refresh...");
final refreshed = await AuthService.refreshToken();
if (refreshed) {
return await LocalStorage.getJwtToken();
} else {
logSafe("Token refresh failed. Logging out...");
await LocalStorage.logout();
return null;
}
}
final expirationDate = JwtDecoder.getExpirationDate(token);
final now = DateTime.now();
final difference = expirationDate.difference(now);
if (difference.inMinutes < 2) {
logSafe(
"Access token is about to expire in ${difference.inSeconds}s. Refreshing...");
final refreshed = await AuthService.refreshToken();
if (refreshed) {
return await LocalStorage.getJwtToken();
}
}
} catch (e) {
logSafe("Token decoding error: $e", level: LogLevel.error);
}
return token;
}
static Map<String, String> _headers(String token) => {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
};
static void _log(String message) {
if (enableLogs) logSafe(message);
}
static dynamic _parseResponse(http.Response response, {String label = ''}) {
_log("$label Response: ${response.body}");
try {
final json = jsonDecode(response.body);
if (response.statusCode == 200 && json['success'] == true) {
return json['data'];
}
_log("API Error [$label]: ${json['message'] ?? 'Unknown error'}");
} catch (e) {
_log("Response parsing error [$label]: $e");
}
return null;
}
static dynamic _parseResponseForAllData(http.Response response,
{String label = ''}) {
_log("$label Response: ${response.body}");
try {
final body = response.body.trim();
if (body.isEmpty) throw FormatException("Empty response body");
final json = jsonDecode(body);
if (response.statusCode == 200 && json['success'] == true) {
return json;
}
_log("API Error [$label]: ${json['message'] ?? 'Unknown error'}");
} catch (e) {
_log("Response parsing error [$label]: $e");
}
return null;
}
static Future<http.Response?> _getRequest(
String endpoint, {
Map<String, String>? queryParams,
bool hasRetried = false,
}) async {
String? token = await _getToken();
if (token == null) {
logSafe("Token is null. Cannot proceed with GET request.",
level: LogLevel.error);
return null;
}
final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint")
.replace(queryParameters: queryParams);
logSafe("Initiating GET request", level: LogLevel.debug);
logSafe("URL: $uri", level: LogLevel.debug);
logSafe("Query Parameters: ${queryParams ?? {}}", level: LogLevel.debug);
logSafe("Headers: ${_headers(token)}", level: LogLevel.debug);
try {
final response =
await http.get(uri, headers: _headers(token)).timeout(timeout);
logSafe("Response Status: ${response.statusCode}", level: LogLevel.debug);
logSafe("Response Body: ${response.body}", level: LogLevel.debug);
if (response.statusCode == 401 && !hasRetried) {
logSafe("Unauthorized (401). Attempting token refresh...",
level: LogLevel.warning);
if (await AuthService.refreshToken()) {
logSafe("Token refresh succeeded. Retrying request...",
level: LogLevel.info);
return await _getRequest(
endpoint,
queryParams: queryParams,
hasRetried: true,
);
}
logSafe("Token refresh failed. Aborting request.",
level: LogLevel.error);
}
return response;
} catch (e) {
logSafe("HTTP GET Exception: $e", level: LogLevel.error);
return null;
}
}
static Future<http.Response?> _postRequest(
String endpoint,
dynamic body, {
Duration customTimeout = timeout,
bool hasRetried = false,
}) async {
String? token = await _getToken();
if (token == null) return null;
final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint");
logSafe(
"POST $uri\nHeaders: ${_headers(token)}\nBody: $body",
);
try {
final response = await http
.post(uri, headers: _headers(token), body: jsonEncode(body))
.timeout(customTimeout);
if (response.statusCode == 401 && !hasRetried) {
logSafe("Unauthorized POST. Attempting token refresh...");
if (await AuthService.refreshToken()) {
return await _postRequest(endpoint, body,
customTimeout: customTimeout, hasRetried: true);
}
}
return response;
} catch (e) {
logSafe("HTTP POST Exception: $e", level: LogLevel.error);
return null;
}
}
static Future<http.Response?> _putRequest(
String endpoint,
dynamic body, {
Map<String, String>? additionalHeaders,
Duration customTimeout = timeout,
bool hasRetried = false,
}) async {
String? token = await _getToken();
if (token == null) return null;
final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint");
logSafe(
"PUT $uri\nHeaders: ${_headers(token)}\nBody: $body",
);
final headers = {
..._headers(token),
if (additionalHeaders != null) ...additionalHeaders,
};
logSafe(
"PUT $uri\nHeaders: $headers\nBody: $body",
);
try {
final response = await http
.put(uri, headers: headers, body: jsonEncode(body))
.timeout(customTimeout);
if (response.statusCode == 401 && !hasRetried) {
logSafe("Unauthorized PUT. Attempting token refresh...");
if (await AuthService.refreshToken()) {
return await _putRequest(endpoint, body,
additionalHeaders: additionalHeaders,
customTimeout: customTimeout,
hasRetried: true);
}
}
return response;
} catch (e) {
logSafe("HTTP PUT Exception: $e", level: LogLevel.error);
return null;
}
}
// === Dashboard Endpoints ===
static Future<List<dynamic>?> getDashboardAttendanceOverview(
String projectId, int days) async {
if (projectId.isEmpty) throw ArgumentError('projectId must not be empty');
if (days <= 0) throw ArgumentError('days must be greater than 0');
final endpoint =
"${ApiEndpoints.getDashboardAttendanceOverview}/$projectId?days=$days";
return _getRequest(endpoint).then((res) => res != null
? _parseResponse(res, label: 'Dashboard Attendance Overview')
: null);
}
/// Directory calling the API
static Future<bool> deleteBucket(String id) async {
final endpoint = "${ApiEndpoints.updateBucket}/$id";
try {
final token = await _getToken();
if (token == null) {
logSafe("Token is null. Cannot proceed with DELETE request.",
level: LogLevel.error);
return false;
}
final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint");
logSafe("Sending DELETE request to $uri", level: LogLevel.debug);
final response =
await http.delete(uri, headers: _headers(token)).timeout(timeout);
logSafe("DELETE bucket response status: ${response.statusCode}");
logSafe("DELETE bucket response body: ${response.body}");
final json = jsonDecode(response.body);
if (response.statusCode == 200 && json['success'] == true) {
logSafe("Bucket deleted successfully.");
return true;
} else {
logSafe(
"Failed to delete bucket: ${json['message'] ?? 'Unknown error'}",
level: LogLevel.warning);
}
} catch (e, stack) {
logSafe("Exception during deleteBucket API: $e", level: LogLevel.error);
logSafe("StackTrace: $stack", level: LogLevel.debug);
}
return false;
}
static Future<bool> updateBucket({
required String id,
required String name,
required String description,
}) async {
final payload = {
"id": id,
"name": name,
"description": description,
};
final endpoint = "${ApiEndpoints.updateBucket}/$id";
logSafe("Updating bucket with payload: $payload");
try {
final response = await _putRequest(endpoint, payload);
if (response == null) {
logSafe("Update bucket failed: null response", level: LogLevel.error);
return false;
}
logSafe("Update bucket response status: ${response.statusCode}");
logSafe("Update bucket response body: ${response.body}");
final json = jsonDecode(response.body);
if (json['success'] == true) {
logSafe("Bucket updated successfully: ${json['data']}");
return true;
} else {
logSafe("Failed to update bucket: ${json['message']}",
level: LogLevel.warning);
}
} catch (e, stack) {
logSafe("Exception during updateBucket API: $e", level: LogLevel.error);
logSafe("StackTrace: $stack", level: LogLevel.debug);
}
return false;
}
/// Assign employees to a bucket
static Future<bool> assignEmployeesToBucket({
required String bucketId,
required List<Map<String, dynamic>> employees,
}) async {
final endpoint = "${ApiEndpoints.assignBucket}/$bucketId";
logSafe("Assigning employees to bucket $bucketId: $employees");
try {
final response = await _postRequest(endpoint, employees);
if (response == null) {
logSafe("Assign employees failed: null response",
level: LogLevel.error);
return false;
}
logSafe("Assign employees response status: ${response.statusCode}");
logSafe("Assign employees response body: ${response.body}");
final json = jsonDecode(response.body);
if (json['success'] == true) {
logSafe("Employees assigned successfully");
return true;
} else {
logSafe("Failed to assign employees: ${json['message']}",
level: LogLevel.warning);
}
} catch (e, stack) {
logSafe("Exception during assignEmployeesToBucket API: $e",
level: LogLevel.error);
logSafe("StackTrace: $stack", level: LogLevel.debug);
}
return false;
}
static Future<bool> createBucket({
required String name,
required String description,
}) async {
final payload = {
"name": name,
"description": description,
};
final endpoint = ApiEndpoints.createBucket;
logSafe("Creating bucket with payload: $payload");
try {
final response = await _postRequest(endpoint, payload);
if (response == null) {
logSafe("Create bucket failed: null response", level: LogLevel.error);
return false;
}
logSafe("Create bucket response status: ${response.statusCode}");
logSafe("Create bucket response body: ${response.body}");
final json = jsonDecode(response.body);
if (json['success'] == true) {
logSafe("Bucket created successfully: ${json['data']}");
return true;
} else {
logSafe("Failed to create bucket: ${json['message']}",
level: LogLevel.warning);
}
} catch (e, stack) {
logSafe("Exception during createBucket API: ${e.toString()}",
level: LogLevel.error);
logSafe("StackTrace: ${stack.toString()}", level: LogLevel.debug);
}
return false;
}
static Future<Map<String, dynamic>?> getDirectoryNotes({
int pageSize = 1000,
int pageNumber = 1,
}) async {
final queryParams = {
'pageSize': pageSize.toString(),
'pageNumber': pageNumber.toString(),
};
final response = await _getRequest(
ApiEndpoints.getDirectoryNotes,
queryParams: queryParams,
);
final data = response != null
? _parseResponse(response, label: 'Directory Notes')
: null;
return data is Map<String, dynamic> ? data : null;
}
static Future<bool> addContactComment(String note, String contactId) async {
final payload = {
"note": note,
"contactId": contactId,
};
final endpoint = ApiEndpoints.updateDirectoryNotes;
logSafe("Adding new comment with payload: $payload");
logSafe("Sending add comment request to $endpoint");
try {
final response = await _postRequest(endpoint, payload);
if (response == null) {
logSafe("Add comment failed: null response", level: LogLevel.error);
return false;
}
logSafe("Add comment response status: ${response.statusCode}");
logSafe("Add comment response body: ${response.body}");
final json = jsonDecode(response.body);
if (json['success'] == true) {
logSafe("Comment added successfully for contactId: $contactId");
return true;
} else {
logSafe("Failed to add comment: ${json['message']}",
level: LogLevel.warning);
}
} catch (e, stack) {
logSafe("Exception during addComment API: ${e.toString()}",
level: LogLevel.error);
logSafe("StackTrace: ${stack.toString()}", level: LogLevel.debug);
}
return false;
}
static Future<bool> updateContactComment(
String commentId, String note, String contactId) async {
final payload = {
"id": commentId,
"contactId": contactId,
"note": note,
};
final endpoint = "${ApiEndpoints.updateDirectoryNotes}/$commentId";
final headers = {
"comment-id": commentId,
};
logSafe("Updating comment with payload: $payload");
logSafe("Headers for update comment: $headers");
logSafe("Sending update comment request to $endpoint");
try {
final response = await _putRequest(
endpoint,
payload,
additionalHeaders: headers,
);
if (response == null) {
logSafe("Update comment failed: null response", level: LogLevel.error);
return false;
}
logSafe("Update comment response status: ${response.statusCode}");
logSafe("Update comment response body: ${response.body}");
final json = jsonDecode(response.body);
if (json['success'] == true) {
logSafe("Comment updated successfully. commentId: $commentId");
return true;
} else {
logSafe("Failed to update comment: ${json['message']}",
level: LogLevel.warning);
}
} catch (e, stack) {
logSafe("Exception during updateComment API: ${e.toString()}",
level: LogLevel.error);
logSafe("StackTrace: ${stack.toString()}", level: LogLevel.debug);
}
return false;
}
static Future<List<dynamic>?> getDirectoryComments(String contactId) async {
final url = "${ApiEndpoints.getDirectoryNotes}/$contactId";
final response = await _getRequest(url);
final data = response != null
? _parseResponse(response, label: 'Directory Comments')
: null;
return data is List ? data : null;
}
static Future<bool> updateContact(
String contactId, Map<String, dynamic> payload) async {
try {
final endpoint = "${ApiEndpoints.updateContact}/$contactId";
logSafe("Updating contact [$contactId] with payload: $payload");
final response = await _putRequest(endpoint, payload);
if (response != null) {
final json = jsonDecode(response.body);
if (json['success'] == true) {
logSafe("Contact updated successfully.");
return true;
} else {
logSafe("Update contact failed: ${json['message']}",
level: LogLevel.warning);
}
}
} catch (e) {
logSafe("Error updating contact: $e", level: LogLevel.error);
}
return false;
}
static Future<bool> createContact(Map<String, dynamic> payload) async {
try {
logSafe("Submitting contact payload: $payload");
final response = await _postRequest(ApiEndpoints.createContact, payload);
if (response != null) {
final json = jsonDecode(response.body);
if (json['success'] == true) {
logSafe("Contact created successfully.");
return true;
} else {
logSafe("Create contact failed: ${json['message']}",
level: LogLevel.warning);
}
}
} catch (e) {
logSafe("Error creating contact: $e", level: LogLevel.error);
}
return false;
}
static Future<List<String>> getOrganizationList() async {
try {
final url = ApiEndpoints.getDirectoryOrganization;
logSafe("Sending GET request to: $url", level: LogLevel.info);
final response = await _getRequest(url);
logSafe("Response status: ${response?.statusCode}",
level: LogLevel.debug);
logSafe("Response body: ${response?.body}", level: LogLevel.debug);
if (response != null && response.statusCode == 200) {
final body = jsonDecode(response.body);
if (body['success'] == true && body['data'] is List) {
return List<String>.from(body['data']);
}
}
} catch (e, stackTrace) {
logSafe("Failed to fetch organization names: $e", level: LogLevel.error);
logSafe("Stack trace: $stackTrace", level: LogLevel.debug);
}
return [];
}
static Future<Map<String, dynamic>?> getContactCategoryList() async =>
_getRequest(ApiEndpoints.getDirectoryContactCategory).then((res) =>
res != null
? _parseResponseForAllData(res, label: 'Contact Category List')
: null);
static Future<Map<String, dynamic>?> getContactTagList() async =>
_getRequest(ApiEndpoints.getDirectoryContactTags).then((res) =>
res != null
? _parseResponseForAllData(res, label: 'Contact Tag List')
: null);
static Future<List<dynamic>?> getDirectoryData(
{required bool isActive}) async {
final queryParams = {
"active": isActive.toString(),
};
return _getRequest(ApiEndpoints.getDirectoryContacts,
queryParams: queryParams)
.then((res) =>
res != null ? _parseResponse(res, label: 'Directory Data') : null);
}
static Future<Map<String, dynamic>?> getContactBucketList() async =>
_getRequest(ApiEndpoints.getDirectoryBucketList).then((res) => res != null
? _parseResponseForAllData(res, label: 'Contact Bucket List')
: null);
// === Attendance APIs ===
static Future<List<dynamic>?> getProjects() async =>
_getRequest(ApiEndpoints.getProjects).then(
(res) => res != null ? _parseResponse(res, label: 'Projects') : null);
static Future<List<dynamic>?> getGlobalProjects() async =>
_getRequest(ApiEndpoints.getGlobalProjects).then((res) =>
res != null ? _parseResponse(res, label: 'Global Projects') : null);
static Future<List<dynamic>?> getEmployeesByProject(String projectId) async =>
_getRequest(ApiEndpoints.getEmployeesByProject,
queryParams: {"projectId": projectId})
.then((res) =>
res != null ? _parseResponse(res, label: 'Employees') : null);
static Future<List<dynamic>?> getAttendanceLogs(
String projectId, {
DateTime? dateFrom,
DateTime? dateTo,
}) async {
final query = {
"projectId": projectId,
if (dateFrom != null)
"dateFrom": DateFormat('yyyy-MM-dd').format(dateFrom),
if (dateTo != null) "dateTo": DateFormat('yyyy-MM-dd').format(dateTo),
};
return _getRequest(ApiEndpoints.getAttendanceLogs, queryParams: query).then(
(res) =>
res != null ? _parseResponse(res, label: 'Attendance Logs') : null);
}
static Future<List<dynamic>?> getAttendanceLogView(String id) async =>
_getRequest("${ApiEndpoints.getAttendanceLogView}/$id").then((res) =>
res != null ? _parseResponse(res, label: 'Log Details') : null);
static Future<List<dynamic>?> getRegularizationLogs(String projectId) async =>
_getRequest(ApiEndpoints.getRegularizationLogs,
queryParams: {"projectId": projectId})
.then((res) => res != null
? _parseResponse(res, label: 'Regularization Logs')
: null);
static Future<bool> uploadAttendanceImage(
String id,
String employeeId,
XFile? imageFile,
double latitude,
double longitude, {
required String imageName,
required String projectId,
String comment = "",
required int action,
bool imageCapture = true,
String? markTime,
}) async {
final now = DateTime.now();
final body = {
"id": id,
"employeeId": employeeId,
"projectId": projectId,
"markTime": markTime ?? DateFormat('hh:mm a').format(now),
"comment": comment,
"action": action,
"date": DateFormat('yyyy-MM-dd').format(now),
if (imageCapture) "latitude": '$latitude',
if (imageCapture) "longitude": '$longitude',
};
if (imageCapture && imageFile != null) {
try {
final bytes = await imageFile.readAsBytes();
final fileSize = await imageFile.length();
final contentType = "image/${imageFile.path.split('.').last}";
body["image"] = {
"fileName": imageName,
"contentType": contentType,
"fileSize": fileSize,
"description": "Employee attendance photo",
"base64Data": base64Encode(bytes),
};
} catch (e) {
logSafe("Image encoding error: $e", level: LogLevel.error);
return false;
}
}
final response = await _postRequest(
ApiEndpoints.uploadAttendanceImage,
body,
customTimeout: extendedTimeout,
);
if (response == null) return false;
final json = jsonDecode(response.body);
if (response.statusCode == 200 && json['success'] == true) return true;
logSafe("Failed to upload image: ${json['message'] ?? 'Unknown error'}");
return false;
}
static String generateImageName(String employeeId, int count) {
final now = DateTime.now();
final dateStr = DateFormat('yyyyMMdd_HHmmss').format(now);
final imageNumber = count.toString().padLeft(3, '0');
return "${employeeId}_${dateStr}_$imageNumber.jpg";
}
// === Employee APIs ===
static Future<List<dynamic>?> getAllEmployeesByProject(
String projectId) async {
if (projectId.isEmpty) throw ArgumentError('projectId must not be empty');
final endpoint = "${ApiEndpoints.getAllEmployeesByProject}/$projectId";
return _getRequest(endpoint).then((res) => res != null
? _parseResponse(res, label: 'Employees by Project')
: null);
}
static Future<List<dynamic>?> getAllEmployees() async =>
_getRequest(ApiEndpoints.getAllEmployees).then((res) =>
res != null ? _parseResponse(res, label: 'All Employees') : null);
static Future<List<dynamic>?> getRoles() async =>
_getRequest(ApiEndpoints.getRoles).then(
(res) => res != null ? _parseResponse(res, label: 'Roles') : null);
static Future<bool> createEmployee({
required String firstName,
required String lastName,
required String phoneNumber,
required String gender,
required String jobRoleId,
}) async {
final body = {
"firstName": firstName,
"lastName": lastName,
"phoneNumber": phoneNumber,
"gender": gender,
"jobRoleId": jobRoleId,
};
final response = await _postRequest(
ApiEndpoints.createEmployee,
body,
customTimeout: extendedTimeout,
);
if (response == null) return false;
final json = jsonDecode(response.body);
return response.statusCode == 200 && json['success'] == true;
}
static Future<Map<String, dynamic>?> getEmployeeDetails(
String employeeId) async {
final url = "${ApiEndpoints.getEmployeeInfo}/$employeeId";
final response = await _getRequest(url);
final data = response != null
? _parseResponse(response, label: 'Employee Details')
: null;
return data is Map<String, dynamic> ? data : null;
}
// === Daily Task APIs ===
static Future<List<dynamic>?> getDailyTasks(
String projectId, {
DateTime? dateFrom,
DateTime? dateTo,
}) async {
final query = {
"projectId": projectId,
if (dateFrom != null)
"dateFrom": DateFormat('yyyy-MM-dd').format(dateFrom),
if (dateTo != null) "dateTo": DateFormat('yyyy-MM-dd').format(dateTo),
};
return _getRequest(ApiEndpoints.getDailyTask, queryParams: query).then(
(res) =>
res != null ? _parseResponse(res, label: 'Daily Tasks') : null);
}
static Future<bool> reportTask({
required String id,
required int completedTask,
required String comment,
required List<Map<String, dynamic>> checkList,
List<Map<String, dynamic>>? images,
}) async {
final body = {
"id": id,
"completedTask": completedTask,
"comment": comment,
"reportedDate": DateTime.now().toUtc().toIso8601String(),
"checkList": checkList,
if (images != null && images.isNotEmpty) "images": images,
};
final response = await _postRequest(
ApiEndpoints.reportTask,
body,
customTimeout: extendedTimeout,
);
if (response == null) return false;
final json = jsonDecode(response.body);
if (response.statusCode == 200 && json['success'] == true) {
Get.back();
return true;
}
logSafe("Failed to report task: ${json['message'] ?? 'Unknown error'}");
return false;
}
static Future<bool> commentTask({
required String id,
required String comment,
List<Map<String, dynamic>>? images,
}) async {
final body = {
"taskAllocationId": id,
"comment": comment,
"commentDate": DateTime.now().toUtc().toIso8601String(),
if (images != null && images.isNotEmpty) "images": images,
};
final response = await _postRequest(ApiEndpoints.commentTask, body);
if (response == null) return false;
final json = jsonDecode(response.body);
return response.statusCode == 200 && json['success'] == true;
}
static Future<Map<String, dynamic>?> getDailyTasksDetails(
String projectId) async {
final url = "${ApiEndpoints.dailyTaskDetails}/$projectId";
final response = await _getRequest(url);
return response != null
? _parseResponseForAllData(response, label: 'Daily Task Details')
as Map<String, dynamic>?
: null;
}
static Future<bool> assignDailyTask({
required String workItemId,
required int plannedTask,
required String description,
required List<String> taskTeam,
DateTime? assignmentDate,
}) async {
final body = {
"workItemId": workItemId,
"plannedTask": plannedTask,
"description": description,
"taskTeam": taskTeam,
"assignmentDate":
(assignmentDate ?? DateTime.now()).toUtc().toIso8601String(),
};
final response = await _postRequest(ApiEndpoints.assignDailyTask, body);
if (response == null) return false;
final json = jsonDecode(response.body);
if (response.statusCode == 200 && json['success'] == true) {
Get.back();
return true;
}
logSafe(
"Failed to assign daily task: ${json['message'] ?? 'Unknown error'}");
return false;
}
static Future<Map<String, dynamic>?> getWorkStatus() async {
final res = await _getRequest(ApiEndpoints.getWorkStatus);
if (res == null) {
logSafe('Work Status API returned null');
return null;
}
logSafe('Work Status raw response: ${res.body}');
return _parseResponseForAllData(res, label: 'Work Status')
as Map<String, dynamic>?;
}
static Future<Map<String, dynamic>?> getMasterWorkCategories() async =>
_getRequest(ApiEndpoints.getmasterWorkCategories).then((res) =>
res != null
? _parseResponseForAllData(res, label: 'Master Work Categories')
: null);
static Future<bool> approveTask({
required String id,
required String comment,
required String workStatus,
required int approvedTask,
List<Map<String, dynamic>>? images,
}) async {
final body = {
"id": id,
"workStatus": workStatus,
"approvedTask": approvedTask,
"comment": comment,
if (images != null && images.isNotEmpty) "images": images,
};
final response = await _postRequest(ApiEndpoints.approveReportAction, body);
if (response == null) return false;
final json = jsonDecode(response.body);
return response.statusCode == 200 && json['success'] == true;
}
static Future<bool> createTask({
required String parentTaskId,
required int plannedTask,
required String comment,
required String workAreaId,
required String activityId,
DateTime? assignmentDate,
required String categoryId,
}) async {
final body = [
{
"parentTaskId": parentTaskId,
"plannedWork": plannedTask,
"comment": comment,
"workAreaID": workAreaId,
"activityID": activityId,
"workCategoryId": categoryId,
'completedWork': 0,
}
];
final response = await _postRequest(ApiEndpoints.assignTask, body);
if (response == null) return false;
final json = jsonDecode(response.body);
if (response.statusCode == 200 && json['success'] == true) {
Get.back();
return true;
}
logSafe("Failed to create task: ${json['message'] ?? 'Unknown error'}");
return false;
}
}