diff --git a/assets/images/arrived_icon.svg b/assets/images/arrived_icon.svg new file mode 100644 index 00000000..a5951d03 --- /dev/null +++ b/assets/images/arrived_icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/clock.svg b/assets/images/clock.svg new file mode 100644 index 00000000..7c816867 --- /dev/null +++ b/assets/images/clock.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/drag_icon.svg b/assets/images/drag_icon.svg new file mode 100644 index 00000000..168ad9f8 --- /dev/null +++ b/assets/images/drag_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/image-plus.svg b/assets/images/image-plus.svg new file mode 100644 index 00000000..105b9c3e --- /dev/null +++ b/assets/images/image-plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/request_icon.svg b/assets/images/request_icon.svg new file mode 100644 index 00000000..a0e0d462 --- /dev/null +++ b/assets/images/request_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/scan_asset.svg b/assets/images/scan_asset.svg new file mode 100644 index 00000000..b2dd1353 --- /dev/null +++ b/assets/images/scan_asset.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 03e76360..a28859a9 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -35,7 +35,11 @@ class URLs { static get engineerRejectUrl=> '$_baseUrl/ServiceRequest/EngineerReject'; static get engineerFixRemotlyUrl=> '$_baseUrl/ServiceRequest/EngineerFixRemotly'; static get engineerNeedVisitUrl=> '$_baseUrl/ServiceRequest/EngineerNeedVisit'; + static get engineerMarkAsFixUrl=> '$_baseUrl/ServiceRequest/EngineerMarkAsFix'; static get getWorkOrderByIdUrl=> '$_baseUrl/ServiceRequest/GetWorkOrderById'; + static get deleteActivitySparePartUrl=> '$_baseUrl/ServiceRequest/DeleteActivitySparePart'; + static get createActivitySparePartUrl=> '$_baseUrl/ServiceRequest/CreateActivitySparePart'; + static get updateActivitySparePartUrl=> '$_baseUrl/ServiceRequest/UpdateActivitySparePart'; static get assignEngineerToWorkOrderUrl=> '$_baseUrl/ServiceRequest/AssignEngineerToWorkOrder'; static get getDepartments => "$_baseUrl/Customer/GetDepartmentLookup"; // get static get getAssets => "$_baseUrl/Asset/GetAssets"; // get diff --git a/lib/controllers/providers/api/service_requests_provider.dart b/lib/controllers/providers/api/service_requests_provider.dart index 5d8e15e6..406eb304 100644 --- a/lib/controllers/providers/api/service_requests_provider.dart +++ b/lib/controllers/providers/api/service_requests_provider.dart @@ -44,6 +44,14 @@ class ServiceRequestsProvider extends ChangeNotifier { // 500 service not available int stateCode; bool _isDetialLoading=false; + bool _ackhnowledge = false; + + bool get ackhnowledge => _ackhnowledge; + + set ackhnowledge(bool value) { + _ackhnowledge = value; + notifyListeners(); + } bool get isDetialLoading => _isDetialLoading; diff --git a/lib/dashboard_latest/dashboard_view.dart b/lib/dashboard_latest/dashboard_view.dart index 56b2b048..a9348703 100644 --- a/lib/dashboard_latest/dashboard_view.dart +++ b/lib/dashboard_latest/dashboard_view.dart @@ -62,6 +62,8 @@ class _DashboardViewState extends State { allRequestsProvider = Provider.of(context, listen: false); notificationsProvider = Provider.of(context, listen: false); user = userProvider.user; + log('user token i got is ${user.token}'); + await getAllRequests(); await requestDetailProvider.engineerRejectWorkOrder(id: '3',feedBack: 'Abcdef'); diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index fa760b9e..4a5b7342 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -10,6 +10,14 @@ extension StringExtensions on String { DateTime dateTime = DateTime.tryParse(this); return "${DateFormat('dd MMM, yyyy').format(dateTime)}\n${DateFormat('hh:mm a').format(dateTime)}"; } + String get toDragAbleTimerFormat { + DateTime dateTime = DateTime.tryParse(this); + return DateFormat('HH:mm:ss').format(dateTime); + } + String get toInitialVisitCardFormat { + DateTime dateTime = DateTime.tryParse(this); + return "${DateFormat('dd MMM, yyyy').format(dateTime)} at ${DateFormat('hh:mm a').format(dateTime)}"; + } String get toServiceRequestDetailsFormat { try { diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index 35bf5d60..da5cb730 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -73,6 +73,21 @@ "brand": "ماركة", "clearSearch": "تنظيف البحث", "closed": "غلق", + "close": "يغلق", + "attachFiles": "إرفاق الملفات", + "hours": "ساعات", + "internal": "داخلي", + "external": "خارجي", + "addInternalActivity": "إضافة نشاط داخلي", + "addExternalActivity": "إضافة نشاط خارجي", + "remotely": "عن بُعد", + "workshop": "ورشة", + "activityStatus": "حالة النشاط", + "scanOrPickAsset": "امسح أو اختر الأصل", + "takeAction": "اتخذ إجراء", + "pleaseConfirmTheIssueHasBeenResolved": "يرجى تأكيد أن المشكلة قد تم حلها", + "nurseAcknowledge": "أقر بإكمال أمر العمل هذا", + "abroad": "خارج البلاد", "create": "انشاء", "createServiceRequest": "انشاء طلب خدمة", "delete": "مسح", @@ -276,6 +291,18 @@ "timeAndDuration": "الوقت والمدة", "assetsCondition": "حالة الأصول", "attachmentsAcknowledge": "إقرار & المرفقات", + "up_and_running": "قيد التشغيل", + "partially_down": "معطل جزئيًا", + "fully_down": "معطل تمامًا", + "verify_asset_details": "تحقق من تفاصيل الأصل", + "equipment_status": "حالة المعدات", + "failureReason": "سبب الفشل", + "visitDateAndTime": "تاريخ ووقت الزيارة", + "markAsFixed": "تحديد كإصلاح", + "iHaveArrived": "لقد وصلت", + "fixedRemotely": "تم الإصلاح عن بُعد", + "needAVisit": "بحاجة إلى زيارة", + "solutions": "الحلول", "welcome" : "مرحبا،", "openWhatsapp" : "الإنتقال الى الواتس اب", "callUs" : "إتصل بنا", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 275ff9a3..03163f06 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -69,6 +69,21 @@ "brand": "manufacture", "clearSearch": "Clear Search", "closed": "Closed", + "close": "Close", + "scanOrPickAsset": "Scan or Pick Asset", + "attachFiles": "Attach Files", + "activityStatus": "Activity Status", + "takeAction": "Take Action", + "pleaseConfirmTheIssueHasBeenResolved": "Please confirm the issue has been resolved", + "nurseAcknowledge": "I acknowledge the completion of this work order", + "hours": "Hours", + "internal": "Internal", + "external": "External", + "addInternalActivity": "Add Internal Activity", + "addExternalActivity": "Add External Activity", + "remotely": "Remotely", + "workshop": "Workshop", + "abroad": "Abroad", "create": "Create", "createServiceRequest": "Create Service Request", "delete": "Delete", @@ -248,6 +263,18 @@ "timeAndDuration": "Time and Duration", "assetsCondition": "Asset’s Condition", "attachmentsAcknowledge": "Attachments & Acknowledge", + "up_and_running": "Up & Running", + "partially_down": "Partially Down", + "needAVisit": "Need a Visit", + "fixedRemotely": "Fixed Remotely", + "iHaveArrived": "I have arrived", + "verify_asset_details": "Verify Asset Details", + "equipment_status": "Equipment Status", + "failureReason": "Failure Reason", + "visitDateAndTime": "Visit Date & Time", + "markAsFixed": "Mark as Fixed", + "fully_down": "Fully Down", + "solutions": "Solutions", "callUs" : "Call Us", "liveChat" : "Live Chat", "feedBack" : "Feedback", diff --git a/lib/models/helper_data_models/spare_part/activity_spare_part_model.dart b/lib/models/helper_data_models/spare_part/activity_spare_part_model.dart new file mode 100644 index 00000000..6293805e --- /dev/null +++ b/lib/models/helper_data_models/spare_part/activity_spare_part_model.dart @@ -0,0 +1,64 @@ +class ActivitySparePartModel { + int id; + int workOrderId; + int partCatalogItemId; + int quantity; + String comment; + List sparePartAttachments; + + ActivitySparePartModel( + {this.id, + this.workOrderId, + this.partCatalogItemId, + this.quantity, + this.comment, + this.sparePartAttachments}); + + ActivitySparePartModel.fromJson(Map json) { + id = json['id']; + workOrderId = json['workOrderId']; + partCatalogItemId = json['partCatalogItemId']; + quantity = json['quantity']; + comment = json['comment']; + if (json['acitiySparePartAttachments'] != null) { + sparePartAttachments = []; + json['acitiySparePartAttachments'].forEach((v) { + sparePartAttachments + .add(SparePartAttachments.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['workOrderId'] = workOrderId; + data['partCatalogItemId'] = partCatalogItemId; + data['quantity'] = quantity; + data['comment'] = comment; + if (sparePartAttachments != null) { + data['acitiySparePartAttachments'] = + sparePartAttachments.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class SparePartAttachments { + int id; + String name; + + SparePartAttachments({this.id, this.name}); + + SparePartAttachments.fromJson(Map json) { + id = json['id']; + name = json['name']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['name'] = name; + return data; + } +} diff --git a/lib/models/helper_data_models/workorder/mark_as_fixed_model.dart b/lib/models/helper_data_models/workorder/mark_as_fixed_model.dart new file mode 100644 index 00000000..a44cb687 --- /dev/null +++ b/lib/models/helper_data_models/workorder/mark_as_fixed_model.dart @@ -0,0 +1,23 @@ +class MarkAsFixed { + int workOrderId; + String feedback; + + MarkAsFixed({ + this.workOrderId, + this.feedback, + }); + + factory MarkAsFixed.fromJson(Map json) { + return MarkAsFixed( + workOrderId: json['workOrderId'], + feedback: json['feedback'], + ); + } + + Map toJson() { + return { + 'workOrderId': workOrderId, + 'feedback': feedback, + }; + } +} diff --git a/lib/models/lookup.dart b/lib/models/lookup.dart index 0878bae1..8552e081 100644 --- a/lib/models/lookup.dart +++ b/lib/models/lookup.dart @@ -25,6 +25,7 @@ class Lookup extends Base { } factory Lookup.fromJson(Map parsedJson) { + if (parsedJson == null) return null; return Lookup( name: parsedJson["name"], diff --git a/lib/models/new_models/workOrderDetail.dart b/lib/models/new_models/workOrderDetail.dart index 2841f195..249570c8 100644 --- a/lib/models/new_models/workOrderDetail.dart +++ b/lib/models/new_models/workOrderDetail.dart @@ -1,3 +1,5 @@ +import 'package:test_sa/models/lookup.dart'; + class WorkOrderDetail { WorkOrder data; String message; @@ -42,20 +44,20 @@ class WorkOrder { WorkOrderCreatedBy workOrderCreatedBy; DateTime requestedDate; Asset asset; - AssetGroup assetGroup; - Manufacturer manufacturer; - Model model; - AssetNDModel assetNDModel; + Lookup assetGroup; + Lookup manufacturer; + Lookup model; + Lookup assetNDModel; Site site; - Building building; - Floor floor; - Department department; + Lookup building; + Lookup floor; + Lookup department; dynamic room; - AssetType assetType; + Lookup assetType; AssignedEmployee assignedEmployee; dynamic lastActivityStatus; - Status status; - NextStep nextStep; + Lookup status; + Lookup nextStep; dynamic assetVerificationType; List workOrderContactPerson; EquipmentStatus equipmentStatus; @@ -128,20 +130,20 @@ class WorkOrder { workOrderCreatedBy: WorkOrderCreatedBy.fromJson(json['workOrderCreatedBy']), requestedDate: DateTime.parse(json['requestedDate']), asset: Asset.fromJson(json['asset']), - assetGroup: AssetGroup.fromJson(json['assetGroup']), - manufacturer: Manufacturer.fromJson(json['manufacturer']), - model: Model.fromJson(json['model']), - assetNDModel: AssetNDModel.fromJson(json['assetNDModel']), + assetGroup: json['assetGroup']??Lookup.fromJson(json['assetGroup']), + manufacturer:json['manufacturer']?? Lookup.fromJson(json['manufacturer']), + model: json['model']?? Lookup.fromJson(json['model']), + assetNDModel:json['assetNDModel']?? Lookup.fromJson(json['assetNDModel']), site: Site.fromJson(json['site']), - building: Building.fromJson(json['building']), - floor: Floor.fromJson(json['floor']), - department: Department.fromJson(json['department']), + building: json['building']??Lookup.fromJson(json['building']), + floor: json['floor']??Lookup.fromJson(json['floor']), + department:json['department']?? Lookup.fromJson(json['department']), room: json['room'], - assetType: AssetType.fromJson(json['assetType']), + assetType: json['assetType']??Lookup.fromJson(json['assetType']), assignedEmployee: AssignedEmployee.fromJson(json['assignedEmployee']), lastActivityStatus: json['lastActivityStatus'], - status: Status.fromJson(json['status']), - nextStep: NextStep.fromJson(json['nextStep']), + status: json['status']??Lookup.fromJson(json['status']), + nextStep: json['nextStep']??Lookup.fromJson(json['nextStep']), assetVerificationType: json['assetVerificationType'], workOrderContactPerson: (json['workOrderContactPerson'] as List) .map((i) => WorkOrderContactPerson.fromJson(i)) @@ -257,262 +259,6 @@ class Asset { } } -class AssetGroup { - int id; - String name; - - AssetGroup({this.id, this.name}); - - factory AssetGroup.fromJson(Map json) { - return AssetGroup( - id: json['id'], - name: json['name'], - ); - } - Map toJson() { - return { - 'id': id, - 'name': name, - }; - } - -} - -class Manufacturer { - int id; - String name; - - Manufacturer({this.id, this.name}); - - factory Manufacturer.fromJson(Map json) { - return Manufacturer( - id: json['id'], - name: json['name'], - ); - } - Map toJson() { - return { - 'id': id, - 'name': name, - }; - } -} - -class Model { - int id; - String name; - - Model({this.id, this.name}); - - factory Model.fromJson(Map json) { - return Model( - id: json['id'], - name: json['name'], - ); - } - Map toJson() { - return { - 'id': id, - 'name': name, - }; - } -} - -class AssetNDModel { - int id; - String name; - - AssetNDModel({this.id, this.name}); - - factory AssetNDModel.fromJson(Map json) { - return AssetNDModel( - id: json['id'], - name: json['name'], - ); - } - Map toJson() { - return { - 'id': id, - 'name': name, - }; - } -} - -class Site { - int id; - String siteName; - - Site({this.id, this.siteName}); - - factory Site.fromJson(Map json) { - return Site( - id: json['id'], - siteName: json['siteName'], - ); - } - Map toJson() { - return { - 'id': id, - 'siteName': siteName, - }; - } -} - -class Building { - int id; - String name; - int value; - - Building({this.id, this.name, this.value}); - - factory Building.fromJson(Map json) { - return Building( - id: json['id'], - name: json['name'], - value: json['value'], - ); - } - Map toJson() { - return { - 'id': id, - 'name': name, - 'value': value, - }; - } -} - -class Floor { - int id; - String name; - int value; - - Floor({this.id, this.name, this.value}); - - factory Floor.fromJson(Map json) { - return Floor( - id: json['id'], - name: json['name'], - value: json['value'], - ); - } - Map toJson() { - return { - 'id': id, - 'name': name, - 'value': value, - }; - } -} - -class Department { - int id; - String name; - - Department({this.id, this.name}); - - factory Department.fromJson(Map json) { - return Department( - id: json['id'], - name: json['name'], - ); - } - Map toJson() { - return { - 'id': id, - 'name': name, - }; - } -} - -class AssetType { - int id; - String name; - int value; - - AssetType({this.id, this.name, this.value}); - - factory AssetType.fromJson(Map json) { - return AssetType( - id: json['id'], - name: json['name'], - value: json['value'], - ); - } - Map toJson() { - return { - 'id': id, - 'name': name, - 'value': value, - }; - } -} - -class AssignedEmployee { - String id; - String userName; - - AssignedEmployee({this.id, this.userName}); - - factory AssignedEmployee.fromJson(Map json) { - return AssignedEmployee( - id: json['id'], - userName: json['userName'], - ); - } - Map toJson() { - return { - 'id': id, - 'userName': userName, - }; - } -} - -class Status { - int id; - String name; - int value; - - Status({this.id, this.name, this.value}); - - factory Status.fromJson(Map json) { - return Status( - id: json['id'], - name: json['name'], - value: json['value'], - ); - } - Map toJson() { - return { - 'id': id, - 'name': name, - 'value': value, - }; - } -} - -class NextStep { - int id; - String name; - int value; - - NextStep({this.id, this.name, this.value}); - - factory NextStep.fromJson(Map json) { - return NextStep( - id: json['id'], - name: json['name'], - value: json['value'], - ); - } - Map toJson() { - return { - 'id': id, - 'name': name, - 'value': value, - }; - } -} - class WorkOrderContactPerson { int id; String name; @@ -585,6 +331,266 @@ class ContactUser { } } +class AssignedEmployee { + String id; + String userName; + + AssignedEmployee({this.id, this.userName}); + + factory AssignedEmployee.fromJson(Map json) { + return AssignedEmployee( + id: json['id'], + userName: json['userName'], + ); + } + Map toJson() { + return { + 'id': id, + 'userName': userName, + }; + } +} + +class Site { + int id; + String siteName; + + Site({this.id, this.siteName}); + + factory Site.fromJson(Map json) { + return Site( + id: json['id'], + siteName: json['siteName'], + ); + } + Map toJson() { + return { + 'id': id, + 'siteName': siteName, + }; + } +} + +/// + +// class AssetGroup { +// int id; +// String name; +// +// AssetGroup({this.id, this.name}); +// +// factory AssetGroup.fromJson(Map json) { +// return AssetGroup( +// id: json['id'], +// name: json['name'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// }; +// } +// +// } +// +// class Manufacturer { +// int id; +// String name; +// +// Manufacturer({this.id, this.name}); +// +// factory Manufacturer.fromJson(Map json) { +// return Manufacturer( +// id: json['id'], +// name: json['name'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// }; +// } +// } +// +// class Model { +// int id; +// String name; +// +// Model({this.id, this.name}); +// +// factory Model.fromJson(Map json) { +// return Model( +// id: json['id'], +// name: json['name'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// }; +// } +// } +// +// class AssetNDModel { +// int id; +// String name; +// +// AssetNDModel({this.id, this.name}); +// +// factory AssetNDModel.fromJson(Map json) { +// return AssetNDModel( +// id: json['id'], +// name: json['name'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// }; +// } +// } +// +// class Building { +// int id; +// String name; +// int value; +// +// Building({this.id, this.name, this.value}); +// +// factory Building.fromJson(Map json) { +// return Building( +// id: json['id'], +// name: json['name'], +// value: json['value'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// 'value': value, +// }; +// } +// } +// +// class Floor { +// int id; +// String name; +// int value; +// +// Floor({this.id, this.name, this.value}); +// +// factory Floor.fromJson(Map json) { +// return Floor( +// id: json['id'], +// name: json['name'], +// value: json['value'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// 'value': value, +// }; +// } +// } +// +// class Department { +// int id; +// String name; +// +// Department({this.id, this.name}); +// +// factory Department.fromJson(Map json) { +// return Department( +// id: json['id'], +// name: json['name'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// }; +// } +// } +// +// class AssetType { +// int id; +// String name; +// int value; +// +// AssetType({this.id, this.name, this.value}); +// +// factory AssetType.fromJson(Map json) { +// return AssetType( +// id: json['id'], +// name: json['name'], +// value: json['value'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// 'value': value, +// }; +// } +// } +// +// class Status { +// int id; +// String name; +// int value; +// +// Status({this.id, this.name, this.value}); +// +// factory Status.fromJson(Map json) { +// return Status( +// id: json['id'], +// name: json['name'], +// value: json['value'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// 'value': value, +// }; +// } +// } +// +// class NextStep { +// int id; +// String name; +// int value; +// +// NextStep({this.id, this.name, this.value}); +// +// factory NextStep.fromJson(Map json) { +// return NextStep( +// id: json['id'], +// name: json['name'], +// value: json['value'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// 'value': value, +// }; +// } +// } + + + class EquipmentStatus { int id; @@ -694,11 +700,11 @@ class ProblemDescription { class WorkOrderHistory { int id; - WorkOrderStatus workOrderStatus; + Lookup workOrderStatus; dynamic activityStatus; // Since activityStatus is null, it's dynamic String date; HistoryUser user; - Step step; + Lookup step; dynamic fixRemotelyStartTime; // Since it's null, it's dynamic dynamic fixRemotelyEndTime; // Since it's null, it's dynamic dynamic fixRemotelyWorkingHours; // Since it's null, it's dynamic @@ -722,11 +728,12 @@ class WorkOrderHistory { factory WorkOrderHistory.fromJson(Map json) { return WorkOrderHistory( id: json['id'], - workOrderStatus: WorkOrderStatus.fromJson(json['workorderStatus']), + //json['assetType'] != null ? Lookup.fromJson(json['assetType']) : null; + workOrderStatus:json['workorderStatus']??Lookup.fromJson(json['workorderStatus']), activityStatus: json['activityStatus'], date: json['date'], user: HistoryUser.fromJson(json['user']), - step: Step.fromJson(json['step']), + step: json['step']??Lookup.fromJson(json['step']), fixRemotelyStartTime: json['fixRemotlyStartTime'], fixRemotelyEndTime: json['fixRemotlyEndTime'], fixRemotelyWorkingHours: json['fixRemotlyWorkingHours'], @@ -738,6 +745,7 @@ class WorkOrderHistory { Map toJson() { return { 'id': id, + // Lookup.fromJson(json['workorderStatus']) 'workorderStatus': workOrderStatus.toJson(), 'activityStatus': activityStatus, 'date': date, @@ -752,33 +760,33 @@ class WorkOrderHistory { } } -class WorkOrderStatus { - int id; - String name; - int value; - - WorkOrderStatus({ - this.id, - this.name, - this.value, - }); - - factory WorkOrderStatus.fromJson(Map json) { - return WorkOrderStatus( - id: json['id'], - name: json['name'], - value: json['value'], - ); - } - - Map toJson() { - return { - 'id': id, - 'name': name, - 'value': value, - }; - } -} +// class WorkOrderStatus { +// int id; +// String name; +// int value; +// +// WorkOrderStatus({ +// this.id, +// this.name, +// this.value, +// }); +// +// factory WorkOrderStatus.fromJson(Map json) { +// return WorkOrderStatus( +// id: json['id'], +// name: json['name'], +// value: json['value'], +// ); +// } +// +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// 'value': value, +// }; +// } +// } class HistoryUser { String id; @@ -804,31 +812,31 @@ class HistoryUser { } } -class Step { - int id; - String name; - int value; - - Step({ - this.id, - this.name, - this.value, - }); - - factory Step.fromJson(Map json) { - return Step( - id: json['id'], - name: json['name'], - value: json['value'], - ); - } - - Map toJson() { - return { - 'id': id, - 'name': name, - 'value': value, - }; - } -} +// class Step { +// int id; +// String name; +// int value; +// +// Step({ +// this.id, +// this.name, +// this.value, +// }); +// +// factory Step.fromJson(Map json) { +// return Step( +// id: json['id'], +// name: json['name'], +// value: json['value'], +// ); +// } +// +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// 'value': value, +// }; +// } +// } diff --git a/lib/new_views/app_style/app_color.dart b/lib/new_views/app_style/app_color.dart index 534cef25..1e57e0c8 100644 --- a/lib/new_views/app_style/app_color.dart +++ b/lib/new_views/app_style/app_color.dart @@ -50,6 +50,7 @@ class AppColor { static const Color red40 = Color(0xffFFDBDC); static const Color red50 = Color(0xffD02127); static const Color red60 = Color(0xff8C050A); + static const Color red70 = Color(0xffF63939); //green static const Color green40 = Color(0xffBAFFE1); diff --git a/lib/new_views/common_widgets/app_bottom_nav_bar.dart b/lib/new_views/common_widgets/app_bottom_nav_bar.dart index a78839dd..13da57ae 100644 --- a/lib/new_views/common_widgets/app_bottom_nav_bar.dart +++ b/lib/new_views/common_widgets/app_bottom_nav_bar.dart @@ -26,7 +26,7 @@ class AppBottomNavigationBar extends StatelessWidget { child: BottomNavigationBar( items: [ navBarItem(context, index: 0, iconName: "overview", label: context.translation.overview), - navBarItem(context, index: 1, iconName: "requests", label: context.translation.request), + navBarItem(context, index: 1, iconName: "request_icon", label: context.translation.request), if (!isEngineer) navBarItem(context, index: 2, iconName: "add_icon", label: context.translation.calendar, showLabel: false), navBarItem(context, index: !isEngineer ? 3 : 2, iconName: "assets", label: context.translation.assets), navBarItem(context, index: !isEngineer ? 4 : 3, iconName: "contact", label: context.translation.contact), diff --git a/lib/new_views/common_widgets/app_dashed_button.dart b/lib/new_views/common_widgets/app_dashed_button.dart index 757d9d77..9fc2f841 100644 --- a/lib/new_views/common_widgets/app_dashed_button.dart +++ b/lib/new_views/common_widgets/app_dashed_button.dart @@ -11,9 +11,10 @@ class AppDashedButton extends StatelessWidget { final String title; final VoidCallback onPressed; double height; + Color buttonColor; Widget icon; - AppDashedButton({@required this.title, @required this.onPressed, Key key,this.height,this.icon}) : super(key: key); + AppDashedButton({@required this.title, @required this.onPressed, Key key,this.height,this.icon,this.buttonColor}) : super(key: key); @override Widget build(BuildContext context) { @@ -25,7 +26,7 @@ class AppDashedButton extends StatelessWidget { child: DottedBorder( strokeWidth: 1, padding: EdgeInsets.symmetric(vertical: 16.toScreenHeight, horizontal: 16.toScreenWidth), - color: context.isDark ? AppColor.primary40 : AppColor.black20, + color: context.isDark ? AppColor.primary40 : buttonColor?? AppColor.black20, dashPattern: const [4, 3], radius: const Radius.circular(10), borderType: BorderType.RRect, @@ -35,10 +36,10 @@ class AppDashedButton extends StatelessWidget { children: [ icon, 7.width, - title.heading6(context).custom(color: context.isDark ? AppColor.primary40 : AppColor.black10).center, + title.heading6(context).custom(color: context.isDark ? AppColor.primary40 : buttonColor??AppColor.black10).center, ], ): - title.heading6(context).custom(color: context.isDark ? AppColor.primary40 : AppColor.primary10).center, + title.heading6(context).custom(color: context.isDark ? AppColor.primary40 : buttonColor?? AppColor.primary10).center, ), ).onPress(onPressed); } diff --git a/lib/new_views/common_widgets/app_filled_button.dart b/lib/new_views/common_widgets/app_filled_button.dart index a9d46b53..a1f8577f 100644 --- a/lib/new_views/common_widgets/app_filled_button.dart +++ b/lib/new_views/common_widgets/app_filled_button.dart @@ -11,13 +11,17 @@ class AppFilledButton extends StatelessWidget { final Color buttonColor; final Color textColor; final bool showBorder; + final bool showIcon; + final Widget icon; const AppFilledButton({ @required this.onPressed, @required this.label, this.maxWidth = false, + this.icon, this.loading = false, this.showBorder = false, + this.showIcon = false, this.buttonColor, this.textColor, Key key, @@ -43,7 +47,18 @@ class AppFilledButton extends StatelessWidget { strokeWidth: 2, ), ) - : label.heading6(context).custom(color: textColor ?? AppColor.background(context)), + : showIcon&&icon!=null? + Center( + child: Row( + mainAxisSize:MainAxisSize.min, + children: [ + icon, + 8.width, + label.heading6(context).custom(color: textColor ?? AppColor.background(context)) + ], + ), + ): + label.heading6(context).custom(color: textColor ?? AppColor.background(context)), ).onPress(onPressed); } } diff --git a/lib/new_views/pages/land_page/land_page.dart b/lib/new_views/pages/land_page/land_page.dart index 82967ba0..2fb2ad43 100644 --- a/lib/new_views/pages/land_page/land_page.dart +++ b/lib/new_views/pages/land_page/land_page.dart @@ -1,3 +1,4 @@ +import 'dart:developer'; import 'dart:io'; import 'package:flutter/material.dart'; diff --git a/lib/service_request_latest/request_detail_provider.dart b/lib/service_request_latest/request_detail_provider.dart index 216efe9a..efd32140 100644 --- a/lib/service_request_latest/request_detail_provider.dart +++ b/lib/service_request_latest/request_detail_provider.dart @@ -1,25 +1,16 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.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/extensions/string_extensions.dart'; +import 'package:test_sa/models/helper_data_models/spare_part/activity_spare_part_model.dart'; import 'package:test_sa/models/helper_data_models/workorder/fix_remotely_model.dart'; +import 'package:test_sa/models/helper_data_models/workorder/mark_as_fixed_model.dart'; import 'package:test_sa/models/helper_data_models/workorder/need_visit_model.dart'; import 'package:test_sa/models/helper_data_models/workorder/nurse_action_model.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; import 'package:test_sa/models/new_models/workOrderDetail.dart'; -import 'package:test_sa/models/service_request/service_report.dart'; -import 'package:test_sa/models/service_request/service_request.dart'; -import 'package:test_sa/models/service_request/spare_parts.dart'; -import 'package:test_sa/models/service_request/supp_engineer_work_orders.dart'; -import 'package:test_sa/models/service_request/supplier_engineer_model.dart'; -import '../../../models/service_request/wo_call_request.dart'; -import '../../../models/user.dart'; -import '../../../new_views/common_widgets/app_lazy_loading.dart'; class RequestDetailProvider extends ChangeNotifier { final pageItemNumber = 10; @@ -28,6 +19,33 @@ class RequestDetailProvider extends ChangeNotifier { stateCode = null; } + DateTime timerStartTime = DateTime(0, 0, 0, 0, 0, 0); // Start from 00:00:00 + Timer timer; + bool isTimerRunning = false; + + void startTimer() { + if (isTimerRunning) return; + timer = Timer.periodic(const Duration(seconds: 1), (Timer t) { + timerStartTime = timerStartTime.add(const Duration(seconds: 1)); + notifyListeners(); // Notify UI when time is updated + }); + isTimerRunning = true; + notifyListeners(); // Notify UI when timer starts + } + + void stopTimer() { + timer?.cancel(); + isTimerRunning = false; + notifyListeners(); // Notify UI when timer stops + } + + void resetTimer() { + timerStartTime = DateTime(0, 0, 0, 0, 0, 0); // Reset to 00:00:00 + notifyListeners(); + } + + // Getter to get the current time + DateTime get currentTime => timerStartTime; bool _isLoading = false; @@ -41,6 +59,23 @@ class RequestDetailProvider extends ChangeNotifier { WorkOrderDetail _currentWorkOrder; FixRemotely _fixRemotelyModel; NeedVisit _needVisitModel; + MarkAsFixed _markAsFixed; + ActivitySparePartModel _activitySparePartModel; + + ActivitySparePartModel get activitySparePartModel => _activitySparePartModel; + + set activitySparePartModel(ActivitySparePartModel value) { + _activitySparePartModel = value; + notifyListeners(); + } + + MarkAsFixed get markAsFixed => _markAsFixed; + + set markAsFixed(MarkAsFixed value) { + _markAsFixed = value; + notifyListeners(); + } + NurseActionModel _nurseActionModel; @@ -83,8 +118,6 @@ class RequestDetailProvider extends ChangeNotifier { _selectedTime = value; notifyListeners(); } // list of user requests - - SparePartsWorkOrders _initialSelectedSparePart = SparePartsWorkOrders(); int _selectedListIndex = 0; int get selectedListIndex => _selectedListIndex; @@ -219,6 +252,30 @@ class RequestDetailProvider extends ChangeNotifier { return CommonResponseModel(); } } + //engineerMarkAsFixed...... + Future engineerMarkAsFixed() async { + try { + isLoading = true; + final response = await ApiManager.instance.post(URLs.engineerMarkAsFixUrl,body: markAsFixed.toJson()); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + CommonResponseModel commonResponseModel = CommonResponseModel.fromJson(json.decode(response.body)); + print('response of Engineer mark as fixed ${commonResponseModel.toJson()}'); + notifyListeners(); + isLoading = false; + return commonResponseModel; + } + isLoading= false; + notifyListeners(); + return CommonResponseModel(); + } + catch (e) { + log("engineer accept [error] : $e"); + isLoading = false; + notifyListeners(); + return CommonResponseModel(); + } + } //assignEngineerToWorkOrder...... Future assignEngineerWorkOrder({@required String workOrderId,@required String engineerId}) async { try { @@ -297,74 +354,12 @@ class RequestDetailProvider extends ChangeNotifier { } - Future updateRequest({@required User user, @required ServiceRequest request}) async { + Future updateActivitySparePart({@required ActivitySparePartModel activitySparePartModel}) async { isLoading = true; - notifyListeners(); - Map serviceRequest = await getWorkOrderById(id: request.id) ?? ""; - final List callSiteContacts = (serviceRequest['callSiteContactPerson'] as List); - final Map callSiteContactPerson = callSiteContacts.isEmpty ? {} : callSiteContacts[0]; - Response response; try { - if ((request.audio ?? "").isNotEmpty) { - request.audio = request.audio.substring(request.audio.indexOf("=") + 1, request.audio.length); - } - } catch (ex) {} - - var body = { - "id": request.id, - "callNo": serviceRequest['callNo'], - "callCreatedBy": serviceRequest['callCreatedBy'], - "requestedDate": request.date ?? "", - "requestedTime": request.date ?? "", - "priority": request.priority?.toJson(), - "defectType": request.defectType?.toJson(), - "typeofRequest": request.type?.toJson(), - "requestedThrough": request.requestedThrough?.toJson(), - "voiceNote": request.audio, - "assets": request.deviceId == null ? [] : [request.deviceId], - "attachmentsCallRequest": (request.devicePhotos?.isNotEmpty ?? false) ? request.devicePhotos?.map((e) => {"name": e.getFileName})?.toList() : [], - "assignedEmployee": { - "id": request.engineerId, - "name": request.engineerName, - }, - "callSiteContactPerson": [ - { - "id": callSiteContactPerson['id'] ?? 0, - "employeeCode": callSiteContactPerson['employeeCode'], - "name": callSiteContactPerson['name'] ?? user.userName, - "telephone": callSiteContactPerson['telephone'] ?? user.phoneNumber, - "job": callSiteContactPerson['job'], - "email": callSiteContactPerson['email'] ?? user.email, - "land": callSiteContactPerson['land'], - "contactUserId": user.userID, - }, - ], - "callComments": request.callComments, - "noofFollowup": 0, - "status": request.statusId == null - ? null - : { - "id": request.statusId, - "name": request.statusLabel, - "value": request.statusValue, - }, - "callLastSituation": null, - "firstAction": request.firstAction?.toJson(), - "loanAvailablity": request.loanAvailability?.toJson(), - "comments": request.comments, - "firstActionDate": request.visitDate, - "visitDate": request.visitDate, - "startDate": request.startDate, - "endDate": request.endDate, - "workingHours": request.workingHours, - "callReview": null, - "reviewComment": null, - //"reviewComment": request.reviewComment, - }; - try { - response = await ApiManager.instance.put( - URLs.updateRequestDate, - body: body, + final response = await ApiManager.instance.put( + URLs.updateActivitySparePartUrl, + body: activitySparePartModel.toJson(), ); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { @@ -380,71 +375,50 @@ class RequestDetailProvider extends ChangeNotifier { return -1; } } - - Future createServiceReport(BuildContext context, {@required ServiceReport report, @required User user, @required ServiceRequest request}) async { - Response response; + Future deleteActivitySparePart({@required int id,@required int workOrderId}) async { + isLoading = true; + var body = { + 'id':id, + 'workOrderId':workOrderId, + }; try { - showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - final body = report.toJson(); - final callRequest = CallRequest(id: num.tryParse(request?.id ?? "")).toJson(); - final contactPerson = [ - { - "id": 0, - // "employeeCode": "", - "name": user.userName, - "telephone": user.phoneNumber, - // "job": "", - "email": user.email, - // "land": "", - "contactUserId": user.userID, - } - ]; - body.update("contactPersonWorkOrders", (value) => contactPerson, ifAbsent: () => contactPerson); - body.update("callRequest", (value) => callRequest, ifAbsent: () => callRequest); - response = await ApiManager.instance.post(URLs.createServiceReport, body: body); + final response = await ApiManager.instance.post( + URLs.deleteActivitySparePartUrl, + body: body, + ); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { - reset(); + //map to the model... notifyListeners(); - Fluttertoast.showToast(msg: context.translation.successfulRequestMessage); - Navigator.of(context).pop(); - } else { - Fluttertoast.showToast(msg: "${context.translation.failedToCompleteRequest}: ${json.decode(response.body)['message']}"); } - Navigator.pop(context); + isLoading = false; + notifyListeners(); return response.statusCode; } catch (error) { - Navigator.pop(context); - print(error); + isLoading = false; + notifyListeners(); return -1; } } - - Future addSupplierEngineer(SupplierEngineer supplierEngineer) async { + Future createActivitySparePart({@required ActivitySparePartModel activitySparePartModel}) async { isLoading = true; - notifyListeners(); - Response response; - SuppEngineerWorkOrders res; try { - response = await ApiManager.instance.post(URLs.addSupplierEngineer, body: supplierEngineer.toJson()); + final response = await ApiManager.instance.put( + URLs.createActivitySparePartUrl, + body: activitySparePartModel.toJson(), + ); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { - res = SuppEngineerWorkOrders.fromJson(json.decode(response.body)["data"]); + // request.engineerName = employee.name; + notifyListeners(); } isLoading = false; notifyListeners(); - return res; + return response.statusCode; } catch (error) { isLoading = false; notifyListeners(); - return res; + return -1; } } - - SparePartsWorkOrders get initialSelectedSparePart => _initialSelectedSparePart; - - set initialSelectedSparePart(SparePartsWorkOrders value) { - _initialSelectedSparePart = value; - notifyListeners(); - } } diff --git a/lib/service_request_latest/views/components/action_button/footer_action_button.dart b/lib/service_request_latest/views/components/action_button/footer_action_button.dart new file mode 100644 index 00000000..09b6b349 --- /dev/null +++ b/lib/service_request_latest/views/components/action_button/footer_action_button.dart @@ -0,0 +1,165 @@ +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/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart'; + +class FooterActionButton { + + static Widget footerContainer({@required Widget child}){ + return Align( + alignment: Alignment.bottomCenter, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth,vertical: 16.toScreenHeight), + color: AppColor.white10, + child: child, + ), + ); + } + + static Widget footerWidget({@required int status,@required BuildContext context}){ + switch(status){ + //accept reject... + case 1: + return footerContainer( + child: + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + AppFilledButton( + label: context.translation.reject, + maxWidth: true, + buttonColor: Colors.white54, + textColor: AppColor.red30, + showBorder: true, + onPressed: () async { + ServiceRequestBottomSheet.rejectRequestBottomSheet(context: context); + }, + ).expanded, + const SizedBox( + width: 20, + ), + AppFilledButton( + label: context.translation.accept, + maxWidth: true, + buttonColor: AppColor.green70, + onPressed: () async { + }, + ).expanded, + ], + ) + ); + break; + //need visit fixed remotely + case 2: + return footerContainer( + child: + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + AppFilledButton( + label: context.translation.needAVisit, + maxWidth: true, + buttonColor: AppColor.neutral50, + onPressed: () async { + ServiceRequestBottomSheet.initialVisitBottomSheet(context: context); + }, + ).expanded, + const SizedBox( + width: 20, + ), + AppFilledButton( + label: context.translation.fixedRemotely, + maxWidth: true, + buttonColor: AppColor.green70, + onPressed: () async { + ServiceRequestBottomSheet.fixRemotelyBottomSheet(context: context); + }, + ).expanded, + ], + ) + ); + break; + //verify Asset Details + case 3: + return footerContainer( + child: + AppFilledButton( + label: context.translation.verify_asset_details, + // maxWidth: true, + buttonColor: AppColor.primary10, + onPressed: () async { + + }, + ) + ); + break; + //Activities + case 4: + return footerContainer( + child: + AppFilledButton( + label: context.translation.activities, + // maxWidth: true, + buttonColor: AppColor.neutral50, + onPressed: () async { + ServiceRequestBottomSheet.activityTypeBottomSheet(context: context); + }, + ) + ); + break; + //I have arrived... + case 5: + return footerContainer( + child: + AppFilledButton( + label: context.translation.iHaveArrived, + showIcon: true, + icon: 'arrived_icon'.toSvgAsset(), + buttonColor: AppColor.green70, + onPressed: () async { + + }, + ) + ); + break; + //Close.. + case 6: + return footerContainer( + child: + AppFilledButton( + label: context.translation.close, + // maxWidth: true, + buttonColor: AppColor.primary10, + onPressed: () async { + + }, + ) + ); + break; + //for nurse to take action... + case 7: + return footerContainer( + child: + AppFilledButton( + label: context.translation.takeAction, + // maxWidth: true, + buttonColor: AppColor.primary10, + onPressed: () async { + + }, + ) + ); + break; + + default: + return const SizedBox(); + } + + } +} diff --git a/lib/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart b/lib/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart index 599854c6..3954fcf1 100644 --- a/lib/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart +++ b/lib/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart @@ -1,15 +1,14 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/app_strings/app_asset.dart'; -import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/device/asset.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/service_request/service_request.dart'; import 'package:test_sa/models/timer_model.dart'; @@ -18,215 +17,13 @@ import 'package:test_sa/providers/service_request_providers/first_action_provide import 'package:test_sa/service_request_latest/views/forms/spare_part/spare_part_request.dart'; import 'package:test_sa/service_request_latest/views/components/verify_arrival_view.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; -import 'package:test_sa/views/widgets/date_and_time/time_picker.dart'; +import 'package:test_sa/views/widgets/e_signature/e_signature.dart'; import 'package:test_sa/views/widgets/timer/app_timer.dart'; import '../../../../controllers/providers/api/service_requests_provider.dart'; import '../../../../new_views/app_style/app_color.dart'; import '../../../../new_views/common_widgets/app_filled_button.dart'; import '../../../../new_views/common_widgets/app_text_form_field.dart'; -// class FixRemotlyBottomSheet extends StatelessWidget { -// -// FixRemotlyBottomSheet({Key key,}) : super(key: key); -// -// final GlobalKey _formKey = GlobalKey(); -// -// @override -// Widget build(BuildContext context) { -// return Consumer( -// builder: (context, serviceRequestProvider,child) { -// return StatefulBuilder( -// builder: (BuildContext context, StateSetter setState) { -// return Container( -// clipBehavior: Clip.antiAlias, -// margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), -// decoration: BoxDecoration( -// color: AppColor.background(context), -// borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), -// ), -// padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), -// child: Form( -// key: _formKey, -// child: SingleChildScrollView( -// child: Column( -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// Center( -// child: Container( -// width: 40.toScreenWidth, -// height: 5.toScreenHeight, -// decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), -// ), -// ), -// Align( -// alignment: AlignmentDirectional.centerStart, -// child: context.translation.fillDetails.heading5(context).custom(fontWeight: FontWeight.w500).paddingOnly(top: 16, bottom: 16), -// ), -// -// 8.height, -// ADatePicker( -// label: context.translation.date, -// height: 80.toScreenHeight, -// backgroundColor: AppColor.neutral90, -// date: DateTime.tryParse(serviceRequestProvider.serviceRequest.startDate ?? ""), -// formatDateWithTime: true, -// onDatePicker: (selectedDate) { -// if (selectedDate != null) { -// showTimePicker( -// context: context, -// initialTime: TimeOfDay.now(), -// ).then((selectedTime) { -// // Handle the selected date and time here. -// if (selectedTime != null) { -// DateTime selectedDateTime = DateTime( -// selectedDate.year, -// selectedDate.month, -// selectedDate.day, -// selectedTime.hour, -// selectedTime.minute, -// ); -// if (selectedDateTime != null) { -// if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.serviceRequest.date))) { -// "Visit Date time must be greater then request date".showToast; -// return; -// } -// -// setState(() { -// serviceRequestProvider.serviceRequest.startDate = selectedDateTime?.toIso8601String(); -// }); -// } -// } -// }); -// } -// }, -// ), -// 8.height, -// ATimePicker( -// label: context.translation.startTime, -// height: 80.toScreenHeight, -// backgroundColor: AppColor.neutral90, -// hint:context.translation.pickTime, -// time: serviceRequestProvider.selectedTime, -// onTimePicker: (selectedTime) { -// //TODO handle selected time here. -// if (selectedTime != null) { -// setState(() { -// serviceRequestProvider.selectedTime = selectedTime; -// }); -// // DateTime selectedDateTime = DateTime( -// // selectedDate.year, -// // selectedDate.month, -// // selectedDate.day, -// // selectedTime.hour, -// // selectedTime.minute, -// // ); -// // if (selectedDateTime != null) { -// // if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.serviceRequest.date))) { -// // "Visit Date time must be greater then request date".showToast; -// // return; -// // } -// // -// -// // } -// } -// }, -// ), -// 8.height, -// ATimePicker( -// label: context.translation.endTime, -// height: 80.toScreenHeight, -// backgroundColor: AppColor.neutral90, -// hint:context.translation.pickTime, -// time: serviceRequestProvider.selectedTime, -// onTimePicker: (selectedTime) { -// //TODO handle selected time here. -// if (selectedTime != null) { -// setState(() { -// serviceRequestProvider.selectedTime = selectedTime; -// }); -// } -// }, -// ), -// 8.height, -// Container( -// width: double.infinity, -// height: 80.toScreenHeight, -// decoration: BoxDecoration( -// borderRadius: BorderRadius.circular(10), -// color:AppColor.neutral90, -// boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], -// ), -// padding: EdgeInsets.symmetric(horizontal: 20.toScreenWidth,vertical: 10.toScreenHeight), -// child: Column( -// crossAxisAlignment: CrossAxisAlignment.start, -// mainAxisAlignment: MainAxisAlignment.start, -// children: [ -// context.translation.workingHours.bodyText2(context), -// //TODo calculate the hours and write here. -// 'No of hours'.bodyText(context).custom(color:AppColor.balck10), -// ], -// ), -// -// ), -// 8.height, -// AppTextFormField( -// labelText: context.translation.comments, -// textInputType: TextInputType.multiline, -// alignLabelWithHint: true, -// backgroundColor: AppColor.neutral90, -// onChange: (text) { -// serviceRequestProvider.serviceRequest.comments = text; -// }, -// onSaved: (text) { -// serviceRequestProvider.serviceRequest.comments = text; -// }, -// ), -// 16.height, -// Row( -// mainAxisAlignment: MainAxisAlignment.spaceBetween, -// children: [ -// SizedBox( -// width: 200.toScreenHeight, -// child: AppFilledButton( -// label: context.translation.cancel, -// loading: false, -// buttonColor: Colors.transparent, -// showBorder: true, -// textColor: AppColor.balck10, -// onPressed: -// () async { -// Navigator.pop(context); -// // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.serviceRequest); -// // Navigator.pop(context, true); -// }, -// ), -// ), -// SizedBox( -// width: 200.toScreenHeight, -// child: AppFilledButton( -// label: context.translation.fixed, -// buttonColor: AppColor.green70, -// loading: false, -// onPressed:(){ -// -// }, -// ), -// ), -// ], -// ), -// 16.height, -// ], -// ), -// ), -// ), -// ); -// } -// ); -// } -// ); -// } -// } - class ServiceRequestBottomSheet { static Future fixRemotelyBottomSheet({@required BuildContext context}) { final GlobalKey _formKey = GlobalKey(); @@ -606,7 +403,6 @@ class ServiceRequestBottomSheet { final List> items = [ {'heading': context.translation.sparePartRequest, 'subHeading': context.translation.sparePartRequestDetail, 'icon': AppAsset.sparePartIcon}, {'heading': context.translation.maintenanceRequest, 'subHeading': context.translation.sparePartRequestDetail, 'icon': AppAsset.maintenanceIcon}, - {'heading': context.translation.assetToBeRetired, 'subHeading': context.translation.sparePartRequestDetail, 'icon': AppAsset.retiredAssetIcon}, ]; Widget listItem({@required BuildContext context, @required String icon, @required String heading, @required String subHeading, @required VoidCallback onTap}) { return Card( @@ -641,6 +437,7 @@ class ServiceRequestBottomSheet { break; case 1: + //push to specific screen... // Navigator.push( // context, @@ -823,4 +620,95 @@ class ServiceRequestBottomSheet { ); })); } + static Future nurseTakeActionBottomSheet({@required BuildContext context}) { + final GlobalKey _formKey = GlobalKey(); + return showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (context) => Consumer(builder: (context, serviceRequestProvider, child) { + return Form( + key: _formKey, + child: SingleChildScrollView( + child: StatefulBuilder(builder: (context, setState) { + bool acknowledge = false; + Uint8List newSignature; + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox().indicatorWidget(), + 8.height, + Align( + alignment: AlignmentDirectional.centerStart, + child: context.translation.pleaseConfirmTheIssueHasBeenResolved.bottomSheetHeadingTextStyle(context), + ), + 10.height, + Row( + children: [ + Checkbox( + value: serviceRequestProvider.ackhnowledge, + activeColor: AppColor.blueStatus(context), + onChanged: (value) { + setState(() { + acknowledge = !value; + }); + print('acknowledge value is $acknowledge'); + + }), + context.translation.nurseAcknowledge.bodyText(context).custom(color: context.isDark ? AppColor.primary50 : AppColor.neutral120), + ], + ), + 17.height, + ESignature( + title: '', + oldSignature: '', + newSignature: newSignature, + backgroundColor: AppColor.neutral100, + showShadow: false, + onSaved: (signature) { + // if (signature == null || signature.isEmpty) { + // setState(() {}); + // return; + // } + if (signature == null || signature.isEmpty) return; + newSignature = signature; + // _subWorkOrders.nurseSignature = signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}" : null; + }, + ), + 16.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + AppFilledButton( + label: context.translation.reject, + maxWidth: true, + buttonColor: Colors.white54, + textColor: AppColor.red30, + showBorder: true, + onPressed: () async { + ServiceRequestBottomSheet.rejectRequestBottomSheet(context: context); + }, + ).expanded, + const SizedBox( + width: 20, + ), + AppFilledButton( + label: context.translation.confirm, + maxWidth: true, + buttonColor: AppColor.green70, + onPressed: () async { + }, + ).expanded, + ], + ) + + ], + ); + }), + ), + ).bottomSheetContainer(context); + })); + } } diff --git a/lib/service_request_latest/views/components/initial_visit_card.dart b/lib/service_request_latest/views/components/initial_visit_card.dart new file mode 100644 index 00000000..4da5616c --- /dev/null +++ b/lib/service_request_latest/views/components/initial_visit_card.dart @@ -0,0 +1,42 @@ +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/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; + +class InitialVisitCard extends StatelessWidget { + const InitialVisitCard({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(14), + color: AppColor.white10, + ), + padding: EdgeInsets.symmetric(horizontal: 12.toScreenWidth, vertical: 14.toScreenHeight), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Text( + DateTime.now().toString().toInitialVisitCardFormat, + textAlign: TextAlign.end, + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + "edit_icon".toSvgAsset(height: 21, width: 21).onPress(() { + //open bottom sheet again with the informations added... + }), + ]), + 2.height, + context.translation.visitDateAndTime.heading6(context).custom(color: AppColor.neutral120), + 8.height, + 'Comments for the visit will be visible here for reference'.heading6(context).custom(color: AppColor.neutral120), + + ], + ), + ); + } +} diff --git a/lib/service_request_latest/views/components/request_detail_view.dart b/lib/service_request_latest/views/components/request_detail_view.dart index 71ef3ae9..0e6cac3b 100644 --- a/lib/service_request_latest/views/components/request_detail_view.dart +++ b/lib/service_request_latest/views/components/request_detail_view.dart @@ -14,10 +14,12 @@ import 'package:test_sa/models/service_request/service_request.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/default_app_bar.dart'; +import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart'; -import 'package:test_sa/service_request_latest/views/forms/work_order/components/asset_conditon_view.dart'; -import 'package:test_sa/service_request_latest/views/forms/work_order/components/attachments_view.dart'; -import 'package:test_sa/service_request_latest/views/forms/work_order/work_order_form_view.dart'; +import 'package:test_sa/service_request_latest/views/components/initial_visit_card.dart'; +import 'package:test_sa/service_request_latest/views/components/timer_widget.dart'; +import 'package:test_sa/service_request_latest/views/forms/asset_retired/asset_retired.dart'; +import 'package:test_sa/service_request_latest/views/nurse/create_new_request_view.dart'; import 'package:test_sa/views/pages/user/requests/comments_bottom_sheet.dart'; import 'package:test_sa/views/pages/user/requests/update_service_request_page.dart'; import 'package:test_sa/views/pages/user/requests/work_order/work_orders_list_page.dart'; @@ -26,12 +28,15 @@ import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart'; import 'package:test_sa/views/widgets/sound/sound_player.dart'; +import '../../../models/lookup.dart'; +import '../forms/maintenance_request/maintenance_request_main.dart'; + class RequestDetailView extends StatefulWidget { static const String id = "/call-details"; ServiceRequest serviceRequest; - bool fromTabView=false; + bool fromTabView = false; - RequestDetailView({Key key, this.serviceRequest,this.fromTabView=false}) : super(key: key); + RequestDetailView({Key key, this.serviceRequest, this.fromTabView = false}) : super(key: key); @override State createState() => _RequestDetailViewState(); @@ -50,135 +55,77 @@ class _RequestDetailViewState extends State { Provider.of(context, listen: false).reset(); ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); serviceRequestsProvider.currentSelectedRequest = await serviceRequestsProvider.getServiceRequestObjectById(requestId: requestId); - print('request id i got is ${serviceRequestsProvider.currentSelectedRequest.id}'); // setState(() {}); }); } + final GlobalKey _detailsCardKey = GlobalKey(); + + void createBreakPoint(){ + + final RenderBox detailContainerBox = + _detailsCardKey.currentContext?.findRenderObject() as RenderBox; + final detailContainerHeight = detailContainerBox?.size?.height; + + } @override Widget build(BuildContext context) { UserProvider _userProvider = Provider.of(context, listen: false); - return !widget.fromTabView? Scaffold( - appBar:DefaultAppBar(title: context.translation.serviceDetails), - body: Padding( - padding: EdgeInsets.only(top: 12.toScreenHeight), - child: Consumer(builder: (context, serviceRequestsProvider, child) { - return requestDetailCard(serviceRequestsProvider: serviceRequestsProvider,userProvider: _userProvider); - }), - ), - ):Consumer(builder: (context, serviceRequestsProvider, child) { - return requestDetailCard(serviceRequestsProvider: serviceRequestsProvider,userProvider: _userProvider); - }); + + return !widget.fromTabView + ? Scaffold( + appBar: DefaultAppBar(title: context.translation.serviceDetails), + body: Padding( + padding: EdgeInsets.only(top: 12.toScreenHeight), + child: Consumer(builder: (context, serviceRequestsProvider, child) { + return requestDetailCard(serviceRequestsProvider: serviceRequestsProvider, userProvider: _userProvider); + }), + ), + ) + : Consumer(builder: (context, serviceRequestsProvider, child) { + return requestDetailCard(serviceRequestsProvider: serviceRequestsProvider, userProvider: _userProvider); + }); } - Widget requestDetailCard({ ServiceRequestsProvider serviceRequestsProvider,UserProvider userProvider}){ + + Widget requestDetailCard({ServiceRequestsProvider serviceRequestsProvider, UserProvider userProvider}) { + if(!serviceRequestsProvider.isDetialLoading){ + createBreakPoint(); + } return SafeArea( + key: _detailsCardKey, child: serviceRequestsProvider.isDetialLoading ? const ALoading().center : serviceRequestsProvider.currentSelectedRequest == null - ? Text( - context.translation.noDataFound, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), - ).center - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SingleChildScrollView( - padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), - child: informationCard(serviceRequestsProvider.currentSelectedRequest,userProvider), - ).expanded, - Center( - child: InkWell( - onTap: () async { - try{ - //use a common list - AllRequestsProvider allRequestProvider = Provider.of(context, listen: false); - int index = allRequestProvider.requestDetailList.requestsDetails.indexWhere((element) => element.id.toString() == serviceRequestsProvider.currentSelectedRequest.id); - if (index != -1 && index != allRequestProvider.requestDetailList.requestsDetails.length) { - getServiceRequest(requestId: allRequestProvider.requestDetailList.requestsDetails[index + 1].id.toString()); - } - }catch(e){ - print(e); - } - }, - child: Text( - context.translation.skipForLater, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, decoration: TextDecoration.underline, fontSize: 16), - ), - ), - ), - 20.height, - if (userProvider.user.type == UsersTypes.engineer || - (serviceRequestsProvider.currentSelectedRequest.statusValue == 5 || serviceRequestsProvider.currentSelectedRequest.statusValue == 3)) - (serviceRequestsProvider.currentSelectedRequest?.firstAction == null - ? Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.min, - children: [ - AppFilledButton( - label: context.translation.reject, - maxWidth: true, - buttonColor: Colors.white54, - textColor: AppColor.red30, - showBorder: true, - onPressed: () async { - // ServiceRequestBottomSheet.rejectRequestBottomSheet(context: context); - Navigator.of(context).push(MaterialPageRoute(builder: (_) => const WorkOrderFormView())); + ? Text( + context.translation.noDataFound, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ).center + : Stack( + children: [ + SingleChildScrollView( + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + informationCard(serviceRequestsProvider.currentSelectedRequest, userProvider), - // bool shouldReloadData = (await showModalBottomSheet( - // context: context, - // useSafeArea: true, - // isScrollControlled: true, - // backgroundColor: Colors.transparent, - // builder: (context) => RejectRequestBottomSheet(), - // )) as bool; - // if (shouldReloadData ?? false) { - // getServiceRequest(); - // } - }, - ).expanded, - const SizedBox( - width: 20, + 40.height, + // skipForLater(serviceRequestsProvider.currentSelectedRequest), + // 20.height, + const InitialVisitCard(), + 20.height, + ], + ), + ), + FooterActionButton.footerWidget(status: 1, context: context), + const TimerWidget(), + ], ), - AppFilledButton( - label: context.translation.accept, - maxWidth: true, - buttonColor: AppColor.green70, - onPressed: () async { - // const SizedBox().flushBar(context: context); - ServiceRequestBottomSheet.feedBackBottomSheet(context: context); - - // ServiceRequestBottomSheet.fixRemotelyBottomSheet(context: context); - // bool shouldReloadData = (await showModalBottomSheet( - // context: context, - // useSafeArea: true, - // isScrollControlled: true, - // backgroundColor: Colors.transparent, - // builder: (context) => InitialVisitBottomSheet(), - // )) as bool; - // if (shouldReloadData ?? false) { - // getServiceRequest(); - // } - }, - ).expanded, - ], - ) - : AppFilledButton( - label: context.translation.viewWorkOrder, - maxWidth: true, - onPressed: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => WorkOrderListPage(serviceRequest: serviceRequestsProvider.currentSelectedRequest)), - ); - // Navigator.of(context).pushNamed(WorkOrderListPage.id, arguments: serviceRequest); - }, - )) - .paddingOnly(start: 16, end: 16, bottom: 24), - ], - ), ); } - Widget informationCard(ServiceRequest serviceRequest,UserProvider userProvider) { + + Widget informationCard(ServiceRequest serviceRequest, UserProvider userProvider) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -320,51 +267,51 @@ class _RequestDetailViewState extends State { ], ).paddingOnly(start: 16, end: 16, top: 16, bottom: 8), (userProvider.user.type == UsersTypes.normal_user - ? Container( - height: 50, - padding: const EdgeInsets.only(left: 16, right: 16), - alignment: Alignment.center, - width: double.infinity, - decoration: ShapeDecoration( - color: context.isDark ? AppColor.neutral50 : AppColor.neutral30, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(20), - bottomRight: Radius.circular(20), - ), - ), - ), - child: Row( - children: [ - Text( - '${context.translation.commentHere}...', - style: AppTextStyles.heading6.copyWith( - color: (context.isDark ? AppColor.neutral30 : AppColor.neutral50).withOpacity(.6), - ), - ).expanded, - "comment_send".toSvgAsset(width: 24, color: context.isDark ? AppColor.primary50 : AppColor.primary70), - ], - ), - ) - : Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Divider().defaultStyle(context), - 16.height, - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - context.translation.viewComments, - style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), - ), - 4.width, - Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) - ], - ), - ], - ).paddingOnly(bottom: 16, start: 16, end: 16)) + ? Container( + height: 50, + padding: const EdgeInsets.only(left: 16, right: 16), + alignment: Alignment.center, + width: double.infinity, + decoration: ShapeDecoration( + color: context.isDark ? AppColor.neutral50 : AppColor.neutral30, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(20), + bottomRight: Radius.circular(20), + ), + ), + ), + child: Row( + children: [ + Text( + '${context.translation.commentHere}...', + style: AppTextStyles.heading6.copyWith( + color: (context.isDark ? AppColor.neutral30 : AppColor.neutral50).withOpacity(.6), + ), + ).expanded, + "comment_send".toSvgAsset(width: 24, color: context.isDark ? AppColor.primary50 : AppColor.primary70), + ], + ), + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Divider().defaultStyle(context), + 16.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewComments, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).paddingOnly(bottom: 16, start: 16, end: 16)) .onPress(() { showModalBottomSheet( context: context, @@ -375,7 +322,56 @@ class _RequestDetailViewState extends State { builder: (context) => CommentsBottomSheet(requestId: serviceRequest.id), ); }), + //set condition for show asset detail button... + if(true)...[ + assetRetiredButton(serviceRequest: serviceRequest), + ] ], ).toShadowContainer(context, padding: 0); } + + Widget assetRetiredButton({ServiceRequest serviceRequest}){ + return Padding( + padding: EdgeInsets.symmetric(horizontal: 16.toScreenHeight,vertical: 12.toScreenWidth), + child: AppFilledButton( + label: context.translation.assetToBeRetired, + maxWidth: true, + buttonColor: Colors.white54, + textColor: AppColor.red30, + showBorder: true, + onPressed: () async { + // ServiceRequestBottomSheet.nurseTakeActionBottomSheet(context: context); + Navigator.push(context, MaterialPageRoute(builder: (context)=>const AssetRetired())); + + } + ), + ); + + + + + } + + Widget skipForLater (ServiceRequest serviceRequest){ + return Center( + child: InkWell( + onTap: () async { + try { + //use a common list + AllRequestsProvider allRequestProvider = Provider.of(context, listen: false); + int index = allRequestProvider.requestDetailList.requestsDetails.indexWhere((element) => element.id.toString() == serviceRequest.id); + if (index != -1 && index != allRequestProvider.requestDetailList.requestsDetails.length) { + getServiceRequest(requestId: allRequestProvider.requestDetailList.requestsDetails[index + 1].id.toString()); + } + } catch (e) { + print(e); + } + }, + child: Text( + context.translation.skipForLater, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, decoration: TextDecoration.underline, fontSize: 16), + ), + ), + ); + } } diff --git a/lib/service_request_latest/views/components/timer_widget.dart b/lib/service_request_latest/views/components/timer_widget.dart new file mode 100644 index 00000000..b96b3186 --- /dev/null +++ b/lib/service_request_latest/views/components/timer_widget.dart @@ -0,0 +1,195 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/models/size_config.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/service_request_latest/request_detail_provider.dart'; + +class TimerWidget extends StatefulWidget { + const TimerWidget({Key key}) : super(key: key); + + @override + _TimerWidgetState createState() => _TimerWidgetState(); +} + + +class _TimerWidgetState extends State { + Offset position = Offset(SizeConfig.screenWidth - 100, SizeConfig.screenHeight / 2 - 50); + @override + void initState() { + // TODO: implement initState + Provider.of(context,listen: false).startTimer(); + super.initState(); + } + @override + void dispose() { + // TODO: implement dispose + //dispose the timer... + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, provider, child) { + return Positioned( + left: position.dx, + top: position.dy, + child: GestureDetector( + onPanEnd: (details){}, + onPanUpdate: (details) { + setState(() { + if (position.dy + details.delta.dy > 0 && position.dy + details.delta.dy < 560) { + position = Offset( + position.dx + details.delta.dx, // Update the X position + position.dy + details.delta.dy, // Update the Y position + ); + } + }); + }, + child: buildTimerWidget(provider), + ), + ); + }, + ); + } + + Widget buildTimerWidget(RequestDetailProvider provider) { + return GestureDetector( + onTap: () { + if (provider.isTimerRunning) { + provider.stopTimer(); + } else { + provider.startTimer(); + } + }, + child: Container( + padding: EdgeInsets.all(8.toScreenHeight), + width: 80.toScreenWidth, + decoration: BoxDecoration( + color: AppColor.black10, + borderRadius: BorderRadius.circular(10), + ), + child: + Column( + children: [ + 'drag_icon'.toSvgAsset(), + 12.height, + provider.currentTime.toString().toDragAbleTimerFormat.tinyFont(context).custom(color: AppColor.white10, fontWeight: FontWeight.w600), + 2.height, + context.translation.hours.tinyFont(context).custom(color: AppColor.white10, fontWeight: FontWeight.w600), + ], + ), + ), + ); + } +} + + //older code... + // DateTime startTime = DateTime(0, 0, 0, 0, 0, 0); // Start from 00:00:00 + // Timer timer; + // bool isRunning = false; + // + // @override + // void initState() { + // super.initState(); + // startTimer(); + // } + // + // void startTimer() { + // if (isRunning) return; + // timer = Timer.periodic(const Duration(seconds: 1), (Timer t) { + // setState(() { + // startTime = startTime.add(const Duration(seconds: 1)); + // }); + // }); + // setState(() { + // isRunning = true; + // }); + // } + // + // void stopTimer() { + // timer?.cancel(); + // setState(() { + // isRunning = false; + // }); + // } + // @override + // void dispose() { + // timer?.cancel(); + // super.dispose(); + // } + // + // @override + // Widget build(BuildContext context) { + // return Positioned( + // left: position.dx, + // top: position.dy, + // child: GestureDetector( + // onPanUpdate: (details) { + // setState(() { + // //calculate the exact bonds to be restrict the drag.. + // if(position.dy + details.delta.dy>0&&position.dy + details.delta.dy<560){ + // position = Offset( + // position.dx + details.delta.dx, // Update the X position + // position.dy + details.delta.dy, // Update the Y position + // ); + // } + // }); + // }, + // child: buildTimerWidget(), + // ), + // ); + // // return Positioned( + // // left: position.dx, + // // top: position.dy, + // // child: Draggable( + // // feedback: buildTimerWidget(), + // // childWhenDragging: Container(), + // // onDragEnd: (dragDetails) { + // // setState(() { + // // // Get the RenderBox of the parent widget (Stack) + // // final renderBox = context.findRenderObject() as RenderBox; + // // + // // // Convert the global position to a local position inside the Stack + // // position = dragDetails.offset; + // // }); + // // }, + // // child: buildTimerWidget(), + // // ), + // // ); + // } + // + // Widget buildTimerWidget() { + // return GestureDetector( + // onTap: (){ + // if(isRunning){ + // stopTimer(); + // }else{ + // startTimer(); + // } + // }, + // child: Container( + // padding: EdgeInsets.all(8.toScreenHeight), + // width: 80.toScreenWidth, + // decoration: BoxDecoration( + // color: AppColor.black10, + // borderRadius: BorderRadius.circular(10), + // ), + // child: Column( + // children: [ + // 'drag_icon'.toSvgAsset(), + // 12.height, + // startTime.toString().toDragAbleTimerFormat.tinyFont(context).custom(color: AppColor.white10, fontWeight: FontWeight.w600), + // 2.height, + // context.translation.hours.tinyFont(context).custom(color: AppColor.white10, fontWeight: FontWeight.w600), + // ], + // ), + // ), + // ); + // } diff --git a/lib/service_request_latest/views/components/verify_arrival_view.dart b/lib/service_request_latest/views/components/verify_arrival_view.dart index 5aa9d97a..a5661d0e 100644 --- a/lib/service_request_latest/views/components/verify_arrival_view.dart +++ b/lib/service_request_latest/views/components/verify_arrival_view.dart @@ -82,7 +82,6 @@ class VerifyArrivalView extends StatelessWidget { } void onItemTap({@required int index, @required ServiceRequest serviceRequest,@required BuildContext context}) { - print('on item tap i got index is $index'); switch(index){ case 0: Navigator.push( diff --git a/lib/service_request_latest/views/components/work_order_card_view.dart b/lib/service_request_latest/views/components/work_order_card_view.dart new file mode 100644 index 00000000..3aaf39cb --- /dev/null +++ b/lib/service_request_latest/views/components/work_order_card_view.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/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/enums/user_types.dart'; +import 'package:test_sa/models/service_request/search_work_order.dart'; +import 'package:test_sa/models/service_request/service_request.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/pages/user/requests/work_order/update_service_report.dart'; +import 'package:test_sa/views/pages/user/requests/work_order/work_order_details_page.dart'; + +import '../../../../views/widgets/requests/request_status.dart'; + +class WorkOrderCardView extends StatelessWidget { + final SearchWorkOrder workOrder; + final ServiceRequest serviceRequest; + final bool showShadow; + + WorkOrderCardView(this.workOrder, this.serviceRequest, {Key key, this.showShadow = true}) : super(key: key); + + @override + Widget build(BuildContext context) { + UserProvider _userProvider = Provider.of(context, listen: false); + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: workOrder.currentSituation.name, + textColor: AppColor.getRequestStatusTextColorByName(context, workOrder.currentSituation.name), + backgroundColor: AppColor.getRequestStatusColorByName(context, workOrder.currentSituation.name), + ), + 8.height, + Text(serviceRequest.requestCode, style: AppTextStyles.heading5.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), + Text( + '${context.translation.assetName}: ${workOrder.callRequest.asset.modelDefinition.assetName?.cleanupWhitespace?.capitalizeFirstOfEach}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + Text( + '${context.translation.currentSituation}: ${workOrder.currentSituation.name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + 16.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.readCompleteThread, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context), decoration: TextDecoration.underline), + ), + // 4.width, + // Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).onPress(() { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => WorkOrderDetailsPage(workOrder: workOrder, serviceRequest: serviceRequest)), + ); + }).expanded, + Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + if (_userProvider.user.type == UsersTypes.engineer && serviceRequest.statusValue != 5 && serviceRequest.statusValue != 3) + "edit_icon".toSvgAsset(height: 21, width: 21).onPress(() { + Navigator.of(context).push( + MaterialPageRoute(builder: (_) => UpdateServiceReport(request: serviceRequest, workOrder: workOrder)), + ); + }), + if (_userProvider.user.type == UsersTypes.engineer && serviceRequest.statusValue != 5 && serviceRequest.statusValue != 3) 8.height, + Text(workOrder.visitDate?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : const Color(0xFF3B3D4A))), + ], + ) + ], + ).toShadowContainer(context); + } +} diff --git a/lib/service_request_latest/views/forms/asset_retired/asset_retired.dart b/lib/service_request_latest/views/forms/asset_retired/asset_retired.dart new file mode 100644 index 00000000..fec8d708 --- /dev/null +++ b/lib/service_request_latest/views/forms/asset_retired/asset_retired.dart @@ -0,0 +1,168 @@ + +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/service_request/service_report.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/work_order/reason_provider.dart'; +import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import '../../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; +import '../../../../../../controllers/providers/api/status_drop_down/report/service_types_provider.dart'; +import '../../../../../../models/lookup.dart'; +import '../../../../../../new_views/common_widgets/default_app_bar.dart'; +class AssetRetired extends StatefulWidget { + static const String id = "/asset-tobe-retired"; + + const AssetRetired({Key key}) : super(key: key); + + @override + _AssetRetiredState createState() => _AssetRetiredState(); +} + +class _AssetRetiredState extends State with TickerProviderStateMixin { + UserProvider _userProvider; + SettingProvider _settingProvider; + ServiceRequestsProvider _serviceRequestsProvider; + ServiceStatusProvider _assetTypeProvider; + ServiceReport _serviceReport; + bool _isLoading = false; + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + void initState() { + _serviceReport = ServiceReport( + // returnToService: DateTime.now(), + // //type: const Lookup(value: 2), + // device: widget.request.device, + sparePartsWorkOrders: [], + ); + super.initState(); + if (context.mounted) { + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).serviceRequestId = serviceRequestsProvider.currentSelectedRequest.id; + } + // _isLoading = true; + } + + Asset loanAvailabilityAsset; + + void getRequestForWorkOrder() async { + _isLoading = true; + setState(() {}); + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); + _serviceReport.callRequest = await _serviceRequestsProvider.getCallRequestForWorkOrder(callId: serviceRequestsProvider.currentSelectedRequest.id); + await _assetTypeProvider.getTypes(user: _userProvider.user, host: _settingProvider.host); + _serviceReport.assignedEmployee = _serviceReport.callRequest?.assignedEmployee; + _serviceReport.equipmentStatus = _serviceReport.callRequest?.defectType; + _serviceReport.serviceType = Lookup(id: 65, name: "Interval", value: 1); // default value in service type as in web + _isLoading = false; + setState(() {}); + } + + @override + Widget build(BuildContext context) { + _userProvider = Provider.of(context); + _settingProvider = Provider.of(context); + _serviceRequestsProvider = Provider.of(context); + _assetTypeProvider = Provider.of(context); + if (_serviceReport.callRequest == null) { + getRequestForWorkOrder(); + } + _serviceReport.assetType = _assetTypeProvider.statuses?.firstWhere( + (element) => element.value == _serviceReport.callRequest?.assetType, + orElse: () => null, + ); + final List _files = []; + + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar(title: context.translation.assetToBeRetired), + body: Consumer(builder: (context, serviceRequestProvider, child) { + return SafeArea( + child: LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + child: Card( + child: Column( + children: [ + 12.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.failureReason, + backgroundColor: AppColor.neutral100, + height: 70.toScreenHeight, + showShadow: false, + // initialValue: _subWorkOrders.reason, + onSelect: (value) { + if (value != null) { + // _subWorkOrders.reason = value; + } + }, + ), + 8.height, + AppTextFormField( + labelText: context.translation.comments, + textInputType: TextInputType.multiline, + showWithoutDecoration: true, + backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral100, + alignLabelWithHint: true, + onChange: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + onSaved: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + ), + 23.height, + MultiFilesPicker(label: context.translation.attachFiles, + files: _files, + buttonIcon: 'image-plus'?.toSvgAsset(), + ), + + + ], + ).paddingOnly(start:13,end: 13,top: 16,bottom: 16), + ).paddingAll(16), + ).expanded, + FooterActionButton.footerContainer( + child: AppFilledButton( + label: context.translation.submit, + buttonColor: AppColor.primary10, + onPressed: () async { + // + }, + ), + ), + ], + ), + ), + ), + ); + }), + ); + } +} diff --git a/lib/service_request_latest/views/forms/asset_retired/verify_asset_detail.dart b/lib/service_request_latest/views/forms/asset_retired/verify_asset_detail.dart new file mode 100644 index 00000000..f37c1852 --- /dev/null +++ b/lib/service_request_latest/views/forms/asset_retired/verify_asset_detail.dart @@ -0,0 +1,283 @@ + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/parts_provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/service_request/service_report.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/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/service_request_providers/loan_availability_provider.dart'; +import 'package:test_sa/providers/work_order/reason_provider.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/views/widgets/equipment/pick_asset.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import '../../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; +import '../../../../../../controllers/providers/api/status_drop_down/report/service_types_provider.dart'; +import '../../../../../../models/lookup.dart'; +import '../../../../../../new_views/common_widgets/default_app_bar.dart'; +class VerifyAssetDetails extends StatefulWidget { + static const String id = "/verify-asset-detail"; + + const VerifyAssetDetails({Key key}) : super(key: key); + + @override + _VerifyAssetDetailsState createState() => _VerifyAssetDetailsState(); +} + +class _VerifyAssetDetailsState extends State with TickerProviderStateMixin { + UserProvider _userProvider; + SettingProvider _settingProvider; + ServiceRequestsProvider _serviceRequestsProvider; + ServiceStatusProvider _assetTypeProvider; + PartsProvider _partsProvider; + ServiceReport _serviceReport; + bool _isLoading = false; + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + int _selectedValue = 1; + + @override + void initState() { + _serviceReport = ServiceReport( + // returnToService: DateTime.now(), + // //type: const Lookup(value: 2), + // device: widget.request.device, + sparePartsWorkOrders: [], + ); + super.initState(); + if (context.mounted) { + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).serviceRequestId = serviceRequestsProvider.currentSelectedRequest.id; + } + // _isLoading = true; + } + + Asset loanAvailabilityAsset; + + void getRequestForWorkOrder() async { + _isLoading = true; + setState(() {}); + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); + _serviceReport.callRequest = await _serviceRequestsProvider.getCallRequestForWorkOrder(callId: serviceRequestsProvider.currentSelectedRequest.id); + await _assetTypeProvider.getTypes(user: _userProvider.user, host: _settingProvider.host); + _serviceReport.assignedEmployee = _serviceReport.callRequest?.assignedEmployee; + _serviceReport.equipmentStatus = _serviceReport.callRequest?.defectType; + _serviceReport.serviceType = Lookup(id: 65, name: "Interval", value: 1); // default value in service type as in web + _isLoading = false; + setState(() {}); + } + + @override + Widget build(BuildContext context) { + _userProvider = Provider.of(context); + _settingProvider = Provider.of(context); + _serviceRequestsProvider = Provider.of(context); + _assetTypeProvider = Provider.of(context); + _partsProvider = Provider.of(context); + if (_serviceReport.callRequest == null) { + getRequestForWorkOrder(); + } + _serviceReport.assetType = _assetTypeProvider.statuses?.firstWhere( + (element) => element.value == _serviceReport.callRequest?.assetType, + orElse: () => null, + ); + + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar(title: context.translation.verify_asset_details), + body: Consumer(builder: (context, serviceRequestProvider, child) { + return SafeArea( + child: LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + child: Card( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + context.translation.equipmentStatus.bodyText(context).custom(color: AppColor.black20), + 12.height, + assetStatusWidget(context), + 24.height, + ADatePicker( + label: context.translation.returnToService, + hideShadow: true, + height: 70.toScreenHeight, + backgroundColor: AppColor.neutral100, + date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest.startDate ?? ""), + formatDateWithTime: true, + onDatePicker: (selectedDate) { + if (selectedDate != null) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + // Handle the selected date and time here. + if (selectedTime != null) { + DateTime selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + if (selectedDateTime != null) { + if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.currentSelectedRequest.date))) { + "Visit Date time must be greater then request date".showToast; + return; + } + + setState(() { + serviceRequestProvider.currentSelectedRequest.startDate = selectedDateTime?.toIso8601String(); + }); + print('start date i got is ${serviceRequestProvider.currentSelectedRequest.startDate}'); + } + } + }); + } + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.loanAvailability, + initialValue: _serviceReport?.loanAvailablity, + onSelect: (status) { + if (status != null) { + setState(() { + _serviceReport.loanAvailablity = status; + if (_serviceReport.loanAvailablity.value != 1) { + loanAvailabilityAsset = null; + _serviceReport.assetLoan = null; + } + }); + } + }, + ), + if (_serviceReport?.loanAvailablity?.value == 1) 8.height, + if (_serviceReport?.loanAvailablity?.value == 1) + PickAsset( + device: loanAvailabilityAsset, // ?? _serviceReport.device, + onPickAsset: (asset) { + if (asset != null) { + _serviceReport.assetLoan = AssetInfo.fromJson(asset.toJson()); + setState(() { + loanAvailabilityAsset = asset; + }); + } + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.failureReason, + backgroundColor: AppColor.neutral100, + height: 70.toScreenHeight, + showShadow: false, + // initialValue: _subWorkOrders.reason, + onSelect: (value) { + if (value != null) { + // _subWorkOrders.reason = value; + } + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.faultDescription, + backgroundColor: AppColor.neutral100, + height: 70.toScreenHeight, + showShadow: false, + // initialValue: _subWorkOrders.reason, + onSelect: (value) { + if (value != null) { + // _subWorkOrders.reason = value; + } + }, + ), + 11.height, + context.translation.solutions.heading6(context).custom(color: AppColor.neutral50), + 11.height, + //TODO solution from api... + 'Solution number one \nSolution number two'.heading6(context).custom(color: AppColor.neutral50), + + ], + ).paddingOnly(start:13,end: 13,top: 16,bottom: 16), + ).paddingAll(16), + ).expanded, + Container( + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth,vertical: 16.toScreenHeight), + color: AppColor.white10, + child: AppFilledButton( + label: context.translation.verify_asset_details, + buttonColor: AppColor.primary10, + onPressed: () async { + }, + ), + ), + ], + ), + ), + ), + ); + }), + ); + } + + Widget assetStatusWidget(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + radioButtonWidget(label: context.translation.up_and_running, value: 1), + radioButtonWidget(label: context.translation.partially_down, value: 2), + radioButtonWidget(label: context.translation.fully_down, value: 3), + ], + ); + } + + Widget radioButtonWidget({@required String label, @required dynamic value}) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 20.toScreenWidth, + height: 40.toScreenHeight, + //TODO use the type required according data.. + child: Radio( + activeColor: AppColor.primary10, + value: value, + groupValue: _selectedValue, + onChanged: (int value) { + setState(() { + _selectedValue = value; + }); + }, + ), + ), + 8.width, + Text( + label, + style: AppTextStyles.tinyFont, + ), + 13.width, + ], + ); + } +} diff --git a/lib/service_request_latest/views/forms/maintenance_request/components/external_request.dart b/lib/service_request_latest/views/forms/maintenance_request/components/external_request.dart new file mode 100644 index 00000000..592f4f9e --- /dev/null +++ b/lib/service_request_latest/views/forms/maintenance_request/components/external_request.dart @@ -0,0 +1,279 @@ + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/parts_provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/service_request/service_report.dart'; +import 'package:test_sa/models/service_request/service_request.dart'; +import 'package:test_sa/models/service_request/supp_engineer_work_orders.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/providers/loading_list_notifier.dart'; +import 'package:test_sa/providers/work_order/reason_provider.dart'; +import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/views/widgets/date_and_time/time_picker.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import '../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; +import '../../../../../controllers/providers/api/status_drop_down/report/service_types_provider.dart'; +import '../../../../../models/lookup.dart'; +import '../../../../../new_views/common_widgets/app_text_form_field.dart'; +import '../../../../../new_views/common_widgets/single_item_drop_down_menu.dart'; + +class ExternalMaintenanceRequest extends StatefulWidget { + static const String id = "/add-external-activity"; + + const ExternalMaintenanceRequest({Key key}) : super(key: key); + + @override + _ExternalMaintenanceRequestState createState() => _ExternalMaintenanceRequestState(); +} + +class _ExternalMaintenanceRequestState extends State with TickerProviderStateMixin { + UserProvider _userProvider; + SettingProvider _settingProvider; + ServiceRequest _request; + ServiceRequestsProvider _serviceRequestsProvider; + ServiceStatusProvider _assetTypeProvider; + ServiceReport _serviceReport; + bool _isLoading = false; + TimeOfDay _startTime; + int _selectedValue = 1; + + TimeOfDay _endTime; + + final GlobalKey _formKey = GlobalKey(); + final TextEditingController _faultController = TextEditingController(); + final TextEditingController _workPreformedController = TextEditingController(); + final TextEditingController _partQtyController = TextEditingController(); + + @override + void initState() { + _serviceReport = ServiceReport( + // returnToService: DateTime.now(), + // //type: const Lookup(value: 2), + // device: widget.request.device, + sparePartsWorkOrders: [], + ); + + super.initState(); + if (context.mounted) { + _request = Provider.of(context, listen: false).currentSelectedRequest; + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).serviceRequestId = _request.id; + } + // _isLoading = true; + } + + Asset loanAvailabilityAsset; + + @override + void dispose() { + _faultController.dispose(); + _workPreformedController.dispose(); + _partQtyController.dispose(); + super.dispose(); + } + + void getRequestForWorkOrder() async { + _isLoading = true; + setState(() {}); + _serviceReport.callRequest = await _serviceRequestsProvider.getCallRequestForWorkOrder(callId: _request.id); + await _assetTypeProvider.getTypes(user: _userProvider.user, host: _settingProvider.host); + _serviceReport.assignedEmployee = _serviceReport.callRequest?.assignedEmployee; + _serviceReport.equipmentStatus = _serviceReport.callRequest?.defectType; + _serviceReport.serviceType = Lookup(id: 65, name: "Interval", value: 1); // default value in service type as in web + _isLoading = false; + setState(() {}); + } + + @override + Widget build(BuildContext context) { + _userProvider = Provider.of(context); + _settingProvider = Provider.of(context); + _serviceRequestsProvider = Provider.of(context); + _assetTypeProvider = Provider.of(context); + if (_serviceReport.callRequest == null) { + getRequestForWorkOrder(); + } + _serviceReport.assetType = _assetTypeProvider.statuses?.firstWhere( + (element) => element.value == _serviceReport.callRequest?.assetType, + orElse: () => null, + ); + + return LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Stack( + children: [ + SingleChildScrollView( + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + 8.height, + SingleItemDropDownMenu( + context: context, + height: 70.toScreenHeight, + title: context.translation.supplier, + showShadow: false, + backgroundColor: AppColor.neutral100, + staticData: Provider.of(context).calls, + initialValue: _serviceReport?.calllastSituation, + onSelect: (status) { + _serviceReport.calllastSituation = status; + }, + ), + // Container( + // height: 60.toScreenHeight, + // width: 60.toScreenWidth, + // decoration: BoxDecoration( + // color: _subWorkOrders.supplier?.suppliername == null ? AppColor.neutral40 : AppColor.background(context), + // borderRadius: BorderRadius.circular(10), + // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], + // ), + // child: Icon( + // Icons.add, + // color: context.isDark ? null : AppColor.neutral60, + // ), + // ).onPress(_subWorkOrders.supplier?.suppliername == null + // ? null + // : () async { + // SuppEngineerWorkOrders suppEngineer = (await showModalBottomSheet( + // context: context, + // useSafeArea: true, + // isScrollControlled: true, + // backgroundColor: Colors.transparent, + // builder: (context) => AddSupplierEngineerBottomSheet(_subWorkOrders.supplier.id), + // )) as SuppEngineerWorkOrders; + // if (suppEngineer != null) { + // _subWorkOrders?.supplier?.suppPersons ??= []; + // _subWorkOrders?.supplier?.suppPersons?.add(SuppPersons.fromJson(suppEngineer.toJson())); + // engineer = suppEngineer; + // setState(() {}); + // } + // }), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + ATimePicker( + label: context.translation.startTime, + hint: context.translation.select, + withBorder: false, + icon: 'clock', + withIcon: true, + backgroundColor: AppColor.neutral100, + height: 70.toScreenHeight, + time: _startTime, + onTimePicker: (selectedTime) { + if (selectedTime != null) { + print('time selected $selectedTime'); + setState(() { + _startTime = selectedTime; + }); + } + }, + ).expanded, + 8.width, + ATimePicker( + label: context.translation.endTime, + hint: context.translation.select, + icon: 'clock', + withIcon: true, + backgroundColor: AppColor.neutral100, + withBorder: false, + height: 70.toScreenHeight, + time: _endTime, + onTimePicker: (selectedTime) { + if (selectedTime != null) { + setState(() { + _endTime = selectedTime; + }); + } + }, + ).expanded, + ], + ), + 8.height, + AppTextFormField( + labelText: context.translation.workingHours, + backgroundColor: AppColor.neutral80, + suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), + contentPadding: EdgeInsets.symmetric(vertical: 18.toScreenHeight, horizontal: 16.toScreenWidth), + initialValue: _serviceReport?.workingHours.toString(), + textAlign: TextAlign.center, + showShadow: false, + enable: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + + ], + ), + ), + ).toShadowContainer(context).paddingOnly(start: 16, end: 16, top: 12), + FooterActionButton.footerContainer( + child: AppFilledButton( + label:context.translation.addExternalActivity, // Use the dynamic label + buttonColor: AppColor.primary10, + onPressed: () async { + // Handle button press + + }, + ), + ), + ], + ), + ); + } + Widget repairLocationWidget(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + radioButtonWidget(label: context.translation.remotely, value: 1), + radioButtonWidget(label: context.translation.workshop, value: 2), + radioButtonWidget(label: context.translation.abroad, value: 3), + ], + ); + } + + Widget radioButtonWidget({@required String label, @required dynamic value}) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 20.toScreenWidth, + height: 40.toScreenHeight, + //TODO use the type required according data.. + child: Radio( + activeColor: AppColor.primary10, + value: value, + groupValue: _selectedValue, + onChanged: (int value) { + setState(() { + _selectedValue = value; + }); + }, + ), + ), + 8.width, + Text( + label, + style: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral120), + ), + 13.width, + ], + ); + } +} 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 new file mode 100644 index 00000000..82dde80e --- /dev/null +++ b/lib/service_request_latest/views/forms/maintenance_request/components/internal_request.dart @@ -0,0 +1,303 @@ + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/parts_provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/service_request/service_report.dart'; +import 'package:test_sa/models/service_request/service_request.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/providers/loading_list_notifier.dart'; +import 'package:test_sa/providers/work_order/reason_provider.dart'; +import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/views/widgets/date_and_time/time_picker.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import '../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; +import '../../../../../controllers/providers/api/status_drop_down/report/service_types_provider.dart'; +import '../../../../../models/lookup.dart'; +import '../../../../../new_views/common_widgets/app_text_form_field.dart'; +import '../../../../../new_views/common_widgets/single_item_drop_down_menu.dart'; + +class InternalMaintenanceRequest extends StatefulWidget { + static const String id = "/add-internal-activity"; + + const InternalMaintenanceRequest({Key key}) : super(key: key); + + @override + _InternalMaintenanceRequestState createState() => _InternalMaintenanceRequestState(); +} + +class _InternalMaintenanceRequestState extends State with TickerProviderStateMixin { + UserProvider _userProvider; + SettingProvider _settingProvider; + ServiceRequest _request; + ServiceRequestsProvider _serviceRequestsProvider; + ServiceStatusProvider _assetTypeProvider; + PartsProvider _partsProvider; + ServiceReport _serviceReport; + bool _isLoading = false; + TimeOfDay _startTime; + int _selectedValue = 1; + + TimeOfDay _endTime; + + final GlobalKey _formKey = GlobalKey(); + final TextEditingController _faultController = TextEditingController(); + final TextEditingController _workPreformedController = TextEditingController(); + final TextEditingController _partQtyController = TextEditingController(); + + @override + void initState() { + _serviceReport = ServiceReport( + // returnToService: DateTime.now(), + // //type: const Lookup(value: 2), + // device: widget.request.device, + sparePartsWorkOrders: [], + ); + + super.initState(); + if (context.mounted) { + _request = Provider.of(context, listen: false).currentSelectedRequest; + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).serviceRequestId = _request.id; + } + // _isLoading = true; + } + + Asset loanAvailabilityAsset; + + @override + void dispose() { + _faultController.dispose(); + _workPreformedController.dispose(); + _partQtyController.dispose(); + super.dispose(); + } + + void getRequestForWorkOrder() async { + _isLoading = true; + setState(() {}); + _serviceReport.callRequest = await _serviceRequestsProvider.getCallRequestForWorkOrder(callId: _request.id); + await _assetTypeProvider.getTypes(user: _userProvider.user, host: _settingProvider.host); + _serviceReport.assignedEmployee = _serviceReport.callRequest?.assignedEmployee; + _serviceReport.equipmentStatus = _serviceReport.callRequest?.defectType; + _serviceReport.serviceType = Lookup(id: 65, name: "Interval", value: 1); // default value in service type as in web + _isLoading = false; + setState(() {}); + } + + @override + Widget build(BuildContext context) { + _userProvider = Provider.of(context); + _settingProvider = Provider.of(context); + _serviceRequestsProvider = Provider.of(context); + _assetTypeProvider = Provider.of(context); + _partsProvider = Provider.of(context); + if (_serviceReport.callRequest == null) { + getRequestForWorkOrder(); + } + _serviceReport.assetType = _assetTypeProvider.statuses?.firstWhere( + (element) => element.value == _serviceReport.callRequest?.assetType, + orElse: () => null, + ); + + return LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Stack( + children: [ + SingleChildScrollView( + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + 8.height, + SingleItemDropDownMenu( + context: context, + height: 70.toScreenHeight, + title: context.translation.activityStatus, + showShadow: false, + backgroundColor: AppColor.neutral100, + staticData: Provider.of(context).calls, + initialValue: _serviceReport?.calllastSituation, + onSelect: (status) { + _serviceReport.calllastSituation = status; + }, + ), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + ATimePicker( + label: context.translation.startTime, + hint: context.translation.select, + withBorder: false, + icon: 'clock', + withIcon: true, + backgroundColor: AppColor.neutral100, + height: 70.toScreenHeight, + time: _startTime, + onTimePicker: (selectedTime) { + if (selectedTime != null) { + print('time selected $selectedTime'); + setState(() { + _startTime = selectedTime; + }); + } + }, + ).expanded, + 8.width, + ATimePicker( + label: context.translation.endTime, + hint: context.translation.select, + icon: 'clock', + withIcon: true, + backgroundColor: AppColor.neutral100, + withBorder: false, + height: 70.toScreenHeight, + time: _endTime, + onTimePicker: (selectedTime) { + if (selectedTime != null) { + setState(() { + _endTime = selectedTime; + }); + } + }, + ).expanded, + ], + ), + 8.height, + AppTextFormField( + labelText: context.translation.workingHours, + backgroundColor: AppColor.neutral80, + suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), + contentPadding: EdgeInsets.symmetric(vertical: 18.toScreenHeight, horizontal: 16.toScreenWidth), + initialValue: _serviceReport?.workingHours.toString(), + textAlign: TextAlign.center, + showShadow: false, + enable: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + + //TODO need to be selected when submit... + // SingleItemDropDownMenu( + // context: context, + // title: context.translation.serviceType, + // initialValue: _serviceReport.serviceType, + // onSelect: (value) { + // _serviceReport.serviceType = value; + // }, + // ), + //Provider.of(context) + + 8.height, + AppTextFormField( + labelText: context.translation.travelingHours, + backgroundColor: AppColor.neutral100, + suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), + initialValue: _serviceReport?.travelingHours?.toString(), + textInputType: TextInputType.number, + contentPadding: EdgeInsets.symmetric(vertical: 18.toScreenHeight, horizontal: 16.toScreenWidth), + showShadow: false, + onSaved: (value) { + _serviceReport.travelingHours = double.tryParse(value) ?? 0.0; + }, + ), + 16.height, + context.translation.repairLocation.bodyText(context).custom(color: AppColor.black20, fontWeight: FontWeight.w500), + 8.height, + repairLocationWidget(context), + 16.height, + AppTextFormField( + labelText: context.translation.assignedEmployee, + backgroundColor: AppColor.neutral80, + contentPadding: EdgeInsets.symmetric(vertical: 18.toScreenHeight, horizontal: 16.toScreenWidth), + initialValue: _serviceReport?.workingHours.toString(), + textAlign: TextAlign.center, + showShadow: false, + enable: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + initialValue: _serviceReport?.comment, + labelText: context.translation.technicalComment, + backgroundColor: AppColor.neutral100, + showShadow: false, + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + onSaved: (value) { + _serviceReport.comment = value; + }, + ), + ], + ), + ), + ).toShadowContainer(context).paddingOnly(start: 16, end: 16, top: 12), + + FooterActionButton.footerContainer( + child: AppFilledButton( + label:context.translation.addInternalActivity, // Use the dynamic label + buttonColor: AppColor.primary10, + onPressed: () async { + // Handle button press + + }, + ), + ), + ], + ), + ); + } + Widget repairLocationWidget(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + radioButtonWidget(label: context.translation.remotely, value: 1), + radioButtonWidget(label: context.translation.workshop, value: 2), + radioButtonWidget(label: context.translation.abroad, value: 3), + ], + ); + } + + Widget radioButtonWidget({@required String label, @required dynamic value}) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 20.toScreenWidth, + height: 40.toScreenHeight, + //TODO use the type required according data.. + child: Radio( + activeColor: AppColor.primary10, + value: value, + groupValue: _selectedValue, + onChanged: (int value) { + setState(() { + _selectedValue = value; + }); + }, + ), + ), + 8.width, + Text( + label, + style: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral120), + ), + 13.width, + ], + ); + } +} 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 new file mode 100644 index 00000000..dbddb731 --- /dev/null +++ b/lib/service_request_latest/views/forms/maintenance_request/maintenance_request_main.dart @@ -0,0 +1,94 @@ +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/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/default_app_bar.dart'; +import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/service_request_latest/views/forms/maintenance_request/components/external_request.dart'; +import 'package:test_sa/service_request_latest/views/forms/maintenance_request/components/internal_request.dart'; + +class MaintenanceRequestForm extends StatefulWidget { + const MaintenanceRequestForm({Key key}) : super(key: key); + + @override + _MaintenanceRequestFormState createState() => _MaintenanceRequestFormState(); +} + +class _MaintenanceRequestFormState extends State with SingleTickerProviderStateMixin { + TabController _tabController; + int initialIndex = 0; + + @override + void initState() { + super.initState(); + // _tabController = TabController(length: 2, vsync: this); + // print('tab controller i got is ${_tabController.length}'); + // _tabController.addListener(() { + // print('add listner called..'); + // setState(() { + // print('index i got is ${_tabController.index}'); + // if (_tabController.index == 0) { + // _buttonLabel = 'abc'; + // } else if (_tabController.index == 1) { + // _buttonLabel = 'def'; + // } + // }); + // }); + } + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColor.neutral100, + appBar: DefaultAppBar(title: context.translation.maintenanceRequest), + body: DefaultTabController( + length: 2, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight), + decoration: BoxDecoration( + color: context.isDark ? AppColor.neutral50 : AppColor.white10, + borderRadius: BorderRadius.circular(10), + ), + child: TabBar( + padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth), + labelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, + unselectedLabelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, + unselectedLabelStyle: AppTextStyles.bodyText, + labelStyle: AppTextStyles.bodyText, + indicatorPadding: EdgeInsets.zero, + indicator: BoxDecoration( + color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, + borderRadius: BorderRadius.circular(7), + ), + tabs: [ + Tab(text: context.translation.internal, height: 57.toScreenHeight), + Tab(text: context.translation.external, height: 57.toScreenHeight), + ], + ), + ), + // 12.height, + const TabBarView( + children: [ + InternalMaintenanceRequest(), + ExternalMaintenanceRequest(), + ], + ).expanded, + + ], + ), + ), + ); + } +} diff --git a/lib/service_request_latest/views/forms/spare_part/spare_part_request.dart b/lib/service_request_latest/views/forms/spare_part/spare_part_request.dart index 47c22606..90ae345f 100644 --- a/lib/service_request_latest/views/forms/spare_part/spare_part_request.dart +++ b/lib/service_request_latest/views/forms/spare_part/spare_part_request.dart @@ -50,8 +50,6 @@ class _SparePartRequestState extends State with TickerProvider final List _files = []; final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); - final TextEditingController _faultController = TextEditingController(); - final TextEditingController _workPreformedController = TextEditingController(); final TextEditingController _partQtyController = TextEditingController(); final TextEditingController _oracleNoController = TextEditingController(); @@ -77,9 +75,8 @@ class _SparePartRequestState extends State with TickerProvider @override void dispose() { - _faultController.dispose(); - _workPreformedController.dispose(); _partQtyController.dispose(); + _oracleNoController.dispose(); super.dispose(); } @@ -145,6 +142,7 @@ class _SparePartRequestState extends State with TickerProvider initialValue: serviceRequestProvider.initialSelectedSparePart.sparePart, backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, onSelect: (part) { + print('part i got is ${part.id}'); serviceRequestProvider.initialSelectedSparePart = SparePartsWorkOrders(id: 0, sparePart: part, qty: 0); }, ), diff --git a/lib/service_request_latest/views/forms/work_order/components/attachments_view.dart b/lib/service_request_latest/views/forms/work_order/components/attachments_view.dart index cb8a981a..5a07b5d1 100644 --- a/lib/service_request_latest/views/forms/work_order/components/attachments_view.dart +++ b/lib/service_request_latest/views/forms/work_order/components/attachments_view.dart @@ -5,7 +5,6 @@ import 'package:test_sa/controllers/providers/api/service_requests_provider.dart import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; -import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; class AttachmentView extends StatelessWidget { 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 new file mode 100644 index 00000000..26e3a6fa --- /dev/null +++ b/lib/service_request_latest/views/nurse/create_new_request_view.dart @@ -0,0 +1,215 @@ + +import 'dart:io'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/devices_provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; +import 'package:test_sa/controllers/validator/validator.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/device/asset.dart'; +import 'package:test_sa/models/device/asset_search.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/providers/work_order/reason_provider.dart'; +import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import 'package:test_sa/views/widgets/qr/scan_qr.dart'; +import '../../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; +import '../../../../../../new_views/common_widgets/default_app_bar.dart'; +class CreateNewRequest extends StatefulWidget { + static const String id = "/create-new-request"; + + const CreateNewRequest({Key key}) : super(key: key); + + @override + _CreateNewRequestState createState() => _CreateNewRequestState(); +} + +class _CreateNewRequestState extends State with TickerProviderStateMixin { + + AssetProvider _devicesProvider; + bool _isLoading = false; + int _selectedEStatus = 1; + bool _isHighPrority = false; + String text; + + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + void initState() { + super.initState(); + if (context.mounted) { + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).serviceRequestId = serviceRequestsProvider.currentSelectedRequest.id; + } + // _isLoading = true; + } + _getDevice(String result, {bool isQr = false}) async { + if (result == null) return; + _devicesProvider.reset(); + await _devicesProvider.getAssets( + search: AssetSearch(assetNo: result, assetSerialNumber: ""), + isQr: isQr, + ); + } + Asset loanAvailabilityAsset; + + + @override + Widget build(BuildContext context) { + + final List _files = []; + + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar(title: context.translation.createNewRequest), + body: Consumer(builder: (context, serviceRequestProvider, child) { + return SafeArea( + child: LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + child: Card( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppFilledButton( + label: context.translation.scanOrPickAsset, + showIcon: true, + icon: "scan_asset".toSvgAsset(height: 20, fit: BoxFit.contain, color: Theme.of(context).scaffoldBackgroundColor), + buttonColor: AppColor.neutral50, + onPressed: () async { + String result = await Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const ScanQr()), + ) as String; + _getDevice(result, isQr: true); + } , + ), + 21.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + context.translation.highPriority.bodyText(context).custom(color: AppColor.black20), + CupertinoSwitch( + value: _isHighPrority, + + onChanged: (value) { + setState(() { + // listingVm.listing[listingVm.listingParameter]['bayut'] = value; + _isHighPrority = value; + }); + }, + thumbColor: AppColor.red70, + activeColor: AppColor.red30.withOpacity(0.4), + + ), + ], + ), + 20.height, + context.translation.equipmentStatus.bodyText(context).custom(color: AppColor.black20), + 12.height, + assetStatusWidget(context), + 8.height, + + 23.height, + MultiFilesPicker(label: context.translation.attachImage, + files: _files, + buttonColor: AppColor.primary10, + onlyImages: true, + buttonIcon: 'image-plus'?.toSvgAsset(color: AppColor.primary10), + ), + AppTextFormField( + labelText: "Type any comment", + backgroundColor: AppColor.neutral30, + alignLabelWithHint: true, + showShadow: false, + validator: (value) => Validator.hasValue(value) ? null : context.translation.requiredField, + textInputType: TextInputType.multiline, + suffixIcon: "comment_send".toSvgAsset().paddingOnly(end: 16).onPress(() { + if (_formKey.currentState.validate()) { + _formKey.currentState.save(); + // final comment = Comment(id: 0, callRequestId: num.tryParse(widget.requestId ?? ""), comment: text); + // commentsProvider.addComment(context, comment: comment); + } + }), + onSaved: (value) { + text = value; + }, + ), + + + ], + ).paddingOnly(start:13,end: 13,top: 15,bottom: 16), + ).paddingAll(16), + ).expanded, + FooterActionButton.footerContainer( + child: AppFilledButton( + label: context.translation.submitRequest, + buttonColor: AppColor.primary10, + onPressed: (){}, + ), + ), + ], + ), + ), + ), + ); + }), + ); + } + Widget assetStatusWidget(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + radioButtonWidget(label: context.translation.up_and_running, value: 1), + radioButtonWidget(label: context.translation.partially_down, value: 2), + radioButtonWidget(label: context.translation.fully_down, value: 3), + ], + ); + } + + Widget radioButtonWidget({@required String label, @required dynamic value}) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 20.toScreenWidth, + height: 40.toScreenHeight, + //TODO use the type required according data.. + child: Radio( + activeColor: AppColor.primary10, + value: value, + groupValue: _selectedEStatus, + onChanged: (int value) { + setState(() { + _selectedEStatus = value; + }); + }, + ), + ), + 8.width, + Text( + label, + style: AppTextStyles.tinyFont, + ), + 13.width, + ], + ); + } +} diff --git a/lib/service_request_latest/views/request_detail_main_view.dart b/lib/service_request_latest/views/request_detail_main_view.dart index 1ab3c9d9..a93e5def 100644 --- a/lib/service_request_latest/views/request_detail_main_view.dart +++ b/lib/service_request_latest/views/request_detail_main_view.dart @@ -7,6 +7,7 @@ import 'package:test_sa/models/service_request/service_request.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/service_request_latest/views/components/history_log_view.dart'; +import 'package:test_sa/service_request_latest/views/components/initial_visit_card.dart'; import 'components/request_detail_view.dart'; @@ -52,7 +53,6 @@ class RequestDetailMain extends StatelessWidget { serviceRequest: ServiceRequest(id: requestId.toString()), fromTabView: true, ), - // HistoryLogView(), const HistoryLogView(), ], ).expanded, diff --git a/lib/views/pages/user/requests/work_order/work_orders_list_page.dart b/lib/views/pages/user/requests/work_order/work_orders_list_page.dart index b29e2383..cf4cd151 100644 --- a/lib/views/pages/user/requests/work_order/work_orders_list_page.dart +++ b/lib/views/pages/user/requests/work_order/work_orders_list_page.dart @@ -4,21 +4,15 @@ import 'package:test_sa/controllers/providers/api/service_requests_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/string_extensions.dart'; -import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/enums/user_types.dart'; import 'package:test_sa/models/service_request/search_work_order.dart'; import 'package:test_sa/models/service_request/service_request.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/default_app_bar.dart'; import 'package:test_sa/service_request_latest/views/components/activity_card_view.dart'; import 'package:test_sa/views/pages/user/requests/work_order/create_service_report.dart'; -import 'package:test_sa/views/pages/user/requests/work_order/update_service_report.dart'; -import 'package:test_sa/views/pages/user/requests/work_order/work_order_details_page.dart'; import 'package:test_sa/views/widgets/loaders/no_item_found.dart'; -import 'package:test_sa/views/widgets/requests/request_status.dart'; class WorkOrderListPage extends StatelessWidget { static const String id = "/work-order-list"; diff --git a/lib/views/widgets/date_and_time/time_picker.dart b/lib/views/widgets/date_and_time/time_picker.dart index 93525999..74ea5bb6 100644 --- a/lib/views/widgets/date_and_time/time_picker.dart +++ b/lib/views/widgets/date_and_time/time_picker.dart @@ -9,6 +9,7 @@ import 'package:test_sa/new_views/app_style/app_color.dart'; class ATimePicker extends StatelessWidget { final TimeOfDay time; final String label; + final String icon; final String hint; final Function(TimeOfDay) onTimePicker; final bool enable, withBorder, withIcon; @@ -19,6 +20,7 @@ class ATimePicker extends StatelessWidget { Key key, @required this.label, this.withBorder = true, + this.icon, this.withIcon = true, this.height, this.backgroundColor, @@ -30,7 +32,6 @@ class ATimePicker extends StatelessWidget { @override Widget build(BuildContext context) { - print('initial time in picker is $time'); return Container( height: height, decoration: BoxDecoration( @@ -61,7 +62,11 @@ class ATimePicker extends StatelessWidget { ).expanded, //: label.bodyText(context).paddingOnly(top: 8, bottom: 8), enable ? 16.width : const Spacer(), - withIcon ? "calender".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null) : const SizedBox(), + withIcon + ? icon != null + ? icon.toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null) + : "calender".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null) + : const SizedBox(), ], ), ).onPress(enable diff --git a/lib/views/widgets/e_signature/e_signature.dart b/lib/views/widgets/e_signature/e_signature.dart index ec25df33..4fbc46ba 100644 --- a/lib/views/widgets/e_signature/e_signature.dart +++ b/lib/views/widgets/e_signature/e_signature.dart @@ -13,11 +13,13 @@ import '../loaders/image_loader.dart'; class ESignature extends StatefulWidget { final String oldSignature; final Uint8List newSignature; + Color backgroundColor; + bool showShadow=true; final Function(Uint8List) onSaved; final Function(Uint8List) onChange; final String title; - const ESignature({Key key, this.title, this.oldSignature, this.onSaved, this.onChange, this.newSignature}) : super(key: key); + ESignature({Key key, this.title, this.oldSignature, this.onSaved, this.onChange, this.newSignature,this.backgroundColor,this.showShadow=true}) : super(key: key); @override State createState() => _ESignatureState(); @@ -63,9 +65,9 @@ class _ESignatureState extends State { width: MediaQuery.of(context).size.width, padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), decoration: BoxDecoration( - color: context.isDark ? AppColor.background(context) : Colors.white, + color:widget.backgroundColor ?? (context.isDark ? AppColor.background(context) : Colors.white), borderRadius: _editable ? const BorderRadius.only(topLeft: Radius.circular(10), topRight: Radius.circular(10)) : BorderRadius.circular(10), - boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], + boxShadow:widget.showShadow? [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)]:[], ), child: Column( crossAxisAlignment: CrossAxisAlignment.center, diff --git a/lib/views/widgets/images/multi_image_picker.dart b/lib/views/widgets/images/multi_image_picker.dart index be2236ca..c8e114bb 100644 --- a/lib/views/widgets/images/multi_image_picker.dart +++ b/lib/views/widgets/images/multi_image_picker.dart @@ -20,10 +20,11 @@ class MultiFilesPicker extends StatefulWidget { final bool enabled, onlyImages; double buttonHeight; Widget buttonIcon; + Color buttonColor; final Function(List) onChange; final bool showAsGrid; - MultiFilesPicker({Key key, this.files, this.label, this.error = false, this.buttonHeight, this.buttonIcon, this.enabled = true, this.onlyImages = false, this.onChange, this.showAsGrid = false}) + MultiFilesPicker({Key key, this.files, this.label, this.error = false, this.buttonHeight, this.buttonIcon, this.enabled = true, this.onlyImages = false, this.onChange, this.showAsGrid = false,this.buttonColor}) : super(key: key); @override @@ -39,6 +40,7 @@ class _MultiFilesPickerState extends State { AppDashedButton( title: widget.label, height: widget.buttonHeight, + buttonColor: widget.buttonColor, icon: widget.buttonIcon, onPressed: (widget.enabled == false) ? () {}