import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:marco/helpers/theme/app_theme.dart'; import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; import 'package:marco/helpers/widgets/my_breadcrumb.dart'; import 'package:marco/helpers/widgets/my_breadcrumb_item.dart'; import 'package:marco/helpers/widgets/my_flex.dart'; import 'package:marco/helpers/widgets/my_flex_item.dart'; import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/view/layouts/layout.dart'; import 'package:marco/controller/permission_controller.dart'; import 'package:marco/helpers/widgets/my_loading_component.dart'; import 'package:marco/helpers/widgets/my_refresh_wrapper.dart'; import 'package:marco/model/my_paginated_table.dart'; import 'package:marco/controller/dashboard/daily_task_controller.dart'; import 'package:marco/helpers/widgets/avatar.dart'; import 'package:intl/intl.dart'; import 'package:marco/helpers/widgets/my_team_model_sheet.dart'; class DailyTaskScreen extends StatefulWidget { const DailyTaskScreen({super.key}); @override State createState() => _DailyTaskScreenState(); } class _DailyTaskScreenState extends State with UIMixin { final DailyTaskController dailyTaskController = Get.put(DailyTaskController()); final PermissionController permissionController = Get.put(PermissionController()); @override Widget build(BuildContext context) { return Layout( child: Obx(() { return LoadingComponent( isLoading: dailyTaskController.isLoading.value, loadingText: 'Loading Tasks...', child: GetBuilder( init: dailyTaskController, builder: (controller) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildHeader(), MySpacing.height(flexSpacing), _buildBreadcrumb(), MySpacing.height(flexSpacing), _buildFilterSection(), MySpacing.height(flexSpacing), _buildTaskList(), ], ); }, ), ); }), ); } Widget _buildHeader() { return Padding( padding: MySpacing.x(flexSpacing), child: MyText.titleMedium( "Daily Progress Report", fontSize: 18, fontWeight: 600, ), ); } Widget _buildBreadcrumb() { return Padding( padding: MySpacing.x(flexSpacing), child: MyBreadcrumb( children: [ MyBreadcrumbItem(name: 'Dashboard'), MyBreadcrumbItem(name: 'Daily Progress Report', active: true), ], ), ); } Widget _buildFilterSection() { return Padding( padding: MySpacing.x(flexSpacing), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ _buildProjectFilter(), const SizedBox(width: 10), _buildDateRangeButton(), ], ), ); } Widget _buildProjectFilter() { return Expanded( child: Container( decoration: BoxDecoration( border: Border.all(color: Colors.black, width: 1.5), borderRadius: BorderRadius.circular(4), ), child: PopupMenuButton( onSelected: (String value) async { if (value.isNotEmpty) { dailyTaskController.selectedProjectId = value; await dailyTaskController.fetchTaskData(value); } dailyTaskController.update(); }, itemBuilder: (BuildContext context) { return dailyTaskController.projects .map>((project) { return PopupMenuItem( value: project.id, child: MyText.bodySmall(project.name), ); }).toList(); }, offset: const Offset(0, 40), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( dailyTaskController.selectedProjectId == null ? dailyTaskController.projects.isNotEmpty ? dailyTaskController.projects.first.name : 'No Tasks' : dailyTaskController.projects .firstWhere((project) => project.id == dailyTaskController.selectedProjectId) .name, overflow: TextOverflow.ellipsis, style: const TextStyle(fontWeight: FontWeight.w600), ), ), const Icon(Icons.arrow_drop_down), ], ), ), ), ), ); } Widget _buildDateRangeButton() { String dateRangeText; if (dailyTaskController.startDateTask != null && dailyTaskController.endDateTask != null) { dateRangeText = '${DateFormat('dd-MM-yyyy').format(dailyTaskController.startDateTask!)}' ' to ' '${DateFormat('dd-MM-yyyy').format(dailyTaskController.endDateTask!)}'; } else { dateRangeText = "Select Date Range"; } return Padding( padding: const EdgeInsets.all(8.0), child: TextButton.icon( icon: const Icon(Icons.date_range), label: Text(dateRangeText), onPressed: () => dailyTaskController.selectDateRangeForTaskData( context, dailyTaskController, ), ), ); } Widget _buildTaskList() { return Padding( padding: MySpacing.x(flexSpacing / 2), child: MyFlex( children: [ MyFlexItem(sizes: 'lg-6', child: employeeListTab()), ], ), ); } Widget employeeListTab() { if (dailyTaskController.dailyTasks.isEmpty) { return Center( child: MyText.bodySmall("No Tasks Assigned to This Project", fontWeight: 600), ); } Map> groupedTasks = {}; for (var task in dailyTaskController.dailyTasks) { String dateKey = DateFormat('dd-MM-yyyy').format(DateTime.parse(task.assignmentDate)); groupedTasks.putIfAbsent(dateKey, () => []).add(task); } // Sort dates descending (latest first) final sortedEntries = groupedTasks.entries.toList() ..sort((a, b) => DateFormat('dd-MM-yyyy') .parse(b.key) .compareTo(DateFormat('dd-MM-yyyy').parse(a.key))); // Flatten grouped data into one list with optional visual separators List allRows = []; for (var entry in sortedEntries) { allRows.add( DataRow( color: WidgetStateProperty.all(Colors.grey.shade200), cells: [ DataCell(MyText.titleSmall('Date: ${entry.key}')), DataCell(MyText.titleSmall('')), DataCell(MyText.titleSmall('')), DataCell(MyText.titleSmall('')), DataCell(MyText.titleSmall('')), DataCell(MyText.titleSmall('')), ], ), ); allRows.addAll(entry.value.map((task) => _buildRow(task))); } return MyRefreshableContent( onRefresh: () async { if (dailyTaskController.selectedProjectId != null) { await dailyTaskController .fetchTaskData(dailyTaskController.selectedProjectId!); } }, child: MyPaginatedTable( columns: _buildColumns(), rows: allRows, ), ); } List _buildColumns() { return [ DataColumn( label: MyText.labelLarge('Activity', color: contentTheme.primary)), DataColumn( label: MyText.labelLarge('Assigned', color: contentTheme.primary)), DataColumn( label: MyText.labelLarge('Completed', color: contentTheme.primary)), DataColumn( label: MyText.labelLarge('Assigned On', color: contentTheme.primary)), DataColumn(label: MyText.labelLarge('Team', color: contentTheme.primary)), DataColumn( label: MyText.labelLarge('Actions', color: contentTheme.primary)), ]; } DataRow _buildRow(dynamic task) { final workItem = task.workItem; final location = [ workItem?.workArea?.floor?.building?.name, workItem?.workArea?.floor?.floorName, workItem?.workArea?.areaName ].where((e) => e != null && e.isNotEmpty).join(' > '); return DataRow(cells: [ DataCell( Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ MyText.bodyMedium(workItem?.activityMaster?.activityName ?? 'N/A', fontWeight: 600), SizedBox(height: 2), MyText.bodySmall(location, color: Colors.grey), ], ), ), DataCell( MyText.bodyMedium( '${task.plannedTask ?? "NA"} / ' '${(workItem?.plannedWork != null && workItem?.completedWork != null) ? (workItem!.plannedWork! - workItem.completedWork!) : "NA"}', ), ), DataCell(MyText.bodyMedium(task.completedTask.toString())), DataCell(MyText.bodyMedium(DateFormat('dd-MM-yyyy') .format(DateTime.parse(task.assignmentDate)))), DataCell(_buildTeamCell(task)), DataCell(Row( children: [ ElevatedButton( onPressed: () { final activityName = task.workItem?.activityMaster?.activityName ?? 'N/A'; final assigned = '${task.plannedTask ?? "NA"} / ' '${(task.workItem?.plannedWork != null && task.workItem?.completedWork != null) ? (task.workItem!.plannedWork! - task.workItem.completedWork!) : "NA"}'; final assignedBy = "${task.assignedBy.firstName} ${task.assignedBy.lastName ?? ''}"; final completed = task.completedTask.toString(); final assignedOn = DateFormat('dd-MM-yyyy') .format(DateTime.parse(task.assignmentDate)); final taskId = task.id; final location = [ task.workItem?.workArea?.floor?.building?.name, task.workItem?.workArea?.floor?.floorName, task.workItem?.workArea?.areaName ].where((e) => e != null && e.isNotEmpty).join(' > '); final teamMembers = task.teamMembers.map((member) => member.firstName).toList(); // Navigate with detailed values Get.toNamed( '/daily-task/report-task', arguments: { 'activity': activityName, 'assigned': assigned, 'taskId': taskId, 'assignedBy': assignedBy, 'completed': completed, 'assignedOn': assignedOn, 'location': location, 'teamSize': task.teamMembers.length, 'teamMembers': teamMembers, }, ); }, style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6), minimumSize: const Size(60, 20), textStyle: const TextStyle(fontSize: 12), ), child: const Text("Report"), ), const SizedBox(width: 8), ElevatedButton( onPressed: () { final activityName = task.workItem?.activityMaster?.activityName ?? 'N/A'; final assigned = '${task.plannedTask ?? "NA"} / ' '${(task.workItem?.plannedWork != null && task.workItem?.completedWork != null) ? (task.workItem!.plannedWork! - task.workItem.completedWork!) : "NA"}'; final plannedWork = '${(task.plannedTask.toString())}'; final assignedBy = "${task.assignedBy.firstName} ${task.assignedBy.lastName ?? ''}"; final completedWork = '${(task.completedTask.toString())}'; final assignedOn = DateFormat('dd-MM-yyyy') .format(DateTime.parse(task.assignmentDate)); final taskId = task.id; final location = [ task.workItem?.workArea?.floor?.building?.name, task.workItem?.workArea?.floor?.floorName, task.workItem?.workArea?.areaName ].where((e) => e != null && e.isNotEmpty).join(' > '); final teamMembers = task.teamMembers.map((member) => member.firstName).toList(); final taskComments = task.comments .map((comment) => comment.comment ?? 'No Content') .toList(); Get.toNamed( '/daily-task/comment-task', arguments: { 'activity': activityName, 'assigned': assigned, 'taskId': taskId, 'assignedBy': assignedBy, 'completedWork': completedWork, 'plannedWork': plannedWork, 'assignedOn': assignedOn, 'location': location, 'teamSize': task.teamMembers.length, 'teamMembers': teamMembers, 'taskComments': taskComments }, ); }, style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6), minimumSize: const Size(60, 20), textStyle: const TextStyle(fontSize: 12), ), child: const Text("Comment"), ), ], )), ]); } Widget _buildTeamCell(dynamic task) { return GestureDetector( onTap: () => TeamBottomSheet.show( context: context, teamMembers: task.teamMembers, ), child: SizedBox( height: 32, width: 100, child: Stack( children: [ for (int i = 0; i < task.teamMembers.length.clamp(0, 3); i++) _buildAvatar(task.teamMembers[i], i * 24.0), if (task.teamMembers.length > 3) _buildExtraMembersIndicator(task.teamMembers.length - 3, 48.0), ], ), ), ); } Widget _buildAvatar(dynamic member, double leftPosition) { return Positioned( left: leftPosition, child: Tooltip( message: member.firstName, child: Avatar(firstName: member.firstName, lastName: '', size: 32), ), ); } Widget _buildExtraMembersIndicator(int extraMembers, double leftPosition) { return Positioned( left: leftPosition, child: CircleAvatar( radius: 16, backgroundColor: Colors.grey.shade300, child: MyText.bodyMedium('+$extraMembers', style: const TextStyle(fontSize: 12, color: Colors.black87)), ), ); } }