333 lines
14 KiB
Dart
333 lines
14 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:get/get.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_snackbar.dart';
|
|
|
|
void showManageTaskBottomSheet({
|
|
required String workArea,
|
|
required String activity,
|
|
required String completedWork,
|
|
required String unit,
|
|
required Function(String) onCategoryChanged,
|
|
required String parentTaskId,
|
|
required int plannedTask,
|
|
required String workItemId,
|
|
required VoidCallback onSubmit,
|
|
}) {
|
|
final controller = Get.put(AddTaskController());
|
|
final ScrollController employeeListScrollController = ScrollController();
|
|
final TextEditingController plannedTaskController =
|
|
TextEditingController(text: plannedTask.toString());
|
|
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(
|
|
StatefulBuilder(
|
|
builder: (context, setState) {
|
|
return LayoutBuilder(
|
|
builder: (context, constraints) {
|
|
final isLarge = constraints.maxWidth > 600;
|
|
final horizontalPadding =
|
|
isLarge ? constraints.maxWidth * 0.2 : 16.0;
|
|
|
|
return SafeArea(
|
|
child: Container(
|
|
constraints: const BoxConstraints(maxHeight: 760),
|
|
padding: EdgeInsets.fromLTRB(
|
|
horizontalPadding, 12, horizontalPadding, 24),
|
|
decoration: const BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
|
),
|
|
child: SingleChildScrollView(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Center(
|
|
child: Container(
|
|
width: 40,
|
|
height: 4,
|
|
margin: const EdgeInsets.only(bottom: 16),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey.shade400,
|
|
borderRadius: BorderRadius.circular(2),
|
|
),
|
|
),
|
|
),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
const SizedBox(width: 8),
|
|
MyText.titleMedium(
|
|
"Create Task",
|
|
fontWeight: 700,
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 16),
|
|
_infoRowWithIcon(
|
|
Icons.workspaces, "Selected Work Area", workArea),
|
|
_infoRowWithIcon(
|
|
Icons.list_alt, "Selected Activity", activity),
|
|
const SizedBox(height: 12),
|
|
_infoRowWithIcon(Icons.check_circle_outline,
|
|
"Completed Work", completedWork),
|
|
const SizedBox(height: 12),
|
|
Row(
|
|
children: [
|
|
Icon(Icons.edit_calendar,
|
|
color: Colors.grey[700], size: 18),
|
|
const SizedBox(width: 8),
|
|
MyText.bodyMedium("Planned Work", fontWeight: 600),
|
|
],
|
|
),
|
|
const SizedBox(height: 6),
|
|
TextField(
|
|
controller: plannedTaskController,
|
|
keyboardType: TextInputType.number,
|
|
decoration: InputDecoration(
|
|
hintText: "Enter planned work",
|
|
border: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(8)),
|
|
contentPadding: const EdgeInsets.symmetric(
|
|
horizontal: 12, vertical: 10),
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
Row(
|
|
children: [
|
|
Icon(Icons.description_outlined,
|
|
color: Colors.grey[700], size: 18),
|
|
const SizedBox(width: 8),
|
|
MyText.bodyMedium("Description", fontWeight: 600),
|
|
],
|
|
),
|
|
const SizedBox(height: 6),
|
|
TextField(
|
|
controller: descriptionController,
|
|
maxLines: 3,
|
|
decoration: InputDecoration(
|
|
hintText: "Enter task description",
|
|
border: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(8)),
|
|
contentPadding: const EdgeInsets.symmetric(
|
|
horizontal: 12, vertical: 10),
|
|
),
|
|
),
|
|
const SizedBox(height: 24),
|
|
Row(
|
|
children: [
|
|
Icon(Icons.group_add_outlined,
|
|
color: Colors.grey[700], size: 18),
|
|
const SizedBox(width: 8),
|
|
MyText.bodyMedium("Select Team Members", fontWeight: 600),
|
|
],
|
|
),
|
|
const SizedBox(height: 8),
|
|
Obx(() {
|
|
if (controller.isLoading.value) {
|
|
return const Center(
|
|
child: CircularProgressIndicator());
|
|
}
|
|
|
|
return Container(
|
|
constraints: const BoxConstraints(maxHeight: 150),
|
|
child: buildEmployeeList(),
|
|
);
|
|
}),
|
|
const SizedBox(height: 12),
|
|
Obx(() {
|
|
if (controller.selectedEmployees.isEmpty) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
return Wrap(
|
|
spacing: 8,
|
|
runSpacing: 8,
|
|
children:
|
|
controller.selectedEmployees.map((employee) {
|
|
return Chip(
|
|
label: Text(employee.name),
|
|
deleteIcon: const Icon(Icons.close),
|
|
onDeleted: () {
|
|
controller.uploadingStates[employee.id]?.value =
|
|
false;
|
|
controller.updateSelectedEmployees();
|
|
},
|
|
backgroundColor: Colors.blue.shade100,
|
|
labelStyle: const TextStyle(color: Colors.black),
|
|
);
|
|
}).toList(),
|
|
);
|
|
}),
|
|
const SizedBox(height: 24),
|
|
Row(
|
|
children: [
|
|
Expanded(
|
|
child: OutlinedButton(
|
|
onPressed: () {
|
|
Get.back(); // Close bottom sheet
|
|
},
|
|
style: OutlinedButton.styleFrom(
|
|
side: const BorderSide(color: Colors.grey),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(10)),
|
|
),
|
|
child: MyText.bodyMedium(
|
|
"Cancel",
|
|
fontWeight: 600,
|
|
color: Colors.black,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: ElevatedButton(
|
|
onPressed: () async {
|
|
final taskTeam = controller.selectedEmployees
|
|
.map((e) => e.id)
|
|
.toList();
|
|
|
|
if (taskTeam.isEmpty) {
|
|
showAppSnackbar(
|
|
title: "Team Required",
|
|
message:
|
|
"Please select at least one team member.",
|
|
type: SnackbarType.warning,
|
|
);
|
|
return;
|
|
}
|
|
|
|
final success = await controller.createTask(
|
|
parentTaskId: parentTaskId,
|
|
plannedTask: int.tryParse(
|
|
plannedTaskController.text.trim()) ??
|
|
0,
|
|
description:
|
|
descriptionController.text.trim(),
|
|
taskTeam: taskTeam,
|
|
workItemId: workItemId,
|
|
assignmentDate: DateTime.now(),
|
|
);
|
|
|
|
if (success) {
|
|
Get.back();
|
|
onSubmit();
|
|
}
|
|
},
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.blueAccent,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(10)),
|
|
),
|
|
child: MyText.bodyMedium(
|
|
"Submit",
|
|
fontWeight: 600,
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
isScrollControlled: true,
|
|
);
|
|
}
|
|
|
|
Widget _infoRowWithIcon(IconData icon, String title, String value) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 6),
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Icon(icon, color: Colors.grey[700], size: 18),
|
|
const SizedBox(width: 8),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
MyText.bodyMedium(title, fontWeight: 600),
|
|
const SizedBox(height: 2),
|
|
MyText.bodySmall(value, color: Colors.grey[800]),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|