199 lines
5.4 KiB
Dart
199 lines
5.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:marco/helpers/services/app_logger.dart';
|
|
import 'package:marco/helpers/services/api_service.dart';
|
|
import 'package:marco/model/project_model.dart';
|
|
import 'package:marco/model/dailyTaskPlanning/daily_task_model.dart';
|
|
import 'package:marco/model/dailyTaskPlanning/daily_progress_report_filter_response_model.dart';
|
|
|
|
class DailyTaskController extends GetxController {
|
|
List<ProjectModel> projects = [];
|
|
String? selectedProjectId;
|
|
|
|
DateTime? startDateTask;
|
|
DateTime? endDateTask;
|
|
|
|
List<TaskModel> dailyTasks = [];
|
|
final RxSet<String> expandedDates = <String>{}.obs;
|
|
|
|
void toggleDate(String dateKey) {
|
|
if (expandedDates.contains(dateKey)) {
|
|
expandedDates.remove(dateKey);
|
|
} else {
|
|
expandedDates.add(dateKey);
|
|
}
|
|
}
|
|
|
|
RxSet<String> selectedBuildings = <String>{}.obs;
|
|
RxSet<String> selectedFloors = <String>{}.obs;
|
|
RxSet<String> selectedActivities = <String>{}.obs;
|
|
RxSet<String> selectedServices = <String>{}.obs;
|
|
|
|
RxBool isFilterLoading = false.obs;
|
|
RxBool isLoading = true.obs;
|
|
RxBool isLoadingMore = false.obs;
|
|
Map<String, List<TaskModel>> groupedDailyTasks = {};
|
|
// Pagination
|
|
int currentPage = 1;
|
|
int pageSize = 20;
|
|
bool hasMore = true;
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
_initializeDefaults();
|
|
}
|
|
|
|
void _initializeDefaults() {
|
|
_setDefaultDateRange();
|
|
}
|
|
|
|
void _setDefaultDateRange() {
|
|
final today = DateTime.now();
|
|
startDateTask = today.subtract(const Duration(days: 7));
|
|
endDateTask = today;
|
|
|
|
logSafe(
|
|
"Default date range set: $startDateTask to $endDateTask",
|
|
level: LogLevel.info,
|
|
);
|
|
}
|
|
|
|
void clearTaskFilters() {
|
|
selectedBuildings.clear();
|
|
selectedFloors.clear();
|
|
selectedActivities.clear();
|
|
selectedServices.clear();
|
|
startDateTask = null;
|
|
endDateTask = null;
|
|
update();
|
|
}
|
|
|
|
Future<void> fetchTaskData(
|
|
String projectId, {
|
|
int pageNumber = 1,
|
|
int pageSize = 20,
|
|
bool isLoadMore = false,
|
|
}) async {
|
|
if (!isLoadMore) {
|
|
isLoading.value = true;
|
|
currentPage = 1;
|
|
hasMore = true;
|
|
groupedDailyTasks.clear();
|
|
dailyTasks.clear();
|
|
} else {
|
|
isLoadingMore.value = true;
|
|
}
|
|
|
|
// Create the filter object
|
|
final filter = {
|
|
"buildingIds": selectedBuildings.toList(),
|
|
"floorIds": selectedFloors.toList(),
|
|
"activityIds": selectedActivities.toList(),
|
|
"serviceIds": selectedServices.toList(),
|
|
"dateFrom": startDateTask?.toIso8601String(),
|
|
"dateTo": endDateTask?.toIso8601String(),
|
|
};
|
|
|
|
final response = await ApiService.getDailyTasks(
|
|
projectId,
|
|
filter: filter,
|
|
pageNumber: pageNumber,
|
|
pageSize: pageSize,
|
|
);
|
|
|
|
if (response != null && response.isNotEmpty) {
|
|
for (var task in response) {
|
|
final assignmentDateKey =
|
|
task.assignmentDate.toIso8601String().split('T')[0];
|
|
groupedDailyTasks.putIfAbsent(assignmentDateKey, () => []).add(task);
|
|
}
|
|
dailyTasks = groupedDailyTasks.values.expand((list) => list).toList();
|
|
currentPage = pageNumber;
|
|
} else {
|
|
hasMore = false;
|
|
}
|
|
|
|
isLoading.value = false;
|
|
isLoadingMore.value = false;
|
|
|
|
update();
|
|
}
|
|
|
|
FilterData? taskFilterData;
|
|
|
|
Future<void> fetchTaskFilter(String projectId) async {
|
|
isFilterLoading.value = true;
|
|
try {
|
|
final filterResponse = await ApiService.getDailyTaskFilter(projectId);
|
|
|
|
if (filterResponse != null && filterResponse.success) {
|
|
taskFilterData =
|
|
filterResponse.data; // now taskFilterData is FilterData?
|
|
logSafe(
|
|
"Task filter fetched successfully. Buildings: ${taskFilterData?.buildings.length}, Floors: ${taskFilterData?.floors.length}",
|
|
level: LogLevel.info,
|
|
);
|
|
} else {
|
|
logSafe(
|
|
"Failed to fetch task filter for projectId: $projectId",
|
|
level: LogLevel.warning,
|
|
);
|
|
}
|
|
} catch (e, stack) {
|
|
logSafe("Exception in fetchTaskFilter: $e", level: LogLevel.error);
|
|
logSafe("StackTrace: $stack", level: LogLevel.debug);
|
|
} finally {
|
|
isFilterLoading.value = false;
|
|
update();
|
|
}
|
|
}
|
|
|
|
Future<void> selectDateRangeForTaskData(
|
|
BuildContext context,
|
|
DailyTaskController controller,
|
|
) async {
|
|
final picked = await showDateRangePicker(
|
|
context: context,
|
|
firstDate: DateTime(2022),
|
|
lastDate: DateTime.now(),
|
|
initialDateRange: DateTimeRange(
|
|
start:
|
|
startDateTask ?? DateTime.now().subtract(const Duration(days: 7)),
|
|
end: endDateTask ?? DateTime.now(),
|
|
),
|
|
);
|
|
|
|
if (picked == null) {
|
|
logSafe("Date range picker cancelled by user.", level: LogLevel.debug);
|
|
return;
|
|
}
|
|
|
|
startDateTask = picked.start;
|
|
endDateTask = picked.end;
|
|
|
|
logSafe(
|
|
"Date range selected: $startDateTask to $endDateTask",
|
|
level: LogLevel.info,
|
|
);
|
|
|
|
// ✅ Add null check before calling fetchTaskData
|
|
final projectId = controller.selectedProjectId;
|
|
if (projectId != null && projectId.isNotEmpty) {
|
|
await controller.fetchTaskData(projectId);
|
|
} else {
|
|
logSafe("Project ID is null or empty, skipping fetchTaskData",
|
|
level: LogLevel.warning);
|
|
}
|
|
}
|
|
|
|
void refreshTasksFromNotification({
|
|
required String projectId,
|
|
required String taskAllocationId,
|
|
}) async {
|
|
// re-fetch tasks
|
|
await fetchTaskData(projectId);
|
|
|
|
update(); // rebuilds UI
|
|
}
|
|
}
|