import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/api/device_transfer_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/device/asset_transfer_attachment.dart'; import 'package:test_sa/models/device/device_transfer.dart'; import 'package:test_sa/models/new_models/assigned_employee.dart'; import 'package:test_sa/models/new_models/assistant_employee.dart'; import 'package:test_sa/models/timer_model.dart'; import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import 'package:test_sa/views/widgets/status/report/service_report_assistant_employee_menu.dart'; import '../../../extensions/text_extensions.dart'; import '../../../models/ppm/ppm.dart'; import '../../../new_views/app_style/app_color.dart'; import '../../../new_views/common_widgets/app_text_form_field.dart'; import '../../../new_views/common_widgets/default_app_bar.dart'; import '../../widgets/timer/app_timer.dart'; class UpdateDeviceTransfer extends StatefulWidget { final DeviceTransfer model; final bool isSender; const UpdateDeviceTransfer({Key? key, required this.model, required this.isSender}) : super(key: key); @override State createState() => _UpdateDeviceTransferState(); } class _UpdateDeviceTransferState extends State { final bool _isLoading = false; late DeviceTransferProvider _deviceTransferProvider; final TextEditingController _requestedQuantityController = TextEditingController(); final DeviceTransfer _formModel = DeviceTransfer(); final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); List _files = []; _update({required int status}) async { _formKey.currentState!.save(); if (_validateForm()) { _formModel.statusValue = status; _formModel.isSender = widget.isSender; _formModel.assetTransferAttachments = []; VisitTimers? deviceTimerPicker; if (_formModel.deviceTimePicker != null) { int durationInSecond = _formModel.deviceTimePicker!.endAt!.difference(_formModel.deviceTimePicker!.startAt!).inSeconds; deviceTimerPicker = VisitTimers( id: 0, startDateTime: _formModel.deviceTimePicker?.startAt?.toIso8601String(), endDateTime: _formModel.deviceTimePicker?.endAt?.toIso8601String(), workingHours: ((durationInSecond) / 60 / 60), ); } int workingHours = _formModel.tbsTimer?.endAt!.difference(_formModel.tbsTimer!.startAt!).inSeconds ?? 0; if (widget.isSender) { _formModel.senderVisitTimers?.add(deviceTimerPicker!); _formModel.senderVisitTimers?.add( VisitTimers( id: 0, startDateTime: _formModel.tbsTimer?.startAt?.toIso8601String(), endDateTime: _formModel.tbsTimer?.endAt?.toIso8601String(), workingHours: ((workingHours) / 60 / 60), ), ); _formModel.assetTransferEngineerTimers = _formModel.senderVisitTimers; } else { _formModel.receiverVisitTimers?.add(deviceTimerPicker!); _formModel.receiverVisitTimers?.add( VisitTimers( id: 0, startDateTime: _formModel.tbsTimer?.startAt?.toIso8601String(), endDateTime: _formModel.tbsTimer?.endAt?.toIso8601String(), workingHours: ((workingHours) / 60 / 60), ), ); _formModel.assetTransferEngineerTimers = _formModel.receiverVisitTimers; } try { for (var file in _files) { String attachmentName = file.path; if (attachmentName.contains("/")) { attachmentName = file.path.split("/").last; attachmentName = "$attachmentName|${base64Encode(file.readAsBytesSync())}"; } _formModel.assetTransferAttachments!.add(AssetTransferAttachment(id: 0, attachmentName: attachmentName)); _formModel.attachments = _formModel.assetTransferAttachments; } } catch (error) { print(error); } if(status ==1){ ServiceRequestBottomSheet.nurseVerifyAssetTransferBottomSheet(context: context,onAckhnowledgePress: (signature) async { //TODO NEED TO CALL API HERE WITH ADDED PARAMETER FOR SIGNATURE FROM BACKEND.. if(signature!=null){ _formModel.nurseSignature = signature; await _deviceTransferProvider.updateRequest(context, model: _formModel); } }); }else { await _deviceTransferProvider.updateRequest(context, model: _formModel); } } } bool _validateForm() { if (_formModel.tbsTimer?.startAt == null) { Fluttertoast.showToast(msg: "Working Hours Required"); return false; } if (_formModel.tbsTimer?.endAt == null || isTimerRunning) { Fluttertoast.showToast(msg: "Please Stop The Timer"); return false; } if (_formModel.assistantEmployees != null) { if (_formModel.modelAssistantEmployees?.startDate == null) { Fluttertoast.showToast(msg: "Please Select Assistant Employee Start Time"); return false; } if (_formModel.modelAssistantEmployees?.endDate == null) { Fluttertoast.showToast(msg: "Please Select Assistant Employee End Time"); return false; } } return true; } @override void initState() { _formModel.fromDetails(widget.model); _files = widget.model.assetTransferAttachments?.map((e) => File(e.attachmentName!)).toList() ?? []; super.initState(); } @override void dispose() { _requestedQuantityController.dispose(); super.dispose(); } bool isTimerRunning = false; @override Widget build(BuildContext context) { _deviceTransferProvider = Provider.of(context, listen: false); double totalWorkingHours = widget.isSender ? (widget.model.senderVisitTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDateTime!).difference(DateTime.parse(item.startDateTime!)).inSeconds) ?? 0) : (widget.model.receiverVisitTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDateTime!).difference(DateTime.parse(item.startDateTime!)).inSeconds) ?? 0); bool isTimerEnable = widget.isSender ? (!(_formModel.senderMachineStatusValue == 3)) : (!(_formModel.receiverMachineStatusValue == 3)); return Scaffold( appBar: DefaultAppBar( title: context.translation.transferAsset, onWillPopScope: () { _update(status: 0); }, ), key: _scaffoldKey, body: SafeArea( child: LoadingManager( isLoading: _isLoading, isFailedLoading: false, stateCode: 200, onRefresh: () async {}, child: Form( key: _formKey, child: Column( children: [ SingleChildScrollView( padding: EdgeInsets.all(12 * AppStyle.getScaleFactor(context)), child: Column( children: [ Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _timerWidget(context, totalWorkingHours, isTimerEnable), 8.height, AppTextFormField( initialValue: widget.isSender ? _formModel.senderComment ?? "" : _formModel.receiverComment ?? "", labelText: context.translation.technicalComment, labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral20), textInputType: TextInputType.multiline, backgroundColor: AppColor.neutral100, showShadow: false, alignLabelWithHint: true, onSaved: (value) { widget.isSender ? _formModel.senderComment = value : _formModel.receiverComment = value; }, ), 8.height, MultiFilesPicker( label: context.translation.attachFiles, files: _files, buttonColor: AppColor.black10, onlyImages: false, buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120), ), 8.height, ], ).toShadowContainer(context), 16.height, AssistantEmployeeCard( isSender: widget.isSender, formModel: _formModel, ).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16)), ], ), ).expanded, FooterActionButton.footerContainer( child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ AppFilledButton( label: context.translation.save, buttonColor: AppColor.white60, textColor: AppColor.black10, onPressed: () => _update(status: 0), ).expanded, 12.width, if (!widget.isSender && _formModel.senderMachineStatusValue == 3) ...[ AppFilledButton( label: context.translation.complete, buttonColor: AppColor.primary10, onPressed: (){ _update(status: 1); } ).expanded, ] else if (widget.isSender) ...[ AppFilledButton( label: context.translation.complete, buttonColor: AppColor.primary10, onPressed: () { _update(status: 1); }, ).expanded, ], ], ), ), ], ), ), ), ), ).handlePopScope( cxt: context, onSave: () { _update(status: 0); }); } void updateTimer({TimerModel? timer}) { _formModel.tbsTimer = timer; if (timer?.startAt != null && timer?.endAt != null) { _formModel.timerModelList = _formModel.timerModelList ?? []; _formModel.timerModelList!.add(timer!); } // notifyListeners(); } Widget _timerWidget(BuildContext context, double totalWorkingHours, bool isTimerEnable) { return Column( mainAxisSize: MainAxisSize.min, children: [ AppTimer( label: context.translation.workingHours, timer: _formModel.tbsTimer, pickerFromDate: DateTime.tryParse(widget.model.createdDate??''), width: double.infinity, enabled: isTimerEnable, decoration: BoxDecoration( color: AppColor.neutral100, borderRadius: BorderRadius.circular(10), ), pickerTimer: _formModel.deviceTimePicker, onPick: (time) { _formModel.deviceTimePicker = time; }, timerProgress: (isRunning) {}, onChange: (timer) async { updateTimer(timer: timer); return true; }, ), if (totalWorkingHours > 0.0) ...[ 12.height, Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: [ 'Total Working Time:'.bodyText2(context).custom(color: AppColor.neutral120), 8.width, Text( ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round()), style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600), ), ], ), ], ], ); } } class AssistantEmployeeCard extends StatefulWidget { bool? isSender = false; DeviceTransfer? formModel; AssistantEmployeeCard({super.key, this.isSender, this.formModel}); @override State createState() => _AssistantEmployeeCardState(); } class _AssistantEmployeeCardState extends State { final TextEditingController _workingHoursController = TextEditingController(text: ''); bool isCurrentUserIsAssistantEmp = false; bool isExpanded = false; List employeeList = []; AssistantEmployees selectedEmployee = AssistantEmployees(); @override void initState() { WidgetsBinding.instance.addPostFrameCallback((_) { getInitialData(); }); super.initState(); } Future getInitialData() async { if (widget.isSender!) { employeeList = widget.formModel!.assetTransferAssistantEmployeesSender ?? []; } else { employeeList = widget.formModel!.assetTransferAssistantEmployeesReceiver ?? []; } widget.formModel?.modelAssistantEmployees = employeeList.isEmpty ? AssetTransferAssistantEmployees() : employeeList[0]; AssignedEmployee? assignedUser = AssignedEmployee(); if (employeeList.isNotEmpty) { assignedUser = AssignedEmployee( id: employeeList[0].employeeId, name: employeeList[0].employeeName, ); } selectedEmployee = AssistantEmployees(userId: assignedUser.id, user: assignedUser); } @override void dispose() { _workingHoursController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Column( children: [ SizedBox( height: 56.toScreenHeight, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ context.translation.assistantEmployee.heading6(context).custom(color: AppColor.black10), Icon(isExpanded ? Icons.keyboard_arrow_up_rounded : Icons.keyboard_arrow_down_rounded), ], ), ).onPress(() { setState(() { isExpanded = !isExpanded; }); }), isExpanded ? Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ ServiceReportAssistantEmployeeMenu( title: context.translation.select, backgroundColor: AppColor.neutral100, assetId: widget.formModel?.assetId ?? 0, initialValue: selectedEmployee, onSelect: (employee) { if (employee == null) { widget.formModel?.assistantEmployees = []; } else { selectedEmployee = employee; widget.formModel?.assistantEmployees = [employee.copyWith(id: 0)]; widget.formModel?.modelAssistantEmployees?.employeeId = employee.user?.id; } }, ), 8.height, Row( mainAxisSize: MainAxisSize.min, children: [ ADatePicker( label: context.translation.startTime, hideShadow: true, backgroundColor: AppColor.neutral100, date: widget.formModel?.modelAssistantEmployees?.startDate, formatDateWithTime: true, onDatePicker: (selectedDate) { showTimePicker( context: context, initialTime: TimeOfDay.now(), ).then((selectedTime) { // Handle the selected date and time here. if (selectedTime != null) { DateTime selectedDateTime = DateTime( selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute, ); widget.formModel?.modelAssistantEmployees?.startDate = selectedDateTime; ServiceRequestUtils.calculateAndAssignWorkingHours( startTime: widget.formModel?.modelAssistantEmployees?.startDate, endTime: widget.formModel?.modelAssistantEmployees?.endDate, workingHoursController: _workingHoursController, updateModel: (hours) { widget.formModel?.modelAssistantEmployees?.workingHours = hours; }); setState(() {}); } }); }, ).expanded, 8.width, ADatePicker( label: context.translation.endTime, hideShadow: true, backgroundColor: AppColor.neutral100, date: widget.formModel?.modelAssistantEmployees?.endDate, formatDateWithTime: true, onDatePicker: (selectedDate) { showTimePicker( context: context, initialTime: TimeOfDay.now(), ).then((selectedTime) { if (selectedTime != null) { DateTime selectedDateTime = DateTime( selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute, ); if (widget.formModel?.modelAssistantEmployees?.startDate != null && selectedDateTime.isBefore(widget.formModel!.modelAssistantEmployees!.startDate!)) { "End Date time must be greater then start date".showToast; return; } widget.formModel?.modelAssistantEmployees?.endDate = selectedDateTime; ServiceRequestUtils.calculateAndAssignWorkingHours( startTime: widget.formModel?.modelAssistantEmployees?.startDate, endTime: widget.formModel?.modelAssistantEmployees?.endDate, workingHoursController: _workingHoursController, updateModel: (hours) { widget.formModel?.modelAssistantEmployees?.workingHours = hours; }); setState(() {}); } }); }, ).expanded, ], ), 8.height, AppTextFormField( labelText: context.translation.workingHours, backgroundColor: AppColor.neutral80, controller: _workingHoursController, suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), initialValue: widget.formModel?.modelAssistantEmployees?.workingHours != null ? widget.formModel?.modelAssistantEmployees?.workingHours.toString() : '', textAlign: TextAlign.center, labelStyle: AppTextStyles.textFieldLabelStyle, enable: false, showShadow: false, style: Theme.of(context).textTheme.titleMedium, ), 8.height, AppTextFormField( initialValue: widget.formModel?.modelAssistantEmployees?.techComment, labelText: context.translation.technicalComment, backgroundColor: AppColor.neutral100, showShadow: false, labelStyle: AppTextStyles.textFieldLabelStyle, alignLabelWithHint: true, textInputType: TextInputType.multiline, onChange: (value) { widget.formModel?.modelAssistantEmployees?.techComment = value; }, onSaved: (value) { widget.formModel?.modelAssistantEmployees?.techComment = value; }, ), 16.height, ], ) : const SizedBox(), ], ); } }