marco.pms.mobileapp/lib/model/dailyTaskPlaning/create_task_botom_sheet.dart
Vaibhav Surve 7ce07c9b47 feat: Enhance AddContactController with submission state management
- Added `isSubmitting` state to prevent multiple submissions in AddContactController.
- Updated the `submitContact` method to handle submission state and validation.
- Refactored `AddContactBottomSheet` to utilize `BaseBottomSheet` for better UI consistency.
- Improved dynamic list handling for email and phone inputs in AddContactBottomSheet.
- Cleaned up controller initialization and field management in AddContactBottomSheet.
- Enhanced error handling and user feedback for required fields.
2025-08-01 16:42:29 +05:30

214 lines
7.2 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';
import 'package:marco/helpers/utils/base_bottom_sheet.dart';
void showCreateTaskBottomSheet({
required String workArea,
required String activity,
required String completedWork,
required String unit,
required Function(String) onCategoryChanged,
required String parentTaskId,
required int plannedTask,
required String activityId,
required String workAreaId,
required VoidCallback onSubmit,
}) {
final controller = Get.put(AddTaskController());
final TextEditingController plannedTaskController =
TextEditingController(text: plannedTask.toString());
final TextEditingController descriptionController = TextEditingController();
Get.bottomSheet(
StatefulBuilder(
builder: (context, setState) {
return BaseBottomSheet(
title: "Create Task",
onCancel: () => Get.back(),
onSubmit: () async {
final plannedValue =
int.tryParse(plannedTaskController.text.trim()) ?? 0;
final comment = descriptionController.text.trim();
final selectedCategoryId = controller.selectedCategoryId.value;
if (selectedCategoryId == null) {
showAppSnackbar(
title: "error",
message: "Please select a work category!",
type: SnackbarType.error,
);
return;
}
final success = await controller.createTask(
parentTaskId: parentTaskId,
plannedTask: plannedValue,
comment: comment,
workAreaId: workAreaId,
activityId: activityId,
categoryId: selectedCategoryId,
);
if (success) {
Get.back();
Future.delayed(const Duration(milliseconds: 300), () {
onSubmit();
showAppSnackbar(
title: "Success",
message: "Task created successfully!",
type: SnackbarType.success,
);
});
}
},
submitText: "Submit",
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_infoCardSection([
_infoRowWithIcon(
Icons.workspaces, "Selected Work Area", workArea),
_infoRowWithIcon(Icons.list_alt, "Selected Activity", activity),
_infoRowWithIcon(Icons.check_circle_outline, "Completed Work",
completedWork),
]),
const SizedBox(height: 16),
_sectionTitle(Icons.edit_calendar, "Planned Work"),
const SizedBox(height: 6),
_customTextField(
controller: plannedTaskController,
hint: "Enter planned work",
keyboardType: TextInputType.number,
),
const SizedBox(height: 16),
_sectionTitle(Icons.description_outlined, "Comment"),
const SizedBox(height: 6),
_customTextField(
controller: descriptionController,
hint: "Enter task description",
maxLines: 3,
),
const SizedBox(height: 16),
_sectionTitle(Icons.category_outlined, "Selected Work Category"),
const SizedBox(height: 6),
Obx(() {
final categoryMap = controller.categoryIdNameMap;
final String selectedName =
controller.selectedCategoryId.value != null
? (categoryMap[controller.selectedCategoryId.value!] ??
'Select Category')
: 'Select Category';
return Container(
width: double.infinity,
padding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 14),
decoration: BoxDecoration(
color: Colors.grey.shade100,
border: Border.all(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(8),
),
child: PopupMenuButton<String>(
padding: EdgeInsets.zero,
onSelected: (val) {
controller.selectCategory(val);
onCategoryChanged(val);
},
itemBuilder: (context) => categoryMap.entries
.map((entry) => PopupMenuItem<String>(
value: entry.key,
child: Text(entry.value),
))
.toList(),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
selectedName,
style: const TextStyle(
fontSize: 14, color: Colors.black87),
),
const Icon(Icons.arrow_drop_down),
],
),
),
);
}),
],
),
);
},
),
isScrollControlled: true,
);
}
Widget _sectionTitle(IconData icon, String title) {
return Row(
children: [
Icon(icon, color: Colors.grey[700], size: 18),
const SizedBox(width: 8),
MyText.bodyMedium(title, fontWeight: 600),
],
);
}
Widget _customTextField({
required TextEditingController controller,
required String hint,
int maxLines = 1,
TextInputType keyboardType = TextInputType.text,
}) {
return TextField(
controller: controller,
maxLines: maxLines,
keyboardType: keyboardType,
decoration: InputDecoration(
hintText: hint,
filled: true,
fillColor: Colors.grey.shade100,
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
),
);
}
Widget _infoCardSection(List<Widget> children) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.grey.shade300),
),
child: Column(children: children),
);
}
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]),
],
),
),
],
),
);
}