Feature_Report_Action #48
@ -1,42 +1,29 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:logger/logger.dart';
|
import 'package:logger/logger.dart';
|
||||||
import 'package:marco/helpers/services/api_service.dart';
|
import 'package:marco/helpers/services/api_service.dart';
|
||||||
import 'package:marco/model/project_model.dart';
|
|
||||||
import 'package:marco/model/employee_model.dart';
|
|
||||||
import 'package:marco/helpers/widgets/my_form_validator.dart';
|
import 'package:marco/helpers/widgets/my_form_validator.dart';
|
||||||
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
||||||
import 'package:marco/controller/project_controller.dart';
|
|
||||||
import 'package:marco/model/dailyTaskPlaning/master_work_category_model.dart';
|
import 'package:marco/model/dailyTaskPlaning/master_work_category_model.dart';
|
||||||
|
|
||||||
final Logger log = Logger();
|
final Logger log = Logger();
|
||||||
|
|
||||||
class AddTaskController extends GetxController {
|
class AddTaskController extends GetxController {
|
||||||
List<ProjectModel> projects = [];
|
|
||||||
List<EmployeeModel> employees = [];
|
|
||||||
RxMap<String, RxBool> uploadingStates = <String, RxBool>{}.obs;
|
RxMap<String, RxBool> uploadingStates = <String, RxBool>{}.obs;
|
||||||
MyFormValidator basicValidator = MyFormValidator();
|
MyFormValidator basicValidator = MyFormValidator();
|
||||||
RxnInt selectedCategoryId = RxnInt();
|
RxnString selectedCategoryId = RxnString();
|
||||||
|
RxnString selectedCategoryName = RxnString();
|
||||||
|
var categoryIdNameMap = <String, String>{}.obs;
|
||||||
|
|
||||||
List<Map<String, dynamic>> roles = [];
|
List<Map<String, dynamic>> roles = [];
|
||||||
RxnString selectedRoleId = RxnString();
|
RxnString selectedRoleId = RxnString();
|
||||||
RxList<EmployeeModel> selectedEmployees = <EmployeeModel>[].obs;
|
|
||||||
RxBool isLoadingWorkMasterCategories = false.obs;
|
RxBool isLoadingWorkMasterCategories = false.obs;
|
||||||
RxList<WorkCategoryModel> workMasterCategories = <WorkCategoryModel>[].obs;
|
RxList<WorkCategoryModel> workMasterCategories = <WorkCategoryModel>[].obs;
|
||||||
|
|
||||||
void updateSelectedEmployees() {
|
|
||||||
final selected =
|
|
||||||
employees.where((e) => uploadingStates[e.id]?.value == true).toList();
|
|
||||||
selectedEmployees.value = selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
RxBool isLoading = false.obs;
|
RxBool isLoading = false.obs;
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
fetchRoles();
|
|
||||||
fetchWorkMasterCategories();
|
fetchWorkMasterCategories();
|
||||||
final projectId = Get.find<ProjectController>().selectedProject?.id;
|
|
||||||
fetchEmployeesByProject(projectId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String? formFieldValidator(String? value, {required String fieldType}) {
|
String? formFieldValidator(String? value, {required String fieldType}) {
|
||||||
@ -56,23 +43,6 @@ class AddTaskController extends GetxController {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> fetchRoles() async {
|
|
||||||
logger.i("Fetching roles...");
|
|
||||||
final result = await ApiService.getRoles();
|
|
||||||
if (result != null) {
|
|
||||||
roles = List<Map<String, dynamic>>.from(result);
|
|
||||||
logger.i("Roles fetched successfully.");
|
|
||||||
update();
|
|
||||||
} else {
|
|
||||||
logger.e("Failed to fetch roles.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void onRoleSelected(String? roleId) {
|
|
||||||
selectedRoleId.value = roleId;
|
|
||||||
logger.i("Role selected: $roleId");
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> assignDailyTask({
|
Future<bool> assignDailyTask({
|
||||||
required String workItemId,
|
required String workItemId,
|
||||||
required int plannedTask,
|
required int plannedTask,
|
||||||
@ -111,10 +81,11 @@ class AddTaskController extends GetxController {
|
|||||||
|
|
||||||
Future<bool> createTask({
|
Future<bool> createTask({
|
||||||
required String parentTaskId,
|
required String parentTaskId,
|
||||||
|
required String workAreaId,
|
||||||
|
required String activityId,
|
||||||
required int plannedTask,
|
required int plannedTask,
|
||||||
required String description,
|
required String comment,
|
||||||
required List<String> taskTeam,
|
required String categoryId,
|
||||||
required String workItemId,
|
|
||||||
DateTime? assignmentDate,
|
DateTime? assignmentDate,
|
||||||
}) async {
|
}) async {
|
||||||
logger.i("Creating new task...");
|
logger.i("Creating new task...");
|
||||||
@ -122,10 +93,12 @@ class AddTaskController extends GetxController {
|
|||||||
final response = await ApiService.createTask(
|
final response = await ApiService.createTask(
|
||||||
parentTaskId: parentTaskId,
|
parentTaskId: parentTaskId,
|
||||||
plannedTask: plannedTask,
|
plannedTask: plannedTask,
|
||||||
description: description,
|
comment: comment,
|
||||||
taskTeam: taskTeam,
|
workAreaId: workAreaId,
|
||||||
workItemId: workItemId,
|
activityId: activityId,
|
||||||
assignmentDate: assignmentDate,
|
assignmentDate: assignmentDate,
|
||||||
|
categoryId: categoryId,
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response == true) {
|
if (response == true) {
|
||||||
@ -147,34 +120,6 @@ class AddTaskController extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> fetchEmployeesByProject(String? projectId) async {
|
|
||||||
if (projectId == null || projectId.isEmpty) {
|
|
||||||
log.e("Project ID is required but was null or empty.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
isLoading.value = true;
|
|
||||||
try {
|
|
||||||
final response = await ApiService.getAllEmployeesByProject(projectId);
|
|
||||||
if (response != null && response.isNotEmpty) {
|
|
||||||
employees =
|
|
||||||
response.map((json) => EmployeeModel.fromJson(json)).toList();
|
|
||||||
for (var emp in employees) {
|
|
||||||
uploadingStates[emp.id] = false.obs;
|
|
||||||
}
|
|
||||||
log.i("Employees fetched: ${employees.length} for project $projectId");
|
|
||||||
} else {
|
|
||||||
log.w("No employees found for project $projectId.");
|
|
||||||
employees = [];
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
log.e("Error fetching employees for project $projectId: $e");
|
|
||||||
}
|
|
||||||
|
|
||||||
update();
|
|
||||||
isLoading.value = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> fetchWorkMasterCategories() async {
|
Future<void> fetchWorkMasterCategories() async {
|
||||||
isLoadingWorkMasterCategories.value = true;
|
isLoadingWorkMasterCategories.value = true;
|
||||||
|
|
||||||
@ -182,15 +127,22 @@ class AddTaskController extends GetxController {
|
|||||||
if (response != null) {
|
if (response != null) {
|
||||||
try {
|
try {
|
||||||
final dataList = response['data'] ?? [];
|
final dataList = response['data'] ?? [];
|
||||||
workMasterCategories.assignAll(
|
|
||||||
List<WorkCategoryModel>.from(
|
final parsedList = List<WorkCategoryModel>.from(
|
||||||
dataList.map((e) => WorkCategoryModel.fromJson(e)),
|
dataList.map((e) => WorkCategoryModel.fromJson(e)),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
workMasterCategories.assignAll(parsedList);
|
||||||
|
final Map<String, String> mapped = {
|
||||||
|
for (var item in parsedList) item.id: item.name,
|
||||||
|
};
|
||||||
|
categoryIdNameMap.assignAll(mapped);
|
||||||
|
|
||||||
logger.i("Work categories fetched: ${dataList.length}");
|
logger.i("Work categories fetched: ${dataList.length}");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.e("Error parsing work categories: $e");
|
logger.e("Error parsing work categories: $e");
|
||||||
workMasterCategories.clear();
|
workMasterCategories.clear();
|
||||||
|
categoryIdNameMap.clear();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.w("No work categories found or API call failed.");
|
logger.w("No work categories found or API call failed.");
|
||||||
@ -199,4 +151,9 @@ class AddTaskController extends GetxController {
|
|||||||
isLoadingWorkMasterCategories.value = false;
|
isLoadingWorkMasterCategories.value = false;
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void selectCategory(String id) {
|
||||||
|
selectedCategoryId.value = id;
|
||||||
|
selectedCategoryName.value = categoryIdNameMap[id];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,6 @@ class ApiEndpoints {
|
|||||||
static const String assignDailyTask = "/task/assign";
|
static const String assignDailyTask = "/task/assign";
|
||||||
static const String getWorkStatus = "/master/work-status";
|
static const String getWorkStatus = "/master/work-status";
|
||||||
static const String approveReportAction = "/task/approve";
|
static const String approveReportAction = "/task/approve";
|
||||||
static const String assignTask = "/task/assign";
|
static const String assignTask = "/project/task";
|
||||||
static const String getmasterWorkCategories = "/Master/work-categories";
|
static const String getmasterWorkCategories = "/Master/work-categories";
|
||||||
}
|
}
|
||||||
|
@ -408,20 +408,21 @@ class ApiService {
|
|||||||
static Future<bool> createTask({
|
static Future<bool> createTask({
|
||||||
required String parentTaskId,
|
required String parentTaskId,
|
||||||
required int plannedTask,
|
required int plannedTask,
|
||||||
required String description,
|
required String comment,
|
||||||
required List<String> taskTeam,
|
required String workAreaId,
|
||||||
required String workItemId,
|
required String activityId,
|
||||||
DateTime? assignmentDate,
|
DateTime? assignmentDate,
|
||||||
|
required String categoryId,
|
||||||
}) async {
|
}) async {
|
||||||
final body = {
|
final body = [{
|
||||||
"assignmentDate":
|
|
||||||
(assignmentDate ?? DateTime.now()).toUtc().toIso8601String(),
|
|
||||||
"parentTaskId": parentTaskId,
|
"parentTaskId": parentTaskId,
|
||||||
"plannedTask": plannedTask,
|
"plannedWork": plannedTask,
|
||||||
"description": description,
|
"comment": comment,
|
||||||
"taskTeam": taskTeam,
|
"workAreaID": workAreaId,
|
||||||
"workItemId": workItemId,
|
"activityID": activityId,
|
||||||
};
|
"workCategoryId": categoryId,
|
||||||
|
'completedWork': 0,
|
||||||
|
}];
|
||||||
|
|
||||||
final response = await _postRequest(ApiEndpoints.assignTask, body);
|
final response = await _postRequest(ApiEndpoints.assignTask, body);
|
||||||
if (response == null) return false;
|
if (response == null) return false;
|
||||||
|
@ -2,8 +2,11 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:marco/controller/task_planing/add_task_controller.dart';
|
import 'package:marco/controller/task_planing/add_task_controller.dart';
|
||||||
import 'package:marco/helpers/widgets/my_text.dart';
|
import 'package:marco/helpers/widgets/my_text.dart';
|
||||||
|
import 'package:logger/logger.dart';
|
||||||
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
||||||
|
|
||||||
|
final Logger log = Logger();
|
||||||
|
|
||||||
void showManageTaskBottomSheet({
|
void showManageTaskBottomSheet({
|
||||||
required String workArea,
|
required String workArea,
|
||||||
required String activity,
|
required String activity,
|
||||||
@ -12,82 +15,15 @@ void showManageTaskBottomSheet({
|
|||||||
required Function(String) onCategoryChanged,
|
required Function(String) onCategoryChanged,
|
||||||
required String parentTaskId,
|
required String parentTaskId,
|
||||||
required int plannedTask,
|
required int plannedTask,
|
||||||
required String workItemId,
|
required String activityId,
|
||||||
|
required String workAreaId,
|
||||||
required VoidCallback onSubmit,
|
required VoidCallback onSubmit,
|
||||||
}) {
|
}) {
|
||||||
final controller = Get.put(AddTaskController());
|
final controller = Get.put(AddTaskController());
|
||||||
final ScrollController employeeListScrollController = ScrollController();
|
|
||||||
final TextEditingController plannedTaskController =
|
final TextEditingController plannedTaskController =
|
||||||
TextEditingController(text: plannedTask.toString());
|
TextEditingController(text: plannedTask.toString());
|
||||||
final TextEditingController descriptionController = TextEditingController();
|
final TextEditingController descriptionController = TextEditingController();
|
||||||
|
|
||||||
Widget buildEmployeeList() {
|
|
||||||
final selectedRoleId = controller.selectedRoleId.value;
|
|
||||||
final filteredEmployees = selectedRoleId == null
|
|
||||||
? controller.employees
|
|
||||||
: controller.employees
|
|
||||||
.where((e) => e.jobRoleID.toString() == selectedRoleId)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
if (filteredEmployees.isEmpty) {
|
|
||||||
return MyText.bodySmall("No employees found for selected role.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Scrollbar(
|
|
||||||
controller: employeeListScrollController,
|
|
||||||
thumbVisibility: true,
|
|
||||||
interactive: true,
|
|
||||||
child: ListView.builder(
|
|
||||||
controller: employeeListScrollController,
|
|
||||||
shrinkWrap: true,
|
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
|
||||||
itemCount: filteredEmployees.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final employee = filteredEmployees[index];
|
|
||||||
final rxBool = controller.uploadingStates[employee.id];
|
|
||||||
|
|
||||||
return Obx(() => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 0),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Theme(
|
|
||||||
data: Theme.of(context)
|
|
||||||
.copyWith(unselectedWidgetColor: Colors.black),
|
|
||||||
child: Checkbox(
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(4),
|
|
||||||
side: const BorderSide(color: Colors.black),
|
|
||||||
),
|
|
||||||
value: rxBool?.value ?? false,
|
|
||||||
onChanged: (bool? selected) {
|
|
||||||
if (rxBool != null) {
|
|
||||||
rxBool.value = selected ?? false;
|
|
||||||
controller.updateSelectedEmployees();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fillColor:
|
|
||||||
WidgetStateProperty.resolveWith<Color>((states) {
|
|
||||||
if (states.contains(WidgetState.selected)) {
|
|
||||||
return const Color.fromARGB(255, 95, 132, 255);
|
|
||||||
}
|
|
||||||
return Colors.transparent;
|
|
||||||
}),
|
|
||||||
checkColor: Colors.white,
|
|
||||||
side: const BorderSide(color: Colors.black),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Expanded(
|
|
||||||
child: MyText.bodySmall(employee.name),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Get.bottomSheet(
|
Get.bottomSheet(
|
||||||
StatefulBuilder(
|
StatefulBuilder(
|
||||||
builder: (context, setState) {
|
builder: (context, setState) {
|
||||||
@ -166,7 +102,7 @@ void showManageTaskBottomSheet({
|
|||||||
Icon(Icons.description_outlined,
|
Icon(Icons.description_outlined,
|
||||||
color: Colors.grey[700], size: 18),
|
color: Colors.grey[700], size: 18),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
MyText.bodyMedium("Description", fontWeight: 600),
|
MyText.bodyMedium("Comment", fontWeight: 600),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
@ -182,48 +118,59 @@ void showManageTaskBottomSheet({
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.group_add_outlined,
|
Icon(Icons.category_outlined,
|
||||||
color: Colors.grey[700], size: 18),
|
color: Colors.grey[700], size: 18),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
MyText.bodyMedium("Select Team Members", fontWeight: 600),
|
MyText.bodyMedium("Selected Work Category",
|
||||||
|
fontWeight: 600),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 6),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
if (controller.isLoading.value) {
|
final categoryMap = controller.categoryIdNameMap;
|
||||||
return const Center(
|
final String selectedName =
|
||||||
child: CircularProgressIndicator());
|
controller.selectedCategoryId.value != null
|
||||||
}
|
? (categoryMap[
|
||||||
|
controller.selectedCategoryId.value!] ??
|
||||||
|
'Select Category')
|
||||||
|
: 'Select Category';
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
constraints: const BoxConstraints(maxHeight: 150),
|
width: double.infinity,
|
||||||
child: buildEmployeeList(),
|
padding: const EdgeInsets.symmetric(
|
||||||
);
|
horizontal: 12, vertical: 14),
|
||||||
}),
|
decoration: BoxDecoration(
|
||||||
const SizedBox(height: 12),
|
border: Border.all(color: Colors.grey.shade300),
|
||||||
Obx(() {
|
borderRadius: BorderRadius.circular(8),
|
||||||
if (controller.selectedEmployees.isEmpty) {
|
),
|
||||||
return const SizedBox.shrink();
|
child: PopupMenuButton<String>(
|
||||||
}
|
padding: EdgeInsets.zero,
|
||||||
return Wrap(
|
onSelected: (val) {
|
||||||
spacing: 8,
|
controller.selectCategory(val);
|
||||||
runSpacing: 8,
|
onCategoryChanged(val);
|
||||||
children:
|
},
|
||||||
controller.selectedEmployees.map((employee) {
|
itemBuilder: (context) => categoryMap.entries
|
||||||
return Chip(
|
.map(
|
||||||
label: Text(employee.name),
|
(entry) => PopupMenuItem<String>(
|
||||||
deleteIcon: const Icon(Icons.close),
|
value: entry.key,
|
||||||
onDeleted: () {
|
child: Text(entry.value),
|
||||||
controller.uploadingStates[employee.id]?.value =
|
),
|
||||||
false;
|
)
|
||||||
controller.updateSelectedEmployees();
|
.toList(),
|
||||||
},
|
child: Row(
|
||||||
backgroundColor: Colors.blue.shade100,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
labelStyle: const TextStyle(color: Colors.black),
|
children: [
|
||||||
);
|
Text(
|
||||||
}).toList(),
|
selectedName,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14, color: Colors.black87),
|
||||||
|
),
|
||||||
|
const Icon(Icons.arrow_drop_down),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
@ -232,7 +179,7 @@ void showManageTaskBottomSheet({
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: OutlinedButton(
|
child: OutlinedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Get.back(); // Close bottom sheet
|
Get.back();
|
||||||
},
|
},
|
||||||
style: OutlinedButton.styleFrom(
|
style: OutlinedButton.styleFrom(
|
||||||
side: const BorderSide(color: Colors.grey),
|
side: const BorderSide(color: Colors.grey),
|
||||||
@ -250,30 +197,42 @@ void showManageTaskBottomSheet({
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final taskTeam = controller.selectedEmployees
|
final plannedValue = int.tryParse(
|
||||||
.map((e) => e.id)
|
plannedTaskController.text.trim()) ??
|
||||||
.toList();
|
0;
|
||||||
|
final comment =
|
||||||
|
descriptionController.text.trim();
|
||||||
|
final assignmentDate = DateTime.now();
|
||||||
|
|
||||||
if (taskTeam.isEmpty) {
|
// 🪵 Log the task creation input values
|
||||||
|
log.i({
|
||||||
|
"message": "Creating task with data",
|
||||||
|
"parentTaskId": parentTaskId,
|
||||||
|
"plannedTask": plannedValue,
|
||||||
|
"comment": comment,
|
||||||
|
"workAreaId": workAreaId,
|
||||||
|
"activityId": activityId,
|
||||||
|
});
|
||||||
|
|
||||||
|
final selectedCategoryId =
|
||||||
|
controller.selectedCategoryId.value;
|
||||||
|
if (selectedCategoryId == null) {
|
||||||
showAppSnackbar(
|
showAppSnackbar(
|
||||||
title: "Team Required",
|
title: "error",
|
||||||
message:
|
message: "Please select a work category!",
|
||||||
"Please select at least one team member.",
|
type: SnackbarType.error,
|
||||||
type: SnackbarType.warning,
|
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final success = await controller.createTask(
|
final success = await controller.createTask(
|
||||||
parentTaskId: parentTaskId,
|
parentTaskId: parentTaskId,
|
||||||
plannedTask: int.tryParse(
|
plannedTask: plannedValue,
|
||||||
plannedTaskController.text.trim()) ??
|
comment: comment,
|
||||||
0,
|
workAreaId: workAreaId,
|
||||||
description:
|
activityId: activityId,
|
||||||
descriptionController.text.trim(),
|
categoryId:
|
||||||
taskTeam: taskTeam,
|
selectedCategoryId,
|
||||||
workItemId: workItemId,
|
|
||||||
assignmentDate: DateTime.now(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
|
@ -18,14 +18,17 @@ class ReportActionBottomSheet extends StatefulWidget {
|
|||||||
final Map<String, dynamic> taskData;
|
final Map<String, dynamic> taskData;
|
||||||
final VoidCallback? onCommentSuccess;
|
final VoidCallback? onCommentSuccess;
|
||||||
final String taskDataId;
|
final String taskDataId;
|
||||||
final String workItemId;
|
final String workAreaId;
|
||||||
|
final String activityId;
|
||||||
final VoidCallback onReportSuccess;
|
final VoidCallback onReportSuccess;
|
||||||
|
|
||||||
const ReportActionBottomSheet({
|
const ReportActionBottomSheet({
|
||||||
super.key,
|
super.key,
|
||||||
required this.taskData,
|
required this.taskData,
|
||||||
this.onCommentSuccess,
|
this.onCommentSuccess,
|
||||||
required this.taskDataId,
|
required this.taskDataId,
|
||||||
required this.workItemId,
|
required this.workAreaId,
|
||||||
|
required this.activityId,
|
||||||
required this.onReportSuccess,
|
required this.onReportSuccess,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -77,8 +80,7 @@ class _ReportActionBottomSheetState extends State<ReportActionBottomSheet>
|
|||||||
controller.basicValidator.getController('comment')?.clear();
|
controller.basicValidator.getController('comment')?.clear();
|
||||||
controller.basicValidator.getController('task_id')?.text =
|
controller.basicValidator.getController('task_id')?.text =
|
||||||
widget.taskDataId;
|
widget.taskDataId;
|
||||||
controller.basicValidator.getController('work_item_id')?.text =
|
|
||||||
widget.workItemId;
|
|
||||||
controller.selectedImages.clear();
|
controller.selectedImages.clear();
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
@ -486,7 +488,10 @@ class _ReportActionBottomSheetState extends State<ReportActionBottomSheet>
|
|||||||
widget.taskData['plannedWork'] ??
|
widget.taskData['plannedWork'] ??
|
||||||
'0') ??
|
'0') ??
|
||||||
0,
|
0,
|
||||||
workItemId: widget.workItemId,
|
activityId:
|
||||||
|
widget.activityId,
|
||||||
|
workAreaId:
|
||||||
|
widget.workAreaId,
|
||||||
onSubmit: () {
|
onSubmit: () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
|
@ -106,7 +106,8 @@ class TaskActionButtons {
|
|||||||
required int completed,
|
required int completed,
|
||||||
required VoidCallback refreshCallback,
|
required VoidCallback refreshCallback,
|
||||||
required String parentTaskID,
|
required String parentTaskID,
|
||||||
required String workItemId,
|
required String activityId,
|
||||||
|
required String workAreaId,
|
||||||
}) {
|
}) {
|
||||||
return OutlinedButton.icon(
|
return OutlinedButton.icon(
|
||||||
icon: const Icon(Icons.report, size: 18, color: Colors.amber),
|
icon: const Icon(Icons.report, size: 18, color: Colors.amber),
|
||||||
@ -131,7 +132,8 @@ class TaskActionButtons {
|
|||||||
child: ReportActionBottomSheet(
|
child: ReportActionBottomSheet(
|
||||||
taskData: taskData,
|
taskData: taskData,
|
||||||
taskDataId: parentTaskID,
|
taskDataId: parentTaskID,
|
||||||
workItemId: workItemId,
|
workAreaId: workAreaId,
|
||||||
|
activityId: activityId,
|
||||||
onReportSuccess: refreshCallback,
|
onReportSuccess: refreshCallback,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -32,8 +32,9 @@ class TaskModel {
|
|||||||
? DateTime.tryParse(json['reportedDate'])
|
? DateTime.tryParse(json['reportedDate'])
|
||||||
: null,
|
: null,
|
||||||
id: json['id'],
|
id: json['id'],
|
||||||
workItem:
|
workItem: json['workItem'] != null
|
||||||
json['workItem'] != null ? WorkItem.fromJson(json['workItem']) : null,
|
? WorkItem.fromJson(json['workItem'])
|
||||||
|
: null,
|
||||||
workItemId: json['workItemId'],
|
workItemId: json['workItemId'],
|
||||||
plannedTask: json['plannedTask'],
|
plannedTask: json['plannedTask'],
|
||||||
completedTask: json['completedTask'],
|
completedTask: json['completedTask'],
|
||||||
@ -87,25 +88,39 @@ class WorkItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ActivityMaster {
|
class ActivityMaster {
|
||||||
|
final String? id; // ✅ Added
|
||||||
final String activityName;
|
final String activityName;
|
||||||
|
|
||||||
ActivityMaster({required this.activityName});
|
ActivityMaster({
|
||||||
|
this.id,
|
||||||
|
required this.activityName,
|
||||||
|
});
|
||||||
|
|
||||||
factory ActivityMaster.fromJson(Map<String, dynamic> json) {
|
factory ActivityMaster.fromJson(Map<String, dynamic> json) {
|
||||||
return ActivityMaster(activityName: json['activityName'] ?? '');
|
return ActivityMaster(
|
||||||
|
id: json['id']?.toString(),
|
||||||
|
activityName: json['activityName'] ?? '',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WorkArea {
|
class WorkArea {
|
||||||
|
final String? id; // ✅ Added
|
||||||
final String areaName;
|
final String areaName;
|
||||||
final Floor? floor;
|
final Floor? floor;
|
||||||
|
|
||||||
WorkArea({required this.areaName, this.floor});
|
WorkArea({
|
||||||
|
this.id,
|
||||||
|
required this.areaName,
|
||||||
|
this.floor,
|
||||||
|
});
|
||||||
|
|
||||||
factory WorkArea.fromJson(Map<String, dynamic> json) {
|
factory WorkArea.fromJson(Map<String, dynamic> json) {
|
||||||
return WorkArea(
|
return WorkArea(
|
||||||
|
id: json['id']?.toString(),
|
||||||
areaName: json['areaName'] ?? '',
|
areaName: json['areaName'] ?? '',
|
||||||
floor: json['floor'] != null ? Floor.fromJson(json['floor']) : null,
|
floor:
|
||||||
|
json['floor'] != null ? Floor.fromJson(json['floor']) : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,6 +368,9 @@ class _DailyProgressReportScreenState extends State<DailyProgressReportScreen>
|
|||||||
|
|
||||||
final activityName =
|
final activityName =
|
||||||
task.workItem?.activityMaster?.activityName ?? 'N/A';
|
task.workItem?.activityMaster?.activityName ?? 'N/A';
|
||||||
|
final activityId = task.workItem?.activityMaster?.id ;
|
||||||
|
final workAreaId =
|
||||||
|
task.workItem?.workArea?.id;
|
||||||
final location = [
|
final location = [
|
||||||
task.workItem?.workArea?.floor?.building?.name,
|
task.workItem?.workArea?.floor?.building?.name,
|
||||||
task.workItem?.workArea?.floor?.floorName,
|
task.workItem?.workArea?.floor?.floorName,
|
||||||
@ -380,7 +383,6 @@ class _DailyProgressReportScreenState extends State<DailyProgressReportScreen>
|
|||||||
? (completed / planned).clamp(0.0, 1.0)
|
? (completed / planned).clamp(0.0, 1.0)
|
||||||
: 0.0;
|
: 0.0;
|
||||||
final parentTaskID = task.id;
|
final parentTaskID = task.id;
|
||||||
final workItemId = task.workItem?.id;
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
@ -474,10 +476,12 @@ class _DailyProgressReportScreenState extends State<DailyProgressReportScreen>
|
|||||||
context: context,
|
context: context,
|
||||||
task: task,
|
task: task,
|
||||||
parentTaskID: parentTaskID,
|
parentTaskID: parentTaskID,
|
||||||
workItemId: workItemId.toString(),
|
workAreaId: workAreaId.toString(),
|
||||||
|
activityId: activityId.toString(),
|
||||||
completed: completed,
|
completed: completed,
|
||||||
refreshCallback: _refreshData,
|
refreshCallback: _refreshData,
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
],
|
],
|
||||||
TaskActionButtons.commentButton(
|
TaskActionButtons.commentButton(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user