From ccef98860fad1d2d455158dc8d462f537a3a4c1f Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Tue, 2 Sep 2025 16:40:10 +0300 Subject: [PATCH] recall and alert type request added --- lib/controllers/api_routes/urls.dart | 8 +- .../providers/api/all_requests_provider.dart | 2 +- .../task_request/task_request_model.dart | 33 +- .../tasks_wo/task_request_detail_view.dart | 3 +- .../tasks_wo/update_task_request_view.dart | 850 ++++++++++++------ .../common_widgets/app_bottom_nav_bar.dart | 3 +- .../create_request-type_bottomsheet.dart | 4 +- .../my_request/all_requests_filter_page.dart | 12 +- .../my_request/my_requests_page.dart | 8 +- .../widgets/request_item_view_list.dart | 2 + .../task_request_provider.dart | 4 + 11 files changed, 625 insertions(+), 304 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index f8226e55..fb68f4ef 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -3,14 +3,14 @@ class URLs { static const String appReleaseBuildNumber = "24"; - static const host1 = "https://atomsm.hmg.com"; // production url + // static const host1 = "https://atomsm.hmg.com"; // production url // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static String _baseUrl = "$_host/mobile"; // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis - // static final String _baseUrl = "$_host/mobile"; // host local UAT - static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM + static final String _baseUrl = "$_host/mobile"; // host local UAT + // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM static String _host = host1; diff --git a/lib/controllers/providers/api/all_requests_provider.dart b/lib/controllers/providers/api/all_requests_provider.dart index a2e3ec40..54fd7776 100644 --- a/lib/controllers/providers/api/all_requests_provider.dart +++ b/lib/controllers/providers/api/all_requests_provider.dart @@ -143,7 +143,7 @@ class AllRequestsProvider extends ChangeNotifier { } final type = typeTransaction == null ? search?.typeTransaction == null || (search?.typeTransaction?.isEmpty ?? false) - ? [1, 2, 3, 4, 5, 6] //added 6 to get task request ... + ? [1, 2, 3, 4, 5, 6,7] : search!.typeTransaction : [typeTransaction]; List status = (search?.statuses == null || (search?.statuses?.isEmpty ?? false)) ? (((search?.isArchived ?? false) ? [3] : [1, 2, 4])) : search!.statuses!; diff --git a/lib/models/new_models/task_request/task_request_model.dart b/lib/models/new_models/task_request/task_request_model.dart index f9950df1..08e03519 100644 --- a/lib/models/new_models/task_request/task_request_model.dart +++ b/lib/models/new_models/task_request/task_request_model.dart @@ -63,7 +63,7 @@ class TaskData { String? callComment; List? taskJobAttachments; TaskContactUser? assignedEngineer; - List? taskJobAssistantEmployees; + List? taskJobAssistantEmployees = []; TaskJobAssistantEmployees? modelAssistantEmployees; List? assistantEmployees; List? taskJobHistories; @@ -164,19 +164,6 @@ class TaskData { json['taskJobAssistantEmployees'].forEach((v) { taskJobAssistantEmployees!.add(TaskJobAssistantEmployees.fromJson(v)); }); - - if (taskJobAssistantEmployees != null && taskJobAssistantEmployees!.isNotEmpty) { - assistantEmployees = [ - AssistantEmployees.fromJson({ - 'id': null, - 'user': { - 'id': taskJobAssistantEmployees?[0].assistantEngineer?.userId, - 'name': taskJobAssistantEmployees?[0].assistantEngineer?.userName, - } - }) - ]; - } - modelAssistantEmployees = taskJobAssistantEmployees!.isNotEmpty ? taskJobAssistantEmployees!.first : TaskJobAssistantEmployees(); } if (json['taskJobActivityEngineerTimers'] != null) { taskJobActivityEngineerTimers = []; @@ -293,11 +280,12 @@ class TaskData { final Map data = {}; data['id'] = id; data['statusValue'] = statusValue; - if (assistantEmployees != null && assistantEmployees!.isNotEmpty) { - data['taskJobAssistantEmployees'] = [modelAssistantEmployees?.toJson()]; + if (taskJobAssistantEmployees != null && taskJobAssistantEmployees!.isNotEmpty) { + data['taskJobAssistantEmployees'] = taskJobAssistantEmployees; } else { data['taskJobAssistantEmployees'] = []; } + if (taskJobActivityEngineerTimers != null) { data['taskJobActivityEngineerTimers'] = taskJobActivityEngineerTimers!.map((v) => v.toJson()).toList(); } @@ -520,10 +508,12 @@ class TaskJobAssistantEmployees { String? comment; AssignedEmployee? user; AssistantEngineer? assistantEngineer; + AssistantEmployees? employee; TaskJobAssistantEmployees({this.startDate, this.endDate, this.workingHours, this.comment, this.assistantEnginerId, this.user, this.id, this.assistantEngineer}); TaskJobAssistantEmployees.fromJson(Map json) { + Map assistEmpData = {}; id = json['id']; startDate = json['startDate'] != null ? DateTime.parse(json['startDate']) : null; endDate = json['endDate'] != null ? DateTime.parse(json['endDate']) : null; @@ -532,8 +522,19 @@ class TaskJobAssistantEmployees { } else { workingHours = null; } + comment = json['comment']; user = json['assistantEnginer'] != null ? AssignedEmployee.fromJson(json['assistantEnginer']) : null; + if (json['assistantEnginer'] != null) { + assistEmpData = { + 'id': null, + 'user': { + 'id': user?.userId, + 'name': user?.userName, + }, + }; + } + employee = AssistantEmployees.fromJson(assistEmpData); assistantEngineer = json['assistantEnginer'] != null ? AssistantEngineer.fromJson(json['assistantEnginer']) : null; } diff --git a/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart b/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart index 003f275f..4443b111 100644 --- a/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart +++ b/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart @@ -61,6 +61,7 @@ class _TaskRequestDetailsViewState extends State { Widget build(BuildContext context) { userProvider ??= Provider.of(context, listen: false); return Scaffold( + // appBar: DefaultAppBar(title:taskProvider?.taskRequestModel?.taskType?.id==7?'Recall and Alert Details': context.translation.taskRequest), appBar: DefaultAppBar(title: context.translation.taskRequest), body: Consumer(builder: (context, taskProvider, child) { TaskData? taskModel = taskProvider.taskRequestModel; @@ -152,7 +153,7 @@ class _TaskRequestDetailsViewState extends State { if (taskProvider.taskRequestModel?.taskType?.isInstallation == true) { taskProvider.getSiteData(siteId: taskProvider.taskRequestModel?.asset?.siteId); } - Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdateTaskRequest(taskId: widget.taskId))); + Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdateTaskRequest(taskId: widget.taskId,createdDate: widget.requestDetails?.date,))); }, label: context.translation.updateRequest, ), diff --git a/lib/modules/tm_module/tasks_wo/update_task_request_view.dart b/lib/modules/tm_module/tasks_wo/update_task_request_view.dart index 4eae87dc..32a29dd3 100644 --- a/lib/modules/tm_module/tasks_wo/update_task_request_view.dart +++ b/lib/modules/tm_module/tasks_wo/update_task_request_view.dart @@ -12,6 +12,7 @@ import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/new_models/building.dart'; @@ -37,14 +38,14 @@ 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/status/report/service_report_assistant_employee_menu.dart'; import 'package:test_sa/views/widgets/timer/app_timer.dart'; - import '../../../../models/new_models/site.dart'; -import '../../../../models/new_models/work_order_detail_model.dart'; +import '../../../models/new_models/work_order_detail_model.dart'; class UpdateTaskRequest extends StatefulWidget { final int taskId; + final String? createdDate; - const UpdateTaskRequest({Key? key, required this.taskId}) : super(key: key); + const UpdateTaskRequest({Key? key, required this.taskId, this.createdDate}) : super(key: key); @override State createState() => _UpdateTaskRequestState(); @@ -58,8 +59,6 @@ class _UpdateTaskRequestState extends State { List attachments = []; bool installationType = true; String comments = ''; - List _userAttachments = []; - List _readOnlyAttachments = []; @override void initState() { @@ -71,19 +70,15 @@ class _UpdateTaskRequestState extends State { } Future assignData() async { + //may need to pass model in class parameters. _taskProvider = Provider.of(context, listen: false); UserProvider _userProvider = Provider.of(context, listen: false); - - TaskData? taskModel = _taskProvider!.taskRequestModel; - _userAttachments = _taskProvider?.taskRequestModel?.taskJobAttachments?.where((e) => e.createdBy == _userProvider.user?.userID).map((e) => File(e.name ?? '')).toList() ?? []; - _readOnlyAttachments = _taskProvider?.taskRequestModel?.taskJobAttachments?.where((e) => e.createdBy != _userProvider.user?.userID).toList() ?? []; - - _taskProvider?.updateTaskModel(taskModel); - if (taskModel != null) { - attachments.addAll(taskModel.taskJobAttachments!.map((e) => GenericAttachmentModel(id:e.id,name:e.name ?? '')).toList()); - // if (taskModel.taskType?.isInstallation == true) { - // await _taskProvider!.getSiteData(siteId: taskModel.asset?.siteId); - // } + TaskData? taskModel = _taskProvider?.taskRequestModel; + _taskProvider?.refresh(); + if (taskModel?.taskJobAttachments != null) { + attachments.addAll( + taskModel!.taskJobAttachments!.where((e) => e.createdBy == _userProvider.user?.userID).map((e) => GenericAttachmentModel(id: e.id, name: e.name ?? '')).toList(), + ); } } @@ -108,78 +103,90 @@ class _UpdateTaskRequestState extends State { ? const ALoading() : taskProvider.taskRequestModel != null ? Form( - key: _formKey, - child: Column( - children: [ - SingleChildScrollView( - padding: EdgeInsets.all(12 * AppStyle.getScaleFactor(context)), - child: Column( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _timerWidget(context, true, taskProvider), - 8.height, - if (taskProvider.taskRequestModel?.taskType?.isInstallation == true) ...[installationWidget(taskModel: taskProvider.taskRequestModel!)], - if (taskProvider.taskRequestModel?.taskType?.isRecallAndAlert == true) ...[ - recallAlertTypeWidget(taskModel: taskProvider.taskRequestModel!), - ], - // if (previousComments.isNotEmpty) ...[ - // 'Previous Comments'.bodyText2(context).custom(color: AppColor.neutral50), - // 8.height, - buildPreviousComments(taskProvider: taskProvider), - // 8.height, - // ], - AppTextFormField( - initialValue: "", - labelText: context.translation.technicalComment, - textInputType: TextInputType.multiline, - backgroundColor: AppColor.fieldBgColor(context), - labelStyle: TextStyle(color: AppColor.textColor(context)), - showShadow: false, - alignLabelWithHint: true, - onChange: (value) { - comments = value; - setState(() {}); - }, - onSaved: (value) {}, - ), - 20.height, - AttachmentPicker( - label: context.translation.attachFiles, - attachment: attachments, - buttonColor: AppColor.black10, - onlyImages: false, - buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120), - ), + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: EdgeInsets.all(12 * AppStyle.getScaleFactor(context)), + child: Column( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _timerWidget(context, true, taskProvider), + 8.height, + if (taskProvider.taskRequestModel?.taskType?.isInstallation == true) ...[installationWidget(taskModel: taskProvider.taskRequestModel!)], + if (taskProvider.taskRequestModel?.taskType?.isRecallAndAlert == true) ...[ + recallAlertTypeWidget(taskModel: taskProvider.taskRequestModel!), ], - ).toShadowContainer(context), - 16.height, - const AssistantEmployeeCard().toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16)), - ], - ), - ).expanded, - FooterActionButton.footerContainer( - context: context, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - AppFilledButton( - label: context.translation.save, - buttonColor: AppColor.white60, - textColor: AppColor.black10, - onPressed: () => _updateTask(context: context, status: 0), - ).expanded, - 12.width, - AppFilledButton( - label: context.translation.complete, - buttonColor: AppColor.primary10, - onPressed: () => _updateTask(context: context, status: 1), - ).expanded, - ], - ), + // if (previousComments.isNotEmpty) ...[ + // 'Previous Comments'.bodyText2(context).custom(color: AppColor.neutral50), + // 8.height, + buildPreviousComments(taskProvider: taskProvider), + // 8.height, + // ], + AppTextFormField( + initialValue: "", + labelText: context.translation.technicalComment, + textInputType: TextInputType.multiline, + backgroundColor: AppColor.fieldBgColor(context), + labelStyle: TextStyle(color: AppColor.textColor(context)), + showShadow: false, + alignLabelWithHint: true, + onChange: (value) { + comments = value; + setState(() {}); + }, + onSaved: (value) {}, + ), + 20.height, + AttachmentPicker( + label: context.translation.attachFiles, + attachment: attachments, + buttonColor: AppColor.black10, + onlyImages: false, + buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120), + ), + ], + ).toShadowContainer(context), + 16.height, + TaskRequestAssistantEmployeeList( + assetId: taskProvider.taskRequestModel?.asset?.id, + createdDate: widget.createdDate ?? '', + //widget.requestDetails?.date + assistantEmployeeList: taskProvider.taskRequestModel?.taskJobAssistantEmployees, + cardPadding: 0, + onListChanged: (updatedList) { + setState(() { + taskProvider.taskRequestModel?.taskJobAssistantEmployees = updatedList; + }); + }, + ), + // const AssistantEmployeeCard().toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16)), + ], ), - ], + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + AppFilledButton( + label: context.translation.save, + buttonColor: AppColor.white60, + textColor: AppColor.black10, + onPressed: () => _updateTask(context: context, status: 0), + ).expanded, + 12.width, + AppFilledButton( + label: context.translation.complete, + buttonColor: AppColor.primary10, + onPressed: () => _updateTask(context: context, status: 1), + ).expanded, + ], + ), + ), + ], ), ) : NoDataFound(message: context.translation.noDataFound).center, @@ -199,7 +206,7 @@ class _UpdateTaskRequestState extends State { showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); List attachment = []; for (var item in attachments) { - String fileName = ServiceRequestUtils.isLocalUrl(item.name??'') ? ("${item.name??''.split("/").last}|${base64Encode(File(item.name??'').readAsBytesSync())}") :item.name??''; + String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; attachment.add(TaskJobAttachment(id: item.id, name: fileName)); } taskModel?.taskJobAttachments = attachment; @@ -608,218 +615,509 @@ bool validate({TaskData? model}) { } } - if (model?.assistantEmployees != null) { - if (model?.modelAssistantEmployees?.startDate == null) { - Fluttertoast.showToast(msg: "Please Select Assistant Employee Start Time"); - return false; - } - if (model?.modelAssistantEmployees?.endDate == null) { - Fluttertoast.showToast(msg: "Please Select Assistant Employee End Time"); - return false; + if (model!.taskJobAssistantEmployees?.isNotEmpty ?? false) { + for (int i = 0; i < model.taskJobAssistantEmployees!.length; i++) { + final employee = model.taskJobAssistantEmployees![i]; + final position = Utils.getOrdinal(i + 1); + + if (employee.user == null) { + Fluttertoast.showToast( + msg: "Please select the $position assistant employee", + ); + return false; + } + + if (employee.user?.userId != null) { + if (employee.startDate == null) { + Fluttertoast.showToast( + msg: "Please select start time for assistant employee ${employee.user?.userName}", + ); + return false; + } + + if (employee.endDate == null) { + Fluttertoast.showToast( + msg: "Please select end time for assistant employee ${employee.user?.userName}", + ); + return false; + } + } } } return true; } -class AssistantEmployeeCard extends StatefulWidget { - const AssistantEmployeeCard({super.key}); +class TaskRequestAssistantEmployeeList extends StatefulWidget { + final List? assistantEmployeeList; + final ValueChanged>? onListChanged; + final double? cardPadding; + final dynamic assetId; + final String createdDate; + + const TaskRequestAssistantEmployeeList({ + super.key, + this.assistantEmployeeList, + this.onListChanged, + required this.assetId, + this.cardPadding, + required this.createdDate, + }); @override - State createState() => _AssistantEmployeeCardState(); + State createState() => _TaskRequestAssistantEmployeeListState(); } -class _AssistantEmployeeCardState extends State { - bool status = false; - final TextEditingController _workingHoursController = TextEditingController(text: ''); - bool isExpanded = false; - TaskData? taskModel; +class _TaskRequestAssistantEmployeeListState extends State { + late List _list; + late List _controllers; @override void initState() { - TaskRequestProvider taskRequestProvider = Provider.of(context, listen: false); - taskModel = taskRequestProvider.taskRequestModel; - super.initState(); + _list = List.from(widget.assistantEmployeeList ?? []); + _controllers = _list.map((e) => TextEditingController(text: e.workingHours?.toString() ?? '')).toList(); } - @override - void dispose() { - // TODO: implement dispose + void _addNewEntry() { + setState(() { + _list.add(TaskJobAssistantEmployees()); + _controllers.add(TextEditingController()); + }); + widget.onListChanged?.call(_list); + } - _workingHoursController.dispose(); - super.dispose(); + void _removeEntry(int index) { + setState(() { + _list.removeAt(index); + _controllers.removeAt(index); + }); + widget.onListChanged?.call(_list); + } + + void _updateModel(int index, void Function(TaskJobAssistantEmployees model) updateList, {bool updateController = false}) { + setState(() { + updateList(_list[index]); + }); } @override Widget build(BuildContext context) { - return Consumer(builder: (context, taskRequestProvider, child) { - return Column( - children: [ - SizedBox( - height: 56.toScreenHeight, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + return ListView.builder( + itemCount: _list.length + 1, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.all(widget.cardPadding ?? 16), + itemBuilder: (context, index) { + if (index == _list.length) { + return AppFilledButton( + label: "Add Assistant Employee".addTranslation, + maxWidth: true, + textColor: AppColor.textColor(context), + buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, + icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), + showIcon: true, + onPressed: _addNewEntry, + ); + } + return EmployeeCard( + model: _list[index], + assetId: widget.assetId, + index: index, + createdDate: widget.createdDate, + // selectedEmployee: selectedEmployee, + onUpdate: (updateList) => _updateModel(index, updateList), + onRemove: () => _removeEntry(index), + workingHoursController: _controllers[index], + ); + }, + ); + } +} + +class EmployeeCard extends StatelessWidget { + final TaskJobAssistantEmployees model; + final int index; + final dynamic assetId; + final String? createdDate; + final void Function(void Function(TaskJobAssistantEmployees model)) onUpdate; + final VoidCallback onRemove; + final TextEditingController workingHoursController; + + EmployeeCard({ + super.key, + required this.model, + required this.assetId, + required this.index, + required this.onUpdate, + this.createdDate, + required this.onRemove, + required this.workingHoursController, + }); + + // AssistantEmployees selectedEmployee = AssistantEmployees(); + @override + Widget build(BuildContext context) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + context.translation.assistantEmployee.bodyText(context).custom(color: AppColor.textColor(context)), + Container( + height: 32, + width: 32, + padding: const EdgeInsets.all(6), + child: "trash".toSvgAsset(height: 20, width: 20), + ).onPress(onRemove), + ], + ), + 8.height, + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ServiceReportAssistantEmployeeMenu( + title: context.translation.select, + backgroundColor: AppColor.fieldBgColor(context), + assetId: assetId, + initialValue: model.employee, + onSelect: (employee) { + if (employee != null) { + onUpdate((model) { + model.employee = employee.copyWith(id: 0); + model.user = AssignedEmployee( + userId: employee.user?.id, + userName: employee.user?.name, + ); + }); + } + }, + ), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, children: [ - context.translation.assistantEmployee.heading6(context).custom(color: AppColor.textColor(context)), - Icon(isExpanded ? Icons.keyboard_arrow_up_rounded : Icons.keyboard_arrow_down_rounded), + ADatePicker( + label: context.translation.startTime, + hideShadow: true, + backgroundColor: AppColor.fieldBgColor(context), + date: model.startDate, + formatDateWithTime: true, + from: DateTime.tryParse(createdDate ?? ''), + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + if (selectedTime != null) { + final selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + + if (createdDate != null && selectedDateTime.isBefore(DateTime.tryParse(createdDate ?? '')!)) { + "Start time is before the request time.".showToast; + return; + } + + if (selectedDateTime.isAfter(DateTime.now())) { + "Start time is after the current time".showToast; + return; + } + + onUpdate((model) { + model.startDate = selectedDateTime; + ServiceRequestUtils.calculateAndAssignWorkingHours( + startTime: model.startDate, + endTime: model.endDate, + workingHoursController: workingHoursController, + updateModel: (hours) => model.workingHours = hours, + ); + }); + } + }); + }, + ).expanded, + 8.width, + ADatePicker( + label: context.translation.endTime, + hideShadow: true, + backgroundColor: AppColor.fieldBgColor(context), + date: model.endDate, + formatDateWithTime: true, + from: DateTime.tryParse(createdDate ?? ''), + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + if (selectedTime != null) { + final endDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + + if (!endDateTime.isBefore(DateTime.now())) { + "Please select a time before the current time.".showToast; + return; + } + + if (model.startDate == null || !endDateTime.isAfter(model.startDate!)) { + "End date must be after start date".showToast; + return; + } + + onUpdate((model) { + model.endDate = endDateTime; + ServiceRequestUtils.calculateAndAssignWorkingHours( + startTime: model.startDate, + endTime: model.endDate, + workingHoursController: workingHoursController, + updateModel: (hours) => model.workingHours = hours, + ); + }); + } + }); + }, + ).expanded, ], ), - ).onPress(() { - setState(() { - isExpanded = !isExpanded; - }); - }), - isExpanded - ? Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - ServiceReportAssistantEmployeeMenu( - title: context.translation.select, - backgroundColor: AppColor.fieldBgColor(context), - initialValue: (taskModel?.assistantEmployees?.isNotEmpty ?? false) ? taskModel?.assistantEmployees?.first : null, - onSelect: (employee) { - if (employee == null) { - taskModel?.assistantEmployees = []; - } else { - taskModel?.assistantEmployees = [employee.copyWith(id: 0)]; - taskModel?.modelAssistantEmployees?.user = AssignedEmployee(userId: employee.user?.id, userName: employee.user?.name); - } - }, - ), - 8.height, - Row( - mainAxisSize: MainAxisSize.min, - children: [ - ADatePicker( - label: context.translation.startTime, - hideShadow: true, - backgroundColor: AppColor.fieldBgColor(context), - date: taskModel?.modelAssistantEmployees?.startDate, - // from: taskModel?.d, - 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); - // if (widget.pickerFromDate != null && selectedDateTime.isBefore(widget.pickerFromDate!)) { - // "Start time is before the request time.".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } - if (selectedDateTime.isAfter(DateTime.now())) { - "Start time is after than current time".showToast; - selectedTime = null; - return; - } - taskModel?.modelAssistantEmployees?.startDate = selectedDateTime; - taskRequestProvider.updateTaskModel(taskModel); - ServiceRequestUtils.calculateAndAssignWorkingHours( - startTime: taskModel?.modelAssistantEmployees?.startDate, - endTime: taskModel?.modelAssistantEmployees?.startDate, - workingHoursController: _workingHoursController, - updateModel: (hours) { - taskModel!.modelAssistantEmployees!.workingHours = hours; - }); - } - }); - }, - ).expanded, - 8.width, - ADatePicker( - label: context.translation.endTime, - hideShadow: true, - backgroundColor: AppColor.fieldBgColor(context), - date: taskModel?.modelAssistantEmployees?.endDate, - enable: taskModel?.modelAssistantEmployees?.startDate != null, - 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, - // ); - // - // if (taskModel?.modelAssistantEmployees?.startDate != null && selectedDateTime.isBefore(taskModel!.modelAssistantEmployees!.startDate!)) { - // "End Date time must be greater then start date".showToast; - // return; - // } - - selectedDate = selectedDate.add(Duration(hours: selectedTime.hour, minutes: selectedTime.minute)); - bool isBeforeCurrentTime = selectedDate.isBefore(DateTime.now()); - bool isAfterStartTime = selectedDate.isAfter(taskModel!.modelAssistantEmployees!.startDate!); - if (!isBeforeCurrentTime) { - "Please select a time before the current time.".showToast; - return; - } - if (!isAfterStartTime) { - "End Date time must be greater then start date".showToast; - return; - } - - taskModel?.modelAssistantEmployees?.endDate = selectedDate; - taskRequestProvider.updateTaskModel(taskModel); - ServiceRequestUtils.calculateAndAssignWorkingHours( - startTime: taskModel?.modelAssistantEmployees?.startDate, - endTime: taskModel?.modelAssistantEmployees?.endDate, - workingHoursController: _workingHoursController, - updateModel: (hours) { - taskModel!.modelAssistantEmployees!.workingHours = hours; - }); - } - }); - }, - ).expanded, - ], - ), - 8.height, - AppTextFormField( - labelText: context.translation.workingHours, - backgroundColor: AppColor.fieldBgColor(context), - controller: _workingHoursController, - suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), - initialValue: taskModel?.modelAssistantEmployees?.workingHours != null ? taskModel!.modelAssistantEmployees!.workingHours?.toStringAsFixed(2) : '', - textAlign: TextAlign.center, - labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), - enable: false, - showShadow: false, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - AppTextFormField( - initialValue: taskModel?.modelAssistantEmployees?.comment, - labelText: context.translation.comment, - backgroundColor: AppColor.fieldBgColor(context), - showShadow: false, - labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), - alignLabelWithHint: true, - textInputType: TextInputType.multiline, - onChange: (value) { - taskModel?.modelAssistantEmployees?.comment = value; - }, - onSaved: (value) { - taskModel?.modelAssistantEmployees?.comment = value; - }, - ), - 16.height, - ], - ) - : const SizedBox(), - ], - ); - }); + 8.height, + AppTextFormField( + labelText: context.translation.workingHours, + backgroundColor: AppColor.fieldBgColor(context), + controller: workingHoursController, + suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), + textAlign: TextAlign.center, + enable: false, + showShadow: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + initialValue: model.comment, + labelText: context.translation.technicalComment, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: context.isDark ? AppColor.white10 : AppColor.black10), + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + onChange: (value) => onUpdate((model) => model.comment = value), + // onSaved: (value) => onUpdate((model) => model.technicalComment = value), + ), + 8.height, + ], + ) + ], + ).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16, vertical: 12)).paddingOnly(bottom: 12); } } + +// class AssistantEmployeeCard extends StatefulWidget { +// const AssistantEmployeeCard({super.key}); +// +// @override +// State createState() => _AssistantEmployeeCardState(); +// } +// +// class _AssistantEmployeeCardState extends State { +// bool status = false; +// final TextEditingController _workingHoursController = TextEditingController(text: ''); +// bool isExpanded = false; +// TaskData? taskModel; +// +// @override +// void initState() { +// TaskRequestProvider taskRequestProvider = Provider.of(context, listen: false); +// taskModel = taskRequestProvider.taskRequestModel; +// +// super.initState(); +// } +// +// @override +// void dispose() { +// // TODO: implement dispose +// +// _workingHoursController.dispose(); +// super.dispose(); +// } +// +// @override +// Widget build(BuildContext context) { +// return Consumer(builder: (context, taskRequestProvider, child) { +// return Column( +// children: [ +// SizedBox( +// height: 56.toScreenHeight, +// child: Row( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// children: [ +// context.translation.assistantEmployee.heading6(context).custom(color: AppColor.textColor(context)), +// 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.fieldBgColor(context), +// initialValue: (taskModel?.assistantEmployees?.isNotEmpty ?? false) ? taskModel?.assistantEmployees?.first : null, +// onSelect: (employee) { +// if (employee == null) { +// taskModel?.assistantEmployees = []; +// } else { +// taskModel?.assistantEmployees = [employee.copyWith(id: 0)]; +// taskModel?.modelAssistantEmployees?.user = AssignedEmployee(userId: employee.user?.id, userName: employee.user?.name); +// } +// }, +// ), +// 8.height, +// Row( +// mainAxisSize: MainAxisSize.min, +// children: [ +// ADatePicker( +// label: context.translation.startTime, +// hideShadow: true, +// backgroundColor: AppColor.fieldBgColor(context), +// date: taskModel?.modelAssistantEmployees?.startDate, +// // from: taskModel?.d, +// 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); +// // if (widget.pickerFromDate != null && selectedDateTime.isBefore(widget.pickerFromDate!)) { +// // "Start time is before the request time.".showToast; +// // _pickerStartAt = null; +// // selectedTime = null; +// // return; +// // } +// if (selectedDateTime.isAfter(DateTime.now())) { +// "Start time is after than current time".showToast; +// selectedTime = null; +// return; +// } +// taskModel?.modelAssistantEmployees?.startDate = selectedDateTime; +// taskRequestProvider.updateTaskModel(taskModel); +// ServiceRequestUtils.calculateAndAssignWorkingHours( +// startTime: taskModel?.modelAssistantEmployees?.startDate, +// endTime: taskModel?.modelAssistantEmployees?.startDate, +// workingHoursController: _workingHoursController, +// updateModel: (hours) { +// taskModel!.modelAssistantEmployees!.workingHours = hours; +// }); +// } +// }); +// }, +// ).expanded, +// 8.width, +// ADatePicker( +// label: context.translation.endTime, +// hideShadow: true, +// backgroundColor: AppColor.fieldBgColor(context), +// date: taskModel?.modelAssistantEmployees?.endDate, +// enable: taskModel?.modelAssistantEmployees?.startDate != null, +// 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, +// // ); +// // +// // if (taskModel?.modelAssistantEmployees?.startDate != null && selectedDateTime.isBefore(taskModel!.modelAssistantEmployees!.startDate!)) { +// // "End Date time must be greater then start date".showToast; +// // return; +// // } +// +// selectedDate = selectedDate.add(Duration(hours: selectedTime.hour, minutes: selectedTime.minute)); +// bool isBeforeCurrentTime = selectedDate.isBefore(DateTime.now()); +// bool isAfterStartTime = selectedDate.isAfter(taskModel!.modelAssistantEmployees!.startDate!); +// if (!isBeforeCurrentTime) { +// "Please select a time before the current time.".showToast; +// return; +// } +// if (!isAfterStartTime) { +// "End Date time must be greater then start date".showToast; +// return; +// } +// +// taskModel?.modelAssistantEmployees?.endDate = selectedDate; +// taskRequestProvider.updateTaskModel(taskModel); +// ServiceRequestUtils.calculateAndAssignWorkingHours( +// startTime: taskModel?.modelAssistantEmployees?.startDate, +// endTime: taskModel?.modelAssistantEmployees?.endDate, +// workingHoursController: _workingHoursController, +// updateModel: (hours) { +// taskModel!.modelAssistantEmployees!.workingHours = hours; +// }); +// } +// }); +// }, +// ).expanded, +// ], +// ), +// 8.height, +// AppTextFormField( +// labelText: context.translation.workingHours, +// backgroundColor: AppColor.fieldBgColor(context), +// controller: _workingHoursController, +// suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), +// initialValue: taskModel?.modelAssistantEmployees?.workingHours != null ? taskModel!.modelAssistantEmployees!.workingHours?.toStringAsFixed(2) : '', +// textAlign: TextAlign.center, +// labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), +// enable: false, +// showShadow: false, +// style: Theme.of(context).textTheme.titleMedium, +// ), +// 8.height, +// AppTextFormField( +// initialValue: taskModel?.modelAssistantEmployees?.comment, +// labelText: context.translation.comment, +// backgroundColor: AppColor.fieldBgColor(context), +// showShadow: false, +// labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), +// alignLabelWithHint: true, +// textInputType: TextInputType.multiline, +// onChange: (value) { +// taskModel?.modelAssistantEmployees?.comment = value; +// }, +// onSaved: (value) { +// taskModel?.modelAssistantEmployees?.comment = value; +// }, +// ), +// 16.height, +// ], +// ) +// : const SizedBox(), +// ], +// ); +// }); +// } +// } diff --git a/lib/new_views/common_widgets/app_bottom_nav_bar.dart b/lib/new_views/common_widgets/app_bottom_nav_bar.dart index a965f45d..f1c47f6d 100644 --- a/lib/new_views/common_widgets/app_bottom_nav_bar.dart +++ b/lib/new_views/common_widgets/app_bottom_nav_bar.dart @@ -22,7 +22,8 @@ class AppBottomNavigationBar extends StatelessWidget { List navItems = [ NavItemModel(0, "overview", context.translation.overview), NavItemModel(1, "request_icon", context.translation.workOrder), - if (!isEngineer||isUserFMS) + //TODO unCommit this to disable task + // if (!isEngineer||isUserFMS) NavItemModel(2, "add_icon", context.translation.calendar, showLabel: false), NavItemModel(3, "assets", context.translation.assets), NavItemModel(4, "contact", context.translation.contact), diff --git a/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart b/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart index 671d91fc..bc597a88 100644 --- a/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart +++ b/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart @@ -92,13 +92,13 @@ class CreateRequestModel { list.add(CreateRequestModel(context.translation.correctiveMaintenance, "add_icon", CreateNewRequest.id)); } //TODO uncommit this to enable task. - // list.add(CreateRequestModel(context.translation.task, "add_icon", CreateTaskView.id)); + list.add(CreateRequestModel(context.translation.task, "add_icon", CreateTaskView.id)); } else { list.add(CreateRequestModel(context.translation.correctiveMaintenance, "add_icon", CreateNewRequest.id)); list.add(CreateRequestModel(context.translation.gasRefill, "add_icon", GasRefillRequestForm.routeName)); list.add(CreateRequestModel(context.translation.transferAsset, "add_icon", CreateDeviceTransferRequest.id)); //TODO uncommit this to enable task. - // list.add(CreateRequestModel(context.translation.task, "add_icon", CreateTaskView.id)); + list.add(CreateRequestModel(context.translation.task, "add_icon", CreateTaskView.id)); } return list; } diff --git a/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart b/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart index 550bb942..f6368d0b 100644 --- a/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart +++ b/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/controllers/providers/settings/setting_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'; @@ -47,6 +48,7 @@ class _AllRequestsFilterPageState extends State { @override Widget build(BuildContext context) { bool isEngineer = (Provider.of(context, listen: false).user?.type) == UsersTypes.engineer; + bool isUserFMS = Provider.of(context, listen: false).isUserFMS; if (search == null) { search = SearchAllRequestsModel( requestNumber: SearchByRequestNumberModel(context, controller: TextEditingController()), @@ -64,10 +66,16 @@ class _AllRequestsFilterPageState extends State { context.translation.transferAsset: 3, context.translation.preventiveMaintenance: 4, //TODO unCommit this to enable task. - // context.translation.task: 6, + context.translation.task: 6, }; + if (isEngineer) { - types.addAll({context.translation.recurrentWo: 5}); + types[context.translation.recurrentWo] = 5; + } + + if (!isUserFMS) { + // replace with translation + types['Recall and Alert'] = 7; } final statuses = { "All WO": 0, diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index 5f1b9d1e..3e216d8a 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/controllers/providers/settings/setting_provider.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'; @@ -33,6 +34,7 @@ class _MyRequestsPageState extends State { @override Widget build(BuildContext context) { if (_provider == null) { + bool isUserFMS = Provider.of(context, listen: false).isUserFMS; requestsList = [ Request(null, context.translation.allWorkOrder), Request(1, context.translation.correctiveMaintenance), @@ -44,7 +46,11 @@ class _MyRequestsPageState extends State { requestsList.add(Request(5, context.translation.recurrentWo)); } //TODO unCommit this to enable task - // requestsList.add(Request(6, context.translation.taskRequest)); + requestsList.add(Request(6, context.translation.taskRequest)); + //after confirm name add this to translation... + if (!isUserFMS) { + requestsList.add(Request(7, 'Recall and Alert')); + } _provider = Provider.of(context, listen: false); _provider!.reset(); diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart index 980a00eb..a3548947 100644 --- a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart +++ b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart @@ -40,6 +40,8 @@ class RequestItemViewList extends StatelessWidget { return RecurrentWoItemView(requestDetails: list[index]); case 6: return TaskRequestItemView(requestDetails: list[index]); + case 7: + return TaskRequestItemView(requestDetails: list[index]); default: Container( height: 100, diff --git a/lib/providers/task_request_provider/task_request_provider.dart b/lib/providers/task_request_provider/task_request_provider.dart index 590c1bc5..71ca98bc 100644 --- a/lib/providers/task_request_provider/task_request_provider.dart +++ b/lib/providers/task_request_provider/task_request_provider.dart @@ -43,6 +43,10 @@ class TaskRequestProvider extends ChangeNotifier { notifyListeners(); } + + void refresh() { + notifyListeners(); + } Future addTask({ required BuildContext context, required AddTaskModel task,