Feature_Report_Action #48
@ -7,7 +7,7 @@ import 'package:marco/helpers/widgets/my_snackbar.dart';
|
|||||||
|
|
||||||
final Logger log = Logger();
|
final Logger log = Logger();
|
||||||
|
|
||||||
void showManageTaskBottomSheet({
|
void showCreateTaskBottomSheet({
|
||||||
required String workArea,
|
required String workArea,
|
||||||
required String activity,
|
required String activity,
|
||||||
required String completedWork,
|
required String completedWork,
|
||||||
@ -33,232 +33,170 @@ void showManageTaskBottomSheet({
|
|||||||
final horizontalPadding =
|
final horizontalPadding =
|
||||||
isLarge ? constraints.maxWidth * 0.2 : 16.0;
|
isLarge ? constraints.maxWidth * 0.2 : 16.0;
|
||||||
|
|
||||||
return SafeArea(
|
return // Inside showManageTaskBottomSheet...
|
||||||
|
|
||||||
|
SafeArea(
|
||||||
|
child: Material(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
|
||||||
|
child: Container(
|
||||||
|
constraints: const BoxConstraints(maxHeight: 760),
|
||||||
|
padding: EdgeInsets.fromLTRB(horizontalPadding, 12, horizontalPadding, 24),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: const BoxConstraints(maxHeight: 760),
|
width: 40,
|
||||||
padding: EdgeInsets.fromLTRB(
|
height: 4,
|
||||||
horizontalPadding, 12, horizontalPadding, 24),
|
margin: const EdgeInsets.only(bottom: 16),
|
||||||
decoration: const BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.grey.shade400,
|
||||||
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
borderRadius: BorderRadius.circular(2),
|
||||||
),
|
),
|
||||||
child: SingleChildScrollView(
|
),
|
||||||
child: Column(
|
),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
Center(
|
||||||
|
child: MyText.titleLarge(
|
||||||
|
"Create Task",
|
||||||
|
fontWeight: 700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
_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: [
|
children: [
|
||||||
Center(
|
Text(
|
||||||
child: Container(
|
selectedName,
|
||||||
width: 40,
|
style: const TextStyle(fontSize: 14, color: Colors.black87),
|
||||||
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("Comment", 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.category_outlined,
|
|
||||||
color: Colors.grey[700], size: 18),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
MyText.bodyMedium("Selected Work Category",
|
|
||||||
fontWeight: 600),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
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(
|
|
||||||
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),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
const SizedBox(height: 24),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: OutlinedButton(
|
|
||||||
onPressed: () {
|
|
||||||
Get.back();
|
|
||||||
},
|
|
||||||
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 plannedValue = int.tryParse(
|
|
||||||
plannedTaskController.text.trim()) ??
|
|
||||||
0;
|
|
||||||
final comment =
|
|
||||||
descriptionController.text.trim();
|
|
||||||
final assignmentDate = DateTime.now();
|
|
||||||
|
|
||||||
// 🪵 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(
|
|
||||||
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();
|
|
||||||
onSubmit();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: Colors.blueAccent,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10)),
|
|
||||||
),
|
|
||||||
child: MyText.bodyMedium(
|
|
||||||
"Submit",
|
|
||||||
fontWeight: 600,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
|
const Icon(Icons.arrow_drop_down),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
}),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: OutlinedButton.icon(
|
||||||
|
onPressed: () => Get.back(),
|
||||||
|
icon: const Icon(Icons.close, size: 18),
|
||||||
|
label: MyText.bodyMedium("Cancel", fontWeight: 600),
|
||||||
|
style: OutlinedButton.styleFrom(
|
||||||
|
side: const BorderSide(color: Colors.grey),
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: ElevatedButton.icon(
|
||||||
|
onPressed: () 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,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.check, size: 18),
|
||||||
|
label: MyText.bodyMedium("Submit", color: Colors.white, fontWeight: 600),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Colors.blueAccent,
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -266,6 +204,47 @@ void showManageTaskBottomSheet({
|
|||||||
isScrollControlled: true,
|
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) {
|
Widget _infoRowWithIcon(IconData icon, String title, String value) {
|
||||||
return Padding(
|
return Padding(
|
||||||
|
@ -473,7 +473,7 @@ class _ReportActionBottomSheetState extends State<ReportActionBottomSheet>
|
|||||||
if (shouldShowAddTaskSheet) {
|
if (shouldShowAddTaskSheet) {
|
||||||
await Future.delayed(
|
await Future.delayed(
|
||||||
Duration(milliseconds: 100));
|
Duration(milliseconds: 100));
|
||||||
showManageTaskBottomSheet(
|
showCreateTaskBottomSheet(
|
||||||
workArea: widget.taskData['location'] ?? '',
|
workArea: widget.taskData['location'] ?? '',
|
||||||
activity: widget.taskData['activity'] ?? '',
|
activity: widget.taskData['activity'] ?? '',
|
||||||
completedWork:
|
completedWork:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user