diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 786485ff..a1e9f611 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -82,6 +82,10 @@ class URLs { static get swipeUrl=> '$_baseUrl/Swipe/Swipe'; static get getSwipeLastTransactionUrl=> '$_baseUrl/Swipe/GetLastTransaction'; static get getSwipeTransactionHistoryUrl=> '$_baseUrl/Swipe/GetTransactions'; + //Recurrent plan Api... + static get getRecurrentPlanByIdUrl=> '$_baseUrl/PlanRecurrentTasks/GetPlanRecurrentTaskById'; + static get updateRecurrentPlanUrl=> '$_baseUrl/PlanRecurrentTasks/UpdateTaskByEngineer'; + //service request..... static get getServiceRequests => "$_baseUrl/CallRequest/GetCallRequests"; // get diff --git a/lib/controllers/providers/api/all_requests_provider.dart b/lib/controllers/providers/api/all_requests_provider.dart index a4b82bd8..94004f1f 100644 --- a/lib/controllers/providers/api/all_requests_provider.dart +++ b/lib/controllers/providers/api/all_requests_provider.dart @@ -4,8 +4,11 @@ import 'package:flutter/widgets.dart'; import 'package:http/http.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/models/all_requests_and_count_model.dart'; import 'package:test_sa/models/enums/user_types.dart'; +import 'package:test_sa/models/ppm/recurrent_wo.dart'; +import 'package:test_sa/models/timer_model.dart'; import '../../../models/search_all_requests_model.dart'; @@ -17,6 +20,8 @@ class AllRequestsProvider extends ChangeNotifier { bool isOverdueLoading = false; bool isHighPriorityLoading = false; bool isCalendarLoading = false; + bool isLoading = false; + bool _isFilterRequestLoading = false; bool _isRequestCategoryLoading = false; @@ -48,12 +53,24 @@ class AllRequestsProvider extends ChangeNotifier { AllRequestsAndCount? _requestDetailList; AllRequestsAndCount? get allRequestsAndCount => _allRequestsAndCount; + AllRequestsAndCount? get highPriorityRequests => _highPriorityRequests; + AllRequestsAndCount? get overdueRequests => _overdueRequests; + // AllRequestsAndCount? get openRequests => _openRequests; // AllRequestsAndCount? get completedRequests => _completedRequests; AllRequestsAndCount? get requestDetailList => _requestDetailList; + RecurrentWoData? _recurrentWoData=RecurrentWoData(); + + RecurrentWoData? get recurrentWoData => _recurrentWoData; + + set recurrentWoData(RecurrentWoData? value) { + _recurrentWoData = value; + notifyListeners(); + } + set requestDetailList(AllRequestsAndCount? value) { _requestDetailList = value; notifyListeners(); @@ -115,10 +132,9 @@ class AllRequestsProvider extends ChangeNotifier { SearchAllRequestsModel? searchedModel; Future getAllRequests(BuildContext context, {int? typeTransaction, SearchAllRequestsModel? search}) async { - print('loading value is $isAllLoading'); if (isAllLoading == true) return -2; isAllLoading = true; - if (_allRequestsAndCount == null) notifyListeners(); + if (_allRequestsAndCount == null) notifyListeners(); Response response; try { if (search != null) { @@ -128,7 +144,7 @@ class AllRequestsProvider extends ChangeNotifier { } final type = typeTransaction == null ? search?.typeTransaction == null || (search?.typeTransaction?.isEmpty ?? false) - ? [1, 2, 3, 4] + ? [1, 2, 3, 4, 5] //added 5 to get recurrent wo ... : search!.typeTransaction : [typeTransaction]; List status = (search?.statuses == null || (search?.statuses?.isEmpty ?? false)) ? (((search?.isArchived ?? false) ? [3] : [1, 2, 4])) : search!.statuses!; @@ -177,6 +193,49 @@ class AllRequestsProvider extends ChangeNotifier { } } + Future getRecurrentWoById({required int id}) async { + isLoading = true; + Response response; + try { + response = await ApiManager.instance.get(URLs.getRecurrentPlanByIdUrl + "?planRecurrentTaskId=$id"); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + recurrentWoData = RecurrentWoData.fromJson(json.decode(response.body)["data"]); + notifyListeners(); + } + isLoading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + isLoading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } + + Future updateRecurrentWo({required int status}) async { + isLoading = true; + Response response; + try { + response = await ApiManager.instance.post(URLs.updateRecurrentPlanUrl, body: recurrentWoData!.toJson(status: status)); + stateCode = response.statusCode; + isLoading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + isLoading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } + + void updateRecurrentWoTimer({TimerModel? timer}) { + recurrentWoData?.recurrentWoTimerModel = timer; + notifyListeners(); + } + Future getCalendarRequests({required DateTime from, DateTime? to}) async { if (isCalendarLoading == true) return -2; isCalendarLoading = true; diff --git a/lib/controllers/providers/api/gas_refill_provider.dart b/lib/controllers/providers/api/gas_refill_provider.dart index a551ebb2..a5d59016 100644 --- a/lib/controllers/providers/api/gas_refill_provider.dart +++ b/lib/controllers/providers/api/gas_refill_provider.dart @@ -47,6 +47,7 @@ class GasRefillProvider extends ChangeNotifier { Future getGasRefillObjectById(num id) async { try { Response response = await ApiManager.instance.get(URLs.getGasRefillById + "?gazRefillId=$id"); + if (response.statusCode >= 200 && response.statusCode < 300) { return GasRefillModel.fromJson(json.decode(response.body)["data"]); } else { diff --git a/lib/extensions/enum_extensions.dart b/lib/extensions/enum_extensions.dart index 0325affb..c6d10640 100644 --- a/lib/extensions/enum_extensions.dart +++ b/lib/extensions/enum_extensions.dart @@ -1,4 +1,5 @@ import 'package:test_sa/app_strings/app_asset.dart'; +import 'package:test_sa/models/enums/recurrent_task_inspection_data_type.dart'; import 'package:test_sa/models/enums/swipe_type.dart'; import 'package:test_sa/models/enums/work_order_next_step.dart'; @@ -94,6 +95,8 @@ extension IntExtensionsWorkOrder on int { } } + + extension EnumExtensionsSwipeType on SwipeTypeEnum { int getIntFromSwipeTypeEnum() { switch (this) { @@ -106,3 +109,15 @@ extension EnumExtensionsSwipeType on SwipeTypeEnum { } } } +extension StringExtensionsRecurrentTaskInpesctionDataType on String { + RecurrentTaskInspectionDataTypeEnum toRecurrentTaskInspectionDataTypeEnum() { + switch (this) { + case 'bool': + return RecurrentTaskInspectionDataTypeEnum.bool; + case 'number': + return RecurrentTaskInspectionDataTypeEnum.number; + default: + return RecurrentTaskInspectionDataTypeEnum.bool; + } + } +} diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 80a0f88d..6a024697 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -38,6 +38,15 @@ extension StringExtensions on String { return ""; } } + String get toMonthYearFormat { + try { + DateTime dateTime = DateTime.parse(this); + String formattedDate = DateFormat('MMMM d, y').format(dateTime); + return formattedDate; + } catch (e) { + return ""; + } + } String get toAssetDetailsFormat { try { diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index 881d3054..0fa2b641 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -526,10 +526,17 @@ "userName": "اسم المستخدم", "siteName": "اسم الموقع", "pointName": "اسم النقطة", + "checkIn": "تسجيل الدخول", + "createdDate": "تاريخ الإنشاء", + "employeeId": "رقم الموظف", + "extensionNo": "رقم التمديد", + "checkIn": "تسجيل الدخول", "pmWo": "أمر العمل الوقائي", - "recurrentWo": "أمر العمل المتكرر", + "taskNo": "رقم المهمة", "assignEngineer": "تعيين مهندس", - "scheduledDate": "التاريخ المجدول" + "scheduledDate": "التاريخ المجدول", + "complete": "اكتمل", + "recurrentWo": "أمر العمل المتكرر" } \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 7d89a8ba..80cf85eb 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -535,5 +535,9 @@ "recurrentWo": "Recurrent WO", "taskNo": "Task No", "assignEngineer": "Assign Engineer", - "scheduledDate": "Scheduled Date" + "scheduledDate": "Scheduled Date", + "complete": "Complete", + "createdDate": "Created Date", + "employeeId": "Employee ID", + "extensionNo": "Extension No" } \ No newline at end of file diff --git a/lib/models/device/asset_transfer.dart b/lib/models/device/asset_transfer.dart index 26116478..40ae2302 100644 --- a/lib/models/device/asset_transfer.dart +++ b/lib/models/device/asset_transfer.dart @@ -52,6 +52,10 @@ class AssetTransfer { this.destDepartmentName, this.destBuildingName, this.applied, + this.extensionNo, + this.name, + this.employeeId, + this.createdDate, this.createdOn, this.destFloorName, this.destSiteName, @@ -155,6 +159,10 @@ class AssetTransfer { destDepartmentName = json['destDepartmentName']; destBuildingName = json['destBuildingName']; applied = json['applied']; + extensionNo = json['extensionNo']; + employeeId = json['employeeId']; + name = json['name']; + createdDate = json['createdDate']; createdOn = json['createdOn']; destFloorName = json['destFloorName']; destSiteName = json['destSiteName']; @@ -234,6 +242,10 @@ class AssetTransfer { String? receiverMachineStatusName; String? receiverEngSignatureUrl; bool? applied; + dynamic extensionNo; + String? employeeId; + String? name; + String? createdDate; String? createdOn; String? modifiedOn; List? senderVisitTimers; @@ -293,6 +305,10 @@ class AssetTransfer { String? receiverMachineStatusName, String? receiverEngSignatureUrl, bool? applied, + dynamic extensionNo, + String? employeeId, + String? name, + String? createdDate, String? createdOn, String? modifiedOn, String? assetSerialNo, @@ -359,6 +375,10 @@ class AssetTransfer { receiverMachineStatusName: receiverMachineStatusName ?? this.receiverMachineStatusName, receiverEngSignatureUrl: receiverEngSignatureUrl ?? this.receiverEngSignatureUrl, applied: applied ?? this.applied, + extensionNo: extensionNo??this.extensionNo, + employeeId: employeeId??this.employeeId, + name: name??this.name, + createdDate: createdDate??this.createdDate, createdOn: createdOn ?? this.createdOn, modifiedOn: modifiedOn ?? this.modifiedOn, assetSerialNo: assetSerialNo ?? this.assetSerialNo, @@ -436,6 +456,10 @@ class AssetTransfer { map["receiverMachineStatusName"] = receiverMachineStatusName; map["receiverEngSignatureUrl"] = receiverEngSignatureUrl; map["applied"] = applied; + map["extensionNo"] = extensionNo; + map["employeeId"] = employeeId; + map["name"] = name; + map["createdDate"] = createdDate; map["createdOn"] = createdOn; map["modifiedOn"] = modifiedOn; map["assetSerialNo"] = assetSerialNo; @@ -552,6 +576,10 @@ class AssetTransfer { receiverMachineStatusName = assetTransfer.receiverMachineStatusName; receiverEngSignatureUrl = assetTransfer.receiverEngSignatureUrl; applied = assetTransfer.applied; + extensionNo = assetTransfer.extensionNo; + employeeId = assetTransfer.employeeId; + name = assetTransfer.name; + createdDate = assetTransfer.createdDate; createdOn = assetTransfer.createdOn; modifiedOn = assetTransfer.modifiedOn; assetSerialNo = assetTransfer.assetSerialNo; diff --git a/lib/models/enums/recurrent_task_inspection_data_type.dart b/lib/models/enums/recurrent_task_inspection_data_type.dart new file mode 100644 index 00000000..478f780f --- /dev/null +++ b/lib/models/enums/recurrent_task_inspection_data_type.dart @@ -0,0 +1,4 @@ +enum RecurrentTaskInspectionDataTypeEnum { + bool, //bool + number, // number +} diff --git a/lib/models/new_models/gas_refill_model.dart b/lib/models/new_models/gas_refill_model.dart index eb944aa4..938d94e4 100644 --- a/lib/models/new_models/gas_refill_model.dart +++ b/lib/models/new_models/gas_refill_model.dart @@ -24,6 +24,10 @@ class GasRefillModel { this.engSignature, this.nurseSignature, this.workingHours, + this.extensionNo, + this.employeeId, + this.name, + this.createdDate, this.site, this.building, this.floor, @@ -47,6 +51,10 @@ class GasRefillModel { endTime = json['endTime']; comment = json['comment']; workingHours = json['workingHours']; + extensionNo = json['extensionNo']; + employeeId = json['employeeId']; + name = json['name']; + createdDate = json['createdDate']; try { final DateTime? sd = DateTime.tryParse(startDate ?? ""); final DateTime? st = DateTime.tryParse(startTime ?? ""); @@ -90,7 +98,11 @@ class GasRefillModel { String? endTime; // Now nullable String? engSignature; // Now nullable String? nurseSignature; // Now nullable - num? workingHours; // Now nullable + num? workingHours; + dynamic extensionNo; + String? employeeId; + String? name; + String? createdDate; Site? site; // Now nullable Building? building; // Now nullable Floor? floor; // Now nullable @@ -115,6 +127,10 @@ class GasRefillModel { String? engSignature, String? nurseSignature, num? workingHours, + num? extensionNo, + num? employeeId, + String? name, + String? createdDate, Site? site, Building? building, Floor? floor, @@ -161,6 +177,10 @@ class GasRefillModel { map['engSignature'] = engSignature; map['nurseSignature'] = nurseSignature; map['workingHours'] = workingHours; + map['extensionNo'] = extensionNo; + map['employeeId'] = employeeId; + map['name'] = name; + map['createdDate'] = createdDate; map['comment'] = comment; if (site != null) { map['site'] = site?.toJson(addBuildings: false); // Use '?.' for null safety @@ -223,6 +243,10 @@ class GasRefillModel { engSignature = model.engSignature; nurseSignature = model.nurseSignature; workingHours = model.workingHours; + extensionNo = model.extensionNo; + employeeId = model.employeeId; + name = model.name; + createdDate = model.createdDate; } } diff --git a/lib/models/ppm/recurrent_wo.dart b/lib/models/ppm/recurrent_wo.dart new file mode 100644 index 00000000..acea8df2 --- /dev/null +++ b/lib/models/ppm/recurrent_wo.dart @@ -0,0 +1,342 @@ +import 'package:test_sa/extensions/enum_extensions.dart'; +import 'package:test_sa/models/enums/recurrent_task_inspection_data_type.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/timer_model.dart'; + +class RecurrentWo { + RecurrentWoData? recurrentWoData; + String? message; + String? title; + String? innerMessage; + int? responseCode; + bool? isSuccess; + + RecurrentWo({this.recurrentWoData, this.message, this.title, this.innerMessage, this.responseCode, this.isSuccess}); + + RecurrentWo.fromJson(Map json) { + recurrentWoData = json['data'] != null ? RecurrentWoData.fromJson(json['data']) : null; + message = json['message']; + title = json['title']; + innerMessage = json['innerMessage']; + responseCode = json['responseCode']; + isSuccess = json['isSuccess']; + } + + Map toJson() { + final Map data = {}; + if (recurrentWoData != null) { + data['data'] = recurrentWoData!.toJson(); + } + data['message'] = message; + data['title'] = title; + data['innerMessage'] = innerMessage; + data['responseCode'] = responseCode; + data['isSuccess'] = isSuccess; + return data; + } +} + +class RecurrentWoData { + int? id; + Engineer? engineer; + String? scheduleDate; + Status? status; + Site? site; + Lookup? building; + Lookup? floor; + Lookup? department; + Lookup? room; + List? planRecurrentMedicalTaskRooms; + List? planRecurrentTaskTimers; + TimerModel? recurrentWoTimerModel = TimerModel(); + double? totalWorkingHours = 0.0; + + RecurrentWoData( + {this.id, + this.engineer, + this.scheduleDate, + this.status, + this.site, + this.building, + this.recurrentWoTimerModel, + this.floor, + this.department, + this.room, + this.planRecurrentMedicalTaskRooms, + this.planRecurrentTaskTimers, + this.totalWorkingHours}); + + RecurrentWoData.fromJson(Map json) { + id = json['id']; + engineer = json['engineer'] != null ? new Engineer.fromJson(json['engineer']) : null; + scheduleDate = json['scheduleDate']; + status = json['status'] != null ? Status.fromJson(json['status']) : null; + site = json['site'] != null ? Site.fromJson(json['site']) : null; + building = json["building"] == null ? null : Lookup.fromJson(json["building"]); + floor = json["floor"] == null ? null : Lookup.fromJson(json["floor"]); + department = json["department"] == null ? null : Lookup.fromJson(json["department"]); + room = json["room"] == null ? null : Lookup.fromJson(json["room"]); + if (json['planRecurrentMedicalTaskRooms'] != null) { + planRecurrentMedicalTaskRooms = []; + json['planRecurrentMedicalTaskRooms'].forEach((v) { + planRecurrentMedicalTaskRooms!.add(PlanRecurrentMedicalTaskRooms.fromJson(v)); + }); + } + + if (json['planRecurrentTaskTimers'] != null) { + planRecurrentTaskTimers = []; + json['planRecurrentTaskTimers'].forEach((v) { + planRecurrentTaskTimers?.add(PlanRecurrentTaskTimers.fromJson(v)); + }); + //TODO need to test this @waseem.. + totalWorkingHours = json['planRecurrentTaskTimers'].fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item['endDateTime']).difference(DateTime.parse(item['startDateTime'])).inSeconds) ?? 0; + } + } + + Map toJson({int? status = 0}) { + final Map data = {}; + List taskRoomTabAttributesJson = []; + if (planRecurrentMedicalTaskRooms != null) { + taskRoomTabAttributesJson = planRecurrentMedicalTaskRooms + ?.expand((room) => room.planRecurrentMedicalTaskRoomTabs ?? []) + .expand((tab) => tab.planRecurrentMedicalTaskRoomTabAttributes ?? []) + .map((attribute) => attribute.toJson()) + .toList() ?? + []; + } + data['id'] = id; + data['statusValue'] = status; + + if (planRecurrentTaskTimers != null) { + data['planRecurrentTaskTimers'] = planRecurrentTaskTimers!.map((v) => v.toJson()).toList(); + } + if (taskRoomTabAttributesJson.isNotEmpty) { + data['attributes'] = taskRoomTabAttributesJson; + } else { + data['attributes'] = []; + } + + return data; + } +} + +class Engineer { + String? userId; + String? userName; + String? email; + String? employeeId; + int? languageId; + + Engineer({this.userId, this.userName, this.email, this.employeeId, this.languageId}); + + Engineer.fromJson(Map json) { + userId = json['userId']; + userName = json['userName']; + email = json['email']; + employeeId = json['employeeId']; + languageId = json['languageId']; + } + + Map toJson() { + final Map data = {}; + data['userId'] = userId; + data['userName'] = userName; + data['email'] = email; + data['employeeId'] = employeeId; + data['languageId'] = languageId; + return data; + } +} + +class Status { + int? id; + String? name; + int? value; + + Status({this.id, this.name, this.value}); + + Status.fromJson(Map json) { + id = json['id']; + name = json['name']; + value = json['value']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['name'] = name; + data['value'] = value; + return data; + } +} + +class Site { + int? id; + String? siteName; + + Site({this.id, this.siteName}); + + Site.fromJson(Map json) { + id = json['id']; + siteName = json['siteName']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['siteName'] = siteName; + return data; + } +} + +class PlanRecurrentMedicalTaskRooms { + int? id; + Room? room; + List? planRecurrentMedicalTaskRoomTabs; + + PlanRecurrentMedicalTaskRooms({this.id, this.room, this.planRecurrentMedicalTaskRoomTabs}); + + PlanRecurrentMedicalTaskRooms.fromJson(Map json) { + id = json['id']; + room = json['room'] != null ? Room.fromJson(json['room']) : null; + if (json['planRecurrentMedicalTaskRoomTabs'] != null) { + planRecurrentMedicalTaskRoomTabs = []; + json['planRecurrentMedicalTaskRoomTabs'].forEach((v) { + planRecurrentMedicalTaskRoomTabs!.add(PlanRecurrentMedicalTaskRoomTabs.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + if (room != null) { + data['room'] = room!.toJson(); + } + if (planRecurrentMedicalTaskRoomTabs != null) { + data['planRecurrentMedicalTaskRoomTabs'] = planRecurrentMedicalTaskRoomTabs!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class Room { + int? id; + String? roomId; + + Room({this.id, this.roomId}); + + Room.fromJson(Map json) { + id = json['id']; + roomId = json['roomId']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['roomId'] = roomId; + return data; + } +} + +class PlanRecurrentMedicalTaskRoomTabs { + int? id; + String? tabName; + int? tabMedicalRoomId; + List? planRecurrentMedicalTaskRoomTabAttributes; + + PlanRecurrentMedicalTaskRoomTabs({this.id, this.tabName, this.tabMedicalRoomId, this.planRecurrentMedicalTaskRoomTabAttributes}); + + PlanRecurrentMedicalTaskRoomTabs.fromJson(Map json) { + id = json['id']; + tabName = json['tabName']; + tabMedicalRoomId = json['tabMedicalRoomId']; + if (json['planRecurrentMedicalTaskRoomTabAttributes'] != null) { + planRecurrentMedicalTaskRoomTabAttributes = []; + json['planRecurrentMedicalTaskRoomTabAttributes'].forEach((v) { + planRecurrentMedicalTaskRoomTabAttributes!.add(PlanRecurrentMedicalTaskRoomTabAttributes.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['tabName'] = tabName; + data['tabMedicalRoomId'] = tabMedicalRoomId; + if (planRecurrentMedicalTaskRoomTabAttributes != null) { + data['planRecurrentMedicalTaskRoomTabAttributes'] = planRecurrentMedicalTaskRoomTabAttributes!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class PlanRecurrentMedicalTaskRoomTabAttributes { + int? id; + Attribute? attribute; + dynamic attributeValue; + + PlanRecurrentMedicalTaskRoomTabAttributes({this.id, this.attribute, this.attributeValue}); + + PlanRecurrentMedicalTaskRoomTabAttributes.fromJson(Map json) { + id = json['id']; + attribute = json['attribute'] != null ? Attribute.fromJson(json['attribute']) : null; + attributeValue = json['attributeValue'] ?? (json['attribute']['type'] == 'bool' ? (json['attributeValue']?.toString() == 'true') : json['attributeValue']); + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['attributeValue'] = attributeValue != null ? attributeValue.toString() : attributeValue; + return data; + } +} + +class Attribute { + String? name; + String? type; + String? key; + RecurrentTaskInspectionDataTypeEnum? dataTypeEnum; + + Attribute({this.name, this.type, this.key, this.dataTypeEnum}); + + Attribute.fromJson(Map json) { + name = json['name']; + type = json['type']; + dataTypeEnum = json['type'] == null ? null : (json['type'] as String).toRecurrentTaskInspectionDataTypeEnum(); + key = json['key']; + } + + Map toJson() { + final Map data = {}; + data['name'] = name; + data['type'] = type; + data['key'] = key; + return data; + } +} + +class PlanRecurrentTaskTimers { + int? id; + String? startTime; + String? endTime; + dynamic workingHours; + + PlanRecurrentTaskTimers({this.id, this.startTime, this.endTime, this.workingHours}); + + PlanRecurrentTaskTimers.fromJson(Map json) { + id = json['id']; + startTime = json['startDateTime']; + endTime = json['endDateTime']; + workingHours = json['workingHour']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['startDateTime'] = startTime; + data['endDateTime'] = endTime; + data['workingHour'] = workingHours; + return data; + } +} diff --git a/lib/new_views/app_style/app_color.dart b/lib/new_views/app_style/app_color.dart index 448d1950..8ccc5700 100644 --- a/lib/new_views/app_style/app_color.dart +++ b/lib/new_views/app_style/app_color.dart @@ -60,10 +60,12 @@ class AppColor { static const Color red50 = Color(0xffD02127); static const Color red60 = Color(0xff8C050A); static const Color red70 = Color(0xffF63939); + static const Color red80 = Color(0xfffdcdcd); //green static const Color green40 = Color(0xffBAFFE1); static const Color green50 = Color(0xff62BE96); + static const Color green30 = Color(0xffd8efe5); static const Color green60 = Color(0xff065E38); static const Color green70 = Color(0xff54C166); static const Color green15 = Color(0xff157D14); 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 bc0b6863..0519bd03 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 @@ -37,6 +37,7 @@ class _MyRequestsPageState extends State { context.translation.gasRefillRequest, context.translation.deviceTransferRequest, context.translation.preventiveMaintenance, + context.translation.recurrentWo, ]; _provider = Provider.of(context, listen: false); _provider!.reset(); diff --git a/lib/new_views/pages/land_page/requests/recurrent_wo_item_view.dart b/lib/new_views/pages/land_page/requests/recurrent_wo_item_view.dart new file mode 100644 index 00000000..35e111ab --- /dev/null +++ b/lib/new_views/pages/land_page/requests/recurrent_wo_item_view.dart @@ -0,0 +1,75 @@ +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/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/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/all_requests_and_count_model.dart'; +import 'package:test_sa/models/ppm/recurrent_wo.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/pages/user/ppm/ppm_work_order/recurrent_wo/recurrent_work_order_view.dart'; +import '../../../../views/widgets/requests/request_status.dart'; + +class RecurrentWoItemView extends StatelessWidget { + final RequestsDetails? requestDetails; + final bool showShadow; + + const RecurrentWoItemView({Key? key, this.requestDetails, this.showShadow = true}) : super(key: key); + + @override + Widget build(BuildContext context) { + if (requestDetails != null) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: requestDetails!.priority!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails!.priority!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails!.priority!), + ), + 8.width, + StatusLabel( + label: requestDetails!.status!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails!.status!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails!.status!), + ), + 1.width.expanded, + Text( + requestDetails!.date?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + ], + ), + 8.height, + (requestDetails?.nameOfType ?? context.translation.ppmRequest).heading5(context), + 8.height, + '${context.translation.taskNo}: ${requestDetails!.id}'.bodyText(context), + '${context.translation.site}: ${requestDetails!.site}'.bodyText(context), + // '${context.translation.code}: ${request.code}'.bodyText(context), + '${context.translation.requestNo}: ${requestDetails!.requestNo}'.bodyText(context), + 16.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.of(context).push(MaterialPageRoute(builder: (_) => RecurrentWorkOrderView(taskId: requestDetails!.id))); + }); + } + return const SizedBox(); + } +} 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 783671aa..0a06c6d6 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 @@ -7,6 +7,7 @@ import 'package:test_sa/models/all_requests_and_count_model.dart'; import 'package:test_sa/new_views/pages/land_page/requests/asset_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/gas_refill_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/ppm_item_view.dart'; +import 'package:test_sa/new_views/pages/land_page/requests/recurrent_wo_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/service_request_item_view.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; @@ -25,24 +26,43 @@ class RequestItemViewList extends StatelessWidget { shrinkWrap: true, itemBuilder: (cxt, index) { if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading); - bool isServiceRequest = list[index].transactionType == 1; - bool isGasRefill = list[index].transactionType == 2; - bool isAssetTransfer = list[index].transactionType == 3; - bool isPPMs = list[index].transactionType == 4; + switch(list[index].transactionType){ + case 1: + return ServiceRequestItemView(requestDetails: list[index]); + case 2: + return GasRefillItemView(requestDetails: list[index]); + case 3: + return AssetItemView(requestDetails: list[index]); + case 4: + return PpmItemView(requestDetails: list[index]); + case 5: + return RecurrentWoItemView(requestDetails: list[index]); + default: + Container( + height: 100, + width: double.infinity, + color: Colors.grey, + ); - return isServiceRequest - ? ServiceRequestItemView(requestDetails: list[index]) - : isGasRefill - ? GasRefillItemView(requestDetails: list[index]) - : isPPMs - ? PpmItemView(requestDetails: list[index]) - : isAssetTransfer - ? AssetItemView(requestDetails: list[index]) - : Container( - height: 100, - width: double.infinity, - color: Colors.grey, - ); + } + // bool isServiceRequest = list[index].transactionType == 1; + // bool isGasRefill = list[index].transactionType == 2; + // bool isAssetTransfer = list[index].transactionType == 3; + // bool isPPMs = list[index].transactionType == 4; + // + // return isServiceRequest + // ? ServiceRequestItemView(requestDetails: list[index]) + // : isGasRefill + // ? GasRefillItemView(requestDetails: list[index]) + // : isPPMs + // ? PpmItemView(requestDetails: list[index]) + // : isAssetTransfer + // ? AssetItemView(requestDetails: list[index]) + // : Container( + // height: 100, + // width: double.infinity, + // color: Colors.grey, + // ); }, separatorBuilder: (cxt, index) => 8.height, itemCount: isLoading ? 6 : list.length); diff --git a/lib/service_request_latest/views/forms/maintenance_request/components/internal_request.dart b/lib/service_request_latest/views/forms/maintenance_request/components/internal_request.dart index e8043355..118fa3ce 100644 --- a/lib/service_request_latest/views/forms/maintenance_request/components/internal_request.dart +++ b/lib/service_request_latest/views/forms/maintenance_request/components/internal_request.dart @@ -101,6 +101,7 @@ class _InternalMaintenanceRequestState extends State print("timerProgress:$isRunning"); }, onChange: (timer) async { + requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel = timer; return true; }, diff --git a/lib/service_request_latest/views/forms/maintenance_request/maintenance_request_main.dart b/lib/service_request_latest/views/forms/maintenance_request/maintenance_request_main.dart index 3cc8a907..ad7b8a3c 100644 --- a/lib/service_request_latest/views/forms/maintenance_request/maintenance_request_main.dart +++ b/lib/service_request_latest/views/forms/maintenance_request/maintenance_request_main.dart @@ -101,12 +101,6 @@ class _MaintenanceRequestFormState extends State with Si if (validate(model: requestDetailProvider.activityMaintenanceHelperModel!)) { - ActivityMaintenanceTimers model = ActivityMaintenanceTimers( - id: 0, - startTime: requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel?.startAt!.toIso8601String(), // Handle potential null - endTime: requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel?.endAt?.toIso8601String(), // Handle potential null - workingHours: ((requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel?.durationInSecond ?? 0) / 60 / 60), - ); requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimers =requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimers??[]; requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimers?.add( ActivityMaintenanceTimers( diff --git a/lib/service_request_latest/views/nurse/create_new_request_view.dart b/lib/service_request_latest/views/nurse/create_new_request_view.dart index 58e06fe1..1015199d 100644 --- a/lib/service_request_latest/views/nurse/create_new_request_view.dart +++ b/lib/service_request_latest/views/nurse/create_new_request_view.dart @@ -329,8 +329,6 @@ class _CreateNewRequestState extends State with TickerProvider _serviceRequest.requestedThrough = Provider.of(context, listen: false).items.firstWhere((element) => element.value == 3, orElse: null); _serviceRequest.type = Provider.of(context, listen: false).items.firstWhere((element) => element.value == 1, orElse: null); - - print('comments value is ${_serviceRequest.callComments}'); if (_formKey.currentState!.validate() && await _serviceRequest.validateNewRequest(context)) { _formKey.currentState!.save(); diff --git a/lib/views/pages/device_transfer/device_transfer_details.dart b/lib/views/pages/device_transfer/device_transfer_details.dart index 6e1e6481..1815d04c 100644 --- a/lib/views/pages/device_transfer/device_transfer_details.dart +++ b/lib/views/pages/device_transfer/device_transfer_details.dart @@ -79,6 +79,11 @@ class _DeviceTransferDetailsState extends State { _buildTextWidget('${context.translation.sn} : ${_model?.assetSerialNo ?? ""}'), if (_model?.receiverEndUserName != null) _buildTextWidget('${context.translation.receiverName} : ${_model?.receiverEndUserName ?? ""}'), _buildTextWidget('${context.translation.requestNo} : ${_model?.transferCode ?? ""}'), + //TODO need to confirm where to display this new data... + infoText(label:context.translation.gasRequest ,value:_model?.extensionNo ), + infoText(label:context.translation.employeeId ,value:_model?.employeeId ), + infoText(label:context.translation.name ,value:_model?.name ), + infoText(label:context.translation.createdDate ,value:_model?.createdDate?.toInitialVisitCardFormat), if ((_model?.comment ?? "").isNotEmpty) ...[ 8.height, const Divider().defaultStyle(context), @@ -223,4 +228,13 @@ class _DeviceTransferDetailsState extends State { ], ).toShadowContainer(context); } + Widget infoText({String ?label,String ?value,}){ + if(value==null||value.isEmpty){ + return const SizedBox(); + } + else { + return '$label: $value'.bodyText(context); + } + + } } diff --git a/lib/views/pages/user/gas_refill/gas_refill_details.dart b/lib/views/pages/user/gas_refill/gas_refill_details.dart index 036182f4..b341c310 100644 --- a/lib/views/pages/user/gas_refill/gas_refill_details.dart +++ b/lib/views/pages/user/gas_refill/gas_refill_details.dart @@ -108,12 +108,19 @@ class _GasRefillDetailsPageState extends State { 8.height, context.translation.gasRefillRequest.heading5(context), 8.height, + '${context.translation.gasRequest}: ${gasRefillModel.gazRefillDetails![0].gasType?.name}'.bodyText(context), '${context.translation.cylinderType}: ${gasRefillModel.gazRefillDetails![0].cylinderType?.name}'.bodyText(context), '${context.translation.cylinderSize}: ${gasRefillModel.gazRefillDetails![0].cylinderSize?.name}'.bodyText(context), '${context.translation.site}: ${gasRefillModel.site?.name?.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context), '${context.translation.department}: ${gasRefillModel.department?.name?.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context), '${context.translation.requestNo}: ${gasRefillModel.gazRefillNo}'.bodyText(context), + //TODO need to confirm where to display this new data... + infoText(label:context.translation.gasRequest ,value:gasRefillModel.extensionNo ), + infoText(label:context.translation.employeeId ,value:gasRefillModel.employeeId ), + infoText(label:context.translation.name ,value:gasRefillModel.name ), + infoText(label:context.translation.createdDate ,value:gasRefillModel.createdDate?.toInitialVisitCardFormat), + const Divider().defaultStyle(context), '${context.translation.requestedQuantity}: ${gasRefillModel.gazRefillDetails![0].requestedQty ?? 0}'.bodyText(context), '${context.translation.deliveredQuantity}: ${gasRefillModel.gazRefillDetails![0].deliverdQty ?? 0}'.bodyText(context), @@ -221,4 +228,14 @@ class _GasRefillDetailsPageState extends State { ], ).toShadowContainer(context, padding: 0); } + + Widget infoText({String ?label,String ?value,}){ + if(value==null||value.isEmpty){ + return const SizedBox(); + } + else { + return '$label: $value'.bodyText(context); + } + + } } diff --git a/lib/views/pages/user/gas_refill/request_gas_refill.dart b/lib/views/pages/user/gas_refill/request_gas_refill.dart index c5aa13df..462e30c7 100644 --- a/lib/views/pages/user/gas_refill/request_gas_refill.dart +++ b/lib/views/pages/user/gas_refill/request_gas_refill.dart @@ -176,6 +176,7 @@ class _RequestGasRefillState extends State { @override Widget build(BuildContext context) { + _userProvider = Provider.of(context); _settingProvider = Provider.of(context); _gasRefillProvider ??= Provider.of(context, listen: false); diff --git a/lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/asset_info_widget.dart b/lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/asset_info_widget.dart deleted file mode 100644 index 4ab4aa28..00000000 --- a/lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/asset_info_widget.dart +++ /dev/null @@ -1,116 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:test_sa/extensions/context_extension.dart'; -import 'package:test_sa/extensions/int_extensions.dart'; -import 'package:test_sa/extensions/text_extensions.dart'; -import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/all_requests_and_count_model.dart'; -import 'package:test_sa/models/ppm/ppm.dart'; -import 'package:test_sa/models/timer_model.dart'; -import 'package:test_sa/new_views/app_style/app_color.dart'; -import 'package:test_sa/service_request_latest/utilities/service_request_utils.dart'; -import 'package:test_sa/views/widgets/requests/request_status.dart'; -import 'package:test_sa/views/widgets/timer/app_timer.dart'; - -class AssetInfoWidget extends StatelessWidget { - DummyModel ?model; - AssetInfoWidget({super.key,DummyModel ?model}); - - @override - Widget build(BuildContext context) { - return Column( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (model?.request?.priority != null) - StatusLabel( - label: model?.request?.priority, - textColor: AppColor.getRequestStatusTextColorByName(context,model?.request?.priority), - backgroundColor: AppColor.getRequestStatusColorByName(context,model?.request?.priority), - ), - 8.height, - - model!.ppm!.assetName!.heading5(context), - 8.height, - '${context.translation.taskNo}: ${model!.ppm!.assetName}'.bodyText(context), - '${context.translation.site}: ${model!.ppm!.siteName!.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context), - '${context.translation.assignEngineer}: ${model!.ppm!.assignedEmployeeName ?? ""}'.bodyText(context), - '${context.translation.scheduledDate}: ${'July 7, 2024' ?? ""}'.bodyText(context), - ], - ).toShadowContainer(context), - 12.height, - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - buildingInfoWidget(label: context.translation.department, value: model!.ppm!.departmentName!.cleanupWhitespace.capitalizeFirstOfEach,context: context), - 8.height, - buildingInfoWidget(label: context.translation.floor, value: model!.ppm!.floorName!.cleanupWhitespace.capitalizeFirstOfEach,context: context), - 8.height, - buildingInfoWidget(label: context.translation.room, value: model!.ppm!.roomName!.cleanupWhitespace.capitalizeFirstOfEach,context: context), - 8.height, - AppTimer( - label: context.translation.timer, - timer: model!.timerModel, - width:double.infinity, - enabled: model!.timerModel?.endAt == null, - decoration: BoxDecoration( - color: AppColor.neutral100, - borderRadius: BorderRadius.circular(10), - ), - timerProgress: (isRunning) {}, - onChange: (timer) async { - timer = timer; - return true; - }, - ), - // if (totalWorkingHours > 0.0) ...[ - 11.height, - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - "Total Working Time: ", - style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500), - ), - Text( - " ${ServiceRequestUtils.formatTimerDuration(model!.totalWorkingHours.round())}", - style: Theme.of(context).textTheme.bodyMedium, - ), - ], - ), - 8.height, - ], - // ], - ).toShadowContainer(context,padding: 12), - ], - ); - } - - Widget buildingInfoWidget({required String label, required String value, required BuildContext context}) { - return Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - label, - style: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.neutral120), - ), - 3.height, - Text( - value, - style: AppTextStyles.bodyText2.copyWith(color: AppColor.black10), - ) - ], - ).toShadowContainer(context, backgroundColor: AppColor.neutral100, borderRadius: 10, paddingObject: EdgeInsets.all(12.toScreenHeight), showShadow: false); - } -} - -class DummyModel{ - RequestsDetails? request; - Ppm? ppm; - TimerModel? timerModel = TimerModel(); - double totalWorkingHours = 2; - - DummyModel(this.request,this.ppm,this.timerModel,this.totalWorkingHours); -} diff --git a/lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/room_inspection_card.dart b/lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/room_inspection_card.dart new file mode 100644 index 00000000..f827aef5 --- /dev/null +++ b/lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/room_inspection_card.dart @@ -0,0 +1,146 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:test_sa/dashboard_latest/dashboard_view.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/enums/recurrent_task_inspection_data_type.dart'; +import 'package:test_sa/models/ppm/recurrent_wo.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; + +class RoomInspectionCard extends StatefulWidget { + final PlanRecurrentMedicalTaskRoomTabs? inspectionModel; + + RoomInspectionCard({super.key, required this.inspectionModel}); + + @override + State createState() => _RoomInspectionCardState(); +} + +class _RoomInspectionCardState extends State { + late List inspectionValues; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + widget.inspectionModel!.tabName!.bodyText(context).custom(color: AppColor.neutral50, fontWeight: FontWeight.w600), + 8.height, + Column( + children: widget.inspectionModel!.planRecurrentMedicalTaskRoomTabAttributes?.asMap().entries.map((entry) { + final model = entry.value; + final attribute = model.attribute; + + switch (attribute?.dataTypeEnum) { + case RecurrentTaskInspectionDataTypeEnum.bool: + return inspectionStatusRadioWidget( + index: entry.key, + model: model, + context: context, + ); + case RecurrentTaskInspectionDataTypeEnum.number: + return inspectionStatusNumberWidget( + index: entry.key, + model: model, + context: context, + ); + default: + return const SizedBox.shrink(); // Handles any unexpected cases gracefully + } + }).toList() ?? + [], + ) + ], + ).toShadowContainer(context).paddingOnly(top: 12); + } + + Widget inspectionStatusRadioWidget({ + required int index, + required PlanRecurrentMedicalTaskRoomTabAttributes model, + required BuildContext context, + }) { + bool status = model.attribute != null + ? model.attributeValue == 'true' + ? true + : false + : false; + String statusString = status ? 'Pass' : 'Fail'; + + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + model.attribute!.name!.bodyText2(context).custom(color: AppColor.white936, fontWeight: FontWeight.w500), + statusString.bodyText2(context).custom(color: AppColor.neutral120, fontWeight: FontWeight.w500), + ], + ), + SizedBox( + height: 24.toScreenHeight, + width: 41.toScreenWidth, + child: CupertinoSwitch( + thumbColor: status ? AppColor.green50 : AppColor.red30, + activeColor: AppColor.green30, + trackColor: AppColor.red80, + value: status, + onChanged: (state) { + setState(() { + model.attributeValue = state; + status = state; + }); + }, + ), + ) + ], + ).paddingOnly(bottom: 12); + } + + Widget inspectionStatusNumberWidget({ + required int index, + required PlanRecurrentMedicalTaskRoomTabAttributes model, + required BuildContext context, + }) { + final border = OutlineInputBorder( + borderRadius: BorderRadius.circular(4), // Optional: Slight rounding + borderSide: const BorderSide( + color: AppColor.white70, // Border color + width: 1, // 1px border + ), + ); + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + model.attribute!.name!.bodyText2(context).custom(color: AppColor.white936, fontWeight: FontWeight.w500), + TextFormField( + keyboardType: TextInputType.number, + initialValue: model.attributeValue ?? '', + decoration: InputDecoration( + contentPadding: EdgeInsets.symmetric(horizontal: 5.toScreenWidth), + filled: true, + fillColor: AppColor.neutral100, + constraints: const BoxConstraints( + maxHeight: 30, + maxWidth: 50, + ), + border: border, + enabledBorder: border, + focusedBorder: border, + ), + onChanged: (value) { + model.attributeValue = value; + }, + ), + ], + ).paddingOnly(bottom: 12); + } +} diff --git a/lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/room_tabs_widget.dart b/lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/room_tabs_widget.dart new file mode 100644 index 00000000..decd93e1 --- /dev/null +++ b/lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/room_tabs_widget.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/ppm/recurrent_wo.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/room_inspection_card.dart'; +import 'package:test_sa/views/widgets/loaders/app_loading.dart'; + +class RoomTabsWidget extends StatefulWidget { + final RecurrentWoData? model; + const RoomTabsWidget({Key? key,required this.model}) : super(key: key); + + @override + State createState() => _RoomTabsWidgetState(); +} + +class _RoomTabsWidgetState extends State { + int selectedIndex = 0; + bool isLoading = false; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.all(8.toScreenHeight), + height: 57.toScreenHeight, + width: double.infinity, + decoration: BoxDecoration( + color: context.isDark ? AppColor.neutral50 : AppColor.white10, + borderRadius: BorderRadius.circular(10), + ), + child: ListView( + scrollDirection: Axis.horizontal, + // mainAxisAlignment: MainAxisAlignment.spaceAround, + children: widget.model!.planRecurrentMedicalTaskRooms!.asMap().entries.map((entry) { + final int index = entry.key; + final String label = entry.value.room!.roomId!; + return GestureDetector( + onTap: () { + setState(() { + isLoading = true; + selectedIndex = index; + //TODO replace with api response delay... + Future.delayed(const Duration(seconds: 1)).whenComplete(() { + setState(() { + isLoading = false; + }); + }); + }); + }, + child: Container( + // margin: EdgeInsets.only(right: 8.toScreenWidth), + height: 49.toScreenHeight, + padding: EdgeInsets.symmetric( + // vertical: 20.toScreenHeight, + horizontal: 30.toScreenWidth, + ), + alignment: Alignment.center, + decoration: BoxDecoration( + color: selectedIndex == index ? (context.isDark ? AppColor.neutral60 : AppColor.neutral110) : Colors.transparent, + borderRadius: BorderRadius.circular(7), + ), + child: label.bodyText(context).custom( + color:AppColor.white936, + ), + ), + ); + }).toList(), + ), + ), + isLoading + ? SizedBox(height: 120.toScreenHeight, child: const ALoading().center) + : ListView( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + children: widget.model!.planRecurrentMedicalTaskRooms![selectedIndex].planRecurrentMedicalTaskRoomTabs!.map((card) { + return RoomInspectionCard(inspectionModel: card); + }).toList(), + ), + ], + ); + } +} diff --git a/lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/task_info_widget.dart b/lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/task_info_widget.dart new file mode 100644 index 00000000..d3be2d64 --- /dev/null +++ b/lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/task_info_widget.dart @@ -0,0 +1,144 @@ +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/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/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/all_requests_and_count_model.dart'; +import 'package:test_sa/models/ppm/ppm.dart'; +import 'package:test_sa/models/ppm/recurrent_wo.dart'; +import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/service_request_latest/utilities/service_request_utils.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; +import 'package:test_sa/views/widgets/timer/app_timer.dart'; + +class RecurrentTaskInfoWidget extends StatelessWidget { + final RecurrentWoData? model; + + RecurrentTaskInfoWidget({super.key, required this.model}); + + @override + Widget build(BuildContext context) { + + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (model?.status != null) + StatusLabel( + label: model?.status?.name, + textColor: AppColor.getRequestStatusTextColorByName(context, model?.status?.name), + backgroundColor: AppColor.getRequestStatusColorByName(context, model?.status?.name), + ), + 8.height, + model!.site!.siteName!.bodyText(context).custom(color: AppColor.black10), + 2.height, + '${context.translation.taskNo}: ${model!.id!}'.bodyText2(context).custom(color: AppColor.neutral120), + '${context.translation.site}: ${model!.site!.siteName!}'.bodyText2(context).custom(color: AppColor.neutral120), + '${context.translation.assignEngineer}: ${model!.engineer!.userName ?? ""}'.bodyText2(context).custom(color: AppColor.neutral120), + '${context.translation.scheduledDate}: ${model!.scheduleDate!.toMonthYearFormat}'.bodyText2(context).custom(color: AppColor.neutral120), + ], + ).toShadowContainer(context), + 12.height, + model!.planRecurrentMedicalTaskRooms!.isEmpty + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buildingInfoWidget(label: context.translation.department, value: model!.department!.name!.cleanupWhitespace.capitalizeFirstOfEach, context: context), + 8.height, + buildingInfoWidget(label: context.translation.floor, value: model!.floor!.name!.cleanupWhitespace.capitalizeFirstOfEach, context: context), + 8.height, + buildingInfoWidget(label: context.translation.room, value: model!.room!.name!.cleanupWhitespace.capitalizeFirstOfEach, context: context), + 8.height, + _timerWidget(context, model!.totalWorkingHours!) + ], + // ], + ).toShadowContainer(context, padding: 12) + : _timerWidget(context, model!.totalWorkingHours!).toShadowContainer(context, padding: 12), + ], + ); + } + + Widget _timerWidget(BuildContext context, double totalWorkingHours) { + return Consumer( + + builder: (context, snapshot,child) { + return Column( + children: [ + AppTimer( + label: context.translation.timer, + timer: snapshot.recurrentWoData?.recurrentWoTimerModel, + width: double.infinity, + enabled: snapshot.recurrentWoData?.recurrentWoTimerModel?.endAt == null, + decoration: BoxDecoration( + color: AppColor.neutral100, + borderRadius: BorderRadius.circular(10), + ), + timerProgress: (isRunning) {}, + onChange: (timer) async { + snapshot.updateRecurrentWoTimer(timer: timer); + return true; + }, + ), + 11.height, + if (totalWorkingHours > 0.0) ...[ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + "Total Working Time: ", + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: context.isDark ? null : AppColor.neutral20, + fontWeight: FontWeight.w500, + ), + ), + Text( + " ${ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round())}", + style: Theme.of(context).textTheme.bodyMedium, + ), + ], + ), + ], + 8.height, + ], + ); + } + ); + } +} + +Widget buildingInfoWidget({required String label, required String value, required BuildContext context}) { + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + label, + style: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.neutral120), + ), + 3.height, + Text( + value, + style: AppTextStyles.bodyText2.copyWith(color: AppColor.black10), + ) + ], + ).toShadowContainer(context, backgroundColor: AppColor.neutral100, borderRadius: 10, paddingObject: EdgeInsets.all(12.toScreenHeight), showShadow: false); +} + +class DummyModel { + RequestsDetails? request; + Ppm? ppm; + TimerModel? timerModel = TimerModel(); + double totalWorkingHours = 2; + + DummyModel(this.request, this.ppm, this.timerModel, this.totalWorkingHours); +} diff --git a/lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/recurrent_work_order_view.dart b/lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/recurrent_work_order_view.dart index f4afb39f..81cfc5cf 100644 --- a/lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/recurrent_work_order_view.dart +++ b/lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/recurrent_work_order_view.dart @@ -1,23 +1,26 @@ import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; -import 'package:test_sa/controllers/providers/api/ppm_provider.dart'; -import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/all_requests_and_count_model.dart'; -import 'package:test_sa/models/enums/user_types.dart'; -import 'package:test_sa/models/ppm/ppm.dart'; -import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/models/ppm/recurrent_wo.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; -import 'package:test_sa/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/asset_info_widget.dart'; +import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/task_info_widget.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; +import '../../../../../../controllers/providers/api/all_requests_provider.dart'; +import 'components/room_tabs_widget.dart'; class RecurrentWorkOrderView extends StatefulWidget { - static const String id = "/visit-details"; - final RequestsDetails request; + static const String id = "/recurrent_wo"; + final int? taskId; - const RecurrentWorkOrderView({Key? key, required this.request}) : super(key: key); + RecurrentWorkOrderView({Key? key, required this.taskId}) : super(key: key); @override _RecurrentWorkOrderViewState createState() { @@ -26,15 +29,12 @@ class RecurrentWorkOrderView extends StatefulWidget { } class _RecurrentWorkOrderViewState extends State { - UserProvider? userProvider; - TimerModel? timerModel = TimerModel(); - PpmProvider? ppmProvider; - - // double totalWorkingHours = _requestDetailProvider?.activityMaintenanceHelperModel?.activityMaintenanceTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endTime!).difference(DateTime.parse(item.startTime!)).inSeconds) ?? 0; - double totalWorkingHours = 2.0; + AllRequestsProvider? allRequestsProvider; @override void initState() { + allRequestsProvider = Provider.of(context, listen: false); + Provider.of(context, listen: false).getRecurrentWoById(id: widget.taskId!); super.initState(); } @@ -45,50 +45,109 @@ class _RecurrentWorkOrderViewState extends State { @override Widget build(BuildContext context) { - userProvider ??= Provider.of(context, listen: false); - ppmProvider ??= Provider.of(context, listen: false); + return Consumer(builder: (context, requestProvider, child) { + return Scaffold( + appBar: DefaultAppBar(title: context.translation.recurrentWo), + body: allRequestsProvider!.isLoading + ? const ALoading() + : requestProvider.recurrentWoData != null + ? Stack( + children: [ + SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RecurrentTaskInfoWidget(model: requestProvider.recurrentWoData), + // 8.height, + requestProvider.recurrentWoData!.planRecurrentMedicalTaskRooms!.isNotEmpty + ? Column( + children: [ + 8.height, + RoomTabsWidget( + model: requestProvider.recurrentWoData, + ), + ], + ) + : const SizedBox(), + ], + ).paddingAll(12), + ).paddingOnly(bottom: 85), + FooterActionButton.footerContainer( + 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, + ); + }); + } +} + +void _updateTask({required BuildContext context, required int status}) async { + + AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); - return Scaffold( - appBar: DefaultAppBar(title: context.translation.recurrentWo), - body: SafeArea( - child: FutureBuilder( - future: ppmProvider!.getPlanPreventiveVisitById(widget.request.id!), - builder: (context, snap) { - if (snap.connectionState == ConnectionState.waiting) { - return const ALoading(); - } else if (snap.hasData) { - Ppm ppm = snap.data as Ppm; - return Column(children: [ - AssetInfoWidget(model: DummyModel(widget.request, ppm, timerModel, totalWorkingHours)), - ]).paddingAll(12); - } - return NoDataFound(message: context.translation.noDataFound); - }), + if(validate(model: allRequestsProvider.recurrentWoData!)){ + allRequestsProvider.recurrentWoData?.planRecurrentTaskTimers = allRequestsProvider.recurrentWoData?.planRecurrentTaskTimers ?? []; + DateTime ?startTime = allRequestsProvider.recurrentWoData?.recurrentWoTimerModel?.startAt; + DateTime ?endTime = allRequestsProvider.recurrentWoData?.recurrentWoTimerModel?.endAt; + final duration = (endTime?.difference(startTime!)); + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + allRequestsProvider.recurrentWoData?.planRecurrentTaskTimers?.add( + PlanRecurrentTaskTimers( + id: 0, + startTime: startTime?.toIso8601String(), + endTime: endTime?.toIso8601String(), + workingHours: (duration?.inSeconds ?? 0) / 60 / 60, ), ); + await allRequestsProvider.updateRecurrentWo( + status: status, + ).whenComplete((){ + if(status==1){// when click complete then this request remove from the list and status changes to closed.. + //TODO some issues data not properly refreshed need to check waseem + allRequestsProvider.getAllRequests(context,typeTransaction: 5); + } + allRequestsProvider.recurrentWoData?.recurrentWoTimerModel=null; + Navigator.pop(context); + Navigator.pop(context); + }); } -} - -class RoomTabs { - String label; - int tag; - int id; -// - RoomTabs({ - required this.label, - required this.tag, - required this.id, - }); - static List getTabs({required UsersTypes userType, required BuildContext context}) { - List tabs = []; +} - tabs.add(RoomTabs(label: 'Upcoming', tag: 0, id: 0)); - tabs.add(RoomTabs(label: 'UnAssigned Open', tag: 1, id: 1)); - tabs.add(RoomTabs(label: 'Assigned Open', tag: 1, id: 2)); - tabs.add(RoomTabs(label: 'In Progress', tag: 2, id: 3)); - tabs.add(RoomTabs(label: 'Completed', tag: 3, id: 4)); - return tabs; +bool validate({required RecurrentWoData model}) { + if (model.recurrentWoTimerModel?.startAt == null) { + Fluttertoast.showToast(msg: "Working Hours Required"); + return false; + } + if (model.recurrentWoTimerModel?.endAt == null) { + Fluttertoast.showToast(msg: "Please Stop The Timer"); + return false; } + return true; }