From 0f4a409780ada6c346fac6fd2242aa29971a84cf Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Sun, 1 Feb 2026 17:58:08 +0300 Subject: [PATCH 1/7] assign to me added ion gas refill and tasks --- lib/controllers/api_routes/urls.dart | 5 ++ .../providers/api/gas_refill_provider.dart | 33 +++++++- .../gas_refill/gas_refill_details.dart | 55 ++++++++++-- .../tasks/task_request_detail_view.dart | 55 +++++++++--- .../tasks/update_task_request_view.dart | 2 +- .../task_request_provider.dart | 30 +++++++ lib/views/pages/user/profile_page.dart | 3 +- .../rejection_reason_bottom_sheet.dart | 84 +++++++++++++++++++ lib/views/widgets/loaders/app_loading.dart | 6 +- 9 files changed, 251 insertions(+), 22 deletions(-) create mode 100644 lib/views/widgets/bottom_sheets/rejection_reason_bottom_sheet.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 6fe56728..e09e42a1 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -172,6 +172,9 @@ class URLs { static get updateTaskByEngineerUrl => '$_baseUrl/TaskJobs/UpdateByEngineer'; + static get taskJobsAssignEngineerToHimself => "$_baseUrl/TaskJobs/AssignEngineerToHimself"; // get + static get taskJobsEngineerReject => "$_baseUrl/TaskJobs/EngineerReject"; // get + // Task LookUps static get taskJobTypeOfAlert => "$_baseUrl/Lookups/GetLookup?lookupEnum=1260"; @@ -293,6 +296,8 @@ class URLs { static get getGasRefill => "$_baseUrl/GazRefill/GetGazRefills"; // get // static get getGasRefillById => "$_baseUrl/GazRefill/GetGazRefillById"; // get older endpoint.. static get getGasRefillById => "$_baseUrl/GasRefill/GetGasRefillById"; // get + static get gasRefillAssignEngineerToHimself => "$_baseUrl/GasRefill/AssignEngineerToHimself"; // get + static get gasRefillEngineerReject => "$_baseUrl/GasRefill/EngineerReject"; // get static get getGazRefillComments => "$_baseUrl/GazRefill/GetHistoryComments"; // get static get addGazRefillComment => "$_baseUrl/GazRefill/AddHistoryComment"; // add static get updateGasRefillByEngineer => "$_baseUrl/GasRefill/UpdateGasRefillByEngineer"; // update diff --git a/lib/controllers/providers/api/gas_refill_provider.dart b/lib/controllers/providers/api/gas_refill_provider.dart index e1c0525b..3762eb38 100644 --- a/lib/controllers/providers/api/gas_refill_provider.dart +++ b/lib/controllers/providers/api/gas_refill_provider.dart @@ -48,7 +48,10 @@ class GasRefillProvider extends ChangeNotifier { GasRefillModel? gasRefillModel; - Future getGasRefillObjectById(num id) async { + Future getGasRefillObjectById(num id, {bool refresh = false}) async { + if (refresh) { + return gasRefillModel; + } try { gasRefillModel = null; Response response = await ApiManager.instance.get(URLs.getGasRefillById + "?gasRefillId=$id"); @@ -64,6 +67,34 @@ class GasRefillProvider extends ChangeNotifier { } } + Future assignEngineerToHimself(num id) async { + try { + Response response = await ApiManager.instance.post(URLs.gasRefillAssignEngineerToHimself, body: {"gasRefillId": id}); + if (response.statusCode >= 200 && response.statusCode < 300) { + gasRefillModel = GasRefillModel.fromJson(json.decode(response.body)["data"]); + return gasRefillModel; + } else { + return null; + } + } catch (error) { + return null; + } + } + + Future engineerReject(Map body) async { + try { + Response response = await ApiManager.instance.post(URLs.gasRefillEngineerReject, body: body); + if (response.statusCode >= 200 && response.statusCode < 300) { + gasRefillModel = GasRefillModel.fromJson(json.decode(response.body)["data"]); + return gasRefillModel; + } else { + return null; + } + } catch (error) { + return null; + } + } + /// return -2 if request in progress /// return -1 if error happen when sending request /// return state code if request complete may be 200, 404 or 403 diff --git a/lib/modules/tm_module/gas_refill/gas_refill_details.dart b/lib/modules/tm_module/gas_refill/gas_refill_details.dart index c785a6a1..0b2a7090 100644 --- a/lib/modules/tm_module/gas_refill/gas_refill_details.dart +++ b/lib/modules/tm_module/gas_refill/gas_refill_details.dart @@ -10,9 +10,11 @@ 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/helper/utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/cx_module/chat/chat_widget.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/views/widgets/bottom_sheets/rejection_reason_bottom_sheet.dart'; import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; @@ -43,6 +45,7 @@ class _GasRefillDetailsPageState extends State { final GlobalKey _scaffoldKey = GlobalKey(); List _attachments = []; + bool isDataUpdated = false; @override void initState() { @@ -80,14 +83,14 @@ class _GasRefillDetailsPageState extends State { ), key: _scaffoldKey, body: FutureBuilder( - future: gasRefillProvider.getGasRefillObjectById(widget.model.id!), + future: gasRefillProvider.getGasRefillObjectById(widget.model.id!, refresh: isDataUpdated), builder: (context, snap) { if (snap.connectionState == ConnectionState.waiting) { return const ALoading(); } else if (snap.hasData) { _model = snap.data as GasRefillModel; _attachments = _model.gasRefillAttachments?.map((e) => File(e.attachmentName ?? '')).toList() ?? []; - + isDataUpdated = false; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -95,15 +98,55 @@ class _GasRefillDetailsPageState extends State { padding: const EdgeInsets.all(16), child: informationCard(_model), ).expanded, - if (_userProvider.user!.type == UsersTypes.engineer && (_model.status!.value! != 2)) ...[ + if (context.settingProvider.isUserFlowMedical && _userProvider.user!.type == UsersTypes.engineer && (_model.status!.value! == 0)) FooterActionButton.footerContainer( context: context, child: AppFilledButton( onPressed: () async { - await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdateGasRefillRequest(gasRefillModel: _model))); - // getVisitData(); + Utils.showLoading(context); + await gasRefillProvider.assignEngineerToHimself(_model.id!.toInt()); + isDataUpdated = true; + Utils.hideLoading(context); + setState(() {}); }, - label: context.translation.updateRequest, + label: 'Assign To Me', + ), + ) + else if (_userProvider.user!.type == UsersTypes.engineer && (_model.status!.value! == 1)) ...[ + FooterActionButton.footerContainer( + context: context, + child: Row( + children: [ + AppFilledButton( + label: context.translation.cancel, + buttonColor: AppColor.white60, + textColor: AppColor.black10, + loading: false, + onPressed: () async { + context.showBottomSheet( + RejectionReasonBottomSheet( + onRejectPressed: (int reasonId, String comment) async { + await Future.delayed(const Duration(milliseconds: 500)); + var data = await gasRefillProvider.engineerReject({"gasRefillId": _model.id!.toInt(), "rejectReasonId": reasonId, "rejectComment": comment}); + isDataUpdated = data != null; + return isDataUpdated; + }, + onRefreshed: () { + setState(() {}); + }, + ), + title: "Rejection Reason".addTranslation); + }, + ).expanded, + 16.width, + AppFilledButton( + onPressed: () async { + await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdateGasRefillRequest(gasRefillModel: _model))); + // getVisitData(); + }, + label: context.translation.updateRequest, + ).expanded, + ], ), ) ] diff --git a/lib/modules/tm_module/tasks/task_request_detail_view.dart b/lib/modules/tm_module/tasks/task_request_detail_view.dart index 1a60c0b9..c135ea8d 100644 --- a/lib/modules/tm_module/tasks/task_request_detail_view.dart +++ b/lib/modules/tm_module/tasks/task_request_detail_view.dart @@ -7,6 +7,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/all_requests_and_count_model.dart'; import 'package:test_sa/models/new_models/task_request/task_request_model.dart'; import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; @@ -15,6 +16,7 @@ import 'package:test_sa/modules/cx_module/chat/chat_widget.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/working_time_tile.dart'; import 'package:test_sa/providers/task_request_provider/task_request_provider.dart'; +import 'package:test_sa/views/widgets/bottom_sheets/rejection_reason_bottom_sheet.dart'; import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart'; @@ -175,21 +177,54 @@ class _TaskRequestDetailsViewState extends State { ], ).toShadowContainer(context).paddingAll(16), ).expanded, - if (userProvider!.user!.type == UsersTypes.engineer && (taskModel?.taskJobStatus?.value != 4 && taskModel?.taskJobStatus?.value != 3)) + if (context.settingProvider.isUserFlowMedical && userProvider!.user!.type == UsersTypes.engineer && (taskModel?.taskJobStatus?.value == 0)) FooterActionButton.footerContainer( context: context, child: AppFilledButton( onPressed: () async { - if (taskProvider.taskRequestModel?.taskType?.isInstallation == true) { - taskProvider.getSiteData(siteId: taskProvider.taskRequestModel?.asset?.siteId); - } - Navigator.of(context).push(MaterialPageRoute( - builder: (_) => UpdateTaskRequest( - taskId: widget.taskId, - createdDate: widget.requestDetails?.date, - ))); + Utils.showLoading(context); + await taskProvider.assignEngineerToHimself(widget.taskId); + Utils.hideLoading(context); }, - label: context.translation.updateRequest, + label: 'Assign To Me', + ), + ) + else if (userProvider!.user!.type == UsersTypes.engineer && taskModel?.taskJobStatus?.value == 5) + ...[] + else if (userProvider!.user!.type == UsersTypes.engineer && (taskModel?.taskJobStatus?.value != 4 && taskModel?.taskJobStatus?.value != 3)) + FooterActionButton.footerContainer( + context: context, + child: Row( + children: [ + AppFilledButton( + label: context.translation.cancel, + buttonColor: AppColor.white60, + textColor: AppColor.black10, + loading: false, + onPressed: () async { + context.showBottomSheet(RejectionReasonBottomSheet( + onRejectPressed: (int reasonId, String comment) async { + await Future.delayed(const Duration(milliseconds: 500)); + return await taskProvider.engineerReject({"taskJobId": widget.taskId, "rejectReasonId": reasonId, "rejectComment": comment}); + }, + ), title: "Rejection Reason".addTranslation); + }, + ).expanded, + 16.width, + AppFilledButton( + onPressed: () async { + if (taskProvider.taskRequestModel?.taskType?.isInstallation == true) { + taskProvider.getSiteData(siteId: taskProvider.taskRequestModel?.asset?.siteId); + } + Navigator.of(context).push(MaterialPageRoute( + builder: (_) => UpdateTaskRequest( + taskId: widget.taskId, + createdDate: widget.requestDetails?.date, + ))); + }, + label: context.translation.updateRequest, + ).expanded, + ], ), ) ]); diff --git a/lib/modules/tm_module/tasks/update_task_request_view.dart b/lib/modules/tm_module/tasks/update_task_request_view.dart index 20b6148e..a0b0028e 100644 --- a/lib/modules/tm_module/tasks/update_task_request_view.dart +++ b/lib/modules/tm_module/tasks/update_task_request_view.dart @@ -271,7 +271,7 @@ class _UpdateTaskRequestState extends State { taskModel?.timerModelList?.forEach((timer) { int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds; taskModel.taskJobActivityEngineerTimers?.add( - TaskJobActivityEngineerTimer ( + TaskJobActivityEngineerTimer( id: 0, startDate: timer.startAt!.toIso8601String(), endDate: timer.endAt?.toIso8601String(), totalWorkingHour: ((durationInSecond) / 60 / 60), comment: timer.comments ?? comments), ); }); diff --git a/lib/providers/task_request_provider/task_request_provider.dart b/lib/providers/task_request_provider/task_request_provider.dart index 1a517d73..8e733e69 100644 --- a/lib/providers/task_request_provider/task_request_provider.dart +++ b/lib/providers/task_request_provider/task_request_provider.dart @@ -149,4 +149,34 @@ class TaskRequestProvider extends ChangeNotifier { } notifyListeners(); } + + Future assignEngineerToHimself(num id) async { + try { + Response response = await ApiManager.instance.post(URLs.taskJobsAssignEngineerToHimself, body: {"gasRefillId": id}); + if (response.statusCode >= 200 && response.statusCode < 300) { + taskRequestModel = TaskData.fromJson(json.decode(response.body)["data"]); + notifyListeners(); + return taskRequestModel; + } else { + return null; + } + } catch (error) { + return null; + } + } + + Future engineerReject(Map body) async { + try { + Response response = await ApiManager.instance.post(URLs.taskJobsEngineerReject, body: body); + if (response.statusCode >= 200 && response.statusCode < 300) { + taskRequestModel = TaskData.fromJson(json.decode(response.body)["data"]); + notifyListeners(); + return true; + } else { + return false; + } + } catch (error) { + return false; + } + } } diff --git a/lib/views/pages/user/profile_page.dart b/lib/views/pages/user/profile_page.dart index cab6b76d..b58a9002 100644 --- a/lib/views/pages/user/profile_page.dart +++ b/lib/views/pages/user/profile_page.dart @@ -165,8 +165,9 @@ class _ProfilePageState extends State { physics: const NeverScrollableScrollPhysics(), itemCount: _user.departmentName?.length ?? 0, shrinkWrap: true, + padding: EdgeInsets.zero, itemBuilder: (context, index) { - return (_user.departmentName![index] ?? "N/A").heading5(context).paddingOnly(top: 8, bottom: 8); + return (_user.departmentName![index] ?? "N/A").bodyText(context).paddingOnly(top: 4, bottom: 4); }, ), if ((_user.clientName ?? "").isNotEmpty) ...[ diff --git a/lib/views/widgets/bottom_sheets/rejection_reason_bottom_sheet.dart b/lib/views/widgets/bottom_sheets/rejection_reason_bottom_sheet.dart new file mode 100644 index 00000000..0e3c0f5e --- /dev/null +++ b/lib/views/widgets/bottom_sheets/rejection_reason_bottom_sheet.dart @@ -0,0 +1,84 @@ +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/helper/utils.dart'; +import 'package:test_sa/models/lookup.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_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/service_request_providers/reject_reason_provider.dart'; + +class RejectionReasonBottomSheet extends StatelessWidget { + final Future Function(int reasonId, String comment) onRejectPressed; + final VoidCallback? onRefreshed; + + RejectionReasonBottomSheet({Key? key, this.onRefreshed, required this.onRejectPressed}) : super(key: key); + + @override + Widget build(BuildContext context) { + TextEditingController _commentController = TextEditingController(); + final GlobalKey _formKey = GlobalKey(); + + Lookup? selectedReason; + + return Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + SingleItemDropDownMenu( + context: context, + title: context.translation.reason, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + showAsBottomSheet: true, + validator: (value) { + if (value == null) return "Mandatory"; + return null; + }, + onSelect: (value) { + selectedReason = value; + }, + ), + 12.height, + AppTextFormField( + backgroundColor: AppColor.fieldBgColor(context), + labelText: context.translation.comments, + controller: _commentController, + textInputType: TextInputType.multiline, + alignLabelWithHint: true, + showSpeechToText: true, + showShadow: false, + style: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)), + labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff767676)), + floatingLabelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)), + validator: (value) { + if ((value ?? "").isEmpty) return "Mandatory"; + return null; + }, + ), + 16.height, + AppFilledButton( + label: context.translation.reject, + buttonColor: AppColor.red30, + onPressed: () async { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + Utils.showLoading(context); + bool isSuccess = await onRejectPressed(selectedReason!.id!, _commentController.text); + Utils.hideLoading(context); + if (isSuccess) { + Navigator.of(context).pop(); + onRefreshed?.call(); + } + } + }, + ), + 16.height, + ], + ), + ); + } +} diff --git a/lib/views/widgets/loaders/app_loading.dart b/lib/views/widgets/loaders/app_loading.dart index 9b427a7d..2aff9421 100644 --- a/lib/views/widgets/loaders/app_loading.dart +++ b/lib/views/widgets/loaders/app_loading.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; class ALoading extends StatelessWidget { const ALoading({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - return const Center( - child: CircularProgressIndicator(), - ); + return const CircularProgressIndicator(color: AppColor.primary10).center; } } From 8db40947168036fa4bd86272fc14423538b16ef4 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 3 Feb 2026 12:30:30 +0300 Subject: [PATCH 2/7] assign to me & cancel added for asset transfer. --- lib/controllers/api_routes/urls.dart | 2 + .../api/device_transfer_provider.dart | 47 ++++++++++ .../device_transfer_details.dart | 91 ++++++++++++++++++- 3 files changed, 138 insertions(+), 2 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index e09e42a1..c07b1f03 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -313,6 +313,8 @@ class URLs { static get getAssetTransferById => "$_baseUrl/AssetTransfer/GetAssetTransferNewById"; // get static get createAssetTransferRequest => "$_baseUrl/AssetTransfer/AddAssetTransferMobileNew"; // post static get updateDeviceTransfer => "$_baseUrl/AssetTransfer/UpdateEngineerAssetTransferNew"; // get + static get assetTransferAssignEngineerToHimself => "$_baseUrl/AssetTransfer/AssignEngineerToHimself"; // get + static get assetTransferEngineerReject => "$_baseUrl/AssetTransfer/EngineerReject"; // get // employee static get getEmployees => "$_baseUrl/Lookups/GetLookup?lookupEnum=33"; // get diff --git a/lib/controllers/providers/api/device_transfer_provider.dart b/lib/controllers/providers/api/device_transfer_provider.dart index b3191c18..63468cc5 100644 --- a/lib/controllers/providers/api/device_transfer_provider.dart +++ b/lib/controllers/providers/api/device_transfer_provider.dart @@ -222,4 +222,51 @@ class DeviceTransferProvider extends ChangeNotifier { return -1; } } + + Future assignEngineerToHimselfInternal(num id, String empId) async { + try { + Map body = {"assetTransferId": id, "senderAssignEmployeeId": empId, "receiverAssignEmployeeId": empId}; + Response response = await ApiManager.instance.post(URLs.assetTransferAssignEngineerToHimself, body: body); + if (response.statusCode >= 200 && response.statusCode < 300) { + return DeviceTransfer.fromJson(json.decode(response.body)["data"]); + } else { + return null; + } + } catch (error) { + return null; + } + } + + Future assignEngineerToHimselfExternal(num id, bool isSender, String empId) async { + try { + Map body = {"assetTransferId": id}; + if (isSender) { + body["senderAssignEmployeeId"] = empId; + } else { + body["receiverAssignEmployeeId"] = empId; + } + Response response = await ApiManager.instance.post(URLs.assetTransferAssignEngineerToHimself, body: body); + if (response.statusCode >= 200 && response.statusCode < 300) { + return DeviceTransfer.fromJson(json.decode(response.body)["data"]); + } else { + return null; + } + } catch (error) { + return null; + } + } + + Future engineerReject(Map body) async { + try { + Response response = await ApiManager.instance.post(URLs.assetTransferEngineerReject, body: body); + if (response.statusCode >= 200 && response.statusCode < 300) { + // gasRefillModel = DeviceTransfer.fromJson(json.decode(response.body)["data"]); + return DeviceTransfer.fromJson(json.decode(response.body)["data"]); + } else { + return null; + } + } catch (error) { + return null; + } + } } diff --git a/lib/modules/tm_module/device_transfer/device_transfer_details.dart b/lib/modules/tm_module/device_transfer/device_transfer_details.dart index 6e843398..a19456c0 100644 --- a/lib/modules/tm_module/device_transfer/device_transfer_details.dart +++ b/lib/modules/tm_module/device_transfer/device_transfer_details.dart @@ -8,8 +8,11 @@ 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/helper/utils.dart'; import 'package:test_sa/models/device/device_transfer.dart'; import 'package:test_sa/modules/cx_module/chat/chat_widget.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/views/widgets/bottom_sheets/rejection_reason_bottom_sheet.dart'; import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; @@ -191,7 +194,15 @@ class _DeviceTransferDetailsState extends State { _internalRequestDetailsCard() { bool isCurrentEngineerEligibleForEdit = _model?.senderAssignedEmployeeId == _userProvider!.user?.userID; - bool isCurrentRequestEditAble = (!(_model?.senderMachineStatusValue == 3)); + bool isCurrentRequestEditAble = (!(_model?.senderMachineStatusValue == 5)); + bool isCurrentRequestInProgress = (_model?.senderMachineStatusValue == 1); + + // bool isCurrentRequestClosed = isSender ? ((_model?.senderMachineStatusValue == 3)) : ((_model?.receiverMachineStatusValue == 3)); + bool isCurrentRequestOpen = _model?.senderMachineStatusValue == 4; + + bool engineerCanAssignToHimself = (_userProvider!.user?.type == UsersTypes.engineer) && isCurrentRequestOpen && context.settingProvider.isUserFlowMedical; + bool engineerCanCancel = (_userProvider!.user?.type == UsersTypes.engineer) && isCurrentRequestInProgress && isCurrentEngineerEligibleForEdit && context.settingProvider.isUserFlowMedical; + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -257,6 +268,42 @@ class _DeviceTransferDetailsState extends State { style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ), _buildTextWidget(_model?.senderComment ?? ''), + ], + + if (engineerCanAssignToHimself) ...[ + 16.height, + AppFilledButton( + onPressed: () async { + Utils.showLoading(context); + await Provider.of(context, listen: false).assignEngineerToHimselfInternal(_model!.id!.toInt(), context.userProvider.user!.userID!); + Utils.hideLoading(context); + setState(() {}); + }, + label: 'Assign To Me', + ), + ] else if (engineerCanCancel) ...[ + 16.height, + AppFilledButton( + label: context.translation.cancel, + buttonColor: AppColor.white60, + textColor: AppColor.black10, + loading: false, + onPressed: () async { + context.showBottomSheet( + RejectionReasonBottomSheet( + onRejectPressed: (int reasonId, String comment) async { + await Future.delayed(const Duration(milliseconds: 500)); + var data = await Provider.of(context, listen: false) + .engineerReject({"assetTransferId": _model!.id!.toInt(), "rejectReasonId": reasonId, "rejectComment": comment}); + return data != null; + }, + onRefreshed: () { + setState(() {}); + }, + ), + title: "Rejection Reason".addTranslation); + }, + ) ] ], ).toShadowContainer(context); @@ -267,6 +314,11 @@ class _DeviceTransferDetailsState extends State { bool isCurrentEngineerEligibleForEdit = isSender ? _model?.senderAssignedEmployeeId == _userProvider!.user?.userID : _model?.receiverAssignedEmployeeId == _userProvider!.user?.userID; bool isCurrentRequestClosed = isSender ? ((_model?.senderMachineStatusValue == 3)) : ((_model?.receiverMachineStatusValue == 3)); + bool isCurrentRequestOpen = isSender ? ((_model?.senderMachineStatusValue == 4)) : ((_model?.receiverMachineStatusValue == 4)); + + bool engineerCanAssignToHimself = (_userProvider!.user?.type == UsersTypes.engineer) && isCurrentRequestOpen && context.settingProvider.isUserFlowMedical; + bool engineerCanCancel = (_userProvider!.user?.type == UsersTypes.engineer) && isCurrentEngineerEligibleForEdit && context.settingProvider.isUserFlowMedical; + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -287,7 +339,7 @@ class _DeviceTransferDetailsState extends State { isShow: context.settingProvider.isUserFlowMedical && (isSender ? _deviceTransfer.senderMachineStatusValue! : _deviceTransfer.receiverMachineStatusValue!) != 0, isReadOnly: (isSender ? _deviceTransfer.senderMachineStatusValue! : _deviceTransfer.receiverMachineStatusValue) != 1, requestId: widget.model.id!.toInt(), - assigneeEmployeeNumber: isSender ? _deviceTransfer.senderAssignedEmployeeNumber! : _deviceTransfer.receiverAssignedEmployeeNumber!, + assigneeEmployeeNumber: isSender ? _deviceTransfer.senderAssignedEmployeeNumber : _deviceTransfer.receiverAssignedEmployeeNumber, myLoginUserID: context.userProvider.user!.employeeId ?? context.userProvider.user!.username!, contactEmployeeINumber: _deviceTransfer.assetTransferContactPersons!.first.employeeNumber, ), @@ -319,6 +371,41 @@ class _DeviceTransferDetailsState extends State { style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ), _buildTextWidget(comment), + ], + if (engineerCanAssignToHimself) ...[ + 16.height, + AppFilledButton( + onPressed: () async { + Utils.showLoading(context); + await Provider.of(context, listen: false).assignEngineerToHimselfExternal(_model!.id!.toInt(), isSender, context.userProvider.user!.userID!); + Utils.hideLoading(context); + setState(() {}); + }, + label: 'Assign To Me', + ), + ] else if (engineerCanCancel) ...[ + 16.height, + AppFilledButton( + label: context.translation.cancel, + buttonColor: AppColor.white60, + textColor: AppColor.black10, + loading: false, + onPressed: () async { + context.showBottomSheet( + RejectionReasonBottomSheet( + onRejectPressed: (int reasonId, String comment) async { + await Future.delayed(const Duration(milliseconds: 500)); + var data = await Provider.of(context, listen: false) + .engineerReject({"assetTransferId": _model!.id!.toInt(), "rejectReasonId": reasonId, "rejectComment": comment}); + return data != null; + }, + onRefreshed: () { + setState(() {}); + }, + ), + title: "Rejection Reason".addTranslation); + }, + ) ] ], ).toShadowContainer(context); From 4cf45f996d0795fccf164f95eb1c23f8ae9acd5e Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 3 Feb 2026 14:33:19 +0300 Subject: [PATCH 3/7] unassigned api payload changed. --- lib/dashboard_latest/dashboard_provider.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/dashboard_latest/dashboard_provider.dart b/lib/dashboard_latest/dashboard_provider.dart index cc39807f..03ca5104 100644 --- a/lib/dashboard_latest/dashboard_provider.dart +++ b/lib/dashboard_latest/dashboard_provider.dart @@ -303,6 +303,7 @@ class DashBoardProvider extends ChangeNotifier { if (status != null && status == 0) { body["date"] = date ?? upcomingFilterSelectedDate.toIso8601String(); + } else if (status == 1 && tabId == 1) { } else { body["statusValue"] = status; } From 5855b347e921e1bfc73bb8301ee38ef855e9f11a Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 3 Feb 2026 16:29:57 +0300 Subject: [PATCH 4/7] improvements --- lib/modules/tm_module/tasks/task_request_detail_view.dart | 8 ++++---- .../task_request_provider/task_request_provider.dart | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/modules/tm_module/tasks/task_request_detail_view.dart b/lib/modules/tm_module/tasks/task_request_detail_view.dart index c135ea8d..990defd3 100644 --- a/lib/modules/tm_module/tasks/task_request_detail_view.dart +++ b/lib/modules/tm_module/tasks/task_request_detail_view.dart @@ -113,9 +113,9 @@ class _TaskRequestDetailsViewState extends State { ), 8.width, StatusLabel( - label: widget.requestDetails?.status!, - textColor: AppColor.getRequestStatusTextColorByName(context, widget.requestDetails?.status!), - backgroundColor: AppColor.getRequestStatusColorByName(context, widget.requestDetails?.status!), + label: taskModel?.taskJobStatus?.name ?? widget.requestDetails?.status!, + textColor: AppColor.getRequestStatusTextColorByName(context, taskModel?.taskJobStatus?.name ?? widget.requestDetails?.status!), + backgroundColor: AppColor.getRequestStatusColorByName(context, taskModel?.taskJobStatus?.name ?? widget.requestDetails?.status!), ), 1.width.expanded, Text( @@ -177,7 +177,7 @@ class _TaskRequestDetailsViewState extends State { ], ).toShadowContainer(context).paddingAll(16), ).expanded, - if (context.settingProvider.isUserFlowMedical && userProvider!.user!.type == UsersTypes.engineer && (taskModel?.taskJobStatus?.value == 0)) + if (context.settingProvider.isUserFlowMedical && userProvider!.user!.type == UsersTypes.engineer && (taskModel?.taskJobStatus?.value == 1)) FooterActionButton.footerContainer( context: context, child: AppFilledButton( diff --git a/lib/providers/task_request_provider/task_request_provider.dart b/lib/providers/task_request_provider/task_request_provider.dart index 8e733e69..5b49d461 100644 --- a/lib/providers/task_request_provider/task_request_provider.dart +++ b/lib/providers/task_request_provider/task_request_provider.dart @@ -152,7 +152,7 @@ class TaskRequestProvider extends ChangeNotifier { Future assignEngineerToHimself(num id) async { try { - Response response = await ApiManager.instance.post(URLs.taskJobsAssignEngineerToHimself, body: {"gasRefillId": id}); + Response response = await ApiManager.instance.post(URLs.taskJobsAssignEngineerToHimself, body: {"taskJobId": id}); if (response.statusCode >= 200 && response.statusCode < 300) { taskRequestModel = TaskData.fromJson(json.decode(response.body)["data"]); notifyListeners(); From 5391cc324c5bb618f381da8539b200bd7ee144a8 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 3 Feb 2026 16:54:46 +0300 Subject: [PATCH 5/7] improvements --- .../tm_module/device_transfer/device_transfer_details.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/modules/tm_module/device_transfer/device_transfer_details.dart b/lib/modules/tm_module/device_transfer/device_transfer_details.dart index a19456c0..182f2e21 100644 --- a/lib/modules/tm_module/device_transfer/device_transfer_details.dart +++ b/lib/modules/tm_module/device_transfer/device_transfer_details.dart @@ -316,8 +316,10 @@ class _DeviceTransferDetailsState extends State { bool isCurrentRequestClosed = isSender ? ((_model?.senderMachineStatusValue == 3)) : ((_model?.receiverMachineStatusValue == 3)); bool isCurrentRequestOpen = isSender ? ((_model?.senderMachineStatusValue == 4)) : ((_model?.receiverMachineStatusValue == 4)); + bool isCurrentRequestInProgress = isSender ? ((_model?.senderMachineStatusValue == 1)) : ((_model?.receiverMachineStatusValue == 1)); + bool engineerCanAssignToHimself = (_userProvider!.user?.type == UsersTypes.engineer) && isCurrentRequestOpen && context.settingProvider.isUserFlowMedical; - bool engineerCanCancel = (_userProvider!.user?.type == UsersTypes.engineer) && isCurrentEngineerEligibleForEdit && context.settingProvider.isUserFlowMedical; + bool engineerCanCancel = (_userProvider!.user?.type == UsersTypes.engineer) && isCurrentRequestInProgress && context.settingProvider.isUserFlowMedical; return Column( crossAxisAlignment: CrossAxisAlignment.start, From c50e979790cb2a72302d73f7a2cee9a8e7521c2d Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Mon, 9 Feb 2026 17:13:46 +0300 Subject: [PATCH 6/7] keyboard dismiss issue fixed. --- .../rejection_reason_bottom_sheet.dart | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/lib/views/widgets/bottom_sheets/rejection_reason_bottom_sheet.dart b/lib/views/widgets/bottom_sheets/rejection_reason_bottom_sheet.dart index 0e3c0f5e..72f57261 100644 --- a/lib/views/widgets/bottom_sheets/rejection_reason_bottom_sheet.dart +++ b/lib/views/widgets/bottom_sheets/rejection_reason_bottom_sheet.dart @@ -9,19 +9,36 @@ import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; import 'package:test_sa/providers/service_request_providers/reject_reason_provider.dart'; -class RejectionReasonBottomSheet extends StatelessWidget { +class RejectionReasonBottomSheet extends StatefulWidget { final Future Function(int reasonId, String comment) onRejectPressed; final VoidCallback? onRefreshed; - RejectionReasonBottomSheet({Key? key, this.onRefreshed, required this.onRejectPressed}) : super(key: key); + const RejectionReasonBottomSheet({Key? key, this.onRefreshed, required this.onRejectPressed}) : super(key: key); @override - Widget build(BuildContext context) { - TextEditingController _commentController = TextEditingController(); - final GlobalKey _formKey = GlobalKey(); + State createState() => _RejectionReasonBottomSheetState(); +} + +class _RejectionReasonBottomSheetState extends State { + late TextEditingController _commentController; + late GlobalKey _formKey; + Lookup? selectedReason; + + @override + void initState() { + super.initState(); + _commentController = TextEditingController(); + _formKey = GlobalKey(); + } - Lookup? selectedReason; + @override + void dispose() { + _commentController.dispose(); + super.dispose(); + } + @override + Widget build(BuildContext context) { return Form( key: _formKey, child: Column( @@ -67,11 +84,11 @@ class RejectionReasonBottomSheet extends StatelessWidget { if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); Utils.showLoading(context); - bool isSuccess = await onRejectPressed(selectedReason!.id!, _commentController.text); + bool isSuccess = await widget.onRejectPressed(selectedReason!.id!, _commentController.text); Utils.hideLoading(context); if (isSuccess) { Navigator.of(context).pop(); - onRefreshed?.call(); + widget.onRefreshed?.call(); } } }, From d723b6bc16b7a781324c0b533ef14010a2268ce0 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Mon, 23 Feb 2026 14:36:06 +0300 Subject: [PATCH 7/7] refresh screen after update data --- .../tm_module/gas_refill/gas_refill_details.dart | 11 ++++++++++- .../gas_refill/update_gas_refill_request.dart | 6 +++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/modules/tm_module/gas_refill/gas_refill_details.dart b/lib/modules/tm_module/gas_refill/gas_refill_details.dart index 0b2a7090..8b7e0c03 100644 --- a/lib/modules/tm_module/gas_refill/gas_refill_details.dart +++ b/lib/modules/tm_module/gas_refill/gas_refill_details.dart @@ -141,7 +141,16 @@ class _GasRefillDetailsPageState extends State { 16.width, AppFilledButton( onPressed: () async { - await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdateGasRefillRequest(gasRefillModel: _model))); + bool? isRefresh = await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdateGasRefillRequest(gasRefillModel: _model)));; + if (isRefresh != null && isRefresh) { + Utils.showLoading(context); + await gasRefillProvider.getGasRefillObjectById(widget.model.id!); + isDataUpdated = true; + Utils.hideLoading(context); + setState(() {}); + // isDataUpdated = true; + // setState(() {}); + } // getVisitData(); }, label: context.translation.updateRequest, diff --git a/lib/modules/tm_module/gas_refill/update_gas_refill_request.dart b/lib/modules/tm_module/gas_refill/update_gas_refill_request.dart index 7f0fc8c3..66343d3d 100644 --- a/lib/modules/tm_module/gas_refill/update_gas_refill_request.dart +++ b/lib/modules/tm_module/gas_refill/update_gas_refill_request.dart @@ -192,8 +192,12 @@ class _UpdateGasRefillRequestState extends State { // when click complete then this request remove from the list and status changes to closed.. _gasRefillProvider?.reset(); allRequestsProvider.getAllRequests(context, typeTransaction: 2); + // Navigator.pop(context); + Navigator.pop(context,true); + }else{ + Navigator.pop(context,false); + } - Navigator.pop(context); } }); }