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/utils/my_shadow.dart'; import 'package:marco/helpers/widgets/my_card.dart'; import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/controller/permission_controller.dart'; import 'package:marco/controller/task_planing/daily_task_planing_controller.dart'; import 'package:marco/controller/project_controller.dart'; import 'package:percent_indicator/percent_indicator.dart'; import 'package:marco/model/dailyTaskPlaning/assign_task_bottom_sheet .dart'; class DailyTaskPlaningScreen extends StatefulWidget { DailyTaskPlaningScreen({super.key}); @override State createState() => _DailyTaskPlaningScreenState(); } class _DailyTaskPlaningScreenState extends State with UIMixin { final DailyTaskPlaningController dailyTaskPlaningController = Get.put(DailyTaskPlaningController()); final PermissionController permissionController = Get.put(PermissionController()); final ProjectController projectController = Get.find(); @override void initState() { super.initState(); // Initial fetch if a project is already selected final projectId = projectController.selectedProjectId?.value; if (projectId != null) { dailyTaskPlaningController.fetchTaskData(projectId); } // Reactive fetch on project ID change final selectedProject = projectController.selectedProjectId; if (selectedProject != null) { ever( selectedProject, (newProjectId) { if (newProjectId != null) { dailyTaskPlaningController.fetchTaskData(newProjectId); } }, ); } } @override Widget build(BuildContext context) { return Scaffold( appBar: PreferredSize( preferredSize: const Size.fromHeight(80), child: AppBar( backgroundColor: const Color(0xFFF5F5F5), elevation: 0.5, foregroundColor: Colors.black, titleSpacing: 0, centerTitle: false, leading: Padding( padding: const EdgeInsets.only(top: 15.0), // Aligns with title child: IconButton( icon: const Icon(Icons.arrow_back_ios_new, color: Colors.black, size: 20), onPressed: () { Get.offNamed('/dashboard'); }, ), ), title: Padding( padding: const EdgeInsets.only(top: 15.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ MyText.titleLarge( 'Daily Task Planning', fontWeight: 700, color: Colors.black, ), const SizedBox(height: 2), GetBuilder( builder: (projectController) { final projectName = projectController.selectedProject?.name ?? 'Select Project'; return MyText.bodySmall( projectName, fontWeight: 600, maxLines: 1, overflow: TextOverflow.ellipsis, color: Colors.grey[700], ); }, ), ], ), ), ), ), body: SafeArea( child: SingleChildScrollView( padding: MySpacing.x(0), child: GetBuilder( init: dailyTaskPlaningController, tag: 'daily_task_planing_controller', builder: (controller) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ MySpacing.height(flexSpacing), Padding( padding: MySpacing.x(flexSpacing), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ const SizedBox(width: 8), MyText.bodyMedium("Refresh", fontWeight: 600), Tooltip( message: 'Refresh Data', child: InkWell( borderRadius: BorderRadius.circular(24), onTap: () async { final projectId = projectController.selectedProjectId?.value; if (projectId != null) { try { await dailyTaskPlaningController .fetchTaskData(projectId); } catch (e) { debugPrint( 'Error refreshing task data: ${e.toString()}'); } } }, child: MouseRegion( cursor: SystemMouseCursors.click, child: Padding( padding: const EdgeInsets.all(8.0), child: Icon(Icons.refresh, color: Colors.green, size: 28), ), ), ), ), ], ), ), Padding( padding: MySpacing.x(flexSpacing), child: dailyProgressReportTab(), ), ], ); }, ), ), ), ); } Widget dailyProgressReportTab() { return Obx(() { final isLoading = dailyTaskPlaningController.isLoading.value; final dailyTasks = dailyTaskPlaningController.dailyTasks; if (isLoading) { return Center(child: CircularProgressIndicator()); } if (dailyTasks.isEmpty) { return Center( child: MyText.bodySmall( "No Progress Report Found", fontWeight: 600, ), ); } final buildingExpansionState = {}; final floorExpansionState = {}; Widget buildExpandIcon(bool isExpanded) { return Container( width: 32, height: 32, decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.grey.shade200, ), child: Icon( isExpanded ? Icons.remove : Icons.add, size: 20, color: Colors.black87, ), ); } return StatefulBuilder(builder: (context, setMainState) { final filteredBuildings = dailyTasks.expand((task) { return task.buildings.where((building) { return building.floors.any((floor) => floor.workAreas.any((area) => area.workItems.isNotEmpty)); }); }).toList(); if (filteredBuildings.isEmpty) { return Center( child: MyText.bodySmall( "No Progress Report Found", fontWeight: 600, ), ); } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: filteredBuildings.map((building) { final buildingKey = building.id.toString(); return MyCard.bordered( borderRadiusAll: 12, paddingAll: 0, margin: MySpacing.bottom(12), shadow: MyShadow(elevation: 3), child: Theme( data: Theme.of(context) .copyWith(dividerColor: Colors.transparent), child: ExpansionTile( onExpansionChanged: (expanded) { setMainState(() { buildingExpansionState[buildingKey] = expanded; }); }, trailing: buildExpandIcon( buildingExpansionState[buildingKey] ?? false), tilePadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 0), collapsedShape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), leading: Container( decoration: BoxDecoration( color: Colors.blueAccent.withOpacity(0.1), shape: BoxShape.circle, ), padding: const EdgeInsets.all(8), child: Icon( Icons.location_city_rounded, color: Colors.blueAccent, size: 24, ), ), title: MyText.titleMedium( building.name, fontWeight: 700, maxLines: 1, overflow: TextOverflow.ellipsis, ), childrenPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 0), children: building.floors.expand((floor) { final validWorkAreas = floor.workAreas .where((area) => area.workItems.isNotEmpty); // For each valid work area, return a Floor+WorkArea ExpansionTile return validWorkAreas.map((area) { final floorWorkAreaKey = "${buildingKey}_${floor.floorName}_${area.areaName}"; final isExpanded = floorExpansionState[floorWorkAreaKey] ?? false; final totalPlanned = area.workItems .map((wi) => wi.workItem.plannedWork ?? 0) .fold(0, (prev, curr) => prev + curr); final totalCompleted = area.workItems .map((wi) => wi.workItem.completedWork ?? 0) .fold(0, (prev, curr) => prev + curr); final totalProgress = totalPlanned == 0 ? 0.0 : (totalCompleted / totalPlanned).clamp(0.0, 1.0); return ExpansionTile( onExpansionChanged: (expanded) { setMainState(() { floorExpansionState[floorWorkAreaKey] = expanded; }); }, trailing: Icon( isExpanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down, size: 28, color: Colors.black54, ), tilePadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 0), title: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( flex: 3, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ MyText.titleSmall( "Floor: ${floor.floorName}", fontWeight: 600, color: Colors.teal, maxLines: null, overflow: TextOverflow.visible, softWrap: true, ), MySpacing.height(4), MyText.titleSmall( "Work Area: ${area.areaName}", fontWeight: 600, color: Colors.blueGrey, maxLines: null, overflow: TextOverflow.visible, softWrap: true, ), ], ), ), MySpacing.width(12), CircularPercentIndicator( radius: 20.0, lineWidth: 4.0, animation: true, percent: totalProgress, center: Text( "${(totalProgress * 100).toStringAsFixed(0)}%", style: TextStyle( fontWeight: FontWeight.bold, fontSize: 10.0, ), ), circularStrokeCap: CircularStrokeCap.round, progressColor: totalProgress >= 1.0 ? Colors.green : (totalProgress >= 0.5 ? Colors.amber : Colors.red), backgroundColor: Colors.grey[300]!, ), ], ), childrenPadding: const EdgeInsets.only( left: 16, right: 0, bottom: 8), children: area.workItems.map((wItem) { final item = wItem.workItem; final completed = item.completedWork ?? 0; final planned = item.plannedWork ?? 0; final progress = (planned == 0) ? 0.0 : (completed / planned).clamp(0.0, 1.0); return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: MyText.bodyMedium( item.activityMaster?.name ?? "No Activity", fontWeight: 600, maxLines: 2, overflow: TextOverflow.visible, softWrap: true, ), ), MySpacing.width(8), if (item.workCategoryMaster?.name != null) Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 4), decoration: BoxDecoration( color: Colors.blue.shade100, borderRadius: BorderRadius.circular(20), ), child: MyText.bodySmall( item.workCategoryMaster!.name!, fontWeight: 500, color: Colors.blue.shade800, ), ), ], ), MySpacing.height(4), Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( flex: 3, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ MySpacing.height(8), MyText.bodySmall( "Completed: $completed / $planned", fontWeight: 600, color: const Color.fromARGB( 221, 0, 0, 0), ), ], ), ), MySpacing.width(16), if (progress < 1.0) IconButton( icon: Icon( Icons.person_add_alt_1_rounded, color: const Color.fromARGB( 255, 46, 161, 233), ), onPressed: () { final pendingTask = (planned - completed) .clamp(0, planned); showModalBottomSheet( context: context, isScrollControlled: true, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical( top: Radius.circular(16)), ), builder: (context) => AssignTaskBottomSheet( buildingName: building.name, floorName: floor.floorName, workAreaName: area.areaName, workLocation: area.areaName, activityName: item.activityMaster?.name ?? "Unknown Activity", pendingTask: pendingTask, workItemId: item.id.toString(), assignmentDate: DateTime.now(), ), ); }, ), ], ), MySpacing.height(8), Stack( children: [ Container( height: 5, decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(6), ), ), FractionallySizedBox( widthFactor: progress, child: Container( height: 5, decoration: BoxDecoration( color: progress >= 1.0 ? Colors.green : (progress >= 0.5 ? Colors.amber : Colors.red), borderRadius: BorderRadius.circular(6), ), ), ), ], ), SizedBox(height: 4), MyText.bodySmall( "${(progress * 100).toStringAsFixed(1)}%", fontWeight: 500, color: progress >= 1.0 ? Colors.green[700] : (progress >= 0.5 ? Colors.amber[800] : Colors.red[700]), ), ], ), ); }).toList(), ); }).toList(); }).toList(), ), ), ); }).toList(), ); }); }); } }