feat: Enhance daily task planning by fetching infra details and associated tasks; update API service for new endpoints
This commit is contained in:
parent
ae7ce851ee
commit
04cbdab277
@ -18,7 +18,6 @@ class DailyTaskPlanningController extends GetxController {
|
|||||||
MyFormValidator basicValidator = MyFormValidator();
|
MyFormValidator basicValidator = MyFormValidator();
|
||||||
List<Map<String, dynamic>> roles = [];
|
List<Map<String, dynamic>> roles = [];
|
||||||
RxBool isAssigningTask = false.obs;
|
RxBool isAssigningTask = false.obs;
|
||||||
|
|
||||||
RxnString selectedRoleId = RxnString();
|
RxnString selectedRoleId = RxnString();
|
||||||
RxBool isLoading = false.obs;
|
RxBool isLoading = false.obs;
|
||||||
|
|
||||||
@ -50,18 +49,12 @@ class DailyTaskPlanningController extends GetxController {
|
|||||||
final selected =
|
final selected =
|
||||||
employees.where((e) => uploadingStates[e.id]?.value == true).toList();
|
employees.where((e) => uploadingStates[e.id]?.value == true).toList();
|
||||||
selectedEmployees.value = selected;
|
selectedEmployees.value = selected;
|
||||||
logSafe(
|
logSafe("Updated selected employees", level: LogLevel.debug);
|
||||||
"Updated selected employees",
|
|
||||||
level: LogLevel.debug,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onRoleSelected(String? roleId) {
|
void onRoleSelected(String? roleId) {
|
||||||
selectedRoleId.value = roleId;
|
selectedRoleId.value = roleId;
|
||||||
logSafe(
|
logSafe("Role selected", level: LogLevel.info);
|
||||||
"Role selected",
|
|
||||||
level: LogLevel.info,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> fetchRoles() async {
|
Future<void> fetchRoles() async {
|
||||||
@ -94,7 +87,7 @@ class DailyTaskPlanningController extends GetxController {
|
|||||||
assignmentDate: assignmentDate,
|
assignmentDate: assignmentDate,
|
||||||
);
|
);
|
||||||
|
|
||||||
isAssigningTask.value = false;
|
isAssigningTask.value = false;
|
||||||
|
|
||||||
if (response == true) {
|
if (response == true) {
|
||||||
logSafe("Task assigned successfully", level: LogLevel.info);
|
logSafe("Task assigned successfully", level: LogLevel.info);
|
||||||
@ -137,6 +130,7 @@ class DailyTaskPlanningController extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fetch Infra details and then tasks per work area
|
||||||
Future<void> fetchTaskData(String? projectId) async {
|
Future<void> fetchTaskData(String? projectId) async {
|
||||||
if (projectId == null) {
|
if (projectId == null) {
|
||||||
logSafe("Project ID is null", level: LogLevel.warning);
|
logSafe("Project ID is null", level: LogLevel.warning);
|
||||||
@ -145,20 +139,89 @@ class DailyTaskPlanningController extends GetxController {
|
|||||||
|
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
try {
|
try {
|
||||||
final response = await ApiService.getDailyTasksDetails(projectId);
|
final infraResponse = await ApiService.getInfraDetails(projectId);
|
||||||
final data = response?['data'];
|
final infraData = infraResponse?['data'] as List<dynamic>?;
|
||||||
if (data != null) {
|
|
||||||
dailyTasks = [TaskPlanningDetailsModel.fromJson(data)];
|
if (infraData == null || infraData.isEmpty) {
|
||||||
logSafe(
|
logSafe("No infra data found for project $projectId",
|
||||||
"Daily task Planning Details fetched",
|
level: LogLevel.warning);
|
||||||
level: LogLevel.info,
|
dailyTasks = [];
|
||||||
);
|
return;
|
||||||
} else {
|
|
||||||
logSafe("Data field is null", level: LogLevel.warning);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Map infra to dailyTasks structure
|
||||||
|
dailyTasks = infraData.map((buildingJson) {
|
||||||
|
final building = Building(
|
||||||
|
id: buildingJson['id'],
|
||||||
|
name: buildingJson['buildingName'],
|
||||||
|
description: buildingJson['description'],
|
||||||
|
floors: (buildingJson['floors'] as List<dynamic>).map((floorJson) {
|
||||||
|
return Floor(
|
||||||
|
id: floorJson['id'],
|
||||||
|
floorName: floorJson['floorName'],
|
||||||
|
workAreas: (floorJson['workAreas'] as List<dynamic>).map((areaJson) {
|
||||||
|
return WorkArea(
|
||||||
|
id: areaJson['id'],
|
||||||
|
areaName: areaJson['areaName'],
|
||||||
|
workItems: [], // Initially empty, will fill after tasks API
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
|
||||||
|
return TaskPlanningDetailsModel(
|
||||||
|
id: building.id,
|
||||||
|
name: building.name,
|
||||||
|
projectAddress: "",
|
||||||
|
contactPerson: "",
|
||||||
|
startDate: DateTime.now(),
|
||||||
|
endDate: DateTime.now(),
|
||||||
|
projectStatusId: "",
|
||||||
|
buildings: [building],
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
// Fetch tasks for each work area
|
||||||
|
await Future.wait(dailyTasks.expand((task) => task.buildings)
|
||||||
|
.expand((b) => b.floors)
|
||||||
|
.expand((f) => f.workAreas)
|
||||||
|
.map((area) async {
|
||||||
|
try {
|
||||||
|
final taskResponse = await ApiService.getWorkItemsByWorkArea(area.id);
|
||||||
|
final taskData = taskResponse?['data'] as List<dynamic>? ?? [];
|
||||||
|
|
||||||
|
area.workItems.addAll(taskData.map((taskJson) {
|
||||||
|
return WorkItemWrapper(
|
||||||
|
workItemId: taskJson['id'],
|
||||||
|
workItem: WorkItem(
|
||||||
|
id: taskJson['id'],
|
||||||
|
activityMaster: taskJson['activityMaster'] != null
|
||||||
|
? ActivityMaster.fromJson(taskJson['activityMaster'])
|
||||||
|
: null,
|
||||||
|
workCategoryMaster: taskJson['workCategoryMaster'] != null
|
||||||
|
? WorkCategoryMaster.fromJson(taskJson['workCategoryMaster'])
|
||||||
|
: null,
|
||||||
|
plannedWork: (taskJson['plannedWork'] as num?)?.toDouble(),
|
||||||
|
completedWork: (taskJson['completedWork'] as num?)?.toDouble(),
|
||||||
|
todaysAssigned: (taskJson['todaysAssigned'] as num?)?.toDouble(),
|
||||||
|
description: taskJson['description'] as String?,
|
||||||
|
taskDate: taskJson['taskDate'] != null
|
||||||
|
? DateTime.tryParse(taskJson['taskDate'])
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
} catch (e, stack) {
|
||||||
|
logSafe("Error fetching tasks for work area ${area.id}",
|
||||||
|
level: LogLevel.error, error: e, stackTrace: stack);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
logSafe("Fetched infra and tasks for project $projectId",
|
||||||
|
level: LogLevel.info);
|
||||||
} catch (e, stack) {
|
} catch (e, stack) {
|
||||||
logSafe("Error fetching daily task data",
|
logSafe("Error fetching daily task data", level: LogLevel.error, error: e, stackTrace: stack);
|
||||||
level: LogLevel.error, error: e, stackTrace: stack);
|
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
update();
|
update();
|
||||||
|
@ -1880,7 +1880,7 @@ class ApiService {
|
|||||||
_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<Map<String, dynamic>?> createEmployee({
|
||||||
String? id, // Optional, for editing
|
String? id,
|
||||||
required String firstName,
|
required String firstName,
|
||||||
required String lastName,
|
required String lastName,
|
||||||
required String phoneNumber,
|
required String phoneNumber,
|
||||||
@ -1889,7 +1889,7 @@ class ApiService {
|
|||||||
required String joiningDate,
|
required String joiningDate,
|
||||||
}) async {
|
}) async {
|
||||||
final body = {
|
final body = {
|
||||||
if (id != null) "id": id, // Include id only if editing
|
if (id != null) "id": id,
|
||||||
"firstName": firstName,
|
"firstName": firstName,
|
||||||
"lastName": lastName,
|
"lastName": lastName,
|
||||||
"phoneNumber": phoneNumber,
|
"phoneNumber": phoneNumber,
|
||||||
@ -1991,14 +1991,35 @@ class ApiService {
|
|||||||
return response.statusCode == 200 && json['success'] == true;
|
return response.statusCode == 200 && json['success'] == true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<Map<String, dynamic>?> getDailyTasksDetails(
|
/// Fetch infra details for a given project
|
||||||
String projectId) async {
|
static Future<Map<String, dynamic>?> getInfraDetails(String projectId) async {
|
||||||
final url = "${ApiEndpoints.dailyTaskDetails}/$projectId";
|
final endpoint = "/project/infra-details/$projectId";
|
||||||
final response = await _getRequest(url);
|
|
||||||
return response != null
|
final res = await _getRequest(endpoint);
|
||||||
? _parseResponseForAllData(response, label: 'Daily Task Details')
|
if (res == null) {
|
||||||
as Map<String, dynamic>?
|
logSafe('Infra Details API returned null');
|
||||||
: null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
logSafe('Infra Details raw response: ${res.body}');
|
||||||
|
return _parseResponseForAllData(res, label: 'Infra Details')
|
||||||
|
as Map<String, dynamic>?;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch work items for a given work area
|
||||||
|
static Future<Map<String, dynamic>?> getWorkItemsByWorkArea(
|
||||||
|
String workAreaId) async {
|
||||||
|
final endpoint = "/project/tasks/$workAreaId";
|
||||||
|
|
||||||
|
final res = await _getRequest(endpoint);
|
||||||
|
if (res == null) {
|
||||||
|
logSafe('Work Items API returned null');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
logSafe('Work Items raw response: ${res.body}');
|
||||||
|
return _parseResponseForAllData(res, label: 'Work Items')
|
||||||
|
as Map<String, dynamic>?;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<bool> assignDailyTask({
|
static Future<bool> assignDailyTask({
|
||||||
|
@ -68,6 +68,10 @@ class NotificationActionHandler {
|
|||||||
_handleDashboardUpdate(data);
|
_handleDashboardUpdate(data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'Team_Modified':
|
||||||
|
// Call method to handle team modifications and dashboard update
|
||||||
|
_handleDashboardUpdate(data);
|
||||||
|
break;
|
||||||
|
|
||||||
/// 🔹 Tasks
|
/// 🔹 Tasks
|
||||||
case 'Report_Task':
|
case 'Report_Task':
|
||||||
@ -270,7 +274,6 @@ class NotificationActionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ---------------------- DIRECTORY HANDLERS ----------------------
|
|
||||||
/// ---------------------- DIRECTORY HANDLERS ----------------------
|
/// ---------------------- DIRECTORY HANDLERS ----------------------
|
||||||
static void _handleContactModified(Map<String, dynamic> data) {
|
static void _handleContactModified(Map<String, dynamic> data) {
|
||||||
final contactId = data['ContactId'];
|
final contactId = data['ContactId'];
|
||||||
@ -299,8 +302,6 @@ class NotificationActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void _handleContactNoteModified(Map<String, dynamic> data) {
|
static void _handleContactNoteModified(Map<String, dynamic> data) {
|
||||||
final contactId = data['ContactId'];
|
|
||||||
|
|
||||||
// Refresh both contacts and notes when a note is modified
|
// Refresh both contacts and notes when a note is modified
|
||||||
_handleContactModified(data);
|
_handleContactModified(data);
|
||||||
}
|
}
|
||||||
@ -330,14 +331,38 @@ class NotificationActionHandler {
|
|||||||
case 'attendance_updated':
|
case 'attendance_updated':
|
||||||
await controller.fetchRoleWiseAttendance();
|
await controller.fetchRoleWiseAttendance();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'task_updated':
|
case 'task_updated':
|
||||||
await controller.fetchDashboardTasks(
|
await controller.fetchDashboardTasks(
|
||||||
projectId:
|
projectId: controller.projectController.selectedProjectId.value,
|
||||||
controller.projectController.selectedProjectId.value);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'project_progress_update':
|
case 'project_progress_update':
|
||||||
await controller.fetchProjectProgress();
|
await controller.fetchProjectProgress();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'Employee_Suspend':
|
||||||
|
final currentProjectId =
|
||||||
|
controller.projectController.selectedProjectId.value;
|
||||||
|
final projectIdsString = data['ProjectIds'] ?? '';
|
||||||
|
|
||||||
|
// Convert comma-separated string to List<String>
|
||||||
|
final notificationProjectIds =
|
||||||
|
projectIdsString.split(',').map((e) => e.trim()).toList();
|
||||||
|
|
||||||
|
// Refresh only if current project ID is in the list
|
||||||
|
if (notificationProjectIds.contains(currentProjectId)) {
|
||||||
|
await controller.fetchDashboardTeams(projectId: currentProjectId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Team_Modified':
|
||||||
|
final projectId = data['ProjectId'] ??
|
||||||
|
controller.projectController.selectedProjectId.value;
|
||||||
|
await controller.fetchDashboardTeams(projectId: projectId);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'full_dashboard_refresh':
|
case 'full_dashboard_refresh':
|
||||||
default:
|
default:
|
||||||
await controller.refreshDashboard();
|
await controller.refreshDashboard();
|
||||||
|
@ -129,6 +129,7 @@ class WorkItem {
|
|||||||
final WorkCategoryMaster? workCategoryMaster;
|
final WorkCategoryMaster? workCategoryMaster;
|
||||||
final double? plannedWork;
|
final double? plannedWork;
|
||||||
final double? completedWork;
|
final double? completedWork;
|
||||||
|
final String? description;
|
||||||
final double? todaysAssigned;
|
final double? todaysAssigned;
|
||||||
final DateTime? taskDate;
|
final DateTime? taskDate;
|
||||||
final String? tenantId;
|
final String? tenantId;
|
||||||
@ -142,6 +143,7 @@ class WorkItem {
|
|||||||
this.workArea,
|
this.workArea,
|
||||||
this.activityMaster,
|
this.activityMaster,
|
||||||
this.workCategoryMaster,
|
this.workCategoryMaster,
|
||||||
|
this.description,
|
||||||
this.plannedWork,
|
this.plannedWork,
|
||||||
this.completedWork,
|
this.completedWork,
|
||||||
this.todaysAssigned,
|
this.todaysAssigned,
|
||||||
@ -175,7 +177,8 @@ class WorkItem {
|
|||||||
: null,
|
: null,
|
||||||
todaysAssigned: json['todaysAssigned'] != null
|
todaysAssigned: json['todaysAssigned'] != null
|
||||||
? (json['todaysAssigned'] as num).toDouble()
|
? (json['todaysAssigned'] as num).toDouble()
|
||||||
: null, // ✅ added parsing
|
: null,
|
||||||
|
description: json['description'] as String?,
|
||||||
taskDate:
|
taskDate:
|
||||||
json['taskDate'] != null ? DateTime.tryParse(json['taskDate']) : null,
|
json['taskDate'] != null ? DateTime.tryParse(json['taskDate']) : null,
|
||||||
tenantId: json['tenantId'] as String?,
|
tenantId: json['tenantId'] as String?,
|
||||||
|
@ -116,7 +116,7 @@ class _AttendanceLogsTabState extends State<AttendanceLogsTab> {
|
|||||||
final showPendingOnly = widget.controller.showPendingOnly.value;
|
final showPendingOnly = widget.controller.showPendingOnly.value;
|
||||||
final filteredLogs = showPendingOnly
|
final filteredLogs = showPendingOnly
|
||||||
? allLogs
|
? allLogs
|
||||||
.where((emp) => emp.activity == 1 || emp.activity == 2)
|
.where((emp) => emp.activity == 1 )
|
||||||
.toList()
|
.toList()
|
||||||
: allLogs;
|
: allLogs;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user