marco.pms.mobileapp/lib/model/dailyTaskPlaning/create_task_botom_sheet.dart

308 lines
13 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),
),
),
),
_infoRowWithIcon(
Icons.workspaces, "Selected Work Area", workArea),
_infoRowWithIcon(
Icons.list_alt, "Selected Activity", activity),
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: 12),
_infoRowWithIcon(Icons.check_circle_outline,
"Completed Work", completedWork),
const SizedBox(height: 16),
MyText.bodyMedium("Description", fontWeight: 700),
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),
MyText.bodyMedium("Select Team Members", fontWeight: 700),
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]),
],
),
),
],
),
);
}