import 'package:flutter/material.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/modules/cleaner_module/models/one_time_task_data.dart'; import 'package:test_sa/modules/cleaner_module/provider/cleaner_provider.dart'; import 'package:test_sa/modules/cleaner_module/widgets/cleaner_checklist_widget.dart'; import 'package:test_sa/modules/cleaner_module/widgets/cleaner_preview_dialog.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/pages/land_page/land_page.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import 'package:test_sa/views/widgets/dialogs/confirm_dialog.dart'; class OneTimeTaskView extends StatefulWidget { static const String routeName = "/one_time_task"; final int taskId; const OneTimeTaskView({Key? key, required this.taskId}) : super(key: key); @override State createState() => _OneTimeTaskViewState(); } class _OneTimeTaskViewState extends State { OneTimeTaskData? _taskData; bool _isLoading = false; DateTime? _timerStart; @override void initState() { super.initState(); _loadTaskData(); } Future _loadTaskData() async { setState(() { _isLoading = true; }); try { final result = await CleanerProvider().getOneTimeTaskById(id: widget.taskId); if (result['success'] && result['data'] != null) { setState(() { _taskData = OneTimeTaskData.fromJson(result['data']); _isLoading = false; // Start timer automatically if task is in progress if (_taskData?.statusValue == 1 && _taskData?.startTime != null) { _timerStart = DateTime.parse(_taskData!.startTime!); } }); } else { setState(() { _isLoading = false; }); if (mounted) { _showErrorDialog(context, result['message'] ?? 'Failed to load task'); } } } catch (e) { setState(() { _isLoading = false; }); if (mounted) { _showErrorDialog(context, 'Failed to load task data'); } } } bool get isClosed => _taskData?.statusValue == 2; @override Widget build(BuildContext context) { return Scaffold( appBar: DefaultAppBar( title: 'One Time Task', onWillPopScope: isClosed ? null : () { _showExitDialog(); }, ), body: _isLoading ? const ALoading() : _taskData != null ? SafeArea( child: Column( children: [ Expanded( child: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildTaskInfoCard(context), 16.height, CleanerChecklistWidget( isClosed: isClosed, checklistItems: _convertInstructionsToChecklist(), onChecklistChanged: (value) { setState(() { _updateInstructions(value); }); }, capturedImageBase64: _taskData!.imageRoom, onImageCaptured: (imageBase64) { setState(() { _taskData!.imageRoom = imageBase64; }); }, ), ], ), ), ), if (!isClosed) ...[ FooterActionButton.footerContainer( context: context, child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ AppFilledButton( label: context.translation.save, buttonColor: context.isDark ? AppColor.neutral20 : AppColor.white60, textColor: context.isDark ? Colors.white : AppColor.black10, onPressed: () => Navigator.pop(context), ).expanded, 12.width, AppFilledButton( label: context.translation.complete, buttonColor: AppColor.primary10, onPressed: _onComplete, ).expanded, ], ), ), ] ], ), ) : NoDataFound(message: context.translation.noDataFound).center, ).handlePopScope( cxt: context, showPopUp: !isClosed, onSave: () { Navigator.pop(context); }, ); } Widget _buildTaskInfoCard(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ if (_taskData?.statusName != null) Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: _getStatusColor().withOpacity(0.1), borderRadius: BorderRadius.circular(4), ), child: Text( _taskData!.statusName!, style: AppTextStyles.bodyText.copyWith( color: _getStatusColor(), fontWeight: FontWeight.w600, ), ), ), if (_taskData?.createdDate != null) Text( _formatDate(_taskData!.createdDate!), style: AppTextStyles.tinyFont.copyWith( color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, ), ), ], ), 12.height, if (_taskData?.oneTimeSetting?.taskTypeName != null) Text( _taskData!.oneTimeSetting!.taskTypeName!, style: AppTextStyles.heading4.copyWith( color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, ), ), 8.height, if (_taskData?.oneTimeSetting?.instructionDescriptionName != null) Text( _taskData!.oneTimeSetting!.instructionDescriptionName!, style: AppTextStyles.bodyText.copyWith( color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, ), ), 8.height, if (_taskData?.siteName != null) _buildInfoRow('Site', _taskData!.siteName!), if (_taskData?.buildingName != null) _buildInfoRow('Building', _taskData!.buildingName!), if (_taskData?.floorName != null) _buildInfoRow('Floor', _taskData!.floorName!), if (_taskData?.departmentName != null) _buildInfoRow('Department', _taskData!.departmentName!), if (_taskData?.roomName != null) _buildInfoRow('Room', _taskData!.roomName!), if (_taskData?.locationDescription != null) _buildInfoRow('Location', _taskData!.locationDescription!), // Timer display if (_timerStart != null && !isClosed) ...[ 12.height, Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: AppColor.primary10.withOpacity(0.1), borderRadius: BorderRadius.circular(8), border: Border.all(color: AppColor.primary10), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Working Time:', style: AppTextStyles.bodyText.copyWith( fontWeight: FontWeight.w600, color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, ), ), Text( _formatDuration(DateTime.now().difference(_timerStart!)), style: AppTextStyles.heading4.copyWith( color: AppColor.primary10, fontWeight: FontWeight.bold, ), ), ], ), ), ], ], ).paddingOnly(start: 16, end: 16, top: 16, bottom: 16), ], ).toShadowContainer(context, padding: 0); } Widget _buildInfoRow(String label, String value) { return Padding( padding: const EdgeInsets.only(bottom: 4), child: Text( '$label: $value', style: AppTextStyles.bodyText.copyWith( color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, ), ), ); } List _convertInstructionsToChecklist() { return _taskData?.instructions?.map((instruction) { return ChecklistItem( id: instruction.id ?? 0, title: instruction.instructionText ?? '', isChecked: instruction.isDone ?? false, isMandatory: instruction.isRequired ?? false, comment: instruction.comment ?? '', ); }).toList() ?? []; } void _updateInstructions(List checklist) { _taskData?.instructions = checklist.map((item) { return Instruction( id: item.id, instructionTextId: _taskData?.instructions?.firstWhere((i) => i.id == item.id).instructionTextId, instructionText: item.title, isDone: item.isChecked, isRequired: item.isMandatory, comment: item.comment, ); }).toList(); } void _onComplete() { // Validate mandatory items final uncheckedMandatory = _taskData?.instructions?.where((item) => (item.isRequired ?? false) && !(item.isDone ?? false) ).toList() ?? []; if (uncheckedMandatory.isNotEmpty) { _showErrorDialog(context, "Please complete all mandatory tasks (marked with *)"); return; } // Show preview dialog _showPreviewDialog(); } void _showPreviewDialog() { // Calculate working hours double totalWorkingHours = 0; if (_timerStart != null) { final duration = DateTime.now().difference(_timerStart!); totalWorkingHours = duration.inSeconds / 3600.0; } CleanerPreviewDialog.show( context, model: _convertToRecurrentWoData(), totalWorkingHours: totalWorkingHours, onConfirm: _performComplete, ); } // Convert OneTimeTaskData to RecurrentWoData for preview dialog compatibility dynamic _convertToRecurrentWoData() { return { 'siteName': _taskData?.siteName, 'buildingName': _taskData?.buildingName, 'floorName': _taskData?.floorName, 'departmentName': _taskData?.departmentName, 'roomName': _taskData?.roomName, 'locationDescription': _taskData?.locationDescription, 'taskNo': 'OT-${_taskData?.id}', 'title': _taskData?.oneTimeSetting?.taskTypeName, }; } Future _performComplete() async { showDialog( context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading(), ); try { final instructionsPayload = _taskData?.instructions?.map((instruction) { return { 'id': instruction.id, 'instructionTextId': instruction.instructionTextId, 'instructionText': instruction.instructionText, 'isRequired': instruction.isRequired, 'isDone': instruction.isDone, 'comment': instruction.comment, }; }).toList() ?? []; final result = await CleanerProvider().completeOneTimeTask( id: _taskData!.id!, instructions: instructionsPayload, imageRoom: _taskData?.imageRoom, ); if (mounted) Navigator.pop(context); // Close loading dialog if (result['success']) { if (mounted) { // Navigate to dashboard Navigator.of(context).pushNamedAndRemoveUntil( LandPage.routeName, (routes) => false, ); } } else { if (mounted) { _showErrorDialog(context, result['message'] ?? 'Failed to complete task'); } } } catch (e) { if (mounted) Navigator.pop(context); if (mounted) { _showErrorDialog(context, 'Failed to complete task. Please try again.'); } } } void _showExitDialog() { showDialog( context: context, builder: (context) => ConfirmDialog( message: 'Do you want to exit without completing?', title: 'Confirm', onTap: () { Navigator.pop(context); // Close dialog Navigator.pop(context); // Exit screen }, ), ); } void _showErrorDialog(BuildContext context, String message) { showDialog( context: context, builder: (context) => ConfirmDialog( message: message, title: 'Error', onTap: () => Navigator.pop(context), ), ); } Color _getStatusColor() { if (_taskData?.statusValue == 2) { return Colors.green; } return AppColor.primary10; } String _formatDate(String dateStr) { try { final date = DateTime.parse(dateStr); return '${date.day}/${date.month}/${date.year}'; } catch (e) { return dateStr; } } String _formatDuration(Duration duration) { final hours = duration.inHours; final minutes = duration.inMinutes.remainder(60); final seconds = duration.inSeconds.remainder(60); return '${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}'; } }