From 789522b79b02ede78db2ae9be9e6fc51b292c3be Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Tue, 9 Dec 2025 10:30:11 +0300 Subject: [PATCH 01/26] asset delivery modules design flow completed --- .../reports/problems/problems-report.html | 663 ++++++++++++++++++ assets/images/history_icon.svg | 4 + assets/images/web_link_icon.svg | 4 + .../models/asset_inventory_model.dart | 345 +++++++++ .../models/cost_center_model.dart | 27 + .../models/session_model.dart | 234 +++++++ .../pages/asset_delivery_detail_page.dart | 105 +++ .../pages/asset_delivery_item_view.dart | 113 +++ .../pages/asset_delivery_line_card_view.dart | 75 ++ .../pages/asset_delivery_page.dart | 249 +++++++ .../pages/asset_delivery_table_card_view.dart | 75 ++ .../pages/change_status_bottomsheet.dart | 60 ++ .../cost_center_form_view.dart | 213 ++++++ .../delivery_inspection_form_view.dart | 378 ++++++++++ .../cost_center_card_view.dart | 63 ++ .../end_user_acceptance_form_view.dart | 171 +++++ .../end_user_cost_center_list_view.dart | 343 +++++++++ .../update_end_user_cost_center_view.dart | 220 ++++++ .../pages/history_log_view.dart | 187 +++++ .../technical_inpection_asset_card_view.dart | 109 +++ ...nical_inpection_cost_center_card_view.dart | 77 ++ .../technical_inspection_lines_list_view.dart | 336 +++++++++ ...cal_inspection_parent_asset_list_view.dart | 87 +++ .../update_child_asset_view.dart | 145 ++++ .../update_parent_asset_view.dart | 258 +++++++ ...pdate_technical_inspection_lines_view.dart | 224 ++++++ .../provider/asset_delivery_provider.dart | 470 +++++++++++++ .../single_item_drop_down_menu.dart | 8 +- .../my_request/my_requests_page.dart | 3 +- .../requests/request_paginated_listview.dart | 3 + .../widgets/request_item_view_list.dart | 5 + 31 files changed, 5252 insertions(+), 2 deletions(-) create mode 100644 android/build/reports/problems/problems-report.html create mode 100644 assets/images/history_icon.svg create mode 100644 assets/images/web_link_icon.svg create mode 100644 lib/modules/asset_delivery_module/models/asset_inventory_model.dart create mode 100644 lib/modules/asset_delivery_module/models/cost_center_model.dart create mode 100644 lib/modules/asset_delivery_module/models/session_model.dart create mode 100644 lib/modules/asset_delivery_module/pages/asset_delivery_detail_page.dart create mode 100644 lib/modules/asset_delivery_module/pages/asset_delivery_item_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/asset_delivery_page.dart create mode 100644 lib/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/change_status_bottomsheet.dart create mode 100644 lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/end_user_acceptance/cost_center_card_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_acceptance_form_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/history_log_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart create mode 100644 lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart diff --git a/android/build/reports/problems/problems-report.html b/android/build/reports/problems/problems-report.html new file mode 100644 index 00000000..d59d3b0f --- /dev/null +++ b/android/build/reports/problems/problems-report.html @@ -0,0 +1,663 @@ + + + + + + + + + + + + + Gradle Configuration Cache + + + +
+ +
+ Loading... +
+ + + + + + diff --git a/assets/images/history_icon.svg b/assets/images/history_icon.svg new file mode 100644 index 00000000..89ab3df8 --- /dev/null +++ b/assets/images/history_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/web_link_icon.svg b/assets/images/web_link_icon.svg new file mode 100644 index 00000000..9d77b3f7 --- /dev/null +++ b/assets/images/web_link_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/lib/modules/asset_delivery_module/models/asset_inventory_model.dart b/lib/modules/asset_delivery_module/models/asset_inventory_model.dart new file mode 100644 index 00000000..4a4e6587 --- /dev/null +++ b/lib/modules/asset_delivery_module/models/asset_inventory_model.dart @@ -0,0 +1,345 @@ +import 'dart:developer'; + +import 'package:test_sa/models/new_models/building.dart'; +import 'package:test_sa/models/new_models/floor.dart'; +import 'package:test_sa/models/new_models/room_model.dart'; +import 'package:test_sa/models/new_models/site.dart'; +import 'package:test_sa/models/service_request/supplier_details.dart'; +import '../../../models/new_models/department.dart'; + +class AssetInventoryResponse { + num? totalRows; + num? count; + String? message; + String? title; + String? innerMessage; + num? responseCode; + bool? isSuccess; + List? assetList; + + AssetInventoryResponse({ + this.totalRows, + this.count, + this.message, + this.title, + this.innerMessage, + this.responseCode, + this.isSuccess, + this.assetList, + }); + + AssetInventoryResponse.fromJson(Map json) { + totalRows = json['totalRows']; + count = json['count']; + message = json['message']; + title = json['title']; + innerMessage = json['innerMessage']; + responseCode = json['responseCode']; + isSuccess = json['isSuccess']; + if (json['data'] != null) { + assetList = (json['data'] as List).map((item) => AssetInventoryModel.fromJson(item)).toList(); + } + } + + Map toJson() { + return { + 'totalRows': totalRows, + 'count': count, + 'message': message, + 'title': title, + 'innerMessage': innerMessage, + 'responseCode': responseCode, + 'isSuccess': isSuccess, + }; + } +} + +class AssetInventoryModel { + num? id; + num? assetId; + String? transactionDate; + String? assetNumber; + String? serialNo; + String? assetName; + num? assetNameId; + String? model; + String? manufacturer; + String? supplierName; + String? siteName; + String? buildingName; + String? floorName; + String? departmentName; + String? roomName; + num? statusId; + String? status; + num? statusValue; + num? statusByAdminId; + String? statusByAdmin; + num? statusByAdminValue; + bool? isNotRegistered; + num? sessionId; + num? assetImportId; + num? siteId; + num? supplierId; + num? buildingId; + num? floorId; + num? departmentId; + num? roomId; + String? newAssetNumber; + String? newSerialNo; + num? newAssetNameId; + String? newAssetNameText; + num? newModelId; + String? newModelName; + num? manufacturerId; + num? modelId; + num? newManufacturerId; + String? newManufacturerName; + num? newSupplierId; + String? newSupplierName; + String? photo; + String? photoOriginName; + String? remarks; + Site? site; + Building? building; + Floor? floor; + Department? department; + Rooms? room; + SupplierDetails? supplier; + List assetInventoryDetailAssetAttachments = []; + + AssetInventoryModel({ + this.id, + this.sessionId, + this.assetId, + this.transactionDate, + this.assetNumber, + this.assetNameId, + this.serialNo, + this.assetName, + this.model, + this.manufacturer, + this.supplierName, + this.siteName, + this.buildingName, + this.floorName, + this.departmentName, + this.roomName, + this.statusId, + this.status, + this.statusValue, + this.statusByAdminId, + this.statusByAdmin, + this.statusByAdminValue, + this.isNotRegistered, + this.assetImportId, + this.siteId, + this.buildingId, + this.floorId, + this.departmentId, + this.supplierId, + this.roomId, + this.newAssetNumber, + this.manufacturerId, + this.newSerialNo, + this.newAssetNameId, + this.newAssetNameText, + this.newModelId, + this.modelId, + this.newModelName, + this.newManufacturerId, + this.newManufacturerName, + this.newSupplierId, + this.newSupplierName, + this.photo, + this.photoOriginName, + this.remarks, + this.site, + this.department, + this.building, + this.floor, + this.room, + this.supplier, + this.assetInventoryDetailAssetAttachments = const [], + }); + + AssetInventoryModel.fromJson(Map json) { + id = json['id']; + assetId = json['assetId']; + transactionDate = json['transactionDate']; + assetNumber = json['assetNumber']; + assetNameId = json['assetNameId']; + serialNo = json['serialNo']; + assetName = json['assetName']; + model = json['model'] ?? json['modelName']; + manufacturer = json['manufacturer'] ?? json['manufacturerName']; + supplierName = json['supplierName']; + siteName = json['site'] ?? json['siteName']; + buildingName = json['building'] ?? json['buildingName']; + floorName = json['floor'] ?? json['floorName']; + departmentName = json['department'] ?? json['departmentName']; + roomName = json['room'] ?? json['roomName']; + statusId = json['statusId']; + status = json['status'] ?? json['classification']; + statusValue = json['statusValue']; + isNotRegistered = json['isNotRegistered']; + sessionId = json['sessionId']; + assetImportId = json['assetImportId']??json['id']; + siteId = json['siteId']; + buildingId = json['buildingId']; + floorId = json['floorId']; + supplierId = json['supplierId']; + departmentId = json['departmentId']; + roomId = json['roomId']; + modelId = json['modelId']; + photo = json['photo']; + photoOriginName = json['photoOriginName']; + remarks = json['remarks']; + if (json['assetTransferAttachments'] != null) { + assetInventoryDetailAssetAttachments = []; + json['assetInventoryDetailAssetAttachments'].forEach((v) { + assetInventoryDetailAssetAttachments.add(AssetInventoryDetailAssetAttachments.fromJson(v)); + }); + } + + //new data.. + // newAssetNumber = json['newAssetNumber'] ?? json['assetNumber']; + // manufacturerId = json['manufacturerId'] ?? json['manufacturerId']; + // newSerialNo = json['newSerialNo'] ?? json['serialNo']; + // newAssetNameId = json['newAssetNameId'] ?? json['assetNameId']; + // newAssetNameText = json['newAssetNameText'] ?? json['assetNameText']; + // newModelId = json['newModelId'] ?? json['modelId']; + // newModelName = json['newModelName'] ?? json['modelName']; + // newManufacturerId = json['newManufacturerId'] ?? json['manufacturerId']; + // newManufacturerName = json['newManufacturerName'] ?? json['manufacturerName']; + // newSupplierId = json['newSupplierId'] ?? json['supplierId']; + // newSupplierName = json['newSupplierName'] ?? json['supplierName']; + } + + Map toJson() { + return { + 'isNotRegistered': isNotRegistered, + 'sessionId': sessionId, + 'assetImportId': assetImportId, + 'transactionDate': transactionDate, + 'assetId': assetId, + 'siteId': siteId, + 'buildingId': buildingId, + 'floorId': floorId, + 'departmentId': departmentId, + 'roomId': roomId, + 'newSerialNo': newSerialNo, + 'newAssetNameId': newAssetNameId, + 'newAssetNameText': newAssetNameText, + 'newAssetNumber': newAssetNumber, + 'newModelId': newModelId, + 'newModelName': newModelName, + 'newManufacturerId': newManufacturerId, + 'newManufacturerName': newManufacturerName, + 'newSupplierId': newSupplierId, + 'newSupplierName': newSupplierName, + 'photo': photo, + 'remarks': remarks, + 'assetInventoryDetailAssetAttachments': assetInventoryDetailAssetAttachments != null + ? assetInventoryDetailAssetAttachments!.map((v) => v.toJson()).toList() + : [], + }; + } + + AssetInventoryModel mergeWith(AssetInventoryModel? other) { + if (other == null) return this; + + return AssetInventoryModel( + id: id ?? other.id, + assetId: assetId ?? other.assetId, + transactionDate: transactionDate ?? other.transactionDate, + assetNumber: assetNumber ?? other.assetNumber, + serialNo: serialNo ?? other.serialNo, + assetName: assetName ?? other.assetName, + assetNameId: assetNameId ?? other.assetNameId, + model: model ?? other.model, + manufacturer: manufacturer ?? other.manufacturer, + supplierName: supplierName ?? other.supplierName, + siteName: siteName ?? other.siteName, + buildingName: buildingName ?? other.buildingName, + floorName: floorName ?? other.floorName, + departmentName: departmentName ?? other.departmentName, + roomName: roomName ?? other.roomName, + statusId: statusId ?? other.statusId, + status: status ?? other.status, + statusValue: statusValue ?? other.statusValue, + statusByAdminId: statusByAdminId ?? other.statusByAdminId, + statusByAdmin: statusByAdmin ?? other.statusByAdmin, + statusByAdminValue: statusByAdminValue ?? other.statusByAdminValue, + isNotRegistered: isNotRegistered ?? other.isNotRegistered, + sessionId: sessionId ?? other.sessionId, + assetImportId: assetImportId ?? other.assetImportId, + siteId: siteId ?? other.siteId, + supplierId: supplierId ?? other.supplierId, + buildingId: buildingId ?? other.buildingId, + floorId: floorId ?? other.floorId, + departmentId: departmentId ?? other.departmentId, + roomId: roomId ?? other.roomId, + newAssetNumber: newAssetNumber ?? other.newAssetNumber, + newSerialNo: newSerialNo ?? other.newSerialNo, + newAssetNameId: newAssetNameId ?? other.newAssetNameId, + newAssetNameText: newAssetNameText ?? other.newAssetNameText, + newModelId: newModelId ?? other.newModelId, + newModelName: newModelName ?? other.newModelName, + manufacturerId: manufacturerId ?? other.manufacturerId, + modelId: modelId ?? other.modelId, + newManufacturerId: newManufacturerId ?? other.newManufacturerId, + newManufacturerName: newManufacturerName ?? other.newManufacturerName, + newSupplierId: newSupplierId ?? other.newSupplierId, + newSupplierName: newSupplierName ?? other.newSupplierName, + photo: photo ?? other.photo, + photoOriginName: photoOriginName ?? other.photoOriginName, + remarks: remarks ?? other.remarks, + site: site ?? other.site, + building: building ?? other.building, + floor: floor ?? other.floor, + department: department ?? other.department, + room: room ?? other.room, + supplier: supplier ?? other.supplier, + assetInventoryDetailAssetAttachments: assetInventoryDetailAssetAttachments??other.assetInventoryDetailAssetAttachments, + ); + } + + +} +class AssetInventoryDetailAssetAttachments { + AssetInventoryDetailAssetAttachments({ + this.id, + this.name, + this.originalName, + }); + + AssetInventoryDetailAssetAttachments.fromJson(dynamic json) { + id = json['id']; + name = json['name']; + originalName = json['originalName']; + } + + num? id; + String? name; + String? originalName; + + AssetInventoryDetailAssetAttachments copyWith({ + num? id, // Parameter is now nullable + String? name, // Parameter is now nullable + String? originalName, // Parameter is now nullable + }) => + AssetInventoryDetailAssetAttachments( + id: id ?? this.id, + name: name??this.name, + originalName: originalName??this.originalName, + ); + + Map toJson() { + final map = {}; + map['id'] = id; + map['name'] = name; + map['originalName'] = originalName; + return map; + } +} diff --git a/lib/modules/asset_delivery_module/models/cost_center_model.dart b/lib/modules/asset_delivery_module/models/cost_center_model.dart new file mode 100644 index 00000000..d465b58d --- /dev/null +++ b/lib/modules/asset_delivery_module/models/cost_center_model.dart @@ -0,0 +1,27 @@ +import 'package:test_sa/models/lookup.dart'; + +class CostCenterModel { + Lookup? costCenter; + double? quantity; + + CostCenterModel({ + this.costCenter, + this.quantity, + }); + + CostCenterModel.fromJson(Map json) { + costCenter = json['costCenter'] != null + ? Lookup.fromJson(json['costCenter']) + : null; + quantity = json['quantity']; + } + + Map toJson() { + final Map data = {}; + if (costCenter != null) { + data['costCenter'] = costCenter!.toJson(); + } + data['quantity'] = quantity; + return data; + } +} diff --git a/lib/modules/asset_delivery_module/models/session_model.dart b/lib/modules/asset_delivery_module/models/session_model.dart new file mode 100644 index 00000000..8de8503b --- /dev/null +++ b/lib/modules/asset_delivery_module/models/session_model.dart @@ -0,0 +1,234 @@ +import 'package:test_sa/models/new_models/site.dart'; + +class SessionModel { + int? id; + String? createdDate; + String? sessionName; + int? sessionTypeId; + int? sessionTypeValue; + String? sessionTypeName; + int? statusId; + String? statusName; + String? startDate; + String? endDate; + List assetInventorySites = []; + List assetInventoryAssignedEmployee = []; + + SessionModel({ + this.id, + this.sessionName, + this.createdDate, + this.sessionTypeId, + this.sessionTypeValue, + this.sessionTypeName, + this.statusId, + this.statusName, + this.startDate, + this.endDate, + List? assetInventorySites, + List? assetInventoryAssignedEmployee, + }) { + this.assetInventorySites = assetInventorySites ?? []; + this.assetInventoryAssignedEmployee = assetInventoryAssignedEmployee ?? []; + } + + SessionModel.fromJson(Map json) { + id = json['id']; + sessionName = json['sessionName']; + sessionTypeId = json['sessionTypeId']; + sessionTypeValue = json['sessionTypeValue']; + sessionTypeName = json['sessionTypeName']; + statusId = json['statusId']; + createdDate = json['createdDate']; + statusName = json['statusName']; + startDate = json['startDate']; + endDate = json['endDate']; + + if (json['assetInventorySites'] != null) { + assetInventorySites = (json['assetInventorySites'] as List).map((e) => Site.fromJson(e)).toList(); + } + + if (json['assetInventoryAssignedEmployee'] != null) { + assetInventoryAssignedEmployee = (json['assetInventoryAssignedEmployee'] as List).map((e) => AssetInventoryAssignedEmployee.fromJson(e)).toList(); + } + } + + Map toJson() { + final map = {}; + map['id'] = id; + map['sessionName'] = sessionName; + map['sessionTypeId'] = sessionTypeId; + map['sessionTypeValue'] = sessionTypeValue; + map['sessionTypeName'] = sessionTypeName; + map['statusId'] = statusId; + map['statusName'] = statusName; + map['createdDate'] = createdDate; + map['startDate'] = startDate; + map['endDate'] = endDate; + map['assetInventorySites'] = assetInventorySites.map((e) => e.toJson()).toList(); + map['assetInventoryAssignedEmployee'] = assetInventoryAssignedEmployee.map((e) => e.toJson()).toList(); + return map; + } +} + +// class AssetInventorySite { +// int? siteId; +// String? siteName; +// List assetInventoryBuildings = []; +// +// AssetInventorySite({ +// this.siteId, +// this.siteName, +// List? assetInventoryBuildings, +// }) { +// this.assetInventoryBuildings = assetInventoryBuildings ?? []; +// } +// +// AssetInventorySite.fromJson(Map json) { +// siteId = json['siteId']; +// siteName = json['siteName']; +// +// if (json['assetInventoryBuildings'] != null) { +// assetInventoryBuildings = (json['assetInventoryBuildings'] as List).map((e) => AssetInventoryBuilding.fromJson(e)).toList(); +// } +// } +// +// Map toJson() { +// final map = {}; +// map['siteId'] = siteId; +// map['siteName'] = siteName; +// map['assetInventoryBuildings'] = assetInventoryBuildings.map((e) => e.toJson()).toList(); +// return map; +// } +// } +// +// class AssetInventoryBuilding { +// int? buildingId; +// String? buildingName; +// List assetInventoryFloors = []; +// +// AssetInventoryBuilding({ +// this.buildingId, +// this.buildingName, +// List? assetInventoryFloors, +// }) { +// this.assetInventoryFloors = assetInventoryFloors ?? []; +// } +// +// AssetInventoryBuilding.fromJson(Map json) { +// buildingId = json['buildingId']; +// buildingName = json['buildingName']; +// +// if (json['assetInventoryFloors'] != null) { +// assetInventoryFloors = (json['assetInventoryFloors'] as List).map((e) => AssetInventoryFloor.fromJson(e)).toList(); +// } +// } +// +// Map toJson() { +// final map = {}; +// map['buildingId'] = buildingId; +// map['buildingName'] = buildingName; +// map['assetInventoryFloors'] = assetInventoryFloors.map((e) => e.toJson()).toList(); +// return map; +// } +// } +// +// class AssetInventoryFloor { +// int? floorId; +// String? floorName; +// List assetInventoryDepartments = []; +// +// AssetInventoryFloor({ +// this.floorId, +// this.floorName, +// List? assetInventoryDepartments, +// }) { +// this.assetInventoryDepartments = assetInventoryDepartments ?? []; +// } +// +// AssetInventoryFloor.fromJson(Map json) { +// floorId = json['floorId']; +// floorName = json['floorName']; +// +// if (json['assetInventoryDepartments'] != null) { +// assetInventoryDepartments = (json['assetInventoryDepartments'] as List).map((e) => AssetInventoryDepartment.fromJson(e)).toList(); +// } +// } +// +// Map toJson() { +// final map = {}; +// map['floorId'] = floorId; +// map['floorName'] = floorName; +// map['assetInventoryDepartments'] = assetInventoryDepartments.map((e) => e.toJson()).toList(); +// return map; +// } +// } +// +// class AssetInventoryDepartment { +// int? departmentId; +// String? departmentName; +// List assetInventoryRooms = []; +// +// AssetInventoryDepartment({ +// this.departmentId, +// this.departmentName, +// List? assetInventoryRooms, +// }) { +// this.assetInventoryRooms = assetInventoryRooms ?? []; +// } +// +// AssetInventoryDepartment.fromJson(Map json) { +// departmentId = json['departmentId']; +// departmentName = json['departmentName']; +// +// if (json['assetInventoryRooms'] != null) { +// assetInventoryRooms = (json['assetInventoryRooms'] as List).map((e) => AssetInventoryRoom.fromJson(e)).toList(); +// } +// } +// +// Map toJson() { +// final map = {}; +// map['departmentId'] = departmentId; +// map['departmentName'] = departmentName; +// map['assetInventoryRooms'] = assetInventoryRooms.map((e) => e.toJson()).toList(); +// return map; +// } +// } +// +// class AssetInventoryRoom { +// int? roomId; +// String? roomName; +// +// AssetInventoryRoom({this.roomId, this.roomName}); +// +// AssetInventoryRoom.fromJson(Map json) { +// roomId = json['roomId']; +// roomName = json['roomName']; +// } +// +// Map toJson() { +// final map = {}; +// map['roomId'] = roomId; +// map['roomName'] = roomName; +// return map; +// } +// } + +class AssetInventoryAssignedEmployee { + String? assignedEngineerId; + String? assignedEngineerName; + + AssetInventoryAssignedEmployee({this.assignedEngineerId, this.assignedEngineerName}); + + AssetInventoryAssignedEmployee.fromJson(Map json) { + assignedEngineerId = json['assignedEngineerId']; + assignedEngineerName = json['assignedEngineerName']; + } + + Map toJson() { + final map = {}; + map['assignedEngineerId'] = assignedEngineerId; + map['assignedEngineerName'] = assignedEngineerName; + return map; + } +} diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_detail_page.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_detail_page.dart new file mode 100644 index 00000000..d0b4f264 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/asset_delivery_detail_page.dart @@ -0,0 +1,105 @@ + +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/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/history_log_view.dart'; +import 'package:test_sa/modules/cm_module/cm_detail_provider.dart'; +import 'package:test_sa/modules/cx_module/chat/chat_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; + +class AssetDeliveryDetailPage extends StatefulWidget { + final int requestId; + + AssetDeliveryDetailPage({Key? key, required this.requestId}) : super(key: key); + + @override + _AssetDeliveryDetailPageState createState() { + return _AssetDeliveryDetailPageState(); + } +} + +class _AssetDeliveryDetailPageState extends State { + late CMDetailProvider _requestProvider; + + static const int moduleId = 1; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + Provider.of(context, listen: false).reset(); + getInitialData(); + }); + } + + Future getInitialData() async { + ///Replace with data ... + // _requestProvider = Provider.of(context, listen: false); + // await _requestProvider.getWorkOrderById(id: widget.requestId); + + } + + @override + void dispose() { + super.dispose(); + } + + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + appBar: DefaultAppBar( + ///Title should be change with view change + title: 'Delivery Inspection'.addTranslation, + onBackPress: () { + Navigator.pop(context); + }, + ), + 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( + //controller: _tabController, + 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, + indicatorSize: TabBarIndicatorSize.tab, + dividerColor: Colors.transparent, + indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)), + onTap: (index) { + // setState(() {}); + }, + tabs: [ + Tab(text: context.translation.details, height: 57.toScreenHeight), + Tab(text: context.translation.historyLogs, height: 57.toScreenHeight), + ], + ), + ), + 12.height, + TabBarView( + children: [ + DeliveryInspectionFormView(), + const AssetDeliveryHistoryLogView(), + ], + ).expanded, + ], + ), + )); + } + +} diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_item_view.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_item_view.dart new file mode 100644 index 00000000..99aafbf3 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/asset_delivery_item_view.dart @@ -0,0 +1,113 @@ +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/models/all_requests_and_count_model.dart'; +import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_page.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_page.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class AssetDeliveryItemView extends StatelessWidget { + final Data? requestData; + final RequestsDetails? requestDetails; + final bool showShadow; + const AssetDeliveryItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); + + @override + Widget build(BuildContext context) { + if (requestData != null) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Row( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // StatusLabel( + // label: requestData!.statusName!, + // textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.statusName!), + // backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.statusName!), + // ), + // 1.width.expanded, + // Text( + // requestData!.transactionDate?.toServiceRequestCardFormat ?? "", + // textAlign: TextAlign.end, + // style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + // ), + // ], + // ), + 8.height, + 'Asset Delivery'.addTranslation.heading5(context), + infoWidget(label: 'Delivery Type'.addTranslation, value: '-', context: context), + infoWidget(label: 'No of Assets'.addTranslation, value: '-', context: context), + infoWidget(label: 'No of Sites'.addTranslation, value: '-', context: context), + // infoWidget(label: 'No of Sites'.addTranslation, value: requestData?.numberOfSites != null ? requestData?.numberOfSites.toString() : '-', context: context), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.of(context).push(MaterialPageRoute(builder: (_) => AssetInventoryPage(sessionId: requestData!.id!, moduleId: requestData!.transactionNo!))); + }); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Row( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // StatusLabel( + // label: requestDetails!.status!, + // textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.status!), + // backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.status!), + // ), + // 1.width.expanded, + // Text( + // requestDetails!.date?.toServiceRequestCardFormat ?? "", + // textAlign: TextAlign.end, + // style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + // ), + // ], + // ), + 8.height, + 'Asset Delivery'.addTranslation.heading5(context), + infoWidget(label: 'Delivery Type'.addTranslation, value: '-', context: context), + infoWidget(label: 'No of Assets'.addTranslation, value: '-', context: context), + infoWidget(label: 'No of Sites'.addTranslation, value: '-', context: context), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.of(context).push(MaterialPageRoute(builder: (_) => AssetDeliveryPage(requestId: requestDetails!.id!))); + }); + } + + Widget infoWidget({required String label, String? value, required BuildContext context}) { + if (value != null && value.isNotEmpty) { + return '$label: $value'.bodyText(context); + } + return const SizedBox(); + } +} diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart new file mode 100644 index 00000000..b8a22248 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.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/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; + +class AssetDeliveryLineCard extends StatelessWidget { + ///Need to replace with Lines model. + AssetInventoryModel deliveryDetails; + ///if include in model skip this + bool isViewOnly; + VoidCallback ?editPress; + + AssetDeliveryLineCard({ + super.key, + required this.isViewOnly, + required this.deliveryDetails, + this.editPress, + }); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + //need to check this @waseem. + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Item No: ${deliveryDetails.transactionDate?.toServiceRequestDetailsFormat ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + if(!isViewOnly) + 'edit_icon'.toSvgAsset().onPress(() { + if(editPress!=null){ + editPress!(); + } + }), + ], + ), + Text( + 'Item Description: ${deliveryDetails.assetNumber ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Quantity: ${deliveryDetails.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Remaining Quantity: ${deliveryDetails.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Quantity of this Delivery: ${deliveryDetails.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Marge Unit: ${deliveryDetails.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Unit price: ${deliveryDetails.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Total: ${deliveryDetails.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12); + } +} diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart new file mode 100644 index 00000000..eba6ccd8 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart @@ -0,0 +1,249 @@ +import 'dart:developer'; + +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/models/new_models/site.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_detail_page.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/change_status_bottomsheet.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/session_model.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/views/widgets/loaders/no_data_found.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class AssetDeliveryPage extends StatefulWidget { + final int? requestId; + + const AssetDeliveryPage({ + Key? key, + this.requestId, + }) : super(key: key); + + @override + State createState() => _AssetDeliveryPageState(); +} + +class _AssetDeliveryPageState extends State { + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + appBar: DefaultAppBar( + title: 'Asset Delivery'.addTranslation, + onBackPress: () { + Navigator.pop(context); + }, + ), + body: widget.requestId == null + ? const NoDataFound() + : ListView( + padding: const EdgeInsets.all(12), + children: [ + requestDetailCard(context), + // const SizedBox(height: 12), + const Divider().defaultStyle(context), + assetDeliveryTableList(context), + ], + ).toShadowContainer(context, borderRadius: 20, padding: 0, margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 12)), + ); + } + + TextStyle infoTextStyle(context) => AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120); + + Widget requestDetailCard(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Row( + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // // + // StatusLabel( + // label: sessionModel.statusName, + // id: sessionModel.statusId, + // radius: 4, + // textColor: AppColor.getRequestStatusTextColorByName(context, sessionModel.statusName), + // backgroundColor: AppColor.getRequestStatusColorByName(context, sessionModel.statusName), + // // textColor: AppColor.green15, + // // backgroundColor: AppColor.greenStatus(context), + // ), + // Text( + // sessionModel.createdDate!.toString().toServiceRequestCardFormat, + // textAlign: TextAlign.end, + // style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + // ) + // ], + // ), + 8.height, + //neutral120 + Text( + 'PO No. Internal'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + 'PO8745623'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Checkbox( + value: true, + activeColor: AppColor.neutral120, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: const VisualDensity(horizontal: -4, vertical: -3), + onChanged: (value) {}, + ), + 8.width, + Text( + 'HMS'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + ], + ), + 8.height, + Text( + 'Operation Units'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + '50'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'PO No.'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + 'PO438'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Warranty Period'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + '1 Year'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Payment Terms Amount'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + '70%'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'EDD (Estimated Delivery Date)'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + '25 December, 2025'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Total'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + '4930'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + ], + ); + } + + Widget assetDeliveryTableList(BuildContext context) { + final assetDeliveryTableList = ['abc', 'def', 'ghi', 'fhg', 'hjhh']; + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Asset Delivery Table", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + Container( + height: 24, + width: 24, + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: AppColor.primary10, // or AppColor.blueStatus(context) + ), + alignment: Alignment.center, + child: const Icon( + Icons.add, + color: Colors.white, + size: 16, + ), + ).onPress(() { + //add entry into table. + }), + // AppFilledButton( + // label: '', + // maxWidth: true, + // textColor: AppColor.textColor(context), + // buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, + // icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), + // showIcon: true, + // onPressed: (){ + // + // }, + // ) + ], + ), + 8.height, + ListView.separated( + itemCount: assetDeliveryTableList.length, + separatorBuilder: (_, __) => 8.height, + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (listContext, itemIndex) { + return AssetDeliveryTableCard( + deliveryDetails: AssetInventoryModel(), + onCardTap: () { + ///TODO need to display bottomsheet to change status if new... + // if(status=='NEW') + // AssetDeliveryBottomSheet.changeStatusBottomSheet(context: context); + Navigator.of(context).push(MaterialPageRoute(builder: (_) => AssetDeliveryDetailPage(requestId: 13,))); + }, + onViewHistoryPress: () {}, + ); + }, + ), + ], + ); + } +} diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart new file mode 100644 index 00000000..bcbf9544 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart @@ -0,0 +1,75 @@ + +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/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class AssetDeliveryTableCard extends StatelessWidget { + //Need to replace with AssetTableCard. + AssetInventoryModel deliveryDetails; + VoidCallback onViewHistoryPress; + VoidCallback onCardTap; + + AssetDeliveryTableCard({ + super.key, + required this.deliveryDetails, + required this.onViewHistoryPress, + required this.onCardTap, + }); + + @override + Widget build(BuildContext context) { + deliveryDetails.status = 'New'; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + StatusLabel( + label: deliveryDetails.status, + textColor: AppColor.getRequestStatusTextColorByName(context, deliveryDetails.status), + backgroundColor: AppColor.getRequestStatusColorByName(context, deliveryDetails.status), + ), + Row( + children: [ + 'history_icon'.toSvgAsset(), + 6.width, + Text( + 'View History'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + ], + ).onPress(() { + onViewHistoryPress(); + }), + ], + ), + 8.height, + Text( + 'Delivery Number: ${deliveryDetails.transactionDate?.toServiceRequestDetailsFormat ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Delivery Amount: ${deliveryDetails.assetNumber ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Invoice Amount: ${deliveryDetails.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Align( + alignment: Alignment.centerRight, + child: Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14), + ), + ], + ).toShadowContainer(context, borderRadius: 20).onPress((){ + onCardTap(); + }); + } +} diff --git a/lib/modules/asset_delivery_module/pages/change_status_bottomsheet.dart b/lib/modules/asset_delivery_module/pages/change_status_bottomsheet.dart new file mode 100644 index 00000000..e0f1baa5 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/change_status_bottomsheet.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; + +class AssetDeliveryBottomSheet { + static buildBottomSheetParent({required BuildContext context, required Widget childWidget, bool? isDismissible}) { + return showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + isDismissible: isDismissible ?? true, + backgroundColor: Colors.transparent, + builder: (context) => SingleChildScrollView( + child: SafeArea(child: childWidget), + ).bottomSheetContainer(context), + ); + } + + static Future changeStatusBottomSheet({required BuildContext context}) { + return buildBottomSheetParent( + context: context, + childWidget: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox().indicatorWidget(), + 8.height, + Align( + alignment: AlignmentDirectional.centerStart, + child: Text('Change Status'.addTranslation,style: TextStyle( + fontSize: 21.toScreenWidth, + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + decoration: TextDecoration.none, + ),), + ), + 10.height, + Row( + children: [ + AppFilledButton( + label: 'Cancel'.addTranslation, + maxWidth: true, + buttonColor: Colors.white, + // textColor: context.isDark ? AppColor.neutral30 : Colors.white, + textColor: AppColor.red30, + showBorder: true, + onPressed: () { + Navigator.pop(context); + }, + ).expanded, + 12.width, + AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: () {}).expanded, + ], + ), + ], + )); + } +} diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart new file mode 100644 index 00000000..afe55e40 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart @@ -0,0 +1,213 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/common_widgets/lookup_autocomplete_field.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/lookup.dart'; +import 'package:test_sa/models/new_models/work_order_detail_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; +import 'package:test_sa/modules/cm_module/cm_detail_provider.dart'; +import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.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/default_app_bar.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/lookups/request_type_lookup_provider.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/views/widgets/status/report/service_report_assistant_employee_menu.dart'; + +class CostCenterFormView extends StatefulWidget { + final List? costCenterList; + final ValueChanged>? onListChanged; + final double? cardPadding; + + const CostCenterFormView({ + super.key, + this.costCenterList, + this.onListChanged, + this.cardPadding, + }); + + @override + State createState() => _CostCenterFormViewState(); +} + +class _CostCenterFormViewState extends State { + late List _list; + + @override + void initState() { + super.initState(); + _list = List.from(widget.costCenterList ?? []); + } + + void _addNewEntry() { + setState(() { + _list.add(CostCenterModel()); + }); + widget.onListChanged?.call(_list); + } + + void _removeEntry(int index) { + setState(() { + _list.removeAt(index); + }); + widget.onListChanged?.call(_list); + } + + void _updateModel(int index, void Function(CostCenterModel model) updateList) { + setState(() { + updateList(_list[index]); + }); + } + + @override + Widget build(BuildContext context) { + ///Need to add check if status changes.. + final isReadOnly = Provider.of(context, listen: false).isReadOnlyRequest; + return Scaffold( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + appBar: DefaultAppBar( + title: 'Cost Center for Item'.addTranslation, + onBackPress: () { + Navigator.pop(context); + }, + ), + body: Column( + children: [ + ListView.builder( + itemCount: _list.length + 1, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.all(widget.cardPadding ?? 16), + itemBuilder: (context, index) { + if (index == _list.length) { + return Visibility( + visible: !isReadOnly, + child: AppFilledButton( + label: "Add Cost Center".addTranslation, + maxWidth: true, + textColor: AppColor.textColor(context), + buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, + icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), + showIcon: true, + onPressed: _addNewEntry, + ), + ); + } + return CostCenterItemCard( + model: _list[index], + index: index, + isReadOnly: isReadOnly, + onUpdate: (updateList) => _updateModel(index, updateList), + onRemove: () => _removeEntry(index), + ); + }, + ).expanded, + 8.height, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: () {}), + ), + ], + ), + ); + } +} + +class CostCenterItemCard extends StatelessWidget { + final CostCenterModel model; + final int index; + final bool isReadOnly; + final void Function(void Function(CostCenterModel model)) onUpdate; + final VoidCallback onRemove; + + const CostCenterItemCard({ + super.key, + required this.model, + required this.index, + required this.isReadOnly, + required this.onUpdate, + required this.onRemove, + }); + + @override + Widget build(BuildContext context) { + final requestedDate = Provider.of(context, listen: false).currentWorkOrder?.data?.requestedDate; + + return Column( + children: [ + if (!isReadOnly) + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + 'Cost Center'.addTranslation.bodyText(context).custom(color: AppColor.textColor(context)), + if (!isReadOnly) + Container( + height: 28, + width: 28, + padding: const EdgeInsets.all(6), + child: "trash".toSvgAsset(height: 20, width: 20), + ).onPress(onRemove), + ], + ), + 8.height, + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ///TODO replace with exact data or type like searchable dropdown... + AppTextFormField( + labelText: 'Item No'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: '232434', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + enable: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Item Description', + backgroundColor: AppColor.fieldBgColor(context), + initialValue: 'test decription abc', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + enable: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + LookUpAutoCompleteField( + clearAfterPick: false, + forAssetName: true, + onChanged: (value) {}, + initialValue: model.costCenter?.name ?? '', + label: 'Cost Center'.addTranslation, + onPick: (value) { + model.costCenter = value; + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + showAsBottomSheet: true, + backgroundColor: AppColor.neutral100, + showShadow: false, + title: 'Quantity'.addTranslation, + initialValue: model.costCenter, + onSelect: (value) { + model.costCenter = value; + }, + ), + ], + ) + ], + ).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16, vertical: 12)).paddingOnly(bottom: 12); + } +} diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart new file mode 100644 index 00000000..cc1310b0 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart @@ -0,0 +1,378 @@ +import 'dart:convert'; +import 'dart:developer'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:flutter_advanced_switch/flutter_advanced_switch.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/common_widgets/lookup_autocomplete_field.dart'; +import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/search_asset_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; +import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; +import '../../../../new_views/common_widgets/app_filled_button.dart'; +import '../../../../new_views/common_widgets/default_app_bar.dart'; + +class DeliveryInspectionFormView extends StatefulWidget { + static const String id = "/delivery-inspection-form"; + + DeliveryInspectionFormView({ + Key? key, + }) : super(key: key); + + @override + State createState() => _DeliveryInspectionFormViewState(); +} + +class _DeliveryInspectionFormViewState extends State { + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + bool viewOnly = true; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (!viewOnly) ...[inspectionDetailsForm()] else ...[inspectionDetails()], + 8.height, + const Divider().defaultStyle(context), + linesList(context), + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12)) + .expanded, + if (!viewOnly) ...[ + 8.height, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap), + ), + 8.height, + ], + FooterActionButton.footerContainer( + context: context, + child: !viewOnly + ? Row( + children: [ + AppFilledButton( + label: 'Cancel'.addTranslation, + maxWidth: true, + buttonColor: AppColor.background(context), + // textColor: context.isDark ? AppColor.neutral30 : Colors.white, + textColor: AppColor.red30, + showBorder: true, + onPressed: _cancelTap, + ).expanded, + 12.width, + AppFilledButton(buttonColor: AppColor.black10, label: 'View History'.addTranslation, maxWidth: true, onPressed: _viewHistoryTap).expanded, + ], + ) + : Row( + children: [ + AppFilledButton(buttonColor: AppColor.black10, label: 'View History'.addTranslation, maxWidth: true, onPressed: _viewHistoryTap).expanded, + 12.width, + AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap).expanded, + ], + ), + ), + ], + ), + ); + } + + Widget linesList(BuildContext context) { + final assetDeliveryTableList = ['abc', 'def', 'ghi', 'fhg', 'hjhh']; + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Lines", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + ListView.separated( + itemCount: assetDeliveryTableList.length, + separatorBuilder: (_, __) => 8.height, + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (listContext, itemIndex) { + return AssetDeliveryLineCard( + deliveryDetails: AssetInventoryModel(), + isViewOnly: viewOnly, + editPress: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CostCenterFormView( + costCenterList: [CostCenterModel()], + onListChanged: (updatedList) { + // requestDetailProvider.activityMaintenanceHelperModel?.assistantEmployList = updatedList; + }, + ))); + }, + ); + }, + ), + ], + ); + } + + Widget inspectionDetailsForm() { + return Column( + children: [ + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Inspected by'.addTranslation, + titleTextColor: AppColor.neutral120, + showShadow: false, + // backgroundColor: AppColor.neutral100, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, + onSelect: (status) { + if (status != null) { + // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; + setState(() {}); + } + }, + ), + // LookUpAutoCompleteField( + // clearAfterPick: false, + // forAssetName: true, + // onChanged: (value) { + // _scannedAssetModel?.newAssetNameId = null; + // _scannedAssetModel?.newAssetNameText = value; + // }, + // initialValue: _scannedAssetModel?.assetName ?? "", + // label: 'Asset Name'.addTranslation, + // onPick: (value) { + // _scannedAssetModel?.newAssetNameText = null; + // _scannedAssetModel?.assetName = value.name; + // _scannedAssetModel?.newAssetNameId = value.id; + // setState(() {}); + // }, + // ), + 8.height, + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Approved by'.addTranslation, + showShadow: false, + titleTextColor: AppColor.neutral120, + // backgroundColor: AppColor.neutral100, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, + onSelect: (status) { + if (status != null) { + // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; + setState(() {}); + } + }, + ), + 8.height, + ADatePicker( + label: 'Inspected Date/Time From'.addTranslation, + hideShadow: true, + height: 56.toScreenHeight, + backgroundColor: AppColor.fieldBgColor(context), + // date: _pickerStartAt, + // from: widget.pickerFromDate, + formatDateWithTime: true, + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + builder: (BuildContext context, Widget? child) { + final ThemeData currentTheme = Theme.of(context); + return Theme( + data: currentTheme.copyWith( + timePickerTheme: TimePickerThemeData( + dialHandColor: AppColor.primary10, + dialBackgroundColor: Colors.grey.withOpacity(0.1), + hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), + dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), + dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), + dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), + entryModeIconColor: AppColor.primary10, + ), + textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), + ), + child: child!, + ); + }, + ).then((selectedTime) { + if (selectedTime != null) { + // _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); + // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { + // "Start time is before the request time.".showToast; + // _pickerStartAt = null; + // selectedTime = null; + // return; + // } + // if (_pickerStartAt!.isAfter(DateTime.now())) { + // "Start time is after than current time".showToast; + // _pickerStartAt = null; + // selectedTime = null; + // return; + // } + setState(() {}); + } + }); + }, + ), + 8.height, + ADatePicker( + label: 'Inspected Date/Time To'.addTranslation, + hideShadow: true, + height: 56.toScreenHeight, + backgroundColor: AppColor.fieldBgColor(context), + // date: _pickerStartAt, + // from: widget.pickerFromDate, + formatDateWithTime: true, + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + builder: (BuildContext context, Widget? child) { + final ThemeData currentTheme = Theme.of(context); + return Theme( + data: currentTheme.copyWith( + timePickerTheme: TimePickerThemeData( + dialHandColor: AppColor.primary10, + dialBackgroundColor: Colors.grey.withOpacity(0.1), + hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), + dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), + dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), + dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), + entryModeIconColor: AppColor.primary10, + ), + textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), + ), + child: child!, + ); + }, + ).then((selectedTime) { + if (selectedTime != null) { + // _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); + // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { + // "Start time is before the request time.".showToast; + // _pickerStartAt = null; + // selectedTime = null; + // return; + // } + // if (_pickerStartAt!.isAfter(DateTime.now())) { + // "Start time is after than current time".showToast; + // _pickerStartAt = null; + // selectedTime = null; + // return; + // } + setState(() {}); + } + }); + }, + ), + ], + ); + } + + Widget inspectionDetails() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Inspected by'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + 'Mahmoud Shrouf'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Approved by'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + 'Mahmoud Shrouf'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Inspected Date/Time From'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + '19 August, 2025'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Inspected Date/Time To'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + '19 August, 2025'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + ], + ); + } + + void _viewHistoryTap() async {} + + void _cancelTap() async {} + + void _nextTap() { + Navigator.push(context, MaterialPageRoute(builder: (context) => TechnicalInspectionLinesListView())); + } + + void _changeStatusTap() async { + _formKey.currentState!.save(); + } +} diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/cost_center_card_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/cost_center_card_view.dart new file mode 100644 index 00000000..d53d3754 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/cost_center_card_view.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.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/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; + +class CostCenterCard extends StatelessWidget { + ///Need to replace with cost model. + AssetInventoryModel deliveryDetails; + ///if include in model skip this + bool isViewOnly; + VoidCallback ?editPress; + + CostCenterCard({ + super.key, + required this.isViewOnly, + required this.deliveryDetails, + this.editPress, + }); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + //need to check this @waseem. + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Item No: ${deliveryDetails.transactionDate?.toServiceRequestDetailsFormat ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + if(!isViewOnly) + 'edit_icon'.toSvgAsset().onPress(() { + if(editPress!=null){ + editPress!(); + } + }), + ], + ), + Text( + 'Asset Number: ${deliveryDetails.assetNumber ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Asset Type: ${deliveryDetails.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Replaced Asset No: ${deliveryDetails.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Serial Number: ${deliveryDetails.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12); + } +} diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_acceptance_form_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_acceptance_form_view.dart new file mode 100644 index 00000000..978a1d93 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_acceptance_form_view.dart @@ -0,0 +1,171 @@ +import 'dart:convert'; +import 'dart:developer'; +import 'dart:io'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_advanced_switch/flutter_advanced_switch.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/common_widgets/lookup_autocomplete_field.dart'; +import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/search_asset_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; +import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; +import 'package:test_sa/providers/service_request_providers/reject_reason_provider.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/views/widgets/e_signature/e_signature.dart'; +import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; +import '../../../../new_views/common_widgets/app_filled_button.dart'; +import '../../../../new_views/common_widgets/default_app_bar.dart'; + +class EndUserAcceptanceFormView extends StatefulWidget { + EndUserAcceptanceFormView({ + Key? key, + }) : super(key: key); + + @override + State createState() => _EndUserAcceptanceFormViewState(); +} + +class _EndUserAcceptanceFormViewState extends State { + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + bool viewOnly = false; + Uint8List? newSignature; + String? endUserSignature; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar( + title: 'Item Details'.addTranslation, + titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Status'.addTranslation, + titleTextColor: AppColor.neutral120, + showShadow: false, + // backgroundColor: AppColor.neutral100, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, + onSelect: (status) { + if (status != null) { + // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; + setState(() {}); + } + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Rejection Reason '.addTranslation, + titleTextColor: AppColor.neutral120, + showShadow: false, + // backgroundColor: AppColor.neutral100, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, + onSelect: (status) { + if (status != null) { + // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; + setState(() {}); + } + }, + ), + 8.height, + AppTextFormField( + initialValue: '', + labelText: 'Description'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + onChange: (value) {}, + onSaved: (value) {}, + ), + 8.height, + ESignature( + title: 'End User Signature', + oldSignature: '', + newSignature: newSignature, + backgroundColor: AppColor.neutral100, + showShadow: false, + onChange: (signature) { + if (signature.isEmpty) return; + setState(() { + newSignature = signature; + endUserSignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; + }); + }, + onSaved: (signature) { + if (signature == null || signature.isEmpty) return; + setState(() { + newSignature = signature; + endUserSignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; + }); + }, + ), + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12)) + .expanded, + FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), + ], + ), + ), + ); + } + + ///Need to check which details show here... + + void _saveTap() async { + AssetInventoryProvider assetInventoryProvider = Provider.of(context, listen: false); + _formKey.currentState!.save(); + } +} diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart new file mode 100644 index 00000000..4af7aa9f --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart @@ -0,0 +1,343 @@ + +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/models/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/cost_center_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import '../../../../new_views/common_widgets/app_filled_button.dart'; +import '../../../../new_views/common_widgets/default_app_bar.dart'; + +class EndUserCostCenterLIstView extends StatefulWidget { + EndUserCostCenterLIstView({ + Key? key, + }) : super(key: key); + + @override + State createState() => _EndUserCostCenterLIstViewState(); +} + +class _EndUserCostCenterLIstViewState extends State { + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + bool viewOnly = false; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar( + title: 'End-User Acceptance'.addTranslation, + titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + linesList(context), + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12)) + .expanded, + if (!viewOnly) ...[ + 8.height, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap), + ), + 8.height, + ], + FooterActionButton.footerContainer( + context: context, + child: !viewOnly + ? Row( + children: [ + AppFilledButton( + label: 'Cancel'.addTranslation, + maxWidth: true, + buttonColor: AppColor.background(context), + // textColor: context.isDark ? AppColor.neutral30 : Colors.white, + textColor: AppColor.red30, + showBorder: true, + onPressed: _cancelTap, + ).expanded, + 12.width, + AppFilledButton(buttonColor: AppColor.black10, label: 'View History'.addTranslation, maxWidth: true, onPressed: _viewHistoryTap).expanded, + ], + ) + : Row( + children: [ + AppFilledButton(buttonColor: AppColor.black10, label: 'View History'.addTranslation, maxWidth: true, onPressed: _viewHistoryTap).expanded, + 12.width, + AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap).expanded, + ], + ), + ), + ], + ), + ), + ); + } + + Widget linesList(BuildContext context) { + final assetDeliveryTableList = ['abc', 'def', 'ghi', 'fhg', 'hjhh']; + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Cost Center", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + ListView.separated( + itemCount: assetDeliveryTableList.length, + separatorBuilder: (_, __) => 8.height, + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (listContext, itemIndex) { + return CostCenterCard( + deliveryDetails : AssetInventoryModel(), + isViewOnly: viewOnly, + editPress: () { + Navigator.push(context, MaterialPageRoute(builder: (context) => UpdateEndUserCostCenterView())); + }, + ); + }, + ), + ], + ); + } + + Widget inspectionDetailsForm() { + return Column( + children: [ + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Inspected by'.addTranslation, + titleTextColor: AppColor.neutral120, + showShadow: false, + // backgroundColor: AppColor.neutral100, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, + onSelect: (status) { + if (status != null) { + // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; + setState(() {}); + } + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Approved by'.addTranslation, + showShadow: false, + titleTextColor: AppColor.neutral120, + // backgroundColor: AppColor.neutral100, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, + onSelect: (status) { + if (status != null) { + // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; + setState(() {}); + } + }, + ), + 8.height, + ADatePicker( + label: 'Inspected Date/Time From'.addTranslation, + hideShadow: true, + height: 56.toScreenHeight, + backgroundColor: AppColor.fieldBgColor(context), + // date: _pickerStartAt, + // from: widget.pickerFromDate, + formatDateWithTime: true, + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + builder: (BuildContext context, Widget? child) { + final ThemeData currentTheme = Theme.of(context); + return Theme( + data: currentTheme.copyWith( + timePickerTheme: TimePickerThemeData( + dialHandColor: AppColor.primary10, + dialBackgroundColor: Colors.grey.withOpacity(0.1), + hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), + dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), + dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), + dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), + entryModeIconColor: AppColor.primary10, + ), + textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), + ), + child: child!, + ); + }, + ).then((selectedTime) { + if (selectedTime != null) { + // _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); + // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { + // "Start time is before the request time.".showToast; + // _pickerStartAt = null; + // selectedTime = null; + // return; + // } + // if (_pickerStartAt!.isAfter(DateTime.now())) { + // "Start time is after than current time".showToast; + // _pickerStartAt = null; + // selectedTime = null; + // return; + // } + setState(() {}); + } + }); + }, + ), + 8.height, + ADatePicker( + label: 'Inspected Date/Time To'.addTranslation, + hideShadow: true, + height: 56.toScreenHeight, + backgroundColor: AppColor.fieldBgColor(context), + // date: _pickerStartAt, + // from: widget.pickerFromDate, + formatDateWithTime: true, + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + builder: (BuildContext context, Widget? child) { + final ThemeData currentTheme = Theme.of(context); + return Theme( + data: currentTheme.copyWith( + timePickerTheme: TimePickerThemeData( + dialHandColor: AppColor.primary10, + dialBackgroundColor: Colors.grey.withOpacity(0.1), + hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), + dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), + dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), + dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), + entryModeIconColor: AppColor.primary10, + ), + textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), + ), + child: child!, + ); + }, + ).then((selectedTime) { + if (selectedTime != null) { + // _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); + // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { + // "Start time is before the request time.".showToast; + // _pickerStartAt = null; + // selectedTime = null; + // return; + // } + // if (_pickerStartAt!.isAfter(DateTime.now())) { + // "Start time is after than current time".showToast; + // _pickerStartAt = null; + // selectedTime = null; + // return; + // } + setState(() {}); + } + }); + }, + ), + ], + ); + } + + Widget inspectionDetails() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Inspected by'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + 'Mahmoud Shrouf'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Approved by'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + 'Mahmoud Shrouf'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Inspected Date/Time From'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + '19 August, 2025'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Inspected Date/Time To'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + '19 August, 2025'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + ], + ); + } + + void _viewHistoryTap() async { + + } + + void _cancelTap() async { + + } + + void _nextTap() async { + Navigator.push(context, MaterialPageRoute(builder: (context) => EndUserCostCenterLIstView())); + } + + void _changeStatusTap() async { + + } +} diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_view.dart new file mode 100644 index 00000000..28136296 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_view.dart @@ -0,0 +1,220 @@ +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/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/modules/asset_delivery_module/pages/end_user_acceptance/end_user_acceptance_form_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import '../../../../new_views/common_widgets/app_filled_button.dart'; +import '../../../../new_views/common_widgets/default_app_bar.dart'; + +class UpdateEndUserCostCenterView extends StatefulWidget { + UpdateEndUserCostCenterView({ + Key? key, + }) : super(key: key); + + @override + State createState() => _UpdateEndUserCostCenterViewState(); +} + +class _UpdateEndUserCostCenterViewState extends State { + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + bool viewOnly = false; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar( + title: 'End-User Acceptance'.addTranslation, + titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + inspectionDetailsForm(), + 8.height, + const Divider().defaultStyle(context), + Text( + "Acceptance Form", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 6.height, + Row( + children: [ + 'warning_icon'.toSvgAsset(height: 16, width: 16), + 6.width, + Text( + 'Review the acceptance form'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 6.width, + 'web_link_icon'.toSvgAsset(height: 20, width: 20), + ], + ), + 16.height, + assetList(context), + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12)) + .expanded, + FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _viewHistoryTap)), + ], + ), + ), + ); + } + + Widget assetList(BuildContext context) { + final assetDeliveryTableList = ['abc', 'def', 'ghi', 'fhg', 'hjhh']; + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Asset", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + ListView.separated( + itemCount: assetDeliveryTableList.length, + separatorBuilder: (_, __) => 8.height, + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (listContext, itemIndex) { + return TechnicalInspectionAssetCard( + assetModel: Asset(), + isViewOnly: viewOnly, + ischild: true, + editPress: () { + Navigator.push(context, MaterialPageRoute(builder: (context) => EndUserAcceptanceFormView())); + }, + ); + }, + ), + ], + ); + } + + Widget inspectionDetailsForm() { + return Column( + children: [ + ADatePicker( + label: 'Accepted Date'.addTranslation, + hideShadow: true, + height: 56.toScreenHeight, + backgroundColor: AppColor.fieldBgColor(context), + // date: _pickerStartAt, + // from: widget.pickerFromDate, + formatDateWithTime: true, + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + builder: (BuildContext context, Widget? child) { + final ThemeData currentTheme = Theme.of(context); + return Theme( + data: currentTheme.copyWith( + timePickerTheme: TimePickerThemeData( + dialHandColor: AppColor.primary10, + dialBackgroundColor: Colors.grey.withOpacity(0.1), + hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), + dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), + dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), + dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), + entryModeIconColor: AppColor.primary10, + ), + textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), + ), + child: child!, + ); + }, + ).then((selectedTime) { + if (selectedTime != null) { + // _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); + // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { + // "Start time is before the request time.".showToast; + // _pickerStartAt = null; + // selectedTime = null; + // return; + // } + // if (_pickerStartAt!.isAfter(DateTime.now())) { + // "Start time is after than current time".showToast; + // _pickerStartAt = null; + // selectedTime = null; + // return; + // } + setState(() {}); + } + }); + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Approved by'.addTranslation, + showShadow: false, + titleTextColor: AppColor.neutral120, + // backgroundColor: AppColor.neutral100, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, + onSelect: (status) { + if (status != null) { + // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; + setState(() {}); + } + }, + ), + ], + ); + } + + void _viewHistoryTap() async { + AssetInventoryProvider assetInventoryProvider = Provider.of(context, listen: false); + _formKey.currentState!.save(); + } + + void _cancelTap() async { + AssetInventoryProvider assetInventoryProvider = Provider.of(context, listen: false); + _formKey.currentState!.save(); + } + + void _nextTap() async { + AssetInventoryProvider assetInventoryProvider = Provider.of(context, listen: false); + _formKey.currentState!.save(); + } + + void _changeStatusTap() async { + AssetInventoryProvider assetInventoryProvider = Provider.of(context, listen: false); + _formKey.currentState!.save(); + } +} diff --git a/lib/modules/asset_delivery_module/pages/history_log_view.dart b/lib/modules/asset_delivery_module/pages/history_log_view.dart new file mode 100644 index 00000000..4990a708 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/history_log_view.dart @@ -0,0 +1,187 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import 'package:test_sa/controllers/api_routes/urls.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/new_models/work_order_detail_model.dart'; +import 'package:test_sa/modules/cm_module/cm_detail_provider.dart'; +import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; + +import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class AssetDeliveryHistoryLogView extends StatelessWidget { + const AssetDeliveryHistoryLogView({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + ///Replace with provider and data.. + return Consumer(builder: (context, requestProvider, _) { + return requestProvider.isLoading + ? const CircularProgressIndicator(color: AppColor.primary10).center + : (requestProvider.currentWorkOrder == null || (requestProvider.currentWorkOrder?.data?.workOrderHistory.isEmpty ?? true) + ? const NoDataFound() + : Stack( + children: [ + Padding( + padding: EdgeInsets.only(left: 122.toScreenWidth), + child: const VerticalDivider( + color: AppColor.white40, + thickness: 2, + width: 20, + indent: 10, + endIndent: 10, + ), + ), + SafeArea( + child: Builder(builder: (cxt) { + List items = []; + String lastStatus = ""; + DateTime? nextDate; + var workOrderHistory = requestProvider.currentWorkOrder!.data!.workOrderHistory; + bool isNurse = (Provider.of(context, listen: false).user?.type) == UsersTypes.normal_user; + if (isNurse) { + workOrderHistory.removeWhere((element) => element.step?.id == 5617); + } + for (int i = 0; i < workOrderHistory.length; i++) { + var object = workOrderHistory[i]; + String currentStatus = object.workorderStatus!.name!; + if (lastStatus.isEmpty) { + lastStatus = currentStatus; + } + if (lastStatus == currentStatus) { + if (i + 1 < workOrderHistory.length) { + nextDate = workOrderHistory[i + 1].date; + String timeDifference = CMRequestUtils.calculateTimeDifference(object.date!, nextDate!); + object.timeDifference = timeDifference; + } else { + object.timeDifference = ''; // Empty string for the last action + } + items.add(historyLogCard(cxt, object)); + } else { + items.add(statusCard(cxt, lastStatus)); + lastStatus = currentStatus; + if (i + 1 < workOrderHistory.length) { + nextDate = workOrderHistory[i + 1].date; + String timeDifference = CMRequestUtils.calculateTimeDifference(object.date!, nextDate!); + object.timeDifference = timeDifference; + } else { + object.timeDifference = ''; // Empty string for the last action + } + items.add(historyLogCard(cxt, object)); + } + } + items.add(statusCard(cxt, lastStatus)); + return SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column(children: items), + ); + }), + ), + ], + )); + }); + } + + Widget historyLogCard(BuildContext context, WorkOrderHistory object) { + String title = object.step!.name!; + + if (object.step!.value == 18 || object.step!.value == 27 || object.step!.value == 28) { + title = object.activityStatus?.name ?? ""; + } + + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Align( + alignment: Alignment.centerLeft, + child: Text( + object.date.toString().toServiceRequestCardFormat, + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + ).expanded, + Expanded( + flex: 2, + //.... + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (object.assetVerificationType?.value == 4 && object.photoVerfication != null) ...[ + Padding( + padding: EdgeInsets.symmetric(vertical: 12.toScreenWidth), + child: InteractiveViewer(child: Image.network(URLs.getFileUrl(object.photoVerfication ?? '')!, height: 143.toScreenHeight)), + ).onPress(() async { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => Scaffold( + body: SafeArea( + child: Stack( + children: [ + InteractiveViewer(child: Image.network(URLs.getFileUrl(object.photoVerfication ?? '')!)).center, + const ABackButton(), + ], + ), + ), + ), + ), + ); + }), + ], + title.bodyText(context).custom(color: AppColor.textColor(context)), + object.timeDifference.isNotEmpty ? object.timeDifference.tinyFont(context).custom(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120) : const SizedBox(), + ], + ), + ), + ], + ).toShadowContainer(context, padding: 16).paddingOnly(bottom: 16); + } + + Widget statusCard(BuildContext context, String status) { + return SizedBox( + width: 153.toScreenWidth, + child: StatusLabel( + radius: 4, + label: statusText(status.toLowerCase()), + labelInCenter: true, + textColor: AppColor.getHistoryLogStatusTextColorByName(status), + backgroundColor: AppColor.getHistoryLogStatusColorByName(status), + ), + ).paddingOnly(bottom: 16, start: 40); + } + + String statusText(String status) { + if (status == "new" || status == "open") { + return "Open Request".addTranslation; + } else if (status == "in progress") { + return "Status update to In Progress".addTranslation; + } else if (status == "closed") { + return "Status update to Closed".addTranslation; + } else if (status == "completed") { + return "Status update to Completed".addTranslation; + } else if (status == "fixed") { + return "Status update to Fixed".addTranslation; + } else if (status == "reject") { + return "Status update to Rejected".addTranslation; + } else + return status; + } +} + +class HistoryLogModel { + String message; + DateTime date; + String? status; + Color? statusColor; + + HistoryLogModel({required this.message, required this.date, this.status, this.statusColor}); +} diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart new file mode 100644 index 00000000..0a4fc871 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart @@ -0,0 +1,109 @@ +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:test_sa/common_widgets/lookup_autocomplete_field.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/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class TechnicalInspectionAssetCard extends StatelessWidget { + Asset assetModel; + + ///if include in model skip this + bool isViewOnly; + bool ischild; + VoidCallback? editPress; + + TechnicalInspectionAssetCard({ + super.key, + required this.isViewOnly, + this.ischild = false, + required this.assetModel, + this.editPress, + }); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ///Need to give specific colors + if (!ischild) ...[ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + StatusLabel( + label: 'Pass', + radius: 4, + textColor: AppColor.getPriorityStatusTextColor(context, 1), + backgroundColor: AppColor.getPriorityStatusColor(context, 1), + ), + if (!isViewOnly) + 'edit_icon'.toSvgAsset().onPress(() { + if (editPress != null) { + editPress!(); + } + }), + ], + ), + 8.height, + ], + if (ischild) ...[ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Asset Number: ${assetModel.assetNumber ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + if (!isViewOnly) + 'edit_icon'.toSvgAsset().onPress(() { + if (editPress != null) { + editPress!(); + } + }), + ], + ), + ], + if (!ischild) + Text( + 'Asset Number: ${assetModel.assetNumber ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Model: ${assetModel.modelDefinition ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Serial Number: ${assetModel.assetSerialNo ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'System ID: ${assetModel.systemID ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + if (!ischild) + Text( + 'Medical Department: ${assetModel.department ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + if (!ischild) + Text( + 'Installation Date: ${assetModel.deliveryInspectionDate ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + if (!ischild) + Text( + 'Asset Type: ${assetModel.assetType ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12); + } +} diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart new file mode 100644 index 00000000..1470c34e --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart @@ -0,0 +1,77 @@ +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.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/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; + +class TechnicalInspectionCostCard extends StatelessWidget { + ///Need to replace with Cost model. + AssetInventoryModel deliveryDetails; + ///if include in model skip this + bool isViewOnly; + VoidCallback ?editPress; + + TechnicalInspectionCostCard({ + super.key, + required this.isViewOnly, + required this.deliveryDetails, + this.editPress, + }); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + //need to check this @waseem. + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Item No: ${deliveryDetails.transactionDate?.toServiceRequestDetailsFormat ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + if(!isViewOnly) + 'edit_icon'.toSvgAsset().onPress(() { + if(editPress!=null){ + editPress!(); + } + }), + ], + ), + Text( + 'Cost Center: ${deliveryDetails.assetNumber ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Power Supply Type: ${deliveryDetails.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Cost Center: ${deliveryDetails.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Power Reading: ${deliveryDetails.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Max Current: ${deliveryDetails.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Voltage: ${deliveryDetails.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Frequency: ${deliveryDetails.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12); + } +} diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart new file mode 100644 index 00000000..82420e30 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart @@ -0,0 +1,336 @@ +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/models/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import '../../../../new_views/common_widgets/app_filled_button.dart'; +import '../../../../new_views/common_widgets/default_app_bar.dart'; + +class TechnicalInspectionLinesListView extends StatefulWidget { + TechnicalInspectionLinesListView({ + Key? key, + }) : super(key: key); + + @override + State createState() => _TechnicalInspectionLinesListViewState(); +} + +class _TechnicalInspectionLinesListViewState extends State { + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + bool viewOnly = true; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar( + title: 'Technical Inspection'.addTranslation, + titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + linesList(context), + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12)) + .expanded, + if (!viewOnly) ...[ + 8.height, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap), + ), + 8.height, + ], + FooterActionButton.footerContainer( + context: context, + child: !viewOnly + ? Row( + children: [ + AppFilledButton( + label: 'Cancel'.addTranslation, + maxWidth: true, + buttonColor: AppColor.background(context), + // textColor: context.isDark ? AppColor.neutral30 : Colors.white, + textColor: AppColor.red30, + showBorder: true, + onPressed: _cancelTap, + ).expanded, + 12.width, + AppFilledButton(buttonColor: AppColor.black10, label: 'View History'.addTranslation, maxWidth: true, onPressed: _viewHistoryTap).expanded, + ], + ) + : Row( + children: [ + AppFilledButton(buttonColor: AppColor.black10, label: 'View History'.addTranslation, maxWidth: true, onPressed: _viewHistoryTap).expanded, + 12.width, + AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap).expanded, + ], + ), + ), + ], + ), + ), + ); + } + + Widget linesList(BuildContext context) { + final assetDeliveryTableList = ['abc', 'def', 'ghi', 'fhg', 'hjhh']; + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Lines", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + ListView.separated( + itemCount: assetDeliveryTableList.length, + separatorBuilder: (_, __) => 8.height, + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (listContext, itemIndex) { + return AssetDeliveryLineCard( + deliveryDetails: AssetInventoryModel(), + isViewOnly: viewOnly, + editPress: () { + Navigator.push(context, MaterialPageRoute(builder: (context) => UpdateTechnicalInspectionLinesView())); + }, + ); + }, + ), + ], + ); + } + + Widget inspectionDetailsForm() { + return Column( + children: [ + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Inspected by'.addTranslation, + titleTextColor: AppColor.neutral120, + showShadow: false, + // backgroundColor: AppColor.neutral100, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, + onSelect: (status) { + if (status != null) { + // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; + setState(() {}); + } + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Approved by'.addTranslation, + showShadow: false, + titleTextColor: AppColor.neutral120, + // backgroundColor: AppColor.neutral100, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, + onSelect: (status) { + if (status != null) { + // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; + setState(() {}); + } + }, + ), + 8.height, + ADatePicker( + label: 'Inspected Date/Time From'.addTranslation, + hideShadow: true, + height: 56.toScreenHeight, + backgroundColor: AppColor.fieldBgColor(context), + // date: _pickerStartAt, + // from: widget.pickerFromDate, + formatDateWithTime: true, + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + builder: (BuildContext context, Widget? child) { + final ThemeData currentTheme = Theme.of(context); + return Theme( + data: currentTheme.copyWith( + timePickerTheme: TimePickerThemeData( + dialHandColor: AppColor.primary10, + dialBackgroundColor: Colors.grey.withOpacity(0.1), + hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), + dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), + dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), + dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), + entryModeIconColor: AppColor.primary10, + ), + textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), + ), + child: child!, + ); + }, + ).then((selectedTime) { + if (selectedTime != null) { + // _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); + // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { + // "Start time is before the request time.".showToast; + // _pickerStartAt = null; + // selectedTime = null; + // return; + // } + // if (_pickerStartAt!.isAfter(DateTime.now())) { + // "Start time is after than current time".showToast; + // _pickerStartAt = null; + // selectedTime = null; + // return; + // } + setState(() {}); + } + }); + }, + ), + 8.height, + ADatePicker( + label: 'Inspected Date/Time To'.addTranslation, + hideShadow: true, + height: 56.toScreenHeight, + backgroundColor: AppColor.fieldBgColor(context), + // date: _pickerStartAt, + // from: widget.pickerFromDate, + formatDateWithTime: true, + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + builder: (BuildContext context, Widget? child) { + final ThemeData currentTheme = Theme.of(context); + return Theme( + data: currentTheme.copyWith( + timePickerTheme: TimePickerThemeData( + dialHandColor: AppColor.primary10, + dialBackgroundColor: Colors.grey.withOpacity(0.1), + hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), + dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), + dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), + dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), + entryModeIconColor: AppColor.primary10, + ), + textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), + ), + child: child!, + ); + }, + ).then((selectedTime) { + if (selectedTime != null) { + // _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); + // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { + // "Start time is before the request time.".showToast; + // _pickerStartAt = null; + // selectedTime = null; + // return; + // } + // if (_pickerStartAt!.isAfter(DateTime.now())) { + // "Start time is after than current time".showToast; + // _pickerStartAt = null; + // selectedTime = null; + // return; + // } + setState(() {}); + } + }); + }, + ), + ], + ); + } + + Widget inspectionDetails() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Inspected by'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + 'Mahmoud Shrouf'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Approved by'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + 'Mahmoud Shrouf'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Inspected Date/Time From'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + '19 August, 2025'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Inspected Date/Time To'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + '19 August, 2025'.addTranslation, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + ], + ); + } + + void _viewHistoryTap() async {} + + void _cancelTap() async {} + + void _nextTap() async { + Navigator.push(context, MaterialPageRoute(builder: (context) => EndUserCostCenterLIstView())); + } + + void _changeStatusTap() async {} +} diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart new file mode 100644 index 00000000..2ea5d088 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart @@ -0,0 +1,87 @@ + +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/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/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import '../../../../new_views/common_widgets/default_app_bar.dart'; + +class TechnicalInspectionParentAssetListView extends StatefulWidget { + TechnicalInspectionParentAssetListView({ + Key? key, + }) : super(key: key); + + @override + State createState() => _TechnicalInspectionParentAssetListViewState(); +} + +class _TechnicalInspectionParentAssetListViewState extends State { + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + bool viewOnly = false; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar( + title: 'Technical Inspection'.addTranslation, + titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + body: Form( + key: _formKey, + child: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: parentAssetList(context).toShadowContainer(context, borderRadius: 20, padding: 12)) + .expanded, + ), + ); + } + + Widget parentAssetList(BuildContext context) { + final assetDeliveryTableList = ['abc', 'def', 'ghi', 'fhg', 'hjhh']; + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Parents", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + ListView.separated( + itemCount: assetDeliveryTableList.length, + separatorBuilder: (_, __) => 8.height, + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (listContext, itemIndex) { + return TechnicalInspectionAssetCard( + assetModel: Asset(), + isViewOnly: viewOnly, + editPress: () { + Navigator.push(context, MaterialPageRoute(builder: (context) => UpdateParentAssetView())); + }, + ); + }, + ), + ], + ); + } + +} diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart new file mode 100644 index 00000000..8733e005 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart @@ -0,0 +1,145 @@ +import 'dart:convert'; +import 'dart:developer'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:flutter_advanced_switch/flutter_advanced_switch.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/common_widgets/lookup_autocomplete_field.dart'; +import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/search_asset_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; +import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; +import '../../../../new_views/common_widgets/app_filled_button.dart'; +import '../../../../new_views/common_widgets/default_app_bar.dart'; + +///convert this to stateless no state needed when impleminting api's +class UpdateChildAssetView extends StatefulWidget { + ///Need to pass model here... + UpdateChildAssetView({ + Key? key, + }) : super(key: key); + + @override + State createState() => _UpdateChildAssetViewState(); +} + +class _UpdateChildAssetViewState extends State { + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + bool viewOnly = false; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar( + title: 'Child Details'.addTranslation, + titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Asset Number'.addTranslation, + titleTextColor: AppColor.neutral120, + showShadow: false, + // backgroundColor: AppColor.neutral100, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, + onSelect: (status) { + if (status != null) { + // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; + setState(() {}); + } + }, + ), + 8.height, + AppTextFormField( + labelText: 'Model'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: '', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + textInputType: TextInputType.number, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Serial Number'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: '', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'System ID'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: '', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12)) + .expanded, + FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), + ], + ), + ), + ); + } + + void _saveTap() async { + AssetInventoryProvider assetInventoryProvider = Provider.of(context, listen: false); + _formKey.currentState!.save(); + } +} diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart new file mode 100644 index 00000000..4ff14e0a --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart @@ -0,0 +1,258 @@ +import 'dart:convert'; +import 'dart:developer'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:flutter_advanced_switch/flutter_advanced_switch.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/common_widgets/lookup_autocomplete_field.dart'; +import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/search_asset_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; +import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; +import '../../../../new_views/common_widgets/app_filled_button.dart'; +import '../../../../new_views/common_widgets/default_app_bar.dart'; + +class UpdateParentAssetView extends StatefulWidget { + UpdateParentAssetView({ + Key? key, + }) : super(key: key); + + @override + State createState() => _UpdateParentAssetViewState(); +} + +class _UpdateParentAssetViewState extends State { + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + bool viewOnly = false; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar( + title: 'Parent Details'.addTranslation, + titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + inspectionDetailsForm(), + 8.height, + const Divider().defaultStyle(context), + 8.height, + childList(context), + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12)) + .expanded, + FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), + ], + ), + ), + ); + } + + Widget childList(BuildContext context) { + final assetDeliveryTableList = ['abc', 'def', 'ghi', 'fhg', 'hjhh']; + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + "Test List", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.width, + 'web_link_icon'.toSvgAsset().onPress((){ + ///Open webview... + }), + ], + ), + 8.height, + ListView.separated( + itemCount: assetDeliveryTableList.length, + separatorBuilder: (_, __) => 8.height, + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (listContext, itemIndex) { + return TechnicalInspectionAssetCard( + assetModel: Asset(), + ischild: true, + editPress: () { + Navigator.push(context, MaterialPageRoute(builder: (context) => UpdateChildAssetView())); + }, + isViewOnly: viewOnly, + ); + }, + ), + ], + ); + } + + Widget inspectionDetailsForm() { + return Column( + children: [ + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Asset Number'.addTranslation, + titleTextColor: AppColor.neutral120, + showShadow: false, + // backgroundColor: AppColor.neutral100, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, + onSelect: (status) { + if (status != null) { + // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; + setState(() {}); + } + }, + ), + 8.height, + AppTextFormField( + labelText: 'Serial Number'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: '', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + textInputType: TextInputType.number, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'System ID'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: '', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Medical Department'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: '', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + ADatePicker( + label: 'Installation Date'.addTranslation, + hideShadow: true, + height: 56.toScreenHeight, + backgroundColor: AppColor.fieldBgColor(context), + // date: _pickerStartAt, + // from: widget.pickerFromDate, + formatDateWithTime: true, + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + builder: (BuildContext context, Widget? child) { + final ThemeData currentTheme = Theme.of(context); + return Theme( + data: currentTheme.copyWith( + timePickerTheme: TimePickerThemeData( + dialHandColor: AppColor.primary10, + dialBackgroundColor: Colors.grey.withOpacity(0.1), + hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), + dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), + dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), + dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), + entryModeIconColor: AppColor.primary10, + ), + textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), + ), + child: child!, + ); + }, + ).then((selectedTime) { + if (selectedTime != null) { + // _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); + // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { + // "Start time is before the request time.".showToast; + // _pickerStartAt = null; + // selectedTime = null; + // return; + // } + // if (_pickerStartAt!.isAfter(DateTime.now())) { + // "Start time is after than current time".showToast; + // _pickerStartAt = null; + // selectedTime = null; + // return; + // } + setState(() {}); + } + }); + }, + ), + 8.height, + AppTextFormField( + labelText: 'Asset Type'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: '', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + ], + ); + } + + ///Need to check which details show here... + + void _saveTap() async { + AssetInventoryProvider assetInventoryProvider = Provider.of(context, listen: false); + _formKey.currentState!.save(); + } +} diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart new file mode 100644 index 00000000..d13ab6b3 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart @@ -0,0 +1,224 @@ +import 'dart:convert'; +import 'dart:developer'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:flutter_advanced_switch/flutter_advanced_switch.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/common_widgets/lookup_autocomplete_field.dart'; +import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/search_asset_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; +import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; +import '../../../../new_views/common_widgets/app_filled_button.dart'; +import '../../../../new_views/common_widgets/default_app_bar.dart'; + +class UpdateTechnicalInspectionLinesView extends StatefulWidget { + static const String id = "/technical-inspection-form"; + + UpdateTechnicalInspectionLinesView({ + Key? key, + }) : super(key: key); + + @override + State createState() => _UpdateTechnicalInspectionLinesViewState(); +} + +class _UpdateTechnicalInspectionLinesViewState extends State { + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar( + title: 'Technical Inspection'.addTranslation, + titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + inspectionDetailsForm(), + 8.height, + const Divider().defaultStyle(context), + costCenterList(context), + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12)) + .expanded, + FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), + ], + ), + ), + ); + } + + Widget costCenterList(BuildContext context) { + final assetDeliveryTableList = ['abc', 'def', 'ghi', 'fhg', 'hjhh']; + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Cost Centers", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + ListView.separated( + itemCount: assetDeliveryTableList.length, + separatorBuilder: (_, __) => 8.height, + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (listContext, itemIndex) { + return TechnicalInspectionCostCard( + deliveryDetails: AssetInventoryModel(), + editPress: () { + Navigator.push(context, MaterialPageRoute(builder: (context) => TechnicalInspectionParentAssetListView())); + }, + isViewOnly: false, + ); + }, + ), + ], + ); + } + + Widget inspectionDetailsForm() { + return Column( + children: [ + AppTextFormField( + labelText: 'Item No'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: '232434', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + enable: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Item Description', + backgroundColor: AppColor.fieldBgColor(context), + initialValue: 'test decription abc', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + enable: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Power Supply Type'.addTranslation, + titleTextColor: AppColor.neutral120, + showShadow: false, + // backgroundColor: AppColor.neutral100, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, + onSelect: (status) { + if (status != null) { + // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; + setState(() {}); + } + }, + ), + // 8.height, + // LookUpAutoCompleteField( + // clearAfterPick: false, + // forAssetName: true, + // onChanged: (value) {}, + // initialValue: '', + // label: 'Cost Center'.addTranslation, + // onPick: (value) {}, + // ), + 8.height, + AppTextFormField( + labelText: 'Power Reading'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: '', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + textInputType: TextInputType.number, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Max Current'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: '', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Voltage'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: '', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Frequency'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: '', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + ], + ); + } + + void _saveTap() async { + AssetInventoryProvider assetInventoryProvider = Provider.of(context, listen: false); + _formKey.currentState!.save(); + } +} diff --git a/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart b/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart new file mode 100644 index 00000000..b87e092c --- /dev/null +++ b/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart @@ -0,0 +1,470 @@ +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/device/asset.dart'; +import 'package:test_sa/models/device/asset_search.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/module_permissions_model.dart'; +import 'package:test_sa/models/service_request/pending_service_request_model.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/service_request_search.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 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; + +import '../../../models/service_request/search_work_order.dart'; +import '../../../models/service_request/wo_call_request.dart'; +import '../../../models/user.dart'; +import '../../../new_views/common_widgets/app_lazy_loading.dart'; + +class AssetDeliveryProvider extends ChangeNotifier { + final pageItemNumber = 10; + final searchPageItemNumber = 10; + int pageNo = 1; + List _devices = []; + List _searchDevices = []; + + List get devices => _devices; + + List get searchDevices => _searchDevices; + SessionModel? sessionModel; + + //TODO need to check i think don't need to create this obj + AssetInventoryResponse? assetInventoryResponse; + AssetInventoryResponse? siteFilterAssetResponse; + + List sessionAssetList = []; + List siteFilterAssetList = []; + + ModulesPermissionsModel? modelPermission; + + void reset() { + pageNo = 1; + modelPermission = null; + assetInventoryResponse = null; + sessionModel = null; + sessionAssetList = []; + stateCode = null; + } + + int? stateCode; + bool isDetailLoading = false; + bool nextPage = false; + bool isNextPageLoading = false; + bool isLoading = false; + bool isAllAssetLoading = false; + + void searchReset() { + stateCode = null; + _searchDevices = []; + } + + Future getSessionById({required int id}) async { + try { + sessionModel = SessionModel(); + isLoading = true; + notifyListeners(); + final response = await ApiManager.instance.get(URLs.getAssetInventoryById + "?assetInventoryId=$id"); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + sessionModel = SessionModel.fromJson(json.decode(response.body)["data"]); + } else { + sessionModel = null; + } + + isLoading = false; + notifyListeners(); + } catch (e) { + log("getSessionError [error] : $e"); + isLoading = false; + sessionModel = null; + notifyListeners(); + return null; + } + } + + Future getAssetsInSession({ + required int sessionId, + bool loadMore = false, + }) async { + if (isLoading || isNextPageLoading) return -2; + if (loadMore) { + isNextPageLoading = true; + pageNo += 1; + } else { + isLoading = true; + pageNo = 1; // reset pagination + } + notifyListeners(); + try { + final payload = { + "pageSize": pageItemNumber, + "pageNumber": pageNo, + "sessionId": sessionId, + }; + final response = await ApiManager.instance.post(URLs.getAssetsInSession, body: payload); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + final Map jsonData = json.decode(response.body); + final newResponse = AssetInventoryResponse.fromJson(jsonData); + + if (loadMore) { + assetInventoryResponse?.assetList?.addAll(newResponse.assetList ?? []); + assetInventoryResponse?.totalRows = newResponse.totalRows; + } else { + assetInventoryResponse = newResponse; + } + nextPage = (assetInventoryResponse?.assetList?.length ?? 0) < (assetInventoryResponse?.totalRows ?? 0); + } else { + nextPage = false; + } + isLoading = false; + isNextPageLoading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + isLoading = false; + isNextPageLoading = false; + stateCode = -1; + nextPage = false; + notifyListeners(); + return -1; + } + } + + ///older code + // Future getAssetsInSession({ + // required int sessionId, + // bool loadMore = false, + // }) async { + // // if (isLoading || nextPage) return -2; + // + // if (loadMore) { + // nextPage = true; + // pageNo += 1; + // } else { + // isLoading = true; + // pageNo = 1; // reset pagination + // } + // + // notifyListeners(); + // log('Fetching page: $pageNo'); + // + // try { + // final payload = { + // "pageSize": pageItemNumber, + // "pageNumber": pageNo, + // "sessionId": sessionId, + // }; + // + // final response = await ApiManager.instance.post(URLs.getAssetsInSession, body: payload); + // stateCode = response.statusCode; + // + // if (response.statusCode >= 200 && response.statusCode < 300) { + // final Map jsonData = json.decode(response.body); + // final newResponse = AssetInventoryResponse.fromJson(jsonData); + // + // if (loadMore) { + // assetInventoryResponse?.assetList?.addAll(newResponse.assetList ?? []); + // assetInventoryResponse?.totalRows = newResponse.totalRows; + // } else { + // assetInventoryResponse = newResponse; + // } + // + // nextPage = (assetInventoryResponse?.assetList?.length ?? 0) < (assetInventoryResponse?.totalRows ?? 0); + // } + // + // isLoading = false; + // nextPage = false; + // notifyListeners(); + // return response.statusCode; + // } catch (error) { + // isLoading = false; + // nextPage = false; + // stateCode = -1; + // notifyListeners(); + // return -1; + // } + // } + + Future getInventoryDetailsByFilter({ + required Map payload, + bool loadMore = false, + }) async { + if (isLoading || isNextPageLoading) return -2; + + if (loadMore) { + isNextPageLoading = true; + pageNo += 1; + } else { + isLoading = true; + pageNo = 1; + } + + notifyListeners(); + log('Fetching inventory page: $pageNo'); + + try { + final paginatedPayload = { + ...payload, + "pageSize": pageItemNumber, + "pageNumber": pageNo, + }; + + final response = await ApiManager.instance.post(URLs.getInventoryDetailsByFilter, body: paginatedPayload); + stateCode = response.statusCode; + + if (response.statusCode >= 200 && response.statusCode < 300) { + final Map jsonData = json.decode(response.body); + final newResponse = AssetInventoryResponse.fromJson(jsonData); + + if (loadMore) { + siteFilterAssetList.addAll(newResponse.assetList ?? []); + siteFilterAssetResponse?.totalRows = newResponse.totalRows; + } else { + siteFilterAssetResponse = newResponse; + siteFilterAssetList = newResponse.assetList ?? []; + } + nextPage = (siteFilterAssetList.length) < (siteFilterAssetResponse?.totalRows ?? 0); + } else { + siteFilterAssetList = []; + nextPage = false; + } + + isLoading = false; + isNextPageLoading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + isLoading = false; + isNextPageLoading = false; + nextPage = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } + + Future searchAsset({ + required Map payload, + }) async { + isLoading = true; + try { + final response = await ApiManager.instance.post(URLs.searchAsset, body: payload); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + final Map jsonData = json.decode(response.body)["data"]; + AssetInventoryModel model = AssetInventoryModel.fromJson(jsonData); + log('model json ${model.toJson()}'); + isLoading = false; + notifyListeners(); + return model; + } else { + isLoading = false; + notifyListeners(); + return null; + } + } catch (error) { + isLoading = false; + stateCode = -1; + notifyListeners(); + return null; + } + } + + Future saveAssetInSession({ + AssetInventoryModel? model, + }) async { + isLoading = true; + try { + final response = await ApiManager.instance.post(URLs.saveAssetInSession, body: model?.toJson() ?? {}); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + isLoading = false; + notifyListeners(); + return true; + } else { + isLoading = false; + notifyListeners(); + return false; + } + } catch (error) { + isLoading = false; + notifyListeners(); + return false; + } + } + + Future getClassification({ + required Map payload, + }) async { + isLoading = true; + String? classification; + try { + final response = await ApiManager.instance.post(URLs.getClassification, body: payload); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + log('classifcation on response ${json.decode(response.body)["data"]['classification']}'); + classification = json.decode(response.body)["data"]['classification']; + isLoading = false; + notifyListeners(); + return classification; + } else { + isLoading = false; + notifyListeners(); + return classification; + } + } catch (error) { + isLoading = false; + notifyListeners(); + return classification; + } + } + + Future deleteAssetISession({required num id}) async { + try { + isLoading = true; + notifyListeners(); + final response = await ApiManager.instance.get(URLs.deleteAssetInSession + "?id=$id"); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + isLoading = false; + notifyListeners(); + return true; + } + isLoading = false; + notifyListeners(); + return false; + } catch (e) { + log("Delete Asset [error] : $e"); + isLoading = false; + notifyListeners(); + return false; + } + } + + Future> getAutoCompleteDetails({ + bool? isManufacturer, + String? query, + int type = 0, + }) async { + try { + String url = ''; + switch (type) { + //for model and manufacturer.. + case 0: + url = URLs.getManufacturerOrModelAutoComplete; + break; + //for asset name.. + case 1: + url = URLs.searchAssetName; + break; + //for supplier... + case 2: + url = URLs.getSuppliersAutoCompleteInventory; + break; + default: + url = URLs.getManufacturerOrModelAutoComplete; + } + final queryParams = {}; + if (isManufacturer != null && type == 0) { + queryParams['isManufacturer'] = isManufacturer.toString(); + } + if (query != null && query.isNotEmpty) { + queryParams['searchText'] = query; + } + if (queryParams.isNotEmpty) { + url += '?${Uri(queryParameters: queryParams).query}'; + } + final response = await ApiManager.instance.get(url); + + List list = []; + if (response.statusCode >= 200 && response.statusCode < 300) { + final data = json.decode(response.body)["data"]; + list = (data as List).map((e) => Lookup.fromJson(e)).toList(); + } + return list; + } catch (error) { + log('error $error'); + return []; + } + } + + Future getAssets({DeviceSearch? search, bool isQr = false, bool isSearchBy = false, num? sessionId}) async { + if (isLoading == true) return -2; + isLoading = true; + notifyListeners(); + late Response response; + try { + final Map body = { + "pageSize": isSearchBy ? searchPageItemNumber : pageItemNumber, + "pageNumber": isSearchBy ? (searchDevices.length / searchPageItemNumber).ceil() + 1 : devices.length ~/ pageItemNumber + 1, + "sessionId": sessionId ?? 0, + "assetSerialNo": search?.assetSerialNumber ?? '', + "assetName": search?.assetName ?? '', + "model": search?.model ?? '', + "manufacturer": search?.manufacturer ?? '', + "supplier": search?.supplier ?? '', + "siteName": search?.site ?? '', + // "buildingName":search?.??'', + // "floorName": search?.f??'', + "departmentName": search?.department ?? '', + // "roomName": search?.room + }; + // if (search != null) body.addAll(search.toJson()); + response = await ApiManager.instance.post(URLs.getAssetsTemp, body: body); + } catch (error) { + isLoading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + // client's request was successfully received + List equipmentListJson = json.decode(response.body)["data"]; + var dList = equipmentListJson.map((asset) => AssetInventoryModel.fromJson(asset)).toList() ?? []; + isSearchBy ? _searchDevices.addAll(dList) : _devices.addAll(dList); + nextPage = true; + } else { + nextPage = false; + } + isLoading = false; + notifyListeners(); + return response.statusCode; + } + + Future markAsComplete({ + required Map payload, + }) async { + isLoading = true; + try { + final response = await ApiManager.instance.post(URLs.convertDetailToComplete, body: payload); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + isLoading = false; + notifyListeners(); + return true; + } else { + isLoading = false; + notifyListeners(); + return false; + } + } catch (error) { + isLoading = false; + notifyListeners(); + return false; + } + } +} diff --git a/lib/new_views/common_widgets/single_item_drop_down_menu.dart b/lib/new_views/common_widgets/single_item_drop_down_menu.dart index d78e5f69..5ea85f7c 100644 --- a/lib/new_views/common_widgets/single_item_drop_down_menu.dart +++ b/lib/new_views/common_widgets/single_item_drop_down_menu.dart @@ -27,6 +27,7 @@ class SingleItemDropDownMenu exte final bool showShadow; final bool showCancel; final Color? backgroundColor; // Now nullable + final Color? titleTextColor; // Now nullable final bool? loading; // Now nullable final int? requestById; final String? Function(T?)? validator; @@ -49,6 +50,7 @@ class SingleItemDropDownMenu exte this.showShadow = true, this.showCancel = false, this.backgroundColor, + this.titleTextColor, this.loading, this.requestById, this.validator, @@ -146,7 +148,11 @@ class _SingleItemDropDownMenuState( value: _selectedItem, diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index 7f75b6bc..70327c4c 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -37,6 +37,7 @@ class _MyRequestsPageState extends State { @override Widget build(BuildContext context) { +//TODO need to refactor this and move out of build... if (_provider == null) { requestsList = [ Request(null, context.translation.allWorkOrder), @@ -67,6 +68,7 @@ class _MyRequestsPageState extends State { if (context.userProvider.isEngineer) { requestsList.add(Request(10, 'Equipment Internal Audit')); requestsList.add(Request(11, 'System Internal Audit')); + requestsList.add(Request(12, "Asset Delivery")); } requestsList.add(Request(12, "Loan Equipment")); @@ -91,7 +93,6 @@ class _MyRequestsPageState extends State { _provider!.getAllRequests(context); }); } - return Scaffold( appBar: AppBar( automaticallyImplyLeading: false, diff --git a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart index 0b76bf87..62580009 100644 --- a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart +++ b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_item_view.dart'; import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart'; import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart'; import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart'; @@ -75,6 +76,8 @@ class RequestPaginatedListview extends StatelessWidget { return SystemInternalAuditItemView(requestData: request); case 12: return LoanEquipmentItemView(requestData: request); + case 13: + return AssetDeliveryItemView(requestData: request); default: return Container( height: 100, diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart index 23512cee..8fc1a0f5 100644 --- a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart +++ b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart @@ -6,6 +6,7 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/all_requests_and_count_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_item_view.dart'; import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart'; import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart'; import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart'; @@ -69,8 +70,12 @@ class RequestItemViewList extends StatelessWidget { return EquipmentInternalAuditItemView(requestDetails: list[index]); case 11: return SystemInternalAuditItemView(requestDetails: list[index]); + //Need to use correct value .... + case 12: + return AssetDeliveryItemView(requestDetails: list[index]); case 12: return LoanEquipmentItemView(requestDetails: list[index]); + default: Container( height: 100, From 6d20e6f30775873ab84be6feb9b112cb80a6b753 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Mon, 22 Dec 2025 11:24:05 +0300 Subject: [PATCH 02/26] chat enable for cm module when engineer assigned. --- .../firebase_notification_manger.dart | 6 +- .../views/nurse/create_new_request_view.dart | 2 +- .../service_request_detail_main_view.dart | 56 +++++++++---------- .../requests/service_request_item_view.dart | 4 +- .../create__device_transfer_request.dart | 4 -- .../requests/pending_requests_screen.dart | 5 +- 6 files changed, 34 insertions(+), 43 deletions(-) diff --git a/lib/controllers/notification/firebase_notification_manger.dart b/lib/controllers/notification/firebase_notification_manger.dart index 77f0a55c..5d3117ba 100644 --- a/lib/controllers/notification/firebase_notification_manger.dart +++ b/lib/controllers/notification/firebase_notification_manger.dart @@ -101,13 +101,13 @@ class FirebaseNotificationManger { break; //these three request are same corrective maintenance.... case "3": - serviceClass = ServiceRequestDetailMain(requestId: int.parse(messageData["requestNumber"].toString())); + serviceClass = ServiceRequestDetailMain(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1); break; case "8": - serviceClass = ServiceRequestDetailMain(requestId: int.parse(messageData["requestNumber"].toString())); + serviceClass = ServiceRequestDetailMain(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1); break; case "11": - serviceClass = ServiceRequestDetailMain(requestId: int.parse(messageData["requestNumber"].toString())); + serviceClass = ServiceRequestDetailMain(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1); break; case "7": serviceClass = DeviceTransferDetails(model: DeviceTransfer(id: int.parse(messageData["requestNumber"].toString())), moduleId: 3); diff --git a/lib/modules/cm_module/views/nurse/create_new_request_view.dart b/lib/modules/cm_module/views/nurse/create_new_request_view.dart index c6e603dc..80e90d94 100644 --- a/lib/modules/cm_module/views/nurse/create_new_request_view.dart +++ b/lib/modules/cm_module/views/nurse/create_new_request_view.dart @@ -300,7 +300,7 @@ class _CreateNewRequestState extends State with TickerProvider bool checkPendingRequest = false; void showPendingRequests() { - Navigator.of(context).push(MaterialPageRoute(builder: (_) => PendingServiceRequestScreen(pendingAssetServiceRequest!))); + Navigator.of(context).push(MaterialPageRoute(builder: (_) => PendingServiceRequestScreen(pendingAssetServiceRequest!, 1))); } void showPendingRequestBottomSheet() async { diff --git a/lib/modules/cm_module/views/service_request_detail_main_view.dart b/lib/modules/cm_module/views/service_request_detail_main_view.dart index 78029461..3e2fab9c 100644 --- a/lib/modules/cm_module/views/service_request_detail_main_view.dart +++ b/lib/modules/cm_module/views/service_request_detail_main_view.dart @@ -13,6 +13,7 @@ import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart'; import 'package:test_sa/modules/cx_module/chat/chat_page.dart'; import 'package:test_sa/modules/cx_module/chat/chat_provider.dart'; +import 'package:test_sa/modules/cx_module/chat/chat_widget.dart'; import 'package:test_sa/modules/cx_module/survey/survey_page.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; @@ -22,8 +23,9 @@ import 'components/service_request_detail_view.dart'; class ServiceRequestDetailMain extends StatefulWidget { final int requestId; + final int moduleId; - ServiceRequestDetailMain({Key? key, required this.requestId}) : super(key: key); + ServiceRequestDetailMain({Key? key, required this.requestId, required this.moduleId}) : super(key: key); @override _ServiceRequestDetailMainState createState() { @@ -88,37 +90,29 @@ class _ServiceRequestDetailMainState extends State { Navigator.pop(context); }, actions: [ - if (context.userProvider.isEngineer || context.userProvider.isNurse) - Selector( - selector: (_, myModel) => myModel.isLoading, // Selects only the userName - builder: (_, isLoading, __) { - if (isLoading) { - return const SizedBox(); - } else { - ServiceRequestDetailProvider provider = Provider.of(context, listen: false); - int? statusValue = provider.currentWorkOrder?.data?.status?.value; - if (statusValue == 2 || statusValue == 3 || statusValue == 5 || statusValue == 6) { - getChatToken(moduleId, provider.currentWorkOrder?.data?.workOrderNo ?? ""); - return Consumer(builder: (pContext, requestProvider, _) { - return IconButton( - icon: const Icon(Icons.chat_bubble), - onPressed: () { - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => ChatPage( - moduleId: moduleId, - requestId: widget.requestId, - title: _requestProvider.currentWorkOrder?.data?.workOrderNo ?? "", - readOnly: _requestProvider.isReadOnlyRequest, - ))); - }, - ).toShimmer(context: context, isShow: requestProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30); - }); - } - return const SizedBox(); + Selector( + selector: (_, myModel) => myModel.isLoading, // Selects only the userName + builder: (_, isLoading, __) { + if (isLoading) { + return const SizedBox(); + } else { + ServiceRequestDetailProvider provider = Provider.of(context, listen: false); + if ((context.userProvider.isEngineer || context.userProvider.isNurse) && + provider.currentWorkOrder?.data?.assignedEmployee != null && + (provider.currentWorkOrder?.data?.workOrderContactPerson?.isNotEmpty ?? false)) { + return ChatWidget( + moduleId: widget.moduleId, + isShow: (context.userProvider.isEngineer || context.userProvider.isNurse) && provider.currentWorkOrder?.data?.assignedEmployee != null, + isReadOnly: _requestProvider.isReadOnlyRequest, + requestId: widget.requestId.toInt(), + assigneeEmployeeNumber: provider.currentWorkOrder?.data?.assignedEmployee!.employeeId!, + myLoginUserID: context.userProvider.user!.username!, + contactEmployeeINumber: provider.currentWorkOrder?.data?.workOrderContactPerson.first.employeeId, + ); } - }), + return const SizedBox(); + } + }), isNurse ? IconButton( icon: 'qr'.toSvgAsset( diff --git a/lib/new_views/pages/land_page/requests/service_request_item_view.dart b/lib/new_views/pages/land_page/requests/service_request_item_view.dart index 0fac59f4..c6b32c87 100644 --- a/lib/new_views/pages/land_page/requests/service_request_item_view.dart +++ b/lib/new_views/pages/land_page/requests/service_request_item_view.dart @@ -81,7 +81,7 @@ class ServiceRequestItemView extends StatelessWidget { ), ], ).toShadowContainer(context, withShadow: showShadow).onPress(() async { - await Navigator.of(context).push(MaterialPageRoute(builder: (_) => ServiceRequestDetailMain(requestId: requestData!.id!))); + await Navigator.of(context).push(MaterialPageRoute(builder: (_) => ServiceRequestDetailMain(requestId: requestData!.id!, moduleId: requestData!.transactionNo!))); if (refreshData) { Provider.of(context, listen: false).refreshDashboard(userType: Provider.of(context, listen: false).user!.type!, context: context); } @@ -140,7 +140,7 @@ class ServiceRequestItemView extends StatelessWidget { ), ], ).toShadowContainer(context, withShadow: showShadow).onPress(() { - Navigator.of(context).push(MaterialPageRoute(builder: (_) => ServiceRequestDetailMain(requestId: requestDetails!.id!))); + Navigator.of(context).push(MaterialPageRoute(builder: (_) => ServiceRequestDetailMain(requestId: requestDetails!.id!, moduleId: requestDetails!.transactionType!))); }); } diff --git a/lib/views/pages/device_transfer/create__device_transfer_request.dart b/lib/views/pages/device_transfer/create__device_transfer_request.dart index 319e9be8..861dbc9b 100644 --- a/lib/views/pages/device_transfer/create__device_transfer_request.dart +++ b/lib/views/pages/device_transfer/create__device_transfer_request.dart @@ -62,10 +62,6 @@ class _CreateDeviceTransferRequestState extends State PendingServiceRequestScreen(pendingAssetServiceRequest!))); - } - void _onSubmit() async { _transferModel.assetId = _pickedAsset?.id; _transferModel.destSiteId = _assetDestination.site?.id; diff --git a/lib/views/pages/user/requests/pending_requests_screen.dart b/lib/views/pages/user/requests/pending_requests_screen.dart index edd02de4..30b4a814 100644 --- a/lib/views/pages/user/requests/pending_requests_screen.dart +++ b/lib/views/pages/user/requests/pending_requests_screen.dart @@ -9,9 +9,10 @@ import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/widgets/sound/sound_player.dart'; class PendingServiceRequestScreen extends StatelessWidget { + final int moduleId; final PendingAssetServiceRequest pendingAssetServiceRequest; - const PendingServiceRequestScreen(this.pendingAssetServiceRequest, {Key? key}) : super(key: key); + const PendingServiceRequestScreen(this.pendingAssetServiceRequest, this.moduleId, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -63,7 +64,7 @@ class PendingServiceRequestScreen extends StatelessWidget { ], ), ).onPress(() { - Navigator.of(context).push(MaterialPageRoute(builder: (_) => ServiceRequestDetailMain(requestId: pendingAssetServiceRequest.details![index].id ?? 0))); + Navigator.of(context).push(MaterialPageRoute(builder: (_) => ServiceRequestDetailMain(requestId: pendingAssetServiceRequest.details![index].id ?? 0, moduleId: moduleId))); }))); } } From 7dd8fff34e47d068bf955a2bfec7f973c4968a62 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Mon, 22 Dec 2025 14:56:29 +0300 Subject: [PATCH 03/26] asset delivery modules completed --- lib/controllers/api_routes/urls.dart | 47 +- .../providers/api/devices_provider.dart | 46 + lib/extensions/enum_extensions.dart | 4 + lib/main.dart | 10 + lib/models/all_requests_and_count_model.dart | 6 + lib/models/device/asset_search.dart | 1 + lib/models/generic_attachment_model.dart | 1 - lib/models/new_models/dashboard_detail.dart | 6 + .../models/asset_delivery_data_model.dart | 383 ++++++++ .../models/asset_inventory_model.dart | 345 ------- .../models/cost_center_model.dart | 51 +- .../delivery_inspection_form_model.dart | 37 + .../models/delivery_line_model.dart | 61 ++ .../models/end_user_asset_details_model.dart | 71 ++ .../models/history_model.dart | 34 + .../models/oracle_user_model.dart | 26 + .../models/session_model.dart | 234 ----- .../technical_inpection_asset_model.dart | 61 ++ .../technical_inspection_asset_model.dart | 215 ++++ .../technical_inspection_form_model.dart | 53 + .../pages/asset_delivery_detail_page.dart | 105 -- .../pages/asset_delivery_item_view.dart | 61 +- .../pages/asset_delivery_line_card_view.dart | 53 +- .../pages/asset_delivery_page.dart | 359 ++++--- .../pages/asset_delivery_table_card_view.dart | 36 +- .../pages/attachment_view.dart | 126 +++ .../pages/change_status_bottomsheet.dart | 14 +- .../cost_center_form_view.dart | 271 ++++-- .../delivery_inspection_form_view.dart | 459 +++++---- .../oracle_user_autocomplete_field.dart | 114 +++ .../cost_center_card_view.dart | 57 +- .../end_user_acceptance_form_view.dart | 171 ---- .../end_user_asset_detail_card.dart | 116 +++ .../end_user_cost_center_list_view.dart | 365 ++----- .../update_end_user_asset_details_view.dart | 180 ++++ ...ate_end_user_cost_center_details_view.dart | 317 ++++++ .../update_end_user_cost_center_view.dart | 220 ----- .../pages/history_log_view.dart | 213 ++-- .../asset_delivery_utils.dart | 18 + .../search_asset_view.dart | 194 ++++ .../status_checklist_view.dart | 137 +++ .../technical_inpection_asset_card_view.dart | 79 +- ...nical_inpection_cost_center_card_view.dart | 61 +- .../technical_inspection_lines_list_view.dart | 314 +++--- ...cal_inspection_parent_asset_list_view.dart | 112 ++- .../update_child_asset_view.dart | 459 +++++++-- .../update_parent_asset_view.dart | 914 +++++++++++++++--- ...pdate_technical_inspection_lines_view.dart | 230 +++-- .../provider/asset_delivery_provider.dart | 825 ++++++++++------ .../provider/cost_center_provider.dart | 45 + ...user_rejection_reason_lookup_provider.dart | 33 + .../end_user_status_lookup_provider.dart | 33 + .../provider/power_supply_type_provider.dart | 33 + .../service_request_bottomsheet.dart | 48 +- .../recurrent_work_order_view.dart | 2 +- .../common_widgets/default_app_bar.dart | 4 +- .../single_item_drop_down_menu.dart | 103 +- .../my_request/my_requests_page.dart | 3 +- .../widgets/request_item_view_list.dart | 5 +- .../widgets/requests/request_status.dart | 2 + 60 files changed, 5657 insertions(+), 2926 deletions(-) create mode 100644 lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart delete mode 100644 lib/modules/asset_delivery_module/models/asset_inventory_model.dart create mode 100644 lib/modules/asset_delivery_module/models/delivery_inspection_form_model.dart create mode 100644 lib/modules/asset_delivery_module/models/delivery_line_model.dart create mode 100644 lib/modules/asset_delivery_module/models/end_user_asset_details_model.dart create mode 100644 lib/modules/asset_delivery_module/models/history_model.dart create mode 100644 lib/modules/asset_delivery_module/models/oracle_user_model.dart delete mode 100644 lib/modules/asset_delivery_module/models/session_model.dart create mode 100644 lib/modules/asset_delivery_module/models/technical_inpection_asset_model.dart create mode 100644 lib/modules/asset_delivery_module/models/technical_inspection_asset_model.dart create mode 100644 lib/modules/asset_delivery_module/models/technical_inspection_form_model.dart delete mode 100644 lib/modules/asset_delivery_module/pages/asset_delivery_detail_page.dart create mode 100644 lib/modules/asset_delivery_module/pages/attachment_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.dart delete mode 100644 lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_acceptance_form_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_asset_detail_card.dart create mode 100644 lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart delete mode 100644 lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/technical_inpection/asset_delivery_utils.dart create mode 100644 lib/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart create mode 100644 lib/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart create mode 100644 lib/modules/asset_delivery_module/provider/cost_center_provider.dart create mode 100644 lib/modules/asset_delivery_module/provider/end_user_rejection_reason_lookup_provider.dart create mode 100644 lib/modules/asset_delivery_module/provider/end_user_status_lookup_provider.dart create mode 100644 lib/modules/asset_delivery_module/provider/power_supply_type_provider.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index c869f0dc..aac9b8b5 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -4,13 +4,14 @@ class URLs { static const String appReleaseBuildNumber = "28"; // static const host1 = "https://atomsm.hmg.com"; // production url - // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + static const host1 = "https://atomsmdev.hmg.com"; // local DEV url + // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url // static String _baseUrl = "$_host/mobile"; - static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis + // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis + static final String _baseUrl = "$_host/v6/mobile"; // for asset delivery module // static final String _baseUrl = "$_host/mobile"; // host local UAT and for internal audit dev // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM // static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation @@ -391,4 +392,44 @@ class URLs { static get getLoanById => '$_baseUrl/Loan/GetLoanById'; static get addLoan => '$_baseUrl/Loan/AddLoan'; + + //Asset Delivery Module + //AssetDeliveryExternal/GetAssetDeliveryExternalById + static get getAssetDeliveryDetailsById => '$_baseUrl/AssetDeliveryExternal/GetAssetDeliveryExternalById'; + + static get getAssetDeliveryTableListById => '$_baseUrl/AssetDeliveryExternalDelivery/GetDeliveriesByMasterId'; + + static get addNewDelivery => '$_baseUrl/AssetDeliveryExternalDelivery/AddNewDelivery'; + + static get changeDeliveryStatusToCancel => '$_baseUrl/AssetDeliveryExternalDelivery/ChangeStatusDeliveryToCancel'; + + static get changeDeliveryStatus => '$_baseUrl/AssetDeliveryExternalDelivery/ChangeStatusDelivery'; + + static get getAssetDeliveryInspectionData => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetAssetDeliveryExternalDeliveryInspectionByDeliveryId'; + + static get getOracleUserList => '$_baseUrl/AssetDeliveryExternal/GetEmployeesFromOracle'; + + static get getLineFromExternalPo => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetLineFromExternalPo'; + static get getCostCenterListToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetCostCenterToLineDeliveryInspection'; + static get getCostCenterToPo => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetCostCenterToPo'; + static get saveCostCenterToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/SaveCostCenterToLineDeliveryInspection'; + static get getDeliveryHistories => '$_baseUrl/AssetDeliveryExternalDelivery/GetDeliveryHistories'; + //Technical Inscption... + static get getLineFromTechnicalInspection => '$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetLineFromDeliveryInspection'; + static get getTechnicalInspectionByDetailId => '$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetTechnicalInspectionByDetailId'; + static get powerSupplyTypeLookUp => "$_baseUrl/Lookups/GetLookup?lookupEnum=527"; + static get saveTechnicalInspection => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/SaveTechnicalInspection"; + static get getTechnicalInspectionParentData => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetTechnicalInspectionItemByCostCenterId"; + static get getAssetFromInternalTechnicalInspection => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetAssetFromInternal"; + static get getAssetDetailsByAssetId => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetAssetByIdFromInternal"; + static get saveTechnicalInspectionAsset => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/SaveTechnicalInspectionItem"; + static get getAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/GetAttachments"; + static get saveAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/Save"; + //End user Acceptance... + static get getEndUserAcceptanceCostCenter => "$_baseUrl/AssetDeliveryEndUserAcceptance/GetEndUserAcceptanceCostCenter"; + static get getCostCenterAssetList => "$_baseUrl/AssetDeliveryEndUserAcceptance/GetItemByCostCenter"; + static get saveEndUserFormData => "$_baseUrl/AssetDeliveryEndUserAcceptance/SaveMaster"; + static get saveEndUserAssetData => "$_baseUrl/AssetDeliveryEndUserAcceptance/SaveDetail"; + static get endUserStatusLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=534"; + static get endUserRejectionReasonLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=5007"; } diff --git a/lib/controllers/providers/api/devices_provider.dart b/lib/controllers/providers/api/devices_provider.dart index 3d031a61..ab196c11 100644 --- a/lib/controllers/providers/api/devices_provider.dart +++ b/lib/controllers/providers/api/devices_provider.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:developer'; import 'package:flutter/cupertino.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -10,6 +11,7 @@ import 'package:test_sa/models/device/asset_by_id_model.dart'; import 'package:test_sa/models/device/asset_search.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/user.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/technical_inpection_asset_model.dart'; import '../../../models/device/asset.dart'; @@ -38,6 +40,7 @@ class AssetProvider extends ChangeNotifier { List _devices = []; List _searchDevices = []; + List technicalInspectionAsset= []; List get devices => _devices; @@ -99,6 +102,49 @@ class AssetProvider extends ChangeNotifier { return response.statusCode; } + Future getAssetsForAssetDelivery({DeviceSearch? search, bool isSearchBy = false, int? lineId}) async { + if (_loading == true) return -2; + _loading = true; + notifyListeners(); + late Response response; + try { + final Map body = { + "pageSize": isSearchBy ? searchPageItemNumber : pageItemNumber, + "pageNumber": isSearchBy ? (searchDevices.length / searchPageItemNumber).ceil() + 1 : devices.length ~/ pageItemNumber + 1, + + ///Uncommit this after testing... + "assetDeliveryExternalDetailId": lineId, + "assetName": search?.assetName, + + // "assetDeliveryExternalDetailId": 2, + // "assetName": "Treatment Center Intego - Dental Chair", + "assetNumber": search?.assetNo, + "model": search?.model, + "manufacturer": search?.manufacturer, + }; + response = await ApiManager.instance.post(URLs.getAssetFromInternalTechnicalInspection, body: body); + } catch (error) { + _loading = false; + _stateCode = -1; + notifyListeners(); + return -1; + } + _stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List equipmentListJson = json.decode(response.body)["data"]; + var dList = equipmentListJson.map((asset) => TechnicalInspectionAssetBasicInfoModel.fromJson(asset)).toList() ?? []; + log('dlist ${dList.length}'); + + technicalInspectionAsset.addAll(dList); + nextPage = true; + } else { + nextPage = false; + } + _loading = false; + notifyListeners(); + return response.statusCode; + } + Future getAssetById(int assetId, AppLocalizations appLocalizations) async { late Response response; try { diff --git a/lib/extensions/enum_extensions.dart b/lib/extensions/enum_extensions.dart index c6d10640..747e2080 100644 --- a/lib/extensions/enum_extensions.dart +++ b/lib/extensions/enum_extensions.dart @@ -121,3 +121,7 @@ extension StringExtensionsRecurrentTaskInpesctionDataType on String { } } } +enum DropDownMatchType { + identifier, + name, +} diff --git a/lib/main.dart b/lib/main.dart index d4544472..ceff381d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -27,6 +27,11 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/report/servic import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_repair_location_provider.dart'; import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/cost_center_provider.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/end_user_rejection_reason_lookup_provider.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/end_user_status_lookup_provider.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/power_supply_type_provider.dart'; import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; import 'package:test_sa/modules/cm_module/cm_detail_provider.dart'; import 'package:test_sa/modules/cm_module/create_cm_request.dart'; @@ -316,6 +321,11 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => LoanProvider()), ChangeNotifierProvider(create: (_) => LoanPeriodProvider()), ChangeNotifierProvider(create: (_) => MedicalDepartmentProvider()), + ChangeNotifierProvider(create: (_) => AssetDeliveryProvider()), + ChangeNotifierProvider(create: (_) => CostCenterProvider()), + ChangeNotifierProvider(create: (_) => PowerSupplyTypeProvider()), + ChangeNotifierProvider(create: (_) => EndUserStatusLookupProvider()), + ChangeNotifierProvider(create: (_) => EndUserRejectionReasonLookupProvider()), ], child: GestureDetector( onTap: () { diff --git a/lib/models/all_requests_and_count_model.dart b/lib/models/all_requests_and_count_model.dart index e980e164..95f19030 100644 --- a/lib/models/all_requests_and_count_model.dart +++ b/lib/models/all_requests_and_count_model.dart @@ -128,6 +128,8 @@ class RequestsDetails { String? date; String? siteTransferFrom; String? siteTransferTo; + String? poInternal; + String? poExternal; int? transactionType; int? numberOfAssets; int? numberOfSites; @@ -156,6 +158,8 @@ class RequestsDetails { this.code, this.siteTransferFrom, this.siteTransferTo, + this.poInternal, + this.poExternal, this.date, this.transactionType}); @@ -182,6 +186,8 @@ class RequestsDetails { assetTransferTo = json['assetTransferTo']; code = json['code']; date = json['date']; + poInternal = json['poInternal']; + poExternal = json['poExternal']; siteTransferFrom = json['siteTransferFrom']; siteTransferTo = json['siteTransferTo']; transactionType = json['transactionType']; diff --git a/lib/models/device/asset_search.dart b/lib/models/device/asset_search.dart index f311b208..1a70196b 100644 --- a/lib/models/device/asset_search.dart +++ b/lib/models/device/asset_search.dart @@ -1,6 +1,7 @@ import 'package:test_sa/models/lookup.dart'; class DeviceSearch { + DeviceSearch( {this.code, this.assetSerialNumber, diff --git a/lib/models/generic_attachment_model.dart b/lib/models/generic_attachment_model.dart index 1d3cd5ea..c0c2b4cf 100644 --- a/lib/models/generic_attachment_model.dart +++ b/lib/models/generic_attachment_model.dart @@ -8,7 +8,6 @@ class GenericAttachmentModel { String ?createdBy; String? originalName; GenericAttachmentModel.fromJson(Map json) { - print('created by here is ${json['createdBy']}'); id = json['id']; name = json['name']; createdBy = json['createdBy']; diff --git a/lib/models/new_models/dashboard_detail.dart b/lib/models/new_models/dashboard_detail.dart index 093019b2..7c39d4ce 100644 --- a/lib/models/new_models/dashboard_detail.dart +++ b/lib/models/new_models/dashboard_detail.dart @@ -55,6 +55,8 @@ class Data { String? assetNumber; String? requestTypeName; String? requestNo; + String? poInternal; + String? poExternal; int? transactionNo; int? numberOfSites; int? numberOfAssets; @@ -75,6 +77,8 @@ class Data { this.assetNumber, this.requestTypeName, this.requestNo, + this.poExternal, + this.poInternal, this.transactionNo}); Data.fromJson(Map json) { @@ -93,6 +97,8 @@ class Data { requestNo = json['requestNo']; rejectReason = json['rejectReason']; transactionNo = json['transactionNo']; + poInternal = json['poInternal']; + poExternal = json['poExternal']; nameOfType = json['nameOfType']; } diff --git a/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart b/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart new file mode 100644 index 00000000..08de3111 --- /dev/null +++ b/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart @@ -0,0 +1,383 @@ +import 'package:test_sa/models/lookup.dart'; + +class AssetDeliveryDataModel { + int? id; + bool? isHMG; + int? operatingUnitId; + String? operatingUnit; + String? clientName; + int? poNumberId; + int? poNumber; + SiteModel? site; + Lookup? paymentTerm; + num? paymentTermAmount; + num? deliveryAmount; + num? total; + num? totalInvoice; + String? edd; + double? warrentyPeriod; + + AssetDeliveryInternalMaster? assetDeliveryInternalMaster; + PurchaseOrderMaster? purchaseOrderMaster; + List? assetDeliveryExternalDetails; + List? assetDeliveryExternalDeliveries; + + AssetDeliveryDataModel(); + + AssetDeliveryDataModel.fromJson(Map json) { + id = json['id']; + isHMG = json['isHMG']; + operatingUnitId = json['operatingUnitId']; + clientName = json['clientName']; + operatingUnit = json['operatingUnit']; + poNumberId = json['poNumberId']; + poNumber = json['poNumber']; + total = json['total']; + totalInvoice = json['totalInvoice']; + edd = json['edd']; + deliveryAmount = json['deliveryAmount']; + site = json['site'] != null + ? SiteModel.fromJson(json['site']) + : null; + paymentTerm = json['paymentTerm'] != null + ? Lookup.fromJson(json['paymentTerm']) + : null; + paymentTermAmount = json['paymentTermAmount']; + warrentyPeriod = json['warrentyPeriod']; + + assetDeliveryInternalMaster = json['assetDeliveryInternalMaster'] != null + ? AssetDeliveryInternalMaster.fromJson(json['assetDeliveryInternalMaster']) + : null; + purchaseOrderMaster = json['purchaseOrderMaster'] != null + ? PurchaseOrderMaster.fromJson(json['purchaseOrderMaster']) + : null; + + if (json['assetDeliveryExternalDetails'] != null) { + assetDeliveryExternalDetails = []; + json['assetDeliveryExternalDetails'].forEach((v) { + assetDeliveryExternalDetails!.add(AssetDeliveryExternalDetail.fromJson(v)); + }); + } + + if (json['assetDeliveryExternalDeliveries'] != null) { + assetDeliveryExternalDeliveries = []; + json['assetDeliveryExternalDeliveries'].forEach((v) { + assetDeliveryExternalDeliveries!.add(AssetDeliveryTableModel.fromJson(v)); + }); + } + } + + Map toJson() { + final data = {}; + + data['id'] = id; + data['isHMG'] = isHMG; + data['operatingUnitId'] = operatingUnitId; + data['operatingUnit'] = operatingUnit; + data['clientName'] = clientName; + data['poNumberId'] = poNumberId; + data['poNumber'] = poNumber; + data['total'] = total; + data['edd'] = edd; + data['totalInvoice'] = totalInvoice; + data['deliveryAmount'] = deliveryAmount; + data['site'] = site; + data['paymentTermAmount'] = paymentTermAmount; + data['warrentyPeriod'] = warrentyPeriod; + + if (paymentTerm != null) data['paymentTerm'] = paymentTerm!.toJson(); + if (assetDeliveryInternalMaster != null) { + data['assetDeliveryInternalMaster'] = + assetDeliveryInternalMaster!.toJson(); + } + if (assetDeliveryExternalDetails != null) { + data['assetDeliveryExternalDetails'] = + assetDeliveryExternalDetails!.map((v) => v.toJson()).toList(); + } + if (assetDeliveryExternalDeliveries != null) { + data['assetDeliveryExternalDeliveries'] = + assetDeliveryExternalDeliveries!.map((v) => v.toJson()).toList(); + } + + return data; + } +} + + +class AssetDeliveryInternalMaster { + int? id; + int? operatingUnitId; + String? operatingUnit; + int? poNumberId; + int? poNumber; + String? supplier; + String? supplierSite; + String? type; + String? buyer; + num? total; + String? currency; + String? remark; + String? status; + String? paymentTerms; + double? warrantyPeriod; + String? assetDeliveryStatus; + String? statusDocument; + String? remarkDocument; + String? edd; + + AssetDeliveryInternalMaster(); + + AssetDeliveryInternalMaster.fromJson(Map json) { + id = json['id']; + operatingUnitId = json['operatingUnitId']; + operatingUnit = json['operatingUnit']; + poNumberId = json['poNumberId']; + poNumber = json['poNumber']; + supplier = json['supplier']; + supplierSite = json['supplierSite']; + type = json['type']; + buyer = json['buyer']; + total = json['total']; + currency = json['currency']; + remark = json['remark']; + status = json['status']; + paymentTerms = json['paymentTerms']; + warrantyPeriod = json['warrantyPeriod']; + assetDeliveryStatus = json['assetDeliveryStatus']; + statusDocument = json['statusDocument']; + remarkDocument = json['remarkDocument']; + edd = json['edd']; + } + + Map toJson() { + return { + 'id': id, + 'operatingUnitId': operatingUnitId, + 'operatingUnit': operatingUnit, + 'poNumberId': poNumberId, + 'poNumber': poNumber, + 'supplier': supplier, + 'supplierSite': supplierSite, + 'type': type, + 'buyer': buyer, + 'total': total, + 'currency': currency, + 'remark': remark, + 'status': status, + 'paymentTerms': paymentTerms, + 'warrantyPeriod': warrantyPeriod, + 'assetDeliveryStatus': assetDeliveryStatus, + 'statusDocument': statusDocument, + 'remarkDocument': remarkDocument, + 'edd': edd, + }; + } +} + +class AssetDeliveryExternalDetail { + int? id; + AssetDeliveryInternalDetail? assetDeliveryInternalDetail; + String? itemNumber; + String? lineType; + String? unitMeasure; + num? qtyOrdered; + num? qtyReceived; + num? qtyBilled; + num? qtyCancelled; + num? unitPrice; + num? unitPriceWithTax; + String? itemDescription; + + AssetDeliveryExternalDetail(); + + AssetDeliveryExternalDetail.fromJson(Map json) { + id = json['id']; + itemNumber = json['itemNumber']; + lineType = json['lineType']; + unitMeasure = json['unitMeasure']; + qtyOrdered = json['qtyOrdered']; + qtyReceived = json['qtyReceived']; + qtyBilled = json['qtyBilled']; + qtyCancelled = json['qtyCancelled']; + unitPrice = json['unitPrice']; + unitPriceWithTax = json['unitPriceWithTax']; + itemDescription = json['itemDescription']; + + assetDeliveryInternalDetail = + json['assetDeliveryInternalDetail'] != null + ? AssetDeliveryInternalDetail.fromJson( + json['assetDeliveryInternalDetail']) + : null; + } + + Map toJson() { + return { + 'id': id, + 'itemNumber': itemNumber, + 'lineType': lineType, + 'unitMeasure': unitMeasure, + 'qtyOrdered': qtyOrdered, + 'qtyReceived': qtyReceived, + 'qtyBilled': qtyBilled, + 'qtyCancelled': qtyCancelled, + 'unitPrice': unitPrice, + 'unitPriceWithTax': unitPriceWithTax, + 'itemDescription': itemDescription, + 'assetDeliveryInternalDetail': + assetDeliveryInternalDetail?.toJson(), + }; + } +} + +class AssetDeliveryInternalDetail { + int? id; + int? lineId; + String? itemNumber; + String? itemDescription; + String? unitMeasure; + num? qtyOrdered; + num? qtyReceived; + num? qtyBilled; + num? qtyCancelled; + num? unitPrice; + num? unitPriceWithTax; + String? itemCategory; + num? totalAssets; + num? childPerAsset; + + AssetDeliveryInternalDetail(); + + AssetDeliveryInternalDetail.fromJson(Map json) { + id = json['id']; + lineId = json['lineId']; + itemNumber = json['itemNumber']; + itemDescription = json['itemDescription']; + unitMeasure = json['unitMeasure']; + qtyOrdered = json['qtyOrdered']; + qtyReceived = json['qtyReceived']; + qtyBilled = json['qtyBilled']; + qtyCancelled = json['qtyCancelled']; + unitPrice = json['unitPrice']; + unitPriceWithTax = json['unitPriceWithTax']; + itemCategory = json['itemCategory']; + totalAssets = json['totalAssets']; + childPerAsset = json['childPerAsset']; + } + + Map toJson() { + return { + 'id': id, + 'lineId': lineId, + 'itemNumber': itemNumber, + 'itemDescription': itemDescription, + 'unitMeasure': unitMeasure, + 'qtyOrdered': qtyOrdered, + 'qtyReceived': qtyReceived, + 'qtyBilled': qtyBilled, + 'qtyCancelled': qtyCancelled, + 'unitPrice': unitPrice, + 'unitPriceWithTax': unitPriceWithTax, + 'itemCategory': itemCategory, + 'totalAssets': totalAssets, + 'childPerAsset': childPerAsset, + }; + } +} +class AssetDeliveryTableModel { + int? id; + Lookup? status; + String? number; + num? deliveryAmount; + num? invoiceAmount; + bool? isContainsTechnicalInspection; + + AssetDeliveryTableModel(); + + AssetDeliveryTableModel.fromJson(Map json) { + id = json['id']; + number = json['number']; + deliveryAmount = json['deliveryAmount']; + invoiceAmount = json['invoiceAmount']; + isContainsTechnicalInspection = json['isContainsTechnicalInspection']; + + status = json['status'] != null + ? Lookup.fromJson(json['status']) + : null; + } + + Map toJson() { + return { + 'id': id, + 'number': number, + 'deliveryAmount': deliveryAmount, + 'invoiceAmount': invoiceAmount, + 'isContainsTechnicalInspection': isContainsTechnicalInspection, + 'status': status?.toJson(), + }; + } +} + +class PurchaseOrderMaster { + int? id; + num? poNumber; + int? siteId; + String? siteName; + num? amount; + String? remarks; + String? statuss; + List? assetDeliveryPurchaseOrderDetails; + + PurchaseOrderMaster({ + this.id, + this.poNumber, + this.siteId, + this.siteName, + this.amount, + this.remarks, + this.statuss, + this.assetDeliveryPurchaseOrderDetails, + }); + + PurchaseOrderMaster.fromJson(Map json) { + id = json['id']; + poNumber = json['poNumber']; + siteId = json['siteId']; + siteName = json['siteName']; + amount = json['amount']; + remarks = json['remarks']; + statuss = json['statuss']; + + if (json['assetDeliveryPurchaseOrderDetails'] != null && + json['assetDeliveryPurchaseOrderDetails'] is List) { + assetDeliveryPurchaseOrderDetails = + (json['assetDeliveryPurchaseOrderDetails'] as List) + .map((e) => PurchaseOrderDetails.fromJson(e)) + .toList(); + } else { + assetDeliveryPurchaseOrderDetails = null; + } + } +} + +class SiteModel{ + int? id; + String? siteName; + + SiteModel({ + this.id, + this.siteName, + }); + + SiteModel.fromJson(Map json) { + id = json['id']; + siteName = json['siteName']; + } +} +///Check this model if required and whats the parm +class PurchaseOrderDetails { + // No fields provided in your JSON – placeholder + PurchaseOrderDetails(); + + PurchaseOrderDetails.fromJson(Map json); +} + diff --git a/lib/modules/asset_delivery_module/models/asset_inventory_model.dart b/lib/modules/asset_delivery_module/models/asset_inventory_model.dart deleted file mode 100644 index 4a4e6587..00000000 --- a/lib/modules/asset_delivery_module/models/asset_inventory_model.dart +++ /dev/null @@ -1,345 +0,0 @@ -import 'dart:developer'; - -import 'package:test_sa/models/new_models/building.dart'; -import 'package:test_sa/models/new_models/floor.dart'; -import 'package:test_sa/models/new_models/room_model.dart'; -import 'package:test_sa/models/new_models/site.dart'; -import 'package:test_sa/models/service_request/supplier_details.dart'; -import '../../../models/new_models/department.dart'; - -class AssetInventoryResponse { - num? totalRows; - num? count; - String? message; - String? title; - String? innerMessage; - num? responseCode; - bool? isSuccess; - List? assetList; - - AssetInventoryResponse({ - this.totalRows, - this.count, - this.message, - this.title, - this.innerMessage, - this.responseCode, - this.isSuccess, - this.assetList, - }); - - AssetInventoryResponse.fromJson(Map json) { - totalRows = json['totalRows']; - count = json['count']; - message = json['message']; - title = json['title']; - innerMessage = json['innerMessage']; - responseCode = json['responseCode']; - isSuccess = json['isSuccess']; - if (json['data'] != null) { - assetList = (json['data'] as List).map((item) => AssetInventoryModel.fromJson(item)).toList(); - } - } - - Map toJson() { - return { - 'totalRows': totalRows, - 'count': count, - 'message': message, - 'title': title, - 'innerMessage': innerMessage, - 'responseCode': responseCode, - 'isSuccess': isSuccess, - }; - } -} - -class AssetInventoryModel { - num? id; - num? assetId; - String? transactionDate; - String? assetNumber; - String? serialNo; - String? assetName; - num? assetNameId; - String? model; - String? manufacturer; - String? supplierName; - String? siteName; - String? buildingName; - String? floorName; - String? departmentName; - String? roomName; - num? statusId; - String? status; - num? statusValue; - num? statusByAdminId; - String? statusByAdmin; - num? statusByAdminValue; - bool? isNotRegistered; - num? sessionId; - num? assetImportId; - num? siteId; - num? supplierId; - num? buildingId; - num? floorId; - num? departmentId; - num? roomId; - String? newAssetNumber; - String? newSerialNo; - num? newAssetNameId; - String? newAssetNameText; - num? newModelId; - String? newModelName; - num? manufacturerId; - num? modelId; - num? newManufacturerId; - String? newManufacturerName; - num? newSupplierId; - String? newSupplierName; - String? photo; - String? photoOriginName; - String? remarks; - Site? site; - Building? building; - Floor? floor; - Department? department; - Rooms? room; - SupplierDetails? supplier; - List assetInventoryDetailAssetAttachments = []; - - AssetInventoryModel({ - this.id, - this.sessionId, - this.assetId, - this.transactionDate, - this.assetNumber, - this.assetNameId, - this.serialNo, - this.assetName, - this.model, - this.manufacturer, - this.supplierName, - this.siteName, - this.buildingName, - this.floorName, - this.departmentName, - this.roomName, - this.statusId, - this.status, - this.statusValue, - this.statusByAdminId, - this.statusByAdmin, - this.statusByAdminValue, - this.isNotRegistered, - this.assetImportId, - this.siteId, - this.buildingId, - this.floorId, - this.departmentId, - this.supplierId, - this.roomId, - this.newAssetNumber, - this.manufacturerId, - this.newSerialNo, - this.newAssetNameId, - this.newAssetNameText, - this.newModelId, - this.modelId, - this.newModelName, - this.newManufacturerId, - this.newManufacturerName, - this.newSupplierId, - this.newSupplierName, - this.photo, - this.photoOriginName, - this.remarks, - this.site, - this.department, - this.building, - this.floor, - this.room, - this.supplier, - this.assetInventoryDetailAssetAttachments = const [], - }); - - AssetInventoryModel.fromJson(Map json) { - id = json['id']; - assetId = json['assetId']; - transactionDate = json['transactionDate']; - assetNumber = json['assetNumber']; - assetNameId = json['assetNameId']; - serialNo = json['serialNo']; - assetName = json['assetName']; - model = json['model'] ?? json['modelName']; - manufacturer = json['manufacturer'] ?? json['manufacturerName']; - supplierName = json['supplierName']; - siteName = json['site'] ?? json['siteName']; - buildingName = json['building'] ?? json['buildingName']; - floorName = json['floor'] ?? json['floorName']; - departmentName = json['department'] ?? json['departmentName']; - roomName = json['room'] ?? json['roomName']; - statusId = json['statusId']; - status = json['status'] ?? json['classification']; - statusValue = json['statusValue']; - isNotRegistered = json['isNotRegistered']; - sessionId = json['sessionId']; - assetImportId = json['assetImportId']??json['id']; - siteId = json['siteId']; - buildingId = json['buildingId']; - floorId = json['floorId']; - supplierId = json['supplierId']; - departmentId = json['departmentId']; - roomId = json['roomId']; - modelId = json['modelId']; - photo = json['photo']; - photoOriginName = json['photoOriginName']; - remarks = json['remarks']; - if (json['assetTransferAttachments'] != null) { - assetInventoryDetailAssetAttachments = []; - json['assetInventoryDetailAssetAttachments'].forEach((v) { - assetInventoryDetailAssetAttachments.add(AssetInventoryDetailAssetAttachments.fromJson(v)); - }); - } - - //new data.. - // newAssetNumber = json['newAssetNumber'] ?? json['assetNumber']; - // manufacturerId = json['manufacturerId'] ?? json['manufacturerId']; - // newSerialNo = json['newSerialNo'] ?? json['serialNo']; - // newAssetNameId = json['newAssetNameId'] ?? json['assetNameId']; - // newAssetNameText = json['newAssetNameText'] ?? json['assetNameText']; - // newModelId = json['newModelId'] ?? json['modelId']; - // newModelName = json['newModelName'] ?? json['modelName']; - // newManufacturerId = json['newManufacturerId'] ?? json['manufacturerId']; - // newManufacturerName = json['newManufacturerName'] ?? json['manufacturerName']; - // newSupplierId = json['newSupplierId'] ?? json['supplierId']; - // newSupplierName = json['newSupplierName'] ?? json['supplierName']; - } - - Map toJson() { - return { - 'isNotRegistered': isNotRegistered, - 'sessionId': sessionId, - 'assetImportId': assetImportId, - 'transactionDate': transactionDate, - 'assetId': assetId, - 'siteId': siteId, - 'buildingId': buildingId, - 'floorId': floorId, - 'departmentId': departmentId, - 'roomId': roomId, - 'newSerialNo': newSerialNo, - 'newAssetNameId': newAssetNameId, - 'newAssetNameText': newAssetNameText, - 'newAssetNumber': newAssetNumber, - 'newModelId': newModelId, - 'newModelName': newModelName, - 'newManufacturerId': newManufacturerId, - 'newManufacturerName': newManufacturerName, - 'newSupplierId': newSupplierId, - 'newSupplierName': newSupplierName, - 'photo': photo, - 'remarks': remarks, - 'assetInventoryDetailAssetAttachments': assetInventoryDetailAssetAttachments != null - ? assetInventoryDetailAssetAttachments!.map((v) => v.toJson()).toList() - : [], - }; - } - - AssetInventoryModel mergeWith(AssetInventoryModel? other) { - if (other == null) return this; - - return AssetInventoryModel( - id: id ?? other.id, - assetId: assetId ?? other.assetId, - transactionDate: transactionDate ?? other.transactionDate, - assetNumber: assetNumber ?? other.assetNumber, - serialNo: serialNo ?? other.serialNo, - assetName: assetName ?? other.assetName, - assetNameId: assetNameId ?? other.assetNameId, - model: model ?? other.model, - manufacturer: manufacturer ?? other.manufacturer, - supplierName: supplierName ?? other.supplierName, - siteName: siteName ?? other.siteName, - buildingName: buildingName ?? other.buildingName, - floorName: floorName ?? other.floorName, - departmentName: departmentName ?? other.departmentName, - roomName: roomName ?? other.roomName, - statusId: statusId ?? other.statusId, - status: status ?? other.status, - statusValue: statusValue ?? other.statusValue, - statusByAdminId: statusByAdminId ?? other.statusByAdminId, - statusByAdmin: statusByAdmin ?? other.statusByAdmin, - statusByAdminValue: statusByAdminValue ?? other.statusByAdminValue, - isNotRegistered: isNotRegistered ?? other.isNotRegistered, - sessionId: sessionId ?? other.sessionId, - assetImportId: assetImportId ?? other.assetImportId, - siteId: siteId ?? other.siteId, - supplierId: supplierId ?? other.supplierId, - buildingId: buildingId ?? other.buildingId, - floorId: floorId ?? other.floorId, - departmentId: departmentId ?? other.departmentId, - roomId: roomId ?? other.roomId, - newAssetNumber: newAssetNumber ?? other.newAssetNumber, - newSerialNo: newSerialNo ?? other.newSerialNo, - newAssetNameId: newAssetNameId ?? other.newAssetNameId, - newAssetNameText: newAssetNameText ?? other.newAssetNameText, - newModelId: newModelId ?? other.newModelId, - newModelName: newModelName ?? other.newModelName, - manufacturerId: manufacturerId ?? other.manufacturerId, - modelId: modelId ?? other.modelId, - newManufacturerId: newManufacturerId ?? other.newManufacturerId, - newManufacturerName: newManufacturerName ?? other.newManufacturerName, - newSupplierId: newSupplierId ?? other.newSupplierId, - newSupplierName: newSupplierName ?? other.newSupplierName, - photo: photo ?? other.photo, - photoOriginName: photoOriginName ?? other.photoOriginName, - remarks: remarks ?? other.remarks, - site: site ?? other.site, - building: building ?? other.building, - floor: floor ?? other.floor, - department: department ?? other.department, - room: room ?? other.room, - supplier: supplier ?? other.supplier, - assetInventoryDetailAssetAttachments: assetInventoryDetailAssetAttachments??other.assetInventoryDetailAssetAttachments, - ); - } - - -} -class AssetInventoryDetailAssetAttachments { - AssetInventoryDetailAssetAttachments({ - this.id, - this.name, - this.originalName, - }); - - AssetInventoryDetailAssetAttachments.fromJson(dynamic json) { - id = json['id']; - name = json['name']; - originalName = json['originalName']; - } - - num? id; - String? name; - String? originalName; - - AssetInventoryDetailAssetAttachments copyWith({ - num? id, // Parameter is now nullable - String? name, // Parameter is now nullable - String? originalName, // Parameter is now nullable - }) => - AssetInventoryDetailAssetAttachments( - id: id ?? this.id, - name: name??this.name, - originalName: originalName??this.originalName, - ); - - Map toJson() { - final map = {}; - map['id'] = id; - map['name'] = name; - map['originalName'] = originalName; - return map; - } -} diff --git a/lib/modules/asset_delivery_module/models/cost_center_model.dart b/lib/modules/asset_delivery_module/models/cost_center_model.dart index d465b58d..4bbfe9aa 100644 --- a/lib/modules/asset_delivery_module/models/cost_center_model.dart +++ b/lib/modules/asset_delivery_module/models/cost_center_model.dart @@ -1,27 +1,62 @@ import 'package:test_sa/models/lookup.dart'; class CostCenterModel { + int? id; + int? assetDeliveryExternalDetailId; Lookup? costCenter; + String? acceptedBy; + String? costCenterName; + DateTime? acceptanceDate; + String? acceptedByEmail; + String? acceptedBySignature; double? quantity; CostCenterModel({ + this.id, + this.assetDeliveryExternalDetailId, this.costCenter, + this.acceptedBy, + this.costCenterName, + this.acceptanceDate, + this.acceptedByEmail, + this.acceptedBySignature, this.quantity, }); CostCenterModel.fromJson(Map json) { - costCenter = json['costCenter'] != null - ? Lookup.fromJson(json['costCenter']) - : null; - quantity = json['quantity']; + costCenterName = json['costCenter'] ?? json['costCenterName']; + acceptanceDate = json['acceptanceDate'] != null ? DateTime.tryParse(json['acceptanceDate']) : null; + acceptedBySignature = json['acceptedBySignature']; + acceptedByEmail = json['acceptedByEmail']; + quantity = json['qty'] ?? json['costCenterQty']; + acceptedBy = json['acceptedBy']; + costCenter = json['costCenter'] != null ? Lookup(name: json['costCenter']) : null; + id = json['id'] ?? json['costCenterId']; + assetDeliveryExternalDetailId = json['assetDeliveryExternalDetailId']; } Map toJson() { final Map data = {}; - if (costCenter != null) { - data['costCenter'] = costCenter!.toJson(); - } - data['quantity'] = quantity; + + data['id'] = id ?? 0; + data['qty'] = quantity; + // data['costCenter'] = costCenter; + // data['acceptedBy'] = acceptedBy; + // data['acceptanceDate'] = acceptanceDate; + // data['acceptedByEmail'] = acceptedByEmail; + // data['acceptedBySignature'] = acceptedBySignature; + data['costCenter'] = costCenterName; + return data; + } + + Map toEndUserAcceptanceFormJson() { + final Map data = {}; + data['assetDeliveryExternalDeliveryId'] = assetDeliveryExternalDetailId; + data['costCenterName'] = costCenterName; + data['acceptedBy'] = acceptedBy; + data['acceptanceDate'] = acceptanceDate?.toIso8601String(); + data['acceptedByEmail'] = acceptedByEmail; + data['acceptedBySignature'] = acceptedBySignature; return data; } } diff --git a/lib/modules/asset_delivery_module/models/delivery_inspection_form_model.dart b/lib/modules/asset_delivery_module/models/delivery_inspection_form_model.dart new file mode 100644 index 00000000..10b45d4f --- /dev/null +++ b/lib/modules/asset_delivery_module/models/delivery_inspection_form_model.dart @@ -0,0 +1,37 @@ +class DeliveryInspectionFormModel { + int? assetDeliveryExternalDeliveryId; + String? deliveryInspectionInspectedBy; + DateTime? deliveryInspectionInspectedDateFrom; + DateTime? deliveryInspectionInspectedDateTo; + num? totalTime; + String? deliveryInspectionApprovedBy; + + DeliveryInspectionFormModel({ + this.assetDeliveryExternalDeliveryId, + this.deliveryInspectionInspectedBy, + this.deliveryInspectionInspectedDateFrom, + this.deliveryInspectionInspectedDateTo, + this.totalTime, + this.deliveryInspectionApprovedBy, + }); + + DeliveryInspectionFormModel.fromJson(Map json) { + assetDeliveryExternalDeliveryId = json['assetDeliveryExternalDeliveryId']; + deliveryInspectionInspectedBy = json['deliveryInspectionInspectedBy']; + deliveryInspectionInspectedDateFrom = json['deliveryInspectionInspectedDateFrom']!=null?DateTime.tryParse(json['deliveryInspectionInspectedDateFrom']):null; + deliveryInspectionInspectedDateTo = json['deliveryInspectionInspectedDateTo']!=null?DateTime.tryParse(json['deliveryInspectionInspectedDateTo']):null; + totalTime = json['totalTime']; + deliveryInspectionApprovedBy = json['deliveryInspectionApprovedBy']; + } + + Map toJson() { + return { + 'assetDeliveryExternalDeliveryId': assetDeliveryExternalDeliveryId, + 'deliveryInspectionInspectedBy': deliveryInspectionInspectedBy, + 'deliveryInspectionInspectedDateFrom': deliveryInspectionInspectedDateFrom?.toIso8601String(), + 'deliveryInspectionInspectedDateTo': deliveryInspectionInspectedDateTo?.toIso8601String(), + 'totalTime': totalTime, + 'deliveryInspectionApprovedBy': deliveryInspectionApprovedBy, + }; + } +} diff --git a/lib/modules/asset_delivery_module/models/delivery_line_model.dart b/lib/modules/asset_delivery_module/models/delivery_line_model.dart new file mode 100644 index 00000000..d715c8c1 --- /dev/null +++ b/lib/modules/asset_delivery_module/models/delivery_line_model.dart @@ -0,0 +1,61 @@ +class DeliveryLineModel { + int? id; + int? assetDeliveryInternalDetailId; + String? itemNumber; + String? itemDescription; + num? qty; + num? remainingQty; + num? usingQtyInThisDelivery; + num? unitPrice; + num? total; + String? unitOfMeasure; + String? lineType; + String? itemCategory; + + DeliveryLineModel({ + this.id, + this.assetDeliveryInternalDetailId, + this.itemNumber, + this.itemDescription, + this.qty, + this.remainingQty, + this.usingQtyInThisDelivery, + this.unitPrice, + this.total, + this.unitOfMeasure, + this.lineType, + this.itemCategory, + }); + + DeliveryLineModel.fromJson(Map json) { + id = json['id']; + assetDeliveryInternalDetailId = json['assetDeliveryInternalDetailId']; + itemNumber = json['itemNumber']; + itemDescription = json['itemDescription']; + qty = json['qty']; + remainingQty = json['remainingQty']; + usingQtyInThisDelivery = json['usingQtyInThisDelivery']; + unitPrice = json['unitPrice']; + total = json['total']; + unitOfMeasure = json['unitOfMeasure']; + lineType = json['lineType']; + itemCategory = json['itemCategory']; + } + + Map toJson() { + return { + 'id': id, + 'assetDeliveryInternalDetailId': assetDeliveryInternalDetailId, + 'itemNumber': itemNumber, + 'itemDescription': itemDescription, + 'qty': qty, + 'remainingQty': remainingQty, + 'usingQtyInThisDelivery': usingQtyInThisDelivery, + 'unitPrice': unitPrice, + 'total': total, + 'unitOfMeasure': unitOfMeasure, + 'lineType': lineType, + 'itemCategory': itemCategory, + }; + } +} diff --git a/lib/modules/asset_delivery_module/models/end_user_asset_details_model.dart b/lib/modules/asset_delivery_module/models/end_user_asset_details_model.dart new file mode 100644 index 00000000..242cf70a --- /dev/null +++ b/lib/modules/asset_delivery_module/models/end_user_asset_details_model.dart @@ -0,0 +1,71 @@ +import 'package:test_sa/models/lookup.dart'; + +class EndUserAssetDetailsModel { + int? id; + int? typeId; + int? assetDeliveryExternalDeliveryId; + String? type; + String? itemNumber; + String? costCenterName; + Lookup? status; + Lookup? rejectionReason; + String? description; + double? receivedQty; + num? rejectedQty; + String? assetNumber; + String? serialNo; + String? assetType; + String? replacedAssetNo; + + EndUserAssetDetailsModel( + {this.costCenterName, + this.rejectedQty, + this.description, + this.id, + this.typeId, + this.status, + this.rejectionReason, + this.assetType, + this.assetNumber, + this.serialNo, + this.itemNumber, + this.type, + this.receivedQty, + this.replacedAssetNo, + this.assetDeliveryExternalDeliveryId}); + + EndUserAssetDetailsModel.fromJson(Map json) { + id = json['id']; + typeId = json['typeId']; + type = json['type']; + itemNumber = json['itemNumber']; + status = json['status'] != null ? Lookup.fromJson(json['status']) : null; + rejectionReason = json['rejectReason'] != null ? Lookup.fromJson(json['rejectReason']) : null; + description = json['description']; + receivedQty = json['receivedQty']; + rejectedQty = json['rejectedQty']; + assetNumber = json['assetNumber']; + serialNo = json['serialNo']; + assetType = json['assetType']; + replacedAssetNo = json['replacedAssetNo']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['assetDeliveryExternalDeliveryId'] = assetDeliveryExternalDeliveryId; + data['costCenterName'] = costCenterName; + data['typeId'] = typeId; + data['type'] = type; + data['itemNumber'] = itemNumber; + data['statusId'] = status?.id; + // data['status'] = status; + // data['rejectionReason'] = rejectionReason; + data['rejectReasonId'] = rejectionReason?.id; + data['description'] = description; + data['receivedQty'] = receivedQty; + data['rejectedQty'] = rejectedQty; + + return data; + } +} diff --git a/lib/modules/asset_delivery_module/models/history_model.dart b/lib/modules/asset_delivery_module/models/history_model.dart new file mode 100644 index 00000000..67fc4e11 --- /dev/null +++ b/lib/modules/asset_delivery_module/models/history_model.dart @@ -0,0 +1,34 @@ +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/new_models/work_order_detail_model.dart'; + +class AssetDeliveryHistoryModel { + WorkOrderAssignedEmployee? user; + Lookup? status; + DateTime? createdDate; + String ?timeDifference; + + AssetDeliveryHistoryModel({ + this.user, + this.status, + this.createdDate, + this.timeDifference, + }); + + AssetDeliveryHistoryModel.fromJson(Map json) { + user = json['user'] != null ? WorkOrderAssignedEmployee.fromJson(json['user']) : null; + status = json['status'] != null ? Lookup.fromJson(json['status']) : null; + createdDate = json['createdDate'] != null ? DateTime.tryParse(json['createdDate']) : null; + timeDifference = ''; + } + + Map toJson() { + final Map data = {}; + if (user != null) { + data['user'] = user!.toJson(); + } + if (status != null) { + data['status'] = status!.toJson(); + } + return data; + } +} diff --git a/lib/modules/asset_delivery_module/models/oracle_user_model.dart b/lib/modules/asset_delivery_module/models/oracle_user_model.dart new file mode 100644 index 00000000..90ed9ee3 --- /dev/null +++ b/lib/modules/asset_delivery_module/models/oracle_user_model.dart @@ -0,0 +1,26 @@ +class OracleUserModel { + String? employeeNumber; + String? fullName; + String? job; + String? employeeMobileNumber; + String? employeeExtensionNumber; + String? employeeEmail; + + OracleUserModel({ + this.employeeNumber, + this.fullName, + this.job, + this.employeeMobileNumber, + this.employeeExtensionNumber, + this.employeeEmail, + }); + + OracleUserModel.fromJson(Map json) { + employeeNumber = json['employeeNumber']; + fullName = json['fullName']; + job = json['job']; + employeeMobileNumber = json['employeeMobileNumber']; + employeeExtensionNumber = json['employeeExtensionNumber']; + employeeEmail = json['employeeEmail']; + } +} diff --git a/lib/modules/asset_delivery_module/models/session_model.dart b/lib/modules/asset_delivery_module/models/session_model.dart deleted file mode 100644 index 8de8503b..00000000 --- a/lib/modules/asset_delivery_module/models/session_model.dart +++ /dev/null @@ -1,234 +0,0 @@ -import 'package:test_sa/models/new_models/site.dart'; - -class SessionModel { - int? id; - String? createdDate; - String? sessionName; - int? sessionTypeId; - int? sessionTypeValue; - String? sessionTypeName; - int? statusId; - String? statusName; - String? startDate; - String? endDate; - List assetInventorySites = []; - List assetInventoryAssignedEmployee = []; - - SessionModel({ - this.id, - this.sessionName, - this.createdDate, - this.sessionTypeId, - this.sessionTypeValue, - this.sessionTypeName, - this.statusId, - this.statusName, - this.startDate, - this.endDate, - List? assetInventorySites, - List? assetInventoryAssignedEmployee, - }) { - this.assetInventorySites = assetInventorySites ?? []; - this.assetInventoryAssignedEmployee = assetInventoryAssignedEmployee ?? []; - } - - SessionModel.fromJson(Map json) { - id = json['id']; - sessionName = json['sessionName']; - sessionTypeId = json['sessionTypeId']; - sessionTypeValue = json['sessionTypeValue']; - sessionTypeName = json['sessionTypeName']; - statusId = json['statusId']; - createdDate = json['createdDate']; - statusName = json['statusName']; - startDate = json['startDate']; - endDate = json['endDate']; - - if (json['assetInventorySites'] != null) { - assetInventorySites = (json['assetInventorySites'] as List).map((e) => Site.fromJson(e)).toList(); - } - - if (json['assetInventoryAssignedEmployee'] != null) { - assetInventoryAssignedEmployee = (json['assetInventoryAssignedEmployee'] as List).map((e) => AssetInventoryAssignedEmployee.fromJson(e)).toList(); - } - } - - Map toJson() { - final map = {}; - map['id'] = id; - map['sessionName'] = sessionName; - map['sessionTypeId'] = sessionTypeId; - map['sessionTypeValue'] = sessionTypeValue; - map['sessionTypeName'] = sessionTypeName; - map['statusId'] = statusId; - map['statusName'] = statusName; - map['createdDate'] = createdDate; - map['startDate'] = startDate; - map['endDate'] = endDate; - map['assetInventorySites'] = assetInventorySites.map((e) => e.toJson()).toList(); - map['assetInventoryAssignedEmployee'] = assetInventoryAssignedEmployee.map((e) => e.toJson()).toList(); - return map; - } -} - -// class AssetInventorySite { -// int? siteId; -// String? siteName; -// List assetInventoryBuildings = []; -// -// AssetInventorySite({ -// this.siteId, -// this.siteName, -// List? assetInventoryBuildings, -// }) { -// this.assetInventoryBuildings = assetInventoryBuildings ?? []; -// } -// -// AssetInventorySite.fromJson(Map json) { -// siteId = json['siteId']; -// siteName = json['siteName']; -// -// if (json['assetInventoryBuildings'] != null) { -// assetInventoryBuildings = (json['assetInventoryBuildings'] as List).map((e) => AssetInventoryBuilding.fromJson(e)).toList(); -// } -// } -// -// Map toJson() { -// final map = {}; -// map['siteId'] = siteId; -// map['siteName'] = siteName; -// map['assetInventoryBuildings'] = assetInventoryBuildings.map((e) => e.toJson()).toList(); -// return map; -// } -// } -// -// class AssetInventoryBuilding { -// int? buildingId; -// String? buildingName; -// List assetInventoryFloors = []; -// -// AssetInventoryBuilding({ -// this.buildingId, -// this.buildingName, -// List? assetInventoryFloors, -// }) { -// this.assetInventoryFloors = assetInventoryFloors ?? []; -// } -// -// AssetInventoryBuilding.fromJson(Map json) { -// buildingId = json['buildingId']; -// buildingName = json['buildingName']; -// -// if (json['assetInventoryFloors'] != null) { -// assetInventoryFloors = (json['assetInventoryFloors'] as List).map((e) => AssetInventoryFloor.fromJson(e)).toList(); -// } -// } -// -// Map toJson() { -// final map = {}; -// map['buildingId'] = buildingId; -// map['buildingName'] = buildingName; -// map['assetInventoryFloors'] = assetInventoryFloors.map((e) => e.toJson()).toList(); -// return map; -// } -// } -// -// class AssetInventoryFloor { -// int? floorId; -// String? floorName; -// List assetInventoryDepartments = []; -// -// AssetInventoryFloor({ -// this.floorId, -// this.floorName, -// List? assetInventoryDepartments, -// }) { -// this.assetInventoryDepartments = assetInventoryDepartments ?? []; -// } -// -// AssetInventoryFloor.fromJson(Map json) { -// floorId = json['floorId']; -// floorName = json['floorName']; -// -// if (json['assetInventoryDepartments'] != null) { -// assetInventoryDepartments = (json['assetInventoryDepartments'] as List).map((e) => AssetInventoryDepartment.fromJson(e)).toList(); -// } -// } -// -// Map toJson() { -// final map = {}; -// map['floorId'] = floorId; -// map['floorName'] = floorName; -// map['assetInventoryDepartments'] = assetInventoryDepartments.map((e) => e.toJson()).toList(); -// return map; -// } -// } -// -// class AssetInventoryDepartment { -// int? departmentId; -// String? departmentName; -// List assetInventoryRooms = []; -// -// AssetInventoryDepartment({ -// this.departmentId, -// this.departmentName, -// List? assetInventoryRooms, -// }) { -// this.assetInventoryRooms = assetInventoryRooms ?? []; -// } -// -// AssetInventoryDepartment.fromJson(Map json) { -// departmentId = json['departmentId']; -// departmentName = json['departmentName']; -// -// if (json['assetInventoryRooms'] != null) { -// assetInventoryRooms = (json['assetInventoryRooms'] as List).map((e) => AssetInventoryRoom.fromJson(e)).toList(); -// } -// } -// -// Map toJson() { -// final map = {}; -// map['departmentId'] = departmentId; -// map['departmentName'] = departmentName; -// map['assetInventoryRooms'] = assetInventoryRooms.map((e) => e.toJson()).toList(); -// return map; -// } -// } -// -// class AssetInventoryRoom { -// int? roomId; -// String? roomName; -// -// AssetInventoryRoom({this.roomId, this.roomName}); -// -// AssetInventoryRoom.fromJson(Map json) { -// roomId = json['roomId']; -// roomName = json['roomName']; -// } -// -// Map toJson() { -// final map = {}; -// map['roomId'] = roomId; -// map['roomName'] = roomName; -// return map; -// } -// } - -class AssetInventoryAssignedEmployee { - String? assignedEngineerId; - String? assignedEngineerName; - - AssetInventoryAssignedEmployee({this.assignedEngineerId, this.assignedEngineerName}); - - AssetInventoryAssignedEmployee.fromJson(Map json) { - assignedEngineerId = json['assignedEngineerId']; - assignedEngineerName = json['assignedEngineerName']; - } - - Map toJson() { - final map = {}; - map['assignedEngineerId'] = assignedEngineerId; - map['assignedEngineerName'] = assignedEngineerName; - return map; - } -} diff --git a/lib/modules/asset_delivery_module/models/technical_inpection_asset_model.dart b/lib/modules/asset_delivery_module/models/technical_inpection_asset_model.dart new file mode 100644 index 00000000..7404b585 --- /dev/null +++ b/lib/modules/asset_delivery_module/models/technical_inpection_asset_model.dart @@ -0,0 +1,61 @@ +class TechnicalInspectionAssetBasicInfoModel { + int? id; + String? assetNumber; + String? assetType; + String? assetOrigin; + String? assetName; + String? model; + String? manufacturer; + String? site; + String? building; + String? floor; + String? department; + String? room; + + TechnicalInspectionAssetBasicInfoModel({ + this.id, + this.assetNumber, + this.assetType, + this.assetOrigin, + this.assetName, + this.model, + this.manufacturer, + this.site, + this.building, + this.floor, + this.department, + this.room, + }); + + TechnicalInspectionAssetBasicInfoModel.fromJson(Map json) { + id = json['id']; + assetNumber = json['assetNumber']; + assetType = json['assetType']; + assetOrigin = json['assetOrigin']; + assetName = json['assetName']; + model = json['model']; + manufacturer = json['manufacturer']; + site = json['site']; + building = json['building']; + floor = json['floor']; + department = json['department']; + room = json['room']; + } + + Map toJson() { + return { + 'id': id, + 'assetNumber': assetNumber, + 'assetType': assetType, + 'assetOrigin': assetOrigin, + 'assetName': assetName, + 'model': model, + 'manufacturer': manufacturer, + 'site': site, + 'building': building, + 'floor': floor, + 'department': department, + 'room': room, + }; + } +} diff --git a/lib/modules/asset_delivery_module/models/technical_inspection_asset_model.dart b/lib/modules/asset_delivery_module/models/technical_inspection_asset_model.dart new file mode 100644 index 00000000..64671b11 --- /dev/null +++ b/lib/modules/asset_delivery_module/models/technical_inspection_asset_model.dart @@ -0,0 +1,215 @@ +import 'dart:developer'; + +import 'package:test_sa/models/device/supplier.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/new_models/building.dart'; +import 'package:test_sa/models/new_models/floor.dart'; +import 'package:test_sa/models/new_models/room_model.dart'; +import 'package:test_sa/models/new_models/site.dart'; + +import '../../../models/device/model_definition.dart'; +import '../../../models/new_models/department.dart'; + +class TechnicalInspectionAssetModel { + num? id; + num? tableItemId; + num? lineId; + num? assetDeliveryInternalDetailAssetId; + num? assetDeliveryInternalDetailAssetChildId; + num? costCenterId; + String? assetNumber; + String? status; + Lookup? assetOrigin; + Lookup? replacedAsset; + AssetModelDefination? modelDefinition; + Supplier? supplier; + Lookup? assetType; // Now nullable + Site? site; // Now nullable + Building? building; // Now nullable + Floor? floor; // Now nullable + Department? department; // Now nullable + Rooms? room; + String? serialNo; + String? systemId; + DateTime? installationDate; + List? childAssetList; + bool? flagphysicalInspection; + bool? flagFunctionPerformance; + bool? flagGroundingResistance; + bool? flagChassiss; + bool? flagLeadsLeakage; + bool? flagAlert; + + TechnicalInspectionAssetModel({ + this.id, + this.assetDeliveryInternalDetailAssetId, + this.assetDeliveryInternalDetailAssetChildId, + this.tableItemId, + this.status, + this.lineId, + this.costCenterId, + this.assetNumber, + this.assetOrigin, + this.assetType, + this.replacedAsset, + this.modelDefinition, + this.supplier, + this.site, + this.building, + this.floor, + this.department, + this.room, + this.serialNo, + this.systemId, + this.installationDate, + this.childAssetList, + this.flagphysicalInspection, + this.flagFunctionPerformance, + this.flagGroundingResistance, + this.flagChassiss, + this.flagLeadsLeakage, + this.flagAlert, + }); + + TechnicalInspectionAssetModel.fromJson(Map json) { + id = json['id']; + assetDeliveryInternalDetailAssetId = json['assetDeliveryInternalDetailAssetId']; + assetDeliveryInternalDetailAssetChildId = json['assetDeliveryInternalDetailAssetChildId']; + assetNumber = json['assetNumber']; + assetOrigin = json['assetOrigin'] != null ? Lookup.fromJson(json['assetOrigin']) : null; + replacedAsset = json['replacedAsset'] != null ? Lookup.fromJson(json['replacedAsset']) : null; + modelDefinition = json['modelDefinition'] != null ? AssetModelDefination.fromJson(json['modelDefinition']) : null; + supplier = json['supplier'] != null ? Supplier.fromJson(json['supplier']) : null; + assetType = json['assetType'] != null ? Lookup.fromJson(json['assetType']) : null; + site = json['site'] != null ? Site.fromJson(json['site']) : null; + building = json['building'] != null ? Building.fromJson(json['building']) : null; + floor = json['floor'] != null ? Floor.fromJson(json['floor']) : null; + department = json['department'] != null ? Department.fromJson(json['department']) : null; + room = json['room'] != null ? Rooms.fromJson(json['room']) : null; + serialNo = json['serialNo']; + systemId = json['systemId']; + installationDate = json['installationDate'] != null ? DateTime.tryParse(json['installationDate']) : null; + childAssetList = + json['assetDeliveryInternalDetailAssetChild'] != null ? (json['assetDeliveryInternalDetailAssetChild'] as List).map((e) => TechnicalInspectionAssetModel.fromJson(e)).toList() : []; + //Need to keep one parm from backend + // childAssetList = json['assetDeliveryExternalDeliveryLineTechnicalInspectionItemChild'] != null + // ? (json['assetDeliveryExternalDeliveryLineTechnicalInspectionItemChild'] as List).map((e) => TechnicalInspectionAssetModel.fromJson(e)).toList() + // : []; + flagphysicalInspection = json['flagphysicalInspection']; + flagFunctionPerformance = json['flagFunctionPerformance']; + flagGroundingResistance = json['flagGroundingResistance']; + flagChassiss = json['flagChassiss']; + flagLeadsLeakage = json['flagLeadsLeakage']; + flagAlert = json['flagAlert']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['assetDeliveryInternalDetailAssetId'] = assetDeliveryInternalDetailAssetId; + data['assetDeliveryExternalDeliveryId'] = tableItemId; + data['assetDeliveryExternalDetailId'] = lineId; + data['costCenterId'] = costCenterId; + data['assetNumber'] = assetNumber; + data['assetOriginId'] = assetOrigin?.id; + data['assetTypeId'] = assetType?.id; + data['replacedAssetId'] = replacedAsset?.id; + data['modelDefinitionId'] = modelDefinition?.modelDefinitionId; + data['supplierId'] = supplier?.id; + data['siteId'] = site?.id; + data['buildingId'] = building?.id; + data['floorId'] = floor?.id; + data['departmentId'] = department?.id; + data['roomId'] = room?.id; + data['serialNo'] = serialNo; + data['systemId'] = systemId; + data['installationDate'] = installationDate?.toIso8601String(); + data['assetDeliveryInternalDetailAssetChild'] = childAssetList?.map((e) => e.toChildJson()).toList(); + data['flagphysicalInspection'] = flagphysicalInspection; + data['flagFunctionPerformance'] = flagFunctionPerformance; + data['flagGroundingResistance'] = flagGroundingResistance; + data['flagChassiss'] = flagChassiss; + data['flagLeadsLeakage'] = flagLeadsLeakage; + data['flagAlert'] = flagAlert; + return data; + } + + Map toChildJson() { + final Map data = {}; + data['id'] = id; + data['assetDeliveryInternalDetailAssetChildId'] = assetDeliveryInternalDetailAssetChildId; + data['assetNumber'] = assetNumber; + data['assetOriginId'] = assetOrigin?.id; + data['assetTypeId'] = assetType?.id; + data['replacedAssetId'] = replacedAsset?.id; + data['modelDefinitionId'] = modelDefinition?.modelDefinitionId; + data['supplierId'] = supplier?.id; + data['siteId'] = site?.id; + data['buildingId'] = building?.id; + data['floorId'] = floor?.id; + data['departmentId'] = department?.id; + data['roomId'] = room?.id; + data['serialNo'] = serialNo; + data['systemId'] = systemId; + data['installationDate'] = installationDate?.toIso8601String(); + data['flagphysicalInspection'] = flagphysicalInspection; + data['flagFunctionPerformance'] = flagFunctionPerformance; + data['flagGroundingResistance'] = flagGroundingResistance; + data['flagChassiss'] = flagChassiss; + data['flagLeadsLeakage'] = flagLeadsLeakage; + data['flagAlert'] = flagAlert; + return data; + } +} + +class InspectionChecklistItem { + String? title; + String? value; + String? status; // "PASS" or "FAIL" + + InspectionChecklistItem({this.title, this.status, this.value}); + + InspectionChecklistItem.fromJson(Map json) { + title = json['title']; + value = json['value']; + status = json['status']; + } + + Map toJson() { + return { + 'title': title, + 'value': value, + 'status': status, + }; + } +} + +class AssetModelDefination { + int? modelDefinitionId; + String? assetName; + String? model; + String? manufacturer; + + AssetModelDefination({ + this.modelDefinitionId, + this.assetName, + this.model, + this.manufacturer, + }); + + AssetModelDefination.fromJson(Map json) { + modelDefinitionId = json['modelDefinitionId']; + assetName = json['assetName']; + model = json['model']; + manufacturer = json['manufacturer']; + } + + Map toJson() { + final Map data = {}; + data['modelDefinitionId'] = modelDefinitionId; + data['assetName'] = assetName; + data['model'] = model; + data['manufacturer'] = manufacturer; + return data; + } +} diff --git a/lib/modules/asset_delivery_module/models/technical_inspection_form_model.dart b/lib/modules/asset_delivery_module/models/technical_inspection_form_model.dart new file mode 100644 index 00000000..cbde7191 --- /dev/null +++ b/lib/modules/asset_delivery_module/models/technical_inspection_form_model.dart @@ -0,0 +1,53 @@ +import 'dart:developer'; + +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; + +class TechnicalInspectionFormModel { + Lookup? powerSupplyType; + num? powerReading; + num? maxCurrent; + num? voltage; + num? frequency; + List? costCenters; + int? tableItemId; + int? lineId; + + TechnicalInspectionFormModel({ + this.powerSupplyType, + this.powerReading, + this.maxCurrent, + this.voltage, + this.frequency, + this.costCenters, + this.lineId, + this.tableItemId, + }); + + TechnicalInspectionFormModel.fromJson(Map json) { + powerSupplyType = json["powerSupplyType"] == null ? null : Lookup.fromJson(json["powerSupplyType"]); + powerReading = json['powerReading']; + maxCurrent = json['maxCurrent']; + voltage = json['voltage']; + frequency = json['frequency']; + if (json['costCenters'] != null) { + costCenters = []; + json['costCenters'].forEach((v) { + costCenters!.add(CostCenterModel.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = {}; + data['powerSupplyTypeId'] = powerSupplyType?.id; + data['assetDeliveryExternalDeliveryId'] = tableItemId; + data['assetDeliveryExternalDetailId'] = lineId; + data['powerReading'] = powerReading; + data['maxCurrent'] = maxCurrent; + data['voltage'] = voltage; + data['frequency'] = frequency; + // data['costCenters'] = costCenters != null ? costCenters!.map((v) => v.toJson()).toList() : []; + return data; + } +} diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_detail_page.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_detail_page.dart deleted file mode 100644 index d0b4f264..00000000 --- a/lib/modules/asset_delivery_module/pages/asset_delivery_detail_page.dart +++ /dev/null @@ -1,105 +0,0 @@ - -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/string_extensions.dart'; -import 'package:test_sa/extensions/text_extensions.dart'; -import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/history_log_view.dart'; -import 'package:test_sa/modules/cm_module/cm_detail_provider.dart'; -import 'package:test_sa/modules/cx_module/chat/chat_provider.dart'; -import 'package:test_sa/new_views/app_style/app_color.dart'; -import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; - -class AssetDeliveryDetailPage extends StatefulWidget { - final int requestId; - - AssetDeliveryDetailPage({Key? key, required this.requestId}) : super(key: key); - - @override - _AssetDeliveryDetailPageState createState() { - return _AssetDeliveryDetailPageState(); - } -} - -class _AssetDeliveryDetailPageState extends State { - late CMDetailProvider _requestProvider; - - static const int moduleId = 1; - - @override - void initState() { - super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_) { - Provider.of(context, listen: false).reset(); - getInitialData(); - }); - } - - Future getInitialData() async { - ///Replace with data ... - // _requestProvider = Provider.of(context, listen: false); - // await _requestProvider.getWorkOrderById(id: widget.requestId); - - } - - @override - void dispose() { - super.dispose(); - } - - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Theme.of(context).scaffoldBackgroundColor, - appBar: DefaultAppBar( - ///Title should be change with view change - title: 'Delivery Inspection'.addTranslation, - onBackPress: () { - Navigator.pop(context); - }, - ), - 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( - //controller: _tabController, - 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, - indicatorSize: TabBarIndicatorSize.tab, - dividerColor: Colors.transparent, - indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)), - onTap: (index) { - // setState(() {}); - }, - tabs: [ - Tab(text: context.translation.details, height: 57.toScreenHeight), - Tab(text: context.translation.historyLogs, height: 57.toScreenHeight), - ], - ), - ), - 12.height, - TabBarView( - children: [ - DeliveryInspectionFormView(), - const AssetDeliveryHistoryLogView(), - ], - ).expanded, - ], - ), - )); - } - -} diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_item_view.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_item_view.dart index 99aafbf3..ff02233c 100644 --- a/lib/modules/asset_delivery_module/pages/asset_delivery_item_view.dart +++ b/lib/modules/asset_delivery_module/pages/asset_delivery_item_view.dart @@ -15,6 +15,7 @@ class AssetDeliveryItemView extends StatelessWidget { final Data? requestData; final RequestsDetails? requestDetails; final bool showShadow; + const AssetDeliveryItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); @override @@ -23,27 +24,10 @@ class AssetDeliveryItemView extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // StatusLabel( - // label: requestData!.statusName!, - // textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.statusName!), - // backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.statusName!), - // ), - // 1.width.expanded, - // Text( - // requestData!.transactionDate?.toServiceRequestCardFormat ?? "", - // textAlign: TextAlign.end, - // style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), - // ), - // ], - // ), 8.height, - 'Asset Delivery'.addTranslation.heading5(context), - infoWidget(label: 'Delivery Type'.addTranslation, value: '-', context: context), - infoWidget(label: 'No of Assets'.addTranslation, value: '-', context: context), - infoWidget(label: 'No of Sites'.addTranslation, value: '-', context: context), + (requestData?.typeTransaction ?? 'Asset Delivery').heading5(context), + infoWidget(label: 'PO Internal'.addTranslation, value: requestData?.poInternal ?? '-', context: context), + infoWidget(label: 'PO External'.addTranslation, value: requestData?.poExternal ?? '-', context: context), // infoWidget(label: 'No of Sites'.addTranslation, value: requestData?.numberOfSites != null ? requestData?.numberOfSites.toString() : '-', context: context), 8.height, Row( @@ -59,33 +43,21 @@ class AssetDeliveryItemView extends StatelessWidget { ), ], ).toShadowContainer(context, withShadow: showShadow).onPress(() async { - Navigator.of(context).push(MaterialPageRoute(builder: (_) => AssetInventoryPage(sessionId: requestData!.id!, moduleId: requestData!.transactionNo!))); + Navigator.of(context).push(MaterialPageRoute( + builder: (_) => AssetDeliveryPage( + requestId: requestData!.id!, + poInternal: requestData?.poInternal, + poExternal: requestData?.poExternal, + ))); }); } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // StatusLabel( - // label: requestDetails!.status!, - // textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.status!), - // backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.status!), - // ), - // 1.width.expanded, - // Text( - // requestDetails!.date?.toServiceRequestCardFormat ?? "", - // textAlign: TextAlign.end, - // style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), - // ), - // ], - // ), 8.height, - 'Asset Delivery'.addTranslation.heading5(context), - infoWidget(label: 'Delivery Type'.addTranslation, value: '-', context: context), - infoWidget(label: 'No of Assets'.addTranslation, value: '-', context: context), - infoWidget(label: 'No of Sites'.addTranslation, value: '-', context: context), + (requestDetails?.nameOfType ?? 'Asset Delivery').heading5(context), + infoWidget(label: 'PO Internal'.addTranslation, value: requestDetails?.poInternal ?? '-', context: context), + infoWidget(label: 'PO External'.addTranslation, value: requestDetails?.poExternal ?? '-', context: context), 8.height, Row( mainAxisSize: MainAxisSize.min, @@ -100,7 +72,12 @@ class AssetDeliveryItemView extends StatelessWidget { ), ], ).toShadowContainer(context, withShadow: showShadow).onPress(() async { - Navigator.of(context).push(MaterialPageRoute(builder: (_) => AssetDeliveryPage(requestId: requestDetails!.id!))); + Navigator.of(context).push(MaterialPageRoute( + builder: (_) => AssetDeliveryPage( + requestId: requestDetails!.id!, + poInternal: requestDetails?.poInternal, + poExternal: requestDetails?.poExternal, + ))); }); } diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart index b8a22248..5337f457 100644 --- a/lib/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart +++ b/lib/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart @@ -1,22 +1,21 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/context_extension.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/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; class AssetDeliveryLineCard extends StatelessWidget { - ///Need to replace with Lines model. - AssetInventoryModel deliveryDetails; - ///if include in model skip this + DeliveryLineModel deliveryLineModel; bool isViewOnly; - VoidCallback ?editPress; + VoidCallback? editPress; + bool isTechnical; AssetDeliveryLineCard({ super.key, required this.isViewOnly, - required this.deliveryDetails, + required this.deliveryLineModel, + this.isTechnical = false, this.editPress, }); @@ -30,43 +29,55 @@ class AssetDeliveryLineCard extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - 'Item No: ${deliveryDetails.transactionDate?.toServiceRequestDetailsFormat ?? '-'}', + 'Item Category: ${deliveryLineModel.itemCategory ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), - if(!isViewOnly) - 'edit_icon'.toSvgAsset().onPress(() { - if(editPress!=null){ - editPress!(); - } - }), + if (!isViewOnly) + 'edit_icon'.toSvgAsset().onPress(() { + if (editPress != null) { + editPress!(); + } + }), ], ), Text( - 'Item Description: ${deliveryDetails.assetNumber ?? '-'}', + 'Item No: ${deliveryLineModel.itemNumber ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - 'Quantity: ${deliveryDetails.assetName ?? '-'}', + 'Item Description: ${deliveryLineModel.itemDescription ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - 'Remaining Quantity: ${deliveryDetails.assetName ?? '-'}', + 'Quantity: ${deliveryLineModel.qty ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), + + if(!isTechnical)...[ + Text( + 'Remaining Quantity: ${deliveryLineModel.remainingQty ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Quantity of this Delivery: ${deliveryLineModel.usingQtyInThisDelivery ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + ], + Text( - 'Quantity of this Delivery: ${deliveryDetails.assetName ?? '-'}', + 'Measure Unit: ${deliveryLineModel.unitOfMeasure ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - 'Marge Unit: ${deliveryDetails.assetName ?? '-'}', + 'Unit price: ${deliveryLineModel.unitPrice ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - 'Unit price: ${deliveryDetails.assetName ?? '-'}', + 'Line Type: ${deliveryLineModel.lineType ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - 'Total: ${deliveryDetails.assetName ?? '-'}', + 'Total: ${deliveryLineModel.total ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), ], diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart index eba6ccd8..aad1d276 100644 --- a/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart +++ b/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart @@ -1,30 +1,31 @@ -import 'dart:developer'; - 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/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/new_models/site.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_detail_page.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/change_status_bottomsheet.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart'; -import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; -import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/history_log_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; -import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; -import 'package:test_sa/views/widgets/requests/request_status.dart'; class AssetDeliveryPage extends StatefulWidget { final int? requestId; + final String? poInternal; + final String? poExternal; const AssetDeliveryPage({ Key? key, this.requestId, + this.poInternal, + this.poExternal, }) : super(key: key); @override @@ -32,11 +33,28 @@ class AssetDeliveryPage extends StatefulWidget { } class _AssetDeliveryPageState extends State { + AssetDeliveryDataModel? dataModel; + AssetDeliveryProvider? assetDeliveryProvider; + @override void initState() { + assetDeliveryProvider = Provider.of(context, listen: false); + WidgetsBinding.instance.addPostFrameCallback((_) { + getDetailsById(); + }); super.initState(); } + Future getDetailsById() async { + final futures = [ + assetDeliveryProvider!.getAssetDeliveryDetailById(requestId: widget.requestId).then((value) => dataModel = value), + assetDeliveryProvider!.getAssetDeliveryTableListById(requestId: widget.requestId), + ]; + + await Future.wait(futures); + } + + @override @override Widget build(BuildContext context) { return Scaffold( @@ -47,17 +65,72 @@ class _AssetDeliveryPageState extends State { Navigator.pop(context); }, ), - body: widget.requestId == null - ? const NoDataFound() - : ListView( - padding: const EdgeInsets.all(12), - children: [ - requestDetailCard(context), - // const SizedBox(height: 12), - const Divider().defaultStyle(context), - assetDeliveryTableList(context), - ], - ).toShadowContainer(context, borderRadius: 20, padding: 0, margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 12)), + body: Consumer( + builder: (context, provider, child) { + final dataModel = provider.assetDeliveryDataModel; + if (provider.isLoading) { + return const CircularProgressIndicator(color: AppColor.primary10).center; + } + if (dataModel == null) { + return const NoDataFound().center; + } + return ListView( + padding: const EdgeInsets.all(12), + children: [ + requestDetailCard(context), + const Divider().defaultStyle(context), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Asset Delivery Table", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + Row( + children: [ + Container( + height: 24, + width: 24, + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: AppColor.primary10, // or AppColor.blueStatus(context) + ), + alignment: Alignment.center, + child: const Icon( + Icons.add, + color: Colors.white, + size: 16, + ), + ), + 4.width, + Text( + "Add more", + style: AppTextStyles.bodyText.copyWith( + color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, + decoration: TextDecoration.underline, + ), + ), + ], + ).onPress(() async { + await assetDeliveryProvider?.addNewDelivery(requestId: widget.requestId).then((status) async { + if (status) { + await assetDeliveryProvider?.getAssetDeliveryTableListById(requestId: widget.requestId); + } + }); + }), + ], + ), + 8.height, + assetDeliveryTableList(context: context, assetDeliveryProvider: provider), + ], + ).toShadowContainer( + context, + borderRadius: 20, + padding: 0, + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + ); + }, + ), ); } @@ -67,183 +140,207 @@ class _AssetDeliveryPageState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text( + 'PO No. Internal'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + widget.poInternal ?? '-', + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Client Name'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + dataModel?.clientName ?? '-', + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), // Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // mainAxisSize: MainAxisSize.min, // children: [ - // // - // StatusLabel( - // label: sessionModel.statusName, - // id: sessionModel.statusId, - // radius: 4, - // textColor: AppColor.getRequestStatusTextColorByName(context, sessionModel.statusName), - // backgroundColor: AppColor.getRequestStatusColorByName(context, sessionModel.statusName), - // // textColor: AppColor.green15, - // // backgroundColor: AppColor.greenStatus(context), + // Checkbox( + // value: dataModel!.isHMG, + // activeColor: AppColor.neutral120, + // materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + // visualDensity: const VisualDensity(horizontal: -4, vertical: -3), + // onChanged: (value) {}, // ), + // 8.width, // Text( - // sessionModel.createdDate!.toString().toServiceRequestCardFormat, - // textAlign: TextAlign.end, - // style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), - // ) + // 'HMG'.addTranslation, + // style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + // ), // ], // ), 8.height, - //neutral120 + if (dataModel?.isHMG == true) ...[ + Text( + 'Operation Units'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + dataModel?.operatingUnit ?? '-', + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + ] else ...[ + Text( + 'Site'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + dataModel?.site?.siteName ?? '-', + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + ], + 8.height, Text( - 'PO No. Internal'.addTranslation, + 'PO No.'.addTranslation, style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), ), 8.height, + //Need to verify this with backend ... + // widget.poInternal?? '-', Text( - 'PO8745623'.addTranslation, + dataModel?.isHMG == true + ? dataModel?.poNumber != null + ? dataModel!.poNumber.toString() + : '-' + : dataModel?.poNumber != null + ? dataModel!.poNumber.toString() + : '-', style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), ), 8.height, - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Checkbox( - value: true, - activeColor: AppColor.neutral120, - materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - visualDensity: const VisualDensity(horizontal: -4, vertical: -3), - onChanged: (value) {}, - ), - 8.width, - Text( - 'HMS'.addTranslation, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), - ), - ], - ), - 8.height, Text( - 'Operation Units'.addTranslation, + 'Warranty Period'.addTranslation, style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), ), 8.height, Text( - '50'.addTranslation, + dataModel?.warrentyPeriod != null ? dataModel!.warrentyPeriod.toString() : '-', style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), ), 8.height, Text( - 'PO No.'.addTranslation, + 'Payment Term'.addTranslation, style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), ), 8.height, Text( - 'PO438'.addTranslation, + dataModel?.paymentTerm != null ? dataModel!.paymentTerm!.name.toString() : '-', style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), ), 8.height, + Text( - 'Warranty Period'.addTranslation, + 'Payment Terms Amount'.addTranslation, style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), ), 8.height, Text( - '1 Year'.addTranslation, + dataModel?.paymentTermAmount != null ? dataModel!.paymentTermAmount.toString() : '-', style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), ), 8.height, Text( - 'Payment Terms Amount'.addTranslation, + 'EDD (Estimated Delivery Date)'.addTranslation, style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), ), 8.height, Text( - '70%'.addTranslation, + dataModel?.edd != null ? dataModel!.edd!.toAssetDetailsFormat : '-', style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), ), 8.height, Text( - 'EDD (Estimated Delivery Date)'.addTranslation, + 'Total'.addTranslation, style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), ), 8.height, Text( - '25 December, 2025'.addTranslation, + dataModel?.total != null ? dataModel!.total.toString() : '-', style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), ), 8.height, Text( - 'Total'.addTranslation, + 'Total Invoice'.addTranslation, style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), ), 8.height, Text( - '4930'.addTranslation, + dataModel?.totalInvoice != null ? dataModel!.totalInvoice.toString() : '-', style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), ), ], ); } - Widget assetDeliveryTableList(BuildContext context) { - final assetDeliveryTableList = ['abc', 'def', 'ghi', 'fhg', 'hjhh']; - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Asset Delivery Table", - style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), - ), - Container( - height: 24, - width: 24, - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: AppColor.primary10, // or AppColor.blueStatus(context) - ), - alignment: Alignment.center, - child: const Icon( - Icons.add, - color: Colors.white, - size: 16, - ), - ).onPress(() { - //add entry into table. - }), - // AppFilledButton( - // label: '', - // maxWidth: true, - // textColor: AppColor.textColor(context), - // buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, - // icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), - // showIcon: true, - // onPressed: (){ - // - // }, - // ) - ], - ), - 8.height, - ListView.separated( - itemCount: assetDeliveryTableList.length, - separatorBuilder: (_, __) => 8.height, - padding: EdgeInsets.zero, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (listContext, itemIndex) { - return AssetDeliveryTableCard( - deliveryDetails: AssetInventoryModel(), - onCardTap: () { - ///TODO need to display bottomsheet to change status if new... - // if(status=='NEW') - // AssetDeliveryBottomSheet.changeStatusBottomSheet(context: context); - Navigator.of(context).push(MaterialPageRoute(builder: (_) => AssetDeliveryDetailPage(requestId: 13,))); - }, - onViewHistoryPress: () {}, - ); - }, - ), - ], - ); + Widget assetDeliveryTableList({required BuildContext context, required AssetDeliveryProvider assetDeliveryProvider}) { + List assetDeliveryTableList = assetDeliveryProvider.assetDeliveryTableList; + return assetDeliveryProvider.isDeliveryTableListLoading + ? SizedBox(height: 200.toScreenHeight, child: const CircularProgressIndicator(color: AppColor.primary10).center) + : assetDeliveryTableList.isEmpty + ? const NoDataFound().center + : ListView.separated( + itemCount: assetDeliveryTableList.length, + separatorBuilder: (_, __) => 8.height, + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (listContext, itemIndex) { + AssetDeliveryTableModel model = assetDeliveryTableList[itemIndex]; + return AssetDeliveryTableCard( + deliveryTableModel: model, + onCardTap: () { + //status new + if (model.status?.value == 1) { + AssetDeliveryBottomSheet.changeStatusBottomSheet( + context: context, + cancelStatusTap: () async { + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + await assetDeliveryProvider.changeDeliveryStatusToCancel(itemId: model.id).then((status) async { + Navigator.pop(context); + if (status) { + Navigator.pop(context); + await assetDeliveryProvider.getAssetDeliveryTableListById(requestId: widget.requestId); + } + }); + }, + statusChangeTap: () async { + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + await assetDeliveryProvider.changeDeliveryStatus(itemId: model.id).then((status) async { + Navigator.pop(context); + if (status) { + Navigator.pop(context); + await assetDeliveryProvider.getAssetDeliveryTableListById(requestId: widget.requestId); + } + }); + }); + } else { + Navigator.of(context).push(MaterialPageRoute( + builder: (_) => DeliveryInspectionFormView( + deliveryTableModel: model, + requestModel: dataModel, + ), + )); + } + }, + onViewHistoryTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AssetDeliveryHistoryLogView( + tableItemId: model.id, + ))); + }, + ); + }, + ); } } diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart index bcbf9544..0d906d49 100644 --- a/lib/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart +++ b/lib/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart @@ -1,30 +1,28 @@ - import 'package:flutter/material.dart'; +import 'package:test_sa/controllers/providers/api/device_transfer_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart'; class AssetDeliveryTableCard extends StatelessWidget { - //Need to replace with AssetTableCard. - AssetInventoryModel deliveryDetails; - VoidCallback onViewHistoryPress; + AssetDeliveryTableModel deliveryTableModel; VoidCallback onCardTap; + VoidCallback onViewHistoryTap; AssetDeliveryTableCard({ super.key, - required this.deliveryDetails, - required this.onViewHistoryPress, + required this.deliveryTableModel, required this.onCardTap, + required this.onViewHistoryTap, }); @override Widget build(BuildContext context) { - deliveryDetails.status = 'New'; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -32,35 +30,35 @@ class AssetDeliveryTableCard extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ StatusLabel( - label: deliveryDetails.status, - textColor: AppColor.getRequestStatusTextColorByName(context, deliveryDetails.status), - backgroundColor: AppColor.getRequestStatusColorByName(context, deliveryDetails.status), + label: deliveryTableModel.status?.name, + textColor: AppColor.neutral50, + backgroundColor: AppColor.orange30, ), Row( children: [ - 'history_icon'.toSvgAsset(), - 6.width, + 'history_icon'.toSvgAsset(height: 14, width: 14), + 8.width, Text( 'View History'.addTranslation, - style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + style: AppTextStyles.bodyText.copyWith(color: AppColor.primary10), ), ], ).onPress(() { - onViewHistoryPress(); + onViewHistoryTap(); }), ], ), 8.height, Text( - 'Delivery Number: ${deliveryDetails.transactionDate?.toServiceRequestDetailsFormat ?? '-'}', + 'Delivery Number: ${deliveryTableModel.number ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - 'Delivery Amount: ${deliveryDetails.assetNumber ?? '-'}', + 'Delivery Amount: ${deliveryTableModel.deliveryAmount ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - 'Invoice Amount: ${deliveryDetails.assetName ?? '-'}', + 'Invoice Amount: ${deliveryTableModel.invoiceAmount ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Align( @@ -68,7 +66,7 @@ class AssetDeliveryTableCard extends StatelessWidget { child: Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14), ), ], - ).toShadowContainer(context, borderRadius: 20).onPress((){ + ).toShadowContainer(context, borderRadius: 20).onPress(() { onCardTap(); }); } diff --git a/lib/modules/asset_delivery_module/pages/attachment_view.dart b/lib/modules/asset_delivery_module/pages/attachment_view.dart new file mode 100644 index 00000000..0c22772e --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/attachment_view.dart @@ -0,0 +1,126 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.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/generic_attachment_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; +import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; + +class AssetDeliveryAttachmentView extends StatefulWidget { + ///Need to check which parm need here. + final int? lineId; + final int? tableItemId; + final int? requestId; + final bool? isHmg; + + const AssetDeliveryAttachmentView({ + super.key, + this.lineId, + this.requestId, + this.tableItemId, + this.isHmg, + }); + + @override + State createState() => _AssetDeliveryAttachmentViewState(); +} + +class _AssetDeliveryAttachmentViewState extends State { + List _attachments = []; + bool isLoading = false; + late AssetDeliveryProvider assetDeliveryProvider; + + @override + void initState() { + super.initState(); + assetDeliveryProvider = Provider.of(context, listen: false); + WidgetsBinding.instance.addPostFrameCallback((_) { + getInitialData(); + }); + } + + void getInitialData() async { + ///get previoues Attachment from Apis. + isLoading = true; + setState(() {}); + _attachments = await assetDeliveryProvider.getAttachments(tableItemId: widget.tableItemId); + isLoading = false; + setState(() {}); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + appBar: DefaultAppBar( + title: 'Attachments'.addTranslation, + onBackPress: () { + Navigator.pop(context); + }, + ), + body: isLoading + ? const CircularProgressIndicator(color: AppColor.primary10).center + : Column( + children: [ + AttachmentPicker( + label: context.translation.attachments, + attachment: _attachments, + buttonColor: AppColor.primary10, + onlyImages: false, + // showAsGrid: true, + buttonIcon: 'quotation_icon'.toSvgAsset(color: AppColor.primary10), + onChange: (attachment) {}, + ) + .toShadowContainer( + context, + borderRadius: 20, + padding: 12, + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + ) + .expanded, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Save'.addTranslation, + maxWidth: true, + onPressed: () async { + List attachement = []; + for (var item in _attachments) { + String fileName = + CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; + attachement.add(GenericAttachmentModel(id: item.id ?? 0, name: fileName)); + } + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + Map payLoad ={ + 'assetDeliveryExternalDeliveryId': widget.tableItemId, + 'attachments':attachement, + }; + await assetDeliveryProvider.saveAttachment(payload:payLoad).then((status) async { + Navigator.pop(context); + if (status) { + ///Need to verify need to stay on this page and refresh or go back.. + Navigator.pop(context); + // assetDeliveryProvider.getDeliveryLinesListById( + // itemId: widget.tableItemId, + // ); + } + }); + }), + ), + ], + ), + ); + } +} diff --git a/lib/modules/asset_delivery_module/pages/change_status_bottomsheet.dart b/lib/modules/asset_delivery_module/pages/change_status_bottomsheet.dart index e0f1baa5..696207bf 100644 --- a/lib/modules/asset_delivery_module/pages/change_status_bottomsheet.dart +++ b/lib/modules/asset_delivery_module/pages/change_status_bottomsheet.dart @@ -1,3 +1,5 @@ + + import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; @@ -19,7 +21,7 @@ class AssetDeliveryBottomSheet { ); } - static Future changeStatusBottomSheet({required BuildContext context}) { + static Future changeStatusBottomSheet({required BuildContext context,required VoidCallback cancelStatusTap,required VoidCallback statusChangeTap}) { return buildBottomSheetParent( context: context, childWidget: Column( @@ -46,12 +48,16 @@ class AssetDeliveryBottomSheet { // textColor: context.isDark ? AppColor.neutral30 : Colors.white, textColor: AppColor.red30, showBorder: true, - onPressed: () { - Navigator.pop(context); + onPressed: () async { + cancelStatusTap(); + }, ).expanded, 12.width, - AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: () {}).expanded, + AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: () { + statusChangeTap(); + + }).expanded, ], ), ], diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart index afe55e40..4dec60db 100644 --- a/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart @@ -1,35 +1,45 @@ + +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:test_sa/common_widgets/lookup_autocomplete_field.dart'; import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/enum_extensions.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/lookup.dart'; -import 'package:test_sa/models/new_models/work_order_detail_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; -import 'package:test_sa/modules/cm_module/cm_detail_provider.dart'; -import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/cost_center_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; -import 'package:test_sa/providers/lookups/request_type_lookup_provider.dart'; -import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; -import 'package:test_sa/views/widgets/status/report/service_report_assistant_employee_menu.dart'; class CostCenterFormView extends StatefulWidget { final List? costCenterList; - final ValueChanged>? onListChanged; + final String? itemNo; + final String? itemDescription; + final int? lineId; + final int? tableItemId; + final int? requestId; + final bool? isHmg; final double? cardPadding; const CostCenterFormView({ super.key, this.costCenterList, - this.onListChanged, + this.lineId, + this.requestId, + this.tableItemId, + this.itemNo, + this.isHmg, + this.itemDescription, this.cardPadding, }); @@ -38,26 +48,47 @@ class CostCenterFormView extends StatefulWidget { } class _CostCenterFormViewState extends State { - late List _list; + List _list = []; + late AssetDeliveryProvider assetDeliveryProvider; @override void initState() { super.initState(); - _list = List.from(widget.costCenterList ?? []); + assetDeliveryProvider = Provider.of(context, listen: false); + WidgetsBinding.instance.addPostFrameCallback((_) { + getInitialData(); + }); + } + + void getInitialData() async { + _list = await assetDeliveryProvider.getAssetDeliveryCostCenterListForLines( + lineId: widget.lineId, + tableItemId: widget.tableItemId, + ); + if (_list.isEmpty) { + _list.add(CostCenterModel( + id: 0, + )); + } + if (widget.isHmg == true) { + CostCenterProvider costCenterProvider = Provider.of(context, listen: false); + if (costCenterProvider.items.isEmpty) { + await costCenterProvider.getData(id: widget.requestId); + } + } + setState(() {}); } void _addNewEntry() { setState(() { - _list.add(CostCenterModel()); + _list.add(CostCenterModel(costCenter: Lookup())); }); - widget.onListChanged?.call(_list); } void _removeEntry(int index) { setState(() { _list.removeAt(index); }); - widget.onListChanged?.call(_list); } void _updateModel(int index, void Function(CostCenterModel model) updateList) { @@ -68,8 +99,6 @@ class _CostCenterFormViewState extends State { @override Widget build(BuildContext context) { - ///Need to add check if status changes.. - final isReadOnly = Provider.of(context, listen: false).isReadOnlyRequest; return Scaffold( backgroundColor: Theme.of(context).scaffoldBackgroundColor, appBar: DefaultAppBar( @@ -78,51 +107,105 @@ class _CostCenterFormViewState extends State { Navigator.pop(context); }, ), - body: Column( - children: [ - ListView.builder( - itemCount: _list.length + 1, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - padding: EdgeInsets.all(widget.cardPadding ?? 16), - itemBuilder: (context, index) { - if (index == _list.length) { - return Visibility( - visible: !isReadOnly, - child: AppFilledButton( - label: "Add Cost Center".addTranslation, - maxWidth: true, - textColor: AppColor.textColor(context), - buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, - icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), - showIcon: true, - onPressed: _addNewEntry, - ), - ); - } - return CostCenterItemCard( - model: _list[index], - index: index, - isReadOnly: isReadOnly, - onUpdate: (updateList) => _updateModel(index, updateList), - onRemove: () => _removeEntry(index), - ); - }, - ).expanded, - 8.height, - FooterActionButton.footerContainer( - context: context, - child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: () {}), - ), - ], - ), + body: Consumer(builder: (context, provider, child) { + return Column( + children: [ + itemDetails(context: context, itemNo: widget.itemNo, itemDescription: widget.itemDescription), + provider.isLoading + ? const CircularProgressIndicator(color: AppColor.primary10).center + : ListView.builder( + itemCount: _list.length + 1, + shrinkWrap: true, + padding: EdgeInsets.all(widget.cardPadding ?? 16), + itemBuilder: (context, index) { + if (index == _list.length) { + return Visibility( + child: AppFilledButton( + label: "Add Cost Center".addTranslation, + maxWidth: true, + textColor: AppColor.textColor(context), + buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, + icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), + showIcon: true, + onPressed: _addNewEntry, + ), + ); + } + return CostCenterItemCard( + model: _list[index], + index: index, + isReadOnly: false, + isHmg: widget.isHmg, + requestId: widget.requestId, + onUpdate: (updateList) => _updateModel(index, updateList), + onRemove: () => _removeEntry(index), + ); + }, + ).expanded, + 8.height, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Save'.addTranslation, + maxWidth: true, + onPressed: () async { + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + await assetDeliveryProvider.saveCostCenterToLineDeliveryInspection(tableItemId: widget.tableItemId, lineId: widget.lineId, list: _list).then((status) async { + Navigator.pop(context); + if (status) { + Navigator.pop(context); + assetDeliveryProvider.getDeliveryLinesListById( + itemId: widget.tableItemId, + ); + } + }); + }), + ), + ], + ); + }), ); } } +Widget itemDetails({required BuildContext context, String? itemNo, String? itemDescription}) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Item No'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + itemNo ?? '-', + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Item Description'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + itemDescription ?? '-', + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + ], + ).toShadowContainer( + context, + borderRadius: 20, + padding: 12, + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + ); +} + class CostCenterItemCard extends StatelessWidget { final CostCenterModel model; + final bool? isHmg; final int index; + final int? requestId; final bool isReadOnly; final void Function(void Function(CostCenterModel model)) onUpdate; final VoidCallback onRemove; @@ -130,6 +213,8 @@ class CostCenterItemCard extends StatelessWidget { const CostCenterItemCard({ super.key, required this.model, + this.requestId, + this.isHmg, required this.index, required this.isReadOnly, required this.onUpdate, @@ -138,8 +223,6 @@ class CostCenterItemCard extends StatelessWidget { @override Widget build(BuildContext context) { - final requestedDate = Provider.of(context, listen: false).currentWorkOrder?.data?.requestedDate; - return Column( children: [ if (!isReadOnly) @@ -160,50 +243,52 @@ class CostCenterItemCard extends StatelessWidget { Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - ///TODO replace with exact data or type like searchable dropdown... - AppTextFormField( - labelText: 'Item No'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), - initialValue: '232434', - textAlign: TextAlign.center, - labelStyle: AppTextStyles.textFieldLabelStyle, - showShadow: false, - enable: false, - style: Theme.of(context).textTheme.titleMedium, - ), + isHmg == true + ? SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Cost Center'.addTranslation, + showShadow: false, + backgroundColor: AppColor.fieldBgColor(context), + requestById: requestId, + showAsBottomSheet: true, + matchBy: DropDownMatchType.name, + initialValue: model.costCenter, + onSelect: (status) { + if (status != null) { + model.costCenter = status; + model.costCenterName = status.name; + } + }, + ) + : AppTextFormField( + labelText: 'Cost Center'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.costCenterName ?? '', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + onChange: (value) { + model.costCenterName = value; + }, + style: Theme.of(context).textTheme.titleMedium, + ), 8.height, AppTextFormField( - labelText: 'Item Description', + labelText: 'Quantity'.addTranslation, backgroundColor: AppColor.fieldBgColor(context), - initialValue: 'test decription abc', + initialValue: model.quantity != null ? model.quantity.toString() : '', textAlign: TextAlign.center, + enable: true, + textInputType: TextInputType.number, labelStyle: AppTextStyles.textFieldLabelStyle, showShadow: false, - enable: false, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - LookUpAutoCompleteField( - clearAfterPick: false, - forAssetName: true, - onChanged: (value) {}, - initialValue: model.costCenter?.name ?? '', - label: 'Cost Center'.addTranslation, - onPick: (value) { - model.costCenter = value; - }, - ), - 8.height, - SingleItemDropDownMenu( - context: context, - showAsBottomSheet: true, - backgroundColor: AppColor.neutral100, - showShadow: false, - title: 'Quantity'.addTranslation, - initialValue: model.costCenter, - onSelect: (value) { - model.costCenter = value; + onChange: (value) { + if (value.isNotEmpty) { + model.quantity = double.tryParse(value); + } }, + style: Theme.of(context).textTheme.titleMedium, ), ], ) diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart index cc1310b0..40a4f61c 100644 --- a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart @@ -1,45 +1,40 @@ -import 'dart:convert'; import 'dart:developer'; -import 'dart:io'; + import 'package:flutter/material.dart'; -import 'package:flutter_advanced_switch/flutter_advanced_switch.dart'; import 'package:provider/provider.dart'; -import 'package:test_sa/common_widgets/lookup_autocomplete_field.dart'; -import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/generic_attachment_model.dart'; -import 'package:test_sa/models/lookup.dart'; -import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/delivery_inspection_form_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart'; -import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; -import 'package:test_sa/modules/asset_inventory_module/pages/search_asset_view.dart'; -import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; -import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; -import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; -import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; -import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; -import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; -import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; -import 'package:test_sa/views/widgets/requests/request_status.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import '../../../../new_views/common_widgets/app_filled_button.dart'; -import '../../../../new_views/common_widgets/default_app_bar.dart'; class DeliveryInspectionFormView extends StatefulWidget { static const String id = "/delivery-inspection-form"; + final AssetDeliveryTableModel deliveryTableModel; + final AssetDeliveryDataModel? requestModel; DeliveryInspectionFormView({ Key? key, + required this.deliveryTableModel, + this.requestModel, }) : super(key: key); @override @@ -48,14 +43,39 @@ class DeliveryInspectionFormView extends StatefulWidget { class _DeliveryInspectionFormViewState extends State { final GlobalKey _formKey = GlobalKey(); - final GlobalKey _scaffoldKey = GlobalKey(); - bool viewOnly = true; + bool viewOnly = false; + AssetDeliveryProvider? assetDeliveryProvider; + DeliveryInspectionFormModel model = DeliveryInspectionFormModel(); + bool isLoading = false; @override void initState() { + viewOnly = widget.deliveryTableModel.status?.value != 2; + WidgetsBinding.instance.addPostFrameCallback((_) { + getInitialData(); + }); super.initState(); } + void getInitialData() async { + assetDeliveryProvider = Provider.of(context, listen: false); + setState(() { + isLoading = true; + }); + final results = await Future.wait([ + assetDeliveryProvider!.getAssetDeliveryInspectionData( + itemId: widget.deliveryTableModel.id, + ), + assetDeliveryProvider!.getDeliveryLinesListById( + itemId: widget.deliveryTableModel.id, + ), + ]); + model = results[0] as DeliveryInspectionFormModel; + setState(() { + isLoading = false; + }); + } + @override void dispose() { super.dispose(); @@ -63,162 +83,189 @@ class _DeliveryInspectionFormViewState extends State @override Widget build(BuildContext context) { - return Form( - key: _formKey, - child: Column( - children: [ - SingleChildScrollView( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (!viewOnly) ...[inspectionDetailsForm()] else ...[inspectionDetails()], - 8.height, - const Divider().defaultStyle(context), - linesList(context), - ], - ).toShadowContainer(context, borderRadius: 20, padding: 12)) - .expanded, - if (!viewOnly) ...[ - 8.height, - FooterActionButton.footerContainer( - context: context, - child: AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap), - ), - 8.height, - ], - FooterActionButton.footerContainer( - context: context, - child: !viewOnly - ? Row( - children: [ - AppFilledButton( - label: 'Cancel'.addTranslation, - maxWidth: true, - buttonColor: AppColor.background(context), - // textColor: context.isDark ? AppColor.neutral30 : Colors.white, - textColor: AppColor.red30, - showBorder: true, - onPressed: _cancelTap, - ).expanded, - 12.width, - AppFilledButton(buttonColor: AppColor.black10, label: 'View History'.addTranslation, maxWidth: true, onPressed: _viewHistoryTap).expanded, - ], - ) - : Row( - children: [ - AppFilledButton(buttonColor: AppColor.black10, label: 'View History'.addTranslation, maxWidth: true, onPressed: _viewHistoryTap).expanded, - 12.width, - AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap).expanded, - ], - ), - ), - ], + return Scaffold( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + appBar: DefaultAppBar( + title: 'Delivery Inspection'.addTranslation, + onBackPress: () { + Navigator.pop(context); + }, ), + body: isLoading + ? const CircularProgressIndicator(color: AppColor.primary10).center + : Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (!viewOnly) ...[inspectionDetailsForm()] else ...[inspectionDetails()], + 8.height, + Text( + 'Total Time'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + model.totalTime != null ? '${model.totalTime.toString()} hours' : '-', + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + const Divider().defaultStyle(context), + Text( + "Lines", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + linesList(context), + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12)) + .expanded, + if (!viewOnly) ...[ + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap), + ), + 8.height, + ], + FooterActionButton.footerContainer( + context: context, + child: !viewOnly + ? Row( + children: [ + AppFilledButton( + label: 'Cancel'.addTranslation, + maxWidth: true, + buttonColor: AppColor.background(context), + // textColor: context.isDark ? AppColor.neutral30 : Colors.white, + textColor: AppColor.red30, + showBorder: true, + onPressed: _cancelTap, + ).expanded, + 12.width, + AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded, + ], + ) + : AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap), + ), + ], + ), + ), ); } Widget linesList(BuildContext context) { - final assetDeliveryTableList = ['abc', 'def', 'ghi', 'fhg', 'hjhh']; - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Lines", - style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), - ), - 8.height, - ListView.separated( - itemCount: assetDeliveryTableList.length, - separatorBuilder: (_, __) => 8.height, - padding: EdgeInsets.zero, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (listContext, itemIndex) { - return AssetDeliveryLineCard( - deliveryDetails: AssetInventoryModel(), - isViewOnly: viewOnly, - editPress: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => CostCenterFormView( - costCenterList: [CostCenterModel()], - onListChanged: (updatedList) { - // requestDetailProvider.activityMaintenanceHelperModel?.assistantEmployList = updatedList; - }, - ))); - }, - ); - }, - ), - ], - ); + return Consumer(builder: (context, provider, child) { + List linesList = provider.deliveryLinesList; + return provider.isDeliveryLineListLoading + ? SizedBox(height: 200.toScreenHeight, child: const CircularProgressIndicator(color: AppColor.primary10).center) + : linesList.isEmpty + ? const NoDataFound().center + : ListView.separated( + itemCount: linesList.length, + separatorBuilder: (_, __) => 8.height, + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (listContext, itemIndex) { + DeliveryLineModel model = linesList[itemIndex]; + return AssetDeliveryLineCard( + deliveryLineModel: model, + isViewOnly: viewOnly, + editPress: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CostCenterFormView( + itemNo: model.itemNumber, + lineId: model.id, + isHmg: widget.requestModel?.isHMG, + tableItemId: widget.deliveryTableModel.id, + requestId: widget.requestModel?.id, + itemDescription: model.itemDescription, + ))); + }, + ); + }, + ); + }); + } + + void calculateTotalTime() { + if (model.deliveryInspectionInspectedDateFrom == null || model.deliveryInspectionInspectedDateTo == null) { + model.totalTime = null; + return; + } + final fromDate = model.deliveryInspectionInspectedDateFrom!; + final toDate = model.deliveryInspectionInspectedDateTo!; + final hours = toDate.difference(fromDate).inSeconds / 3600.0; + model.totalTime = num.parse(hours.toStringAsFixed(3)); } Widget inspectionDetailsForm() { return Column( children: [ - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: 'Inspected by'.addTranslation, - titleTextColor: AppColor.neutral120, - showShadow: false, - // backgroundColor: AppColor.neutral100, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, - onSelect: (status) { - if (status != null) { - // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; + if (widget.requestModel?.isHMG == true) ...[ + OracleUserAutoCompleteField( + clearAfterPick: false, + initialValue: model.deliveryInspectionInspectedBy ?? '', + label: 'Inspected by'.addTranslation, + onPick: (value) { + model.deliveryInspectionInspectedBy = value.fullName; setState(() {}); - } - }, - ), - // LookUpAutoCompleteField( - // clearAfterPick: false, - // forAssetName: true, - // onChanged: (value) { - // _scannedAssetModel?.newAssetNameId = null; - // _scannedAssetModel?.newAssetNameText = value; - // }, - // initialValue: _scannedAssetModel?.assetName ?? "", - // label: 'Asset Name'.addTranslation, - // onPick: (value) { - // _scannedAssetModel?.newAssetNameText = null; - // _scannedAssetModel?.assetName = value.name; - // _scannedAssetModel?.newAssetNameId = value.id; - // setState(() {}); - // }, - // ), - 8.height, - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: 'Approved by'.addTranslation, - showShadow: false, - titleTextColor: AppColor.neutral120, - // backgroundColor: AppColor.neutral100, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, - onSelect: (status) { - if (status != null) { - // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; + }, + onChanged: (value) {}, + ), + 8.height, + OracleUserAutoCompleteField( + clearAfterPick: false, + initialValue: model.deliveryInspectionApprovedBy ?? '', + label: 'Approved by'.addTranslation, + onChanged: (value) {}, + onPick: (value) { + model.deliveryInspectionApprovedBy = value.fullName; setState(() {}); - } - }, - ), + }, + ), + ] //No HMG user free text insted of dropdown ... + else ...[ + AppTextFormField( + labelText: 'Inspected by'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.deliveryInspectionInspectedBy ?? '', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + onChange: (value) { + model.deliveryInspectionInspectedBy = value; + }, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Approved by'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.deliveryInspectionApprovedBy ?? '', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + onChange: (value) { + model.deliveryInspectionApprovedBy = value; + }, + style: Theme.of(context).textTheme.titleMedium, + ), + ], 8.height, ADatePicker( label: 'Inspected Date/Time From'.addTranslation, hideShadow: true, height: 56.toScreenHeight, backgroundColor: AppColor.fieldBgColor(context), - // date: _pickerStartAt, - // from: widget.pickerFromDate, + date: model.deliveryInspectionInspectedDateFrom, + from: DateTime(DateTime.now().year, 1, 1), formatDateWithTime: true, onDatePicker: (selectedDate) { showTimePicker( @@ -244,19 +291,23 @@ class _DeliveryInspectionFormViewState extends State }, ).then((selectedTime) { if (selectedTime != null) { - // _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); + model.deliveryInspectionInspectedDateFrom = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); + // calculateTotalTime(); + + ///need to check if need validation or not. // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { // "Start time is before the request time.".showToast; // _pickerStartAt = null; // selectedTime = null; // return; // } - // if (_pickerStartAt!.isAfter(DateTime.now())) { - // "Start time is after than current time".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } + if (model.deliveryInspectionInspectedDateFrom!.isAfter(DateTime.now())) { + "Start time is after than current time".showToast; + model.deliveryInspectionInspectedDateFrom = null; + selectedTime = null; + return; + } + setState(() {}); } }); @@ -268,8 +319,8 @@ class _DeliveryInspectionFormViewState extends State hideShadow: true, height: 56.toScreenHeight, backgroundColor: AppColor.fieldBgColor(context), - // date: _pickerStartAt, - // from: widget.pickerFromDate, + date: model.deliveryInspectionInspectedDateTo, + from: model.deliveryInspectionInspectedDateFrom, formatDateWithTime: true, onDatePicker: (selectedDate) { showTimePicker( @@ -295,19 +346,22 @@ class _DeliveryInspectionFormViewState extends State }, ).then((selectedTime) { if (selectedTime != null) { - // _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); + model.deliveryInspectionInspectedDateTo = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); + calculateTotalTime(); + + ///Need to check need validation or not.. // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { // "Start time is before the request time.".showToast; // _pickerStartAt = null; // selectedTime = null; // return; // } - // if (_pickerStartAt!.isAfter(DateTime.now())) { - // "Start time is after than current time".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } + if (model.deliveryInspectionInspectedDateTo!.isAfter(DateTime.now())) { + "End time is after than current time".showToast; + model.deliveryInspectionInspectedDateTo = null; + selectedTime = null; + return; + } setState(() {}); } }); @@ -327,7 +381,7 @@ class _DeliveryInspectionFormViewState extends State ), 8.height, Text( - 'Mahmoud Shrouf'.addTranslation, + model.deliveryInspectionInspectedBy ?? '-', style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), ), 8.height, @@ -337,7 +391,7 @@ class _DeliveryInspectionFormViewState extends State ), 8.height, Text( - 'Mahmoud Shrouf'.addTranslation, + model.deliveryInspectionApprovedBy ?? '-', style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), ), 8.height, @@ -347,7 +401,7 @@ class _DeliveryInspectionFormViewState extends State ), 8.height, Text( - '19 August, 2025'.addTranslation, + model.deliveryInspectionInspectedDateFrom != null ? model.deliveryInspectionInspectedDateFrom!.toString().toServiceRequestDetailsFormat : '-', style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), ), 8.height, @@ -357,22 +411,63 @@ class _DeliveryInspectionFormViewState extends State ), 8.height, Text( - '19 August, 2025'.addTranslation, + model.deliveryInspectionInspectedDateTo != null ? model.deliveryInspectionInspectedDateTo!.toString().toServiceRequestDetailsFormat : '-', style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), ), ], ); } - void _viewHistoryTap() async {} + void _attachmentTap() async { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AssetDeliveryAttachmentView( + tableItemId: widget.deliveryTableModel.id, + ))); + } - void _cancelTap() async {} + void _cancelTap() async { + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + await assetDeliveryProvider!.changeDeliveryStatusToCancel(itemId: widget.deliveryTableModel.id).then((status) async { + Navigator.pop(context); + if (status) { + Navigator.pop(context); + await assetDeliveryProvider!.getAssetDeliveryTableListById(requestId: widget.requestModel?.id); + } + }); + } void _nextTap() { - Navigator.push(context, MaterialPageRoute(builder: (context) => TechnicalInspectionLinesListView())); + if (widget.deliveryTableModel.isContainsTechnicalInspection == true) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => TechnicalInspectionLinesListView( + deliveryTableModel: widget.deliveryTableModel, + requestModel: widget.requestModel, + ))); + } else { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => EndUserCostCenterLIstView( + deliveryTableModel: widget.deliveryTableModel, + requestModel: widget.requestModel, + ))); + } } void _changeStatusTap() async { _formKey.currentState!.save(); + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + model.assetDeliveryExternalDeliveryId = widget.deliveryTableModel.id; + await assetDeliveryProvider!.changeDeliveryStatus(requestPayload: model.toJson()).then((status) async { + Navigator.pop(context); + if (status) { + Navigator.pop(context); + await assetDeliveryProvider!.getAssetDeliveryTableListById(requestId: widget.requestModel?.id); + } + }); } } diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.dart new file mode 100644 index 00000000..5411081a --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.dart @@ -0,0 +1,114 @@ +import 'dart:developer'; + +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/modules/asset_delivery_module/models/oracle_user_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/app_style/app_text_style.dart'; +import 'package:test_sa/views/app_style/sizing.dart'; + +class OracleUserAutoCompleteField extends StatefulWidget { + final String initialValue; + final String label; + final bool clearAfterPick; + final Function(OracleUserModel) onPick; + final Function(String)? onChanged; + + const OracleUserAutoCompleteField({Key? key, required this.initialValue, required this.label, required this.onPick, this.clearAfterPick = true, this.onChanged}) : super(key: key); + + @override + _AutoCompletePartsFieldState createState() => _AutoCompletePartsFieldState(); +} + +class _AutoCompletePartsFieldState extends State { + AssetDeliveryProvider? assetDeliveryProvider; + late TextEditingController _controller; + + @override + void initState() { + _controller = TextEditingController(text: widget.initialValue); + super.initState(); + } + + @override + void didUpdateWidget(covariant OracleUserAutoCompleteField oldWidget) { + if (widget.initialValue != oldWidget.initialValue) { + _controller = TextEditingController(text: widget.initialValue); + } + super.didUpdateWidget(oldWidget); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + assetDeliveryProvider ??= Provider.of(context); + final border = UnderlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(10)); + return Container( + decoration: BoxDecoration( + color: AppColor.background(context), + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], + ), + child: Autocomplete( + optionsBuilder: (TextEditingValue textEditingValue) async { + if (textEditingValue.text.isEmpty) { + return const Iterable.empty(); + } + return await assetDeliveryProvider!.getOracleUserAutoCompleteDetails(query: textEditingValue.text); + }, + displayStringForOption: (OracleUserModel option) => option.fullName ?? "", + fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) { + return TextField( + controller: _controller, + focusNode: fieldFocusNode, + style: AppTextStyles.bodyText.copyWith(color: AppColor.black10), + textAlign: TextAlign.start, + decoration: InputDecoration( + border: border, + disabledBorder: border, + focusedBorder: border, + enabledBorder: border, + errorBorder: border, + contentPadding: EdgeInsets.symmetric(vertical: 8.toScreenHeight, horizontal: 16.toScreenWidth), + constraints: const BoxConstraints(), + suffixIconConstraints: const BoxConstraints(minWidth: 0), + filled: true, + fillColor: AppColor.fieldBgColor(context), + errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60), + floatingLabelStyle: AppTextStyle.body1.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? null : AppColor.neutral20), + labelText: widget.label, + labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)), + ), + textInputAction: TextInputAction.search, + onChanged: (text) { + if (widget.onChanged != null) { + widget.onChanged!(text); + fieldTextEditingController.text = text; + } + }, + onSubmitted: (String value) { + onFieldSubmitted(); + }, + ); + }, + onSelected: (OracleUserModel selection) { + if (widget.clearAfterPick) { + _controller.clear(); + } else { + _controller.text = selection.fullName ?? ''; + } + widget.onPick(selection); + }, + ), + ); + } +} diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/cost_center_card_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/cost_center_card_view.dart index d53d3754..59237ffd 100644 --- a/lib/modules/asset_delivery_module/pages/end_user_acceptance/cost_center_card_view.dart +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/cost_center_card_view.dart @@ -1,23 +1,26 @@ +import 'dart:developer'; + import 'package:flutter/material.dart'; +import 'package:test_sa/common_widgets/lookup_autocomplete_field.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/modules/asset_delivery_module/models/cost_center_model.dart'; import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; -class CostCenterCard extends StatelessWidget { - ///Need to replace with cost model. - AssetInventoryModel deliveryDetails; - ///if include in model skip this +class EndUserCostCenterCardView extends StatelessWidget { + CostCenterModel costModel; + VoidCallback? editPress; bool isViewOnly; - VoidCallback ?editPress; - CostCenterCard({ + EndUserCostCenterCardView({ super.key, - required this.isViewOnly, - required this.deliveryDetails, + required this.costModel, this.editPress, + required this.isViewOnly, }); @override @@ -29,32 +32,30 @@ class CostCenterCard extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - 'Item No: ${deliveryDetails.transactionDate?.toServiceRequestDetailsFormat ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + Flexible( + child: Text( + 'Cost Center Name: ${costModel.costCenterName ?? '-'}', + overflow: TextOverflow.ellipsis, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), ), - if(!isViewOnly) - 'edit_icon'.toSvgAsset().onPress(() { - if(editPress!=null){ - editPress!(); - } - }), + 8.width, + if (!isViewOnly) + 'edit_icon'.toSvgAsset(height: 18, width: 18).onPress(() { + if (editPress != null) { + editPress!(); + } + }), ], ), Text( - 'Asset Number: ${deliveryDetails.assetNumber ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - 'Asset Type: ${deliveryDetails.assetName ?? '-'}', + 'Accepted By: ${costModel.acceptedBy ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - 'Replaced Asset No: ${deliveryDetails.assetName ?? '-'}', + ),Text( + 'Accepted By Email: ${costModel.acceptedByEmail ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - 'Serial Number: ${deliveryDetails.assetName ?? '-'}', + ),Text( + 'Acceptance Date: ${costModel.acceptanceDate!=null? costModel.acceptanceDate.toString().toAssetDetailsFormat: '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), ], diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_acceptance_form_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_acceptance_form_view.dart deleted file mode 100644 index 978a1d93..00000000 --- a/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_acceptance_form_view.dart +++ /dev/null @@ -1,171 +0,0 @@ -import 'dart:convert'; -import 'dart:developer'; -import 'dart:io'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_advanced_switch/flutter_advanced_switch.dart'; -import 'package:provider/provider.dart'; -import 'package:test_sa/common_widgets/lookup_autocomplete_field.dart'; -import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; -import 'package:test_sa/extensions/context_extension.dart'; -import 'package:test_sa/extensions/int_extensions.dart'; -import 'package:test_sa/extensions/string_extensions.dart'; -import 'package:test_sa/extensions/text_extensions.dart'; -import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/device/asset.dart'; -import 'package:test_sa/models/generic_attachment_model.dart'; -import 'package:test_sa/models/lookup.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart'; -import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; -import 'package:test_sa/modules/asset_inventory_module/pages/search_asset_view.dart'; -import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; -import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; -import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; -import 'package:test_sa/new_views/app_style/app_color.dart'; -import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; -import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; -import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; -import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; -import 'package:test_sa/providers/service_request_providers/reject_reason_provider.dart'; -import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; -import 'package:test_sa/views/widgets/e_signature/e_signature.dart'; -import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; -import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; -import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; -import 'package:test_sa/views/widgets/requests/request_status.dart'; -import '../../../../new_views/common_widgets/app_filled_button.dart'; -import '../../../../new_views/common_widgets/default_app_bar.dart'; - -class EndUserAcceptanceFormView extends StatefulWidget { - EndUserAcceptanceFormView({ - Key? key, - }) : super(key: key); - - @override - State createState() => _EndUserAcceptanceFormViewState(); -} - -class _EndUserAcceptanceFormViewState extends State { - final GlobalKey _formKey = GlobalKey(); - final GlobalKey _scaffoldKey = GlobalKey(); - bool viewOnly = false; - Uint8List? newSignature; - String? endUserSignature; - - @override - void initState() { - super.initState(); - } - - @override - void dispose() { - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - key: _scaffoldKey, - appBar: DefaultAppBar( - title: 'Item Details'.addTranslation, - titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), - ), - body: Form( - key: _formKey, - child: Column( - children: [ - SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: 'Status'.addTranslation, - titleTextColor: AppColor.neutral120, - showShadow: false, - // backgroundColor: AppColor.neutral100, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, - onSelect: (status) { - if (status != null) { - // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; - setState(() {}); - } - }, - ), - 8.height, - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: 'Rejection Reason '.addTranslation, - titleTextColor: AppColor.neutral120, - showShadow: false, - // backgroundColor: AppColor.neutral100, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, - onSelect: (status) { - if (status != null) { - // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; - setState(() {}); - } - }, - ), - 8.height, - AppTextFormField( - initialValue: '', - labelText: 'Description'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), - showShadow: false, - labelStyle: AppTextStyles.textFieldLabelStyle, - alignLabelWithHint: true, - textInputType: TextInputType.multiline, - onChange: (value) {}, - onSaved: (value) {}, - ), - 8.height, - ESignature( - title: 'End User Signature', - oldSignature: '', - newSignature: newSignature, - backgroundColor: AppColor.neutral100, - showShadow: false, - onChange: (signature) { - if (signature.isEmpty) return; - setState(() { - newSignature = signature; - endUserSignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; - }); - }, - onSaved: (signature) { - if (signature == null || signature.isEmpty) return; - setState(() { - newSignature = signature; - endUserSignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; - }); - }, - ), - ], - ).toShadowContainer(context, borderRadius: 20, padding: 12)) - .expanded, - FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), - ], - ), - ), - ); - } - - ///Need to check which details show here... - - void _saveTap() async { - AssetInventoryProvider assetInventoryProvider = Provider.of(context, listen: false); - _formKey.currentState!.save(); - } -} diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_asset_detail_card.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_asset_detail_card.dart new file mode 100644 index 00000000..838ba850 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_asset_detail_card.dart @@ -0,0 +1,116 @@ +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/modules/asset_delivery_module/models/end_user_asset_details_model.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class EndUserAssetDetailCard extends StatelessWidget { + EndUserAssetDetailsModel assetModel; + bool isViewOnly; + VoidCallback? editPress; + + EndUserAssetDetailCard({ + super.key, + required this.isViewOnly, + required this.assetModel, + this.editPress, + }); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + assetModel.status != null + ? StatusLabel( + label: assetModel.status?.name, + radius: 4, + textColor: getAssetStatusColor(context: context, status: assetModel.status?.name ?? '', isBackground: false), + backgroundColor: getAssetStatusColor(context: context, status: assetModel.status?.name ?? ''), + ) + : const SizedBox(), + if (!isViewOnly) + 'edit_icon'.toSvgAsset().onPress(() { + if (editPress != null) { + editPress!(); + } + }), + ], + ), + 8.height, + if (assetModel.type == 'Accessory') ...[ + Text( + 'Type: ${assetModel.type ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Item Number: ${assetModel.itemNumber ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Received Quantity: ${assetModel.receivedQty ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Rejection Reason: ${assetModel.rejectionReason?.name ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Rejected Quantity: ${assetModel.rejectedQty ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Description: ${assetModel.description ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + ] else ...[ + Text( + 'Type: ${assetModel.type ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Item Number: ${assetModel.itemNumber ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Asset Number: ${assetModel.assetNumber ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Serial No: ${assetModel.serialNo ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Replaced Asset No: ${assetModel.replacedAssetNo ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Rejection Reason: ${assetModel.rejectionReason?.name ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Description: ${assetModel.description ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + ], + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12); + } + + Color getAssetStatusColor({required BuildContext context, required String status, bool? isBackground = true}) { + switch (status) { + case 'Accept': + return isBackground! ? AppColor.green70.withOpacity(0.4) : AppColor.green15; + case 'Reject': + return isBackground! ? AppColor.red30.withOpacity(0.4) : AppColor.red30; + default: + return Colors.blueGrey; + } + } +} diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart index 4af7aa9f..3711f237 100644 --- a/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart @@ -1,26 +1,30 @@ - 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/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/cost_center_card_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart'; -import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; -import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; -import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; -import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import '../../../../new_views/common_widgets/app_filled_button.dart'; import '../../../../new_views/common_widgets/default_app_bar.dart'; class EndUserCostCenterLIstView extends StatefulWidget { + final AssetDeliveryTableModel deliveryTableModel; + final AssetDeliveryDataModel? requestModel; + EndUserCostCenterLIstView({ Key? key, + required this.deliveryTableModel, + this.requestModel, }) : super(key: key); @override @@ -31,12 +35,33 @@ class _EndUserCostCenterLIstViewState extends State { final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); bool viewOnly = false; + List costCenterList = []; + AssetDeliveryProvider? assetDeliveryProvider; + bool isLoading = false; @override void initState() { + WidgetsBinding.instance.addPostFrameCallback((_) { + getInitialData(); + }); super.initState(); } + void getInitialData() async { + assetDeliveryProvider = Provider.of(context, listen: false); + isLoading = true; + if (widget.deliveryTableModel.status?.value != null && widget.deliveryTableModel.status!.value! > 4) { + viewOnly = true; + } + setState(() {}); + costCenterList = (await assetDeliveryProvider?.getEndUserCostCenterList( + tableItemId: widget.deliveryTableModel.id, + )) ?? + []; + isLoading = false; + setState(() {}); + } + @override void dispose() { super.dispose(); @@ -52,59 +77,45 @@ class _EndUserCostCenterLIstViewState extends State { ), body: Form( key: _formKey, - child: Column( - children: [ - SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - linesList(context), - ], - ).toShadowContainer(context, borderRadius: 20, padding: 12)) - .expanded, - if (!viewOnly) ...[ - 8.height, - FooterActionButton.footerContainer( - context: context, - child: AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap), - ), - 8.height, - ], - FooterActionButton.footerContainer( - context: context, - child: !viewOnly - ? Row( - children: [ - AppFilledButton( - label: 'Cancel'.addTranslation, - maxWidth: true, - buttonColor: AppColor.background(context), - // textColor: context.isDark ? AppColor.neutral30 : Colors.white, - textColor: AppColor.red30, - showBorder: true, - onPressed: _cancelTap, - ).expanded, - 12.width, - AppFilledButton(buttonColor: AppColor.black10, label: 'View History'.addTranslation, maxWidth: true, onPressed: _viewHistoryTap).expanded, - ], - ) - : Row( - children: [ - AppFilledButton(buttonColor: AppColor.black10, label: 'View History'.addTranslation, maxWidth: true, onPressed: _viewHistoryTap).expanded, - 12.width, - AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap).expanded, - ], + child: isLoading + ? const CircularProgressIndicator(color: AppColor.primary10).center + : Column( + children: [ + //Refactor this + SingleChildScrollView(padding: const EdgeInsets.all(16), child: linesList(context).toShadowContainer(context, borderRadius: 20, padding: 12)).expanded, + if (!viewOnly) ...[ + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap), ), - ), - ], - ), + 8.height, + ], + !viewOnly + ? FooterActionButton.footerContainer( + context: context, + child: Row( + children: [ + AppFilledButton( + label: 'Cancel'.addTranslation, + maxWidth: true, + buttonColor: AppColor.background(context), + textColor: AppColor.red30, + showBorder: true, + onPressed: _cancelTap, + ).expanded, + 12.width, + AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded, + ], + )) + : const SizedBox(), + ], + ), ), ); } + //Need to refector don't use listview and singlechildview both @waseem. Widget linesList(BuildContext context) { - final assetDeliveryTableList = ['abc', 'def', 'ghi', 'fhg', 'hjhh']; return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -115,17 +126,27 @@ class _EndUserCostCenterLIstViewState extends State { ), 8.height, ListView.separated( - itemCount: assetDeliveryTableList.length, + itemCount: costCenterList.length, separatorBuilder: (_, __) => 8.height, padding: EdgeInsets.zero, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (listContext, itemIndex) { - return CostCenterCard( - deliveryDetails : AssetInventoryModel(), + return EndUserCostCenterCardView( + costModel: costCenterList[itemIndex], isViewOnly: viewOnly, - editPress: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => UpdateEndUserCostCenterView())); + editPress: () async { + bool isRefresh = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => UpdateEndUserCostCenterDetailsView( + costCenterModel: costCenterList[itemIndex], + tableItemId: widget.deliveryTableModel.id, + isHmg: widget.requestModel?.isHMG, + ))); + if (isRefresh) { + getInitialData(); + } }, ); }, @@ -134,210 +155,38 @@ class _EndUserCostCenterLIstViewState extends State { ); } - Widget inspectionDetailsForm() { - return Column( - children: [ - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: 'Inspected by'.addTranslation, - titleTextColor: AppColor.neutral120, - showShadow: false, - // backgroundColor: AppColor.neutral100, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, - onSelect: (status) { - if (status != null) { - // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; - setState(() {}); - } - }, - ), - 8.height, - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: 'Approved by'.addTranslation, - showShadow: false, - titleTextColor: AppColor.neutral120, - // backgroundColor: AppColor.neutral100, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, - onSelect: (status) { - if (status != null) { - // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; - setState(() {}); - } - }, - ), - 8.height, - ADatePicker( - label: 'Inspected Date/Time From'.addTranslation, - hideShadow: true, - height: 56.toScreenHeight, - backgroundColor: AppColor.fieldBgColor(context), - // date: _pickerStartAt, - // from: widget.pickerFromDate, - formatDateWithTime: true, - onDatePicker: (selectedDate) { - showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - builder: (BuildContext context, Widget? child) { - final ThemeData currentTheme = Theme.of(context); - return Theme( - data: currentTheme.copyWith( - timePickerTheme: TimePickerThemeData( - dialHandColor: AppColor.primary10, - dialBackgroundColor: Colors.grey.withOpacity(0.1), - hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), - dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), - dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), - dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), - entryModeIconColor: AppColor.primary10, - ), - textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), - ), - child: child!, - ); - }, - ).then((selectedTime) { - if (selectedTime != null) { - // _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); - // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { - // "Start time is before the request time.".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } - // if (_pickerStartAt!.isAfter(DateTime.now())) { - // "Start time is after than current time".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } - setState(() {}); - } - }); - }, - ), - 8.height, - ADatePicker( - label: 'Inspected Date/Time To'.addTranslation, - hideShadow: true, - height: 56.toScreenHeight, - backgroundColor: AppColor.fieldBgColor(context), - // date: _pickerStartAt, - // from: widget.pickerFromDate, - formatDateWithTime: true, - onDatePicker: (selectedDate) { - showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - builder: (BuildContext context, Widget? child) { - final ThemeData currentTheme = Theme.of(context); - return Theme( - data: currentTheme.copyWith( - timePickerTheme: TimePickerThemeData( - dialHandColor: AppColor.primary10, - dialBackgroundColor: Colors.grey.withOpacity(0.1), - hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), - dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), - dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), - dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), - entryModeIconColor: AppColor.primary10, - ), - textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), - ), - child: child!, - ); - }, - ).then((selectedTime) { - if (selectedTime != null) { - // _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); - // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { - // "Start time is before the request time.".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } - // if (_pickerStartAt!.isAfter(DateTime.now())) { - // "Start time is after than current time".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } - setState(() {}); - } - }); - }, - ), - ], - ); - } - - Widget inspectionDetails() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Inspected by'.addTranslation, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), - ), - 8.height, - Text( - 'Mahmoud Shrouf'.addTranslation, - style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), - ), - 8.height, - Text( - 'Approved by'.addTranslation, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), - ), - 8.height, - Text( - 'Mahmoud Shrouf'.addTranslation, - style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), - ), - 8.height, - Text( - 'Inspected Date/Time From'.addTranslation, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), - ), - 8.height, - Text( - '19 August, 2025'.addTranslation, - style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), - ), - 8.height, - Text( - 'Inspected Date/Time To'.addTranslation, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), - ), - 8.height, - Text( - '19 August, 2025'.addTranslation, - style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), - ), - ], - ); - } - - void _viewHistoryTap() async { - + void _attachmentTap() async { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AssetDeliveryAttachmentView( + tableItemId: widget.deliveryTableModel.id, + ))); } void _cancelTap() async { - - } - - void _nextTap() async { - Navigator.push(context, MaterialPageRoute(builder: (context) => EndUserCostCenterLIstView())); + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + await assetDeliveryProvider?.changeDeliveryStatusToCancel(itemId: widget.deliveryTableModel.id).then((status) async { + Navigator.pop(context); + if (status) { + Navigator.pop(context); + await assetDeliveryProvider?.getAssetDeliveryTableListById(requestId: widget.requestModel?.id); + } + }); } void _changeStatusTap() async { + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + await assetDeliveryProvider?.changeDeliveryStatus(itemId: widget.deliveryTableModel.id).then((status) async { + Navigator.pop(context); + if (status) { + Navigator.pop(context); + await assetDeliveryProvider?.getAssetDeliveryTableListById(requestId: widget.requestModel?.id); + } + }); + } + void _nextTap() async { + // Navigator.push(context, MaterialPageRoute(builder: (context) => EndUserCostCenterLIstView())); } } diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart new file mode 100644 index 00000000..d48326f8 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart @@ -0,0 +1,180 @@ +import 'dart:developer'; + +import 'package:flutter/foundation.dart'; +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/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/end_user_asset_details_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/end_user_rejection_reason_lookup_provider.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/end_user_status_lookup_provider.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.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 '../../../../new_views/common_widgets/app_filled_button.dart'; +import '../../../../new_views/common_widgets/default_app_bar.dart'; + +class UpdateEndUserAssetDetailsView extends StatefulWidget { + EndUserAssetDetailsModel? assetDetailsModel; + String? costCenterName; + int? tableId; + + UpdateEndUserAssetDetailsView({Key? key, this.assetDetailsModel, this.costCenterName, this.tableId}) : super(key: key); + + @override + State createState() => _UpdateEndUserAssetDetailsViewState(); +} + +class _UpdateEndUserAssetDetailsViewState extends State { + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + bool viewOnly = false; + late AssetDeliveryProvider assetDeliveryProvider; + EndUserAssetDetailsModel model = EndUserAssetDetailsModel(); + late TextEditingController quantityController; + late TextEditingController descriptionController; + + @override + void initState() { + quantityController = TextEditingController(); + descriptionController = TextEditingController(); + WidgetsBinding.instance.addPostFrameCallback((_) { + getInitialData(); + }); + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + void getInitialData() async { + assetDeliveryProvider = Provider.of(context, listen: false); + if (widget.assetDetailsModel != null) { + model = EndUserAssetDetailsModel.fromJson(widget.assetDetailsModel!.toJson()); + model.costCenterName = widget.costCenterName; + model.assetDeliveryExternalDeliveryId = widget.tableId; + model.status = widget.assetDetailsModel?.status; + model.rejectionReason = widget.assetDetailsModel?.rejectionReason; + } + quantityController.text = model.rejectedQty != null ? model.rejectedQty.toString() : ''; + descriptionController.text = model.description ?? ''; + setState(() {}); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar( + title: 'Item Details'.addTranslation, + titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Status'.addTranslation, + titleTextColor: AppColor.neutral120, + showShadow: false, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + initialValue: model.status, + onSelect: (status) { + if (status != null) { + model.status = status; + setState(() {}); + } + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Rejection Reason '.addTranslation, + titleTextColor: AppColor.neutral120, + showShadow: false, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + initialValue: model.rejectionReason, + onSelect: (reason) { + if (reason != null) { + model.rejectionReason = reason; + setState(() {}); + } + }, + ), + 8.height, + if (model.type == 'Accessory') ...[ + AppTextFormField( + labelText: 'Rejected Quantity'.addTranslation, + controller: quantityController, + backgroundColor: AppColor.fieldBgColor(context), + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + textInputType: TextInputType.number, + showShadow: false, + onChange: (value) { + if (value.isNotEmpty) { + model.rejectedQty = model.rejectedQty = num.tryParse(value); + } + }, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + ], + AppTextFormField( + controller: descriptionController, + labelText: 'Description'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + onChange: (value) { + model.description = value; + }, + onSaved: (value) { + model.description = value; + }, + ), + 8.height, + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12)) + .expanded, + FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), + ], + ), + ), + ); + } + + ///Need to check which details show here... + + void _saveTap() async { + _formKey.currentState!.save(); + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + await assetDeliveryProvider.saveEndUserAssetDataData(model: model).then((status) async { + Navigator.pop(context); + if (status) { + Navigator.pop(context, true); + } + }); + } +} diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart new file mode 100644 index 00000000..3b98beaa --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart @@ -0,0 +1,317 @@ +import 'dart:convert'; +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.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/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/end_user_asset_details_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/end_user_asset_detail_card.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/views/widgets/e_signature/e_signature.dart'; +import '../../../../new_views/common_widgets/app_filled_button.dart'; +import '../../../../new_views/common_widgets/default_app_bar.dart'; + +class UpdateEndUserCostCenterDetailsView extends StatefulWidget { + int? tableItemId; + CostCenterModel? costCenterModel; + bool? isHmg; + + UpdateEndUserCostCenterDetailsView({ + Key? key, + this.tableItemId, + this.costCenterModel, + this.isHmg, + }) : super(key: key); + + @override + State createState() => _UpdateEndUserCostCenterDetailsViewState(); +} + +class _UpdateEndUserCostCenterDetailsViewState extends State { + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + bool viewOnly = false; + CostCenterModel model = CostCenterModel(); + List assetList = []; + late AssetDeliveryProvider assetDeliveryProvider; + Uint8List? newSignature; + String? endUserSignature; + bool isLoading = false; + late TextEditingController acceptedByController; + late TextEditingController acceptedByEmailController; + + @override + void initState() { + acceptedByController = TextEditingController(); + acceptedByEmailController = TextEditingController(); + WidgetsBinding.instance.addPostFrameCallback((_) { + getInitialData(); + }); + super.initState(); + } + + void getInitialData() async { + assetDeliveryProvider = Provider.of(context, listen: false); + + if (widget.costCenterModel != null) { + model = CostCenterModel.fromJson(widget.costCenterModel!.toEndUserAcceptanceFormJson()); + _fillControllers(); + } + setState(() { + isLoading = true; + }); + assetList = await assetDeliveryProvider.getEndUserAssetList(tableItemId: widget.tableItemId, costCenterName: widget.costCenterModel?.costCenterName); + setState(() { + isLoading = false; + }); + } + + void _fillControllers() { + acceptedByController.text = model.acceptedBy ?? ''; + acceptedByEmailController.text = model.acceptedByEmail ?? ''; + } + + @override + void dispose() { + acceptedByController.dispose(); + acceptedByEmailController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar( + title: 'End-User Acceptance'.addTranslation, + titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + inspectionDetailsForm(), + 8.height, + const Divider().defaultStyle(context), + + ///Need to implement later as discuss with Ahmed. + // Text( + // "Acceptance Form", + // style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + // ), + // 6.height, + // Row( + // children: [ + // 'warning_icon'.toSvgAsset(height: 16, width: 16), + // 6.width, + // Text( + // 'Review the acceptance form'.addTranslation, + // style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + // ), + // 6.width, + // 'web_link_icon'.toSvgAsset(height: 20, width: 20), + // ], + // ), + 16.height, + Text( + "Items", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + endUserAssetList(context), + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12)) + .expanded, + FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), + ], + ), + ), + ); + } + + Widget endUserAssetList(BuildContext context) { + return isLoading + ? const CircularProgressIndicator(color: AppColor.primary10).center + : ListView.separated( + itemCount: assetList.length, + separatorBuilder: (_, __) => 8.height, + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (listContext, itemIndex) { + EndUserAssetDetailsModel model = assetList[itemIndex]; + return EndUserAssetDetailCard( + assetModel: model, + isViewOnly: viewOnly, + editPress: () async { + bool isRefresh = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => UpdateEndUserAssetDetailsView( + assetDetailsModel: model, + costCenterName: widget.costCenterModel?.costCenterName, + tableId: widget.tableItemId, + ))); + if (isRefresh) { + getInitialData(); + } + }, + ); + }, + ); + } + + Widget inspectionDetailsForm() { + return Column( + children: [ + ADatePicker( + label: 'Accepted Date'.addTranslation, + hideShadow: true, + height: 56.toScreenHeight, + backgroundColor: AppColor.fieldBgColor(context), + date: model.acceptanceDate, + from: DateTime(DateTime.now().year, 1, 1), + formatDateWithTime: true, + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + builder: (BuildContext context, Widget? child) { + final ThemeData currentTheme = Theme.of(context); + return Theme( + data: currentTheme.copyWith( + timePickerTheme: TimePickerThemeData( + dialHandColor: AppColor.primary10, + dialBackgroundColor: Colors.grey.withOpacity(0.1), + hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), + dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), + dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), + dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), + entryModeIconColor: AppColor.primary10, + ), + textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), + ), + child: child!, + ); + }, + ).then((selectedTime) { + if (selectedTime != null) { + model.acceptanceDate = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); + setState(() {}); + } + }); + }, + ), + 8.height, + if (widget.isHmg == true) ...[ + OracleUserAutoCompleteField( + clearAfterPick: false, + initialValue: model.acceptedBy ?? '', + label: 'Accepted By'.addTranslation, + onPick: (value) { + model.acceptedBy = value.fullName; + model.acceptedByEmail = value.employeeEmail; + acceptedByEmailController.text = value.employeeEmail ?? ''; + setState(() {}); + }, + onChanged: (value) {}, + ), + 8.height, + AppTextFormField( + labelText: 'Accepted By Email'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + controller: acceptedByEmailController, + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + enable: false, + style: Theme.of(context).textTheme.titleMedium, + ), + ] else ...[ + AppTextFormField( + labelText: 'Accepted By'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + controller: acceptedByController, + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + onChange: (value) { + model.acceptedBy = value; + }, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Accepted By Email'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + controller: acceptedByEmailController, + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + onChange: (value) { + model.acceptedByEmail = value; + }, + style: Theme.of(context).textTheme.titleMedium, + ), + ], + 8.height, + ESignature( + title: 'End User Signature', + oldSignature: model.acceptedBySignature, + newSignature: newSignature, + backgroundColor: AppColor.neutral100, + showShadow: false, + onChange: (signature) { + log('onChange called.'); + updateSignature(signature: signature); + }, + onSaved: (signature) { + log('onSaved called.'); + updateSignature(signature: signature); + }, + ) + ], + ); + } + + void updateSignature({Uint8List? signature}) { + if (signature == null || signature.isEmpty) { + model.acceptedBySignature = ''; + return; + } + setState(() { + newSignature = signature; + model.acceptedBySignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; + }); + } + + void _saveTap() async { + _formKey.currentState!.save(); + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + model.assetDeliveryExternalDetailId = widget.tableItemId; + await assetDeliveryProvider.saveEndUserFormData(model: model).then((status) async { + Navigator.pop(context); + if (status) { + Navigator.pop(context, true); + } + }); + } +} diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_view.dart deleted file mode 100644 index 28136296..00000000 --- a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_view.dart +++ /dev/null @@ -1,220 +0,0 @@ -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/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/modules/asset_delivery_module/pages/end_user_acceptance/end_user_acceptance_form_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart'; -import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; -import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; -import 'package:test_sa/new_views/app_style/app_color.dart'; -import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; -import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; -import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; -import '../../../../new_views/common_widgets/app_filled_button.dart'; -import '../../../../new_views/common_widgets/default_app_bar.dart'; - -class UpdateEndUserCostCenterView extends StatefulWidget { - UpdateEndUserCostCenterView({ - Key? key, - }) : super(key: key); - - @override - State createState() => _UpdateEndUserCostCenterViewState(); -} - -class _UpdateEndUserCostCenterViewState extends State { - final GlobalKey _formKey = GlobalKey(); - final GlobalKey _scaffoldKey = GlobalKey(); - bool viewOnly = false; - - @override - void initState() { - super.initState(); - } - - @override - void dispose() { - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - key: _scaffoldKey, - appBar: DefaultAppBar( - title: 'End-User Acceptance'.addTranslation, - titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), - ), - body: Form( - key: _formKey, - child: Column( - children: [ - SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - inspectionDetailsForm(), - 8.height, - const Divider().defaultStyle(context), - Text( - "Acceptance Form", - style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), - ), - 6.height, - Row( - children: [ - 'warning_icon'.toSvgAsset(height: 16, width: 16), - 6.width, - Text( - 'Review the acceptance form'.addTranslation, - style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), - ), - 6.width, - 'web_link_icon'.toSvgAsset(height: 20, width: 20), - ], - ), - 16.height, - assetList(context), - ], - ).toShadowContainer(context, borderRadius: 20, padding: 12)) - .expanded, - FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _viewHistoryTap)), - ], - ), - ), - ); - } - - Widget assetList(BuildContext context) { - final assetDeliveryTableList = ['abc', 'def', 'ghi', 'fhg', 'hjhh']; - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Asset", - style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), - ), - 8.height, - ListView.separated( - itemCount: assetDeliveryTableList.length, - separatorBuilder: (_, __) => 8.height, - padding: EdgeInsets.zero, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (listContext, itemIndex) { - return TechnicalInspectionAssetCard( - assetModel: Asset(), - isViewOnly: viewOnly, - ischild: true, - editPress: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => EndUserAcceptanceFormView())); - }, - ); - }, - ), - ], - ); - } - - Widget inspectionDetailsForm() { - return Column( - children: [ - ADatePicker( - label: 'Accepted Date'.addTranslation, - hideShadow: true, - height: 56.toScreenHeight, - backgroundColor: AppColor.fieldBgColor(context), - // date: _pickerStartAt, - // from: widget.pickerFromDate, - formatDateWithTime: true, - onDatePicker: (selectedDate) { - showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - builder: (BuildContext context, Widget? child) { - final ThemeData currentTheme = Theme.of(context); - return Theme( - data: currentTheme.copyWith( - timePickerTheme: TimePickerThemeData( - dialHandColor: AppColor.primary10, - dialBackgroundColor: Colors.grey.withOpacity(0.1), - hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), - dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), - dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), - dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), - entryModeIconColor: AppColor.primary10, - ), - textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), - ), - child: child!, - ); - }, - ).then((selectedTime) { - if (selectedTime != null) { - // _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); - // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { - // "Start time is before the request time.".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } - // if (_pickerStartAt!.isAfter(DateTime.now())) { - // "Start time is after than current time".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } - setState(() {}); - } - }); - }, - ), - 8.height, - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: 'Approved by'.addTranslation, - showShadow: false, - titleTextColor: AppColor.neutral120, - // backgroundColor: AppColor.neutral100, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, - onSelect: (status) { - if (status != null) { - // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; - setState(() {}); - } - }, - ), - ], - ); - } - - void _viewHistoryTap() async { - AssetInventoryProvider assetInventoryProvider = Provider.of(context, listen: false); - _formKey.currentState!.save(); - } - - void _cancelTap() async { - AssetInventoryProvider assetInventoryProvider = Provider.of(context, listen: false); - _formKey.currentState!.save(); - } - - void _nextTap() async { - AssetInventoryProvider assetInventoryProvider = Provider.of(context, listen: false); - _formKey.currentState!.save(); - } - - void _changeStatusTap() async { - AssetInventoryProvider assetInventoryProvider = Provider.of(context, listen: false); - _formKey.currentState!.save(); - } -} diff --git a/lib/modules/asset_delivery_module/pages/history_log_view.dart b/lib/modules/asset_delivery_module/pages/history_log_view.dart index 4990a708..9aace55d 100644 --- a/lib/modules/asset_delivery_module/pages/history_log_view.dart +++ b/lib/modules/asset_delivery_module/pages/history_log_view.dart @@ -1,102 +1,114 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; - -import 'package:test_sa/controllers/api_routes/urls.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/new_models/work_order_detail_model.dart'; -import 'package:test_sa/modules/cm_module/cm_detail_provider.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/history_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; - -import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; -import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart'; -class AssetDeliveryHistoryLogView extends StatelessWidget { - const AssetDeliveryHistoryLogView({Key? key}) : super(key: key); +class AssetDeliveryHistoryLogView extends StatefulWidget { + final int? tableItemId; + const AssetDeliveryHistoryLogView({Key? key,this.tableItemId}) : super(key: key); + + @override + State createState() => _AssetDeliveryHistoryLogViewState(); +} + + + +class _AssetDeliveryHistoryLogViewState extends State { + List history = []; + @override + void initState() { + WidgetsBinding.instance.addPostFrameCallback((_) { + getInitialData(); + }); + super.initState(); + } + + + void getInitialData() async { + history = await Provider.of(context, listen: false).getHistory(tableItemId: widget.tableItemId); + } @override Widget build(BuildContext context) { - ///Replace with provider and data.. - return Consumer(builder: (context, requestProvider, _) { - return requestProvider.isLoading - ? const CircularProgressIndicator(color: AppColor.primary10).center - : (requestProvider.currentWorkOrder == null || (requestProvider.currentWorkOrder?.data?.workOrderHistory.isEmpty ?? true) - ? const NoDataFound() - : Stack( - children: [ - Padding( - padding: EdgeInsets.only(left: 122.toScreenWidth), - child: const VerticalDivider( - color: AppColor.white40, - thickness: 2, - width: 20, - indent: 10, - endIndent: 10, + return Scaffold( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + appBar: DefaultAppBar( + title: 'History Log'.addTranslation, + onBackPress: () { + Navigator.pop(context); + }, + ), + body: Consumer(builder: (context, provider, _) { + return provider.isLoading + ? const CircularProgressIndicator(color: AppColor.primary10).center + : Stack( + children: [ + Padding( + padding: EdgeInsets.only(left: 122.toScreenWidth), + child: const VerticalDivider( + color: AppColor.white40, + thickness: 2, + width: 20, + indent: 10, + endIndent: 10, + ), ), - ), - SafeArea( - child: Builder(builder: (cxt) { - List items = []; - String lastStatus = ""; - DateTime? nextDate; - var workOrderHistory = requestProvider.currentWorkOrder!.data!.workOrderHistory; - bool isNurse = (Provider.of(context, listen: false).user?.type) == UsersTypes.normal_user; - if (isNurse) { - workOrderHistory.removeWhere((element) => element.step?.id == 5617); - } - for (int i = 0; i < workOrderHistory.length; i++) { - var object = workOrderHistory[i]; - String currentStatus = object.workorderStatus!.name!; - if (lastStatus.isEmpty) { - lastStatus = currentStatus; - } - if (lastStatus == currentStatus) { - if (i + 1 < workOrderHistory.length) { - nextDate = workOrderHistory[i + 1].date; - String timeDifference = CMRequestUtils.calculateTimeDifference(object.date!, nextDate!); - object.timeDifference = timeDifference; - } else { - object.timeDifference = ''; // Empty string for the last action + SafeArea( + child: Builder(builder: (cxt) { + List items = []; + String lastStatus = ""; + DateTime? nextDate; + for (int i = 0; i < history.length; i++) { + var object = history[i]; + String currentStatus = object.status!.name!; + if (lastStatus.isEmpty) { + lastStatus = currentStatus; } - items.add(historyLogCard(cxt, object)); - } else { - items.add(statusCard(cxt, lastStatus)); - lastStatus = currentStatus; - if (i + 1 < workOrderHistory.length) { - nextDate = workOrderHistory[i + 1].date; - String timeDifference = CMRequestUtils.calculateTimeDifference(object.date!, nextDate!); - object.timeDifference = timeDifference; + if (lastStatus == currentStatus) { + if (i + 1 < history.length) { + nextDate = history[i + 1].createdDate; + String timeDifference = CMRequestUtils.calculateTimeDifference(object.createdDate!, nextDate!); + object.timeDifference = timeDifference; + } else { + object.timeDifference = ''; // Empty string for the last action + } + items.add(historyLogCard(cxt, object)); } else { - object.timeDifference = ''; // Empty string for the last action + items.add(statusCard(cxt, lastStatus)); + lastStatus = currentStatus; + if (i + 1 < history.length) { + nextDate = history[i + 1].createdDate; + String timeDifference = CMRequestUtils.calculateTimeDifference(object.createdDate!, nextDate!); + object.timeDifference = timeDifference; + } else { + object.timeDifference = ''; // Empty string for the last action + } + items.add(historyLogCard(cxt, object)); } - items.add(historyLogCard(cxt, object)); } - } - items.add(statusCard(cxt, lastStatus)); - return SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column(children: items), - ); - }), - ), - ], - )); - }); - } - - Widget historyLogCard(BuildContext context, WorkOrderHistory object) { - String title = object.step!.name!; + items.add(statusCard(cxt, lastStatus)); + return SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column(children: items), + ); + }), + ), + ], + ); + }), + );} - if (object.step!.value == 18 || object.step!.value == 27 || object.step!.value == 28) { - title = object.activityStatus?.name ?? ""; - } + Widget historyLogCard(BuildContext context, AssetDeliveryHistoryModel object) { + String title = object.status!.name!; return Row( crossAxisAlignment: CrossAxisAlignment.center, @@ -105,40 +117,18 @@ class AssetDeliveryHistoryLogView extends StatelessWidget { Align( alignment: Alignment.centerLeft, child: Text( - object.date.toString().toServiceRequestCardFormat, + object.createdDate.toString().toServiceRequestCardFormat, textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), ), ).expanded, Expanded( flex: 2, - //.... child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (object.assetVerificationType?.value == 4 && object.photoVerfication != null) ...[ - Padding( - padding: EdgeInsets.symmetric(vertical: 12.toScreenWidth), - child: InteractiveViewer(child: Image.network(URLs.getFileUrl(object.photoVerfication ?? '')!, height: 143.toScreenHeight)), - ).onPress(() async { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => Scaffold( - body: SafeArea( - child: Stack( - children: [ - InteractiveViewer(child: Image.network(URLs.getFileUrl(object.photoVerfication ?? '')!)).center, - const ABackButton(), - ], - ), - ), - ), - ), - ); - }), - ], title.bodyText(context).custom(color: AppColor.textColor(context)), - object.timeDifference.isNotEmpty ? object.timeDifference.tinyFont(context).custom(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120) : const SizedBox(), + // object.timeDifference.isNotEmpty ? object.timeDifference?.tinyFont(context).custom(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120) : const SizedBox(), ], ), ), @@ -153,15 +143,15 @@ class AssetDeliveryHistoryLogView extends StatelessWidget { radius: 4, label: statusText(status.toLowerCase()), labelInCenter: true, - textColor: AppColor.getHistoryLogStatusTextColorByName(status), - backgroundColor: AppColor.getHistoryLogStatusColorByName(status), + textColor: AppColor.neutral50, + backgroundColor: AppColor.orange30, ), ).paddingOnly(bottom: 16, start: 40); } - +// Need to check status text we have String statusText(String status) { if (status == "new" || status == "open") { - return "Open Request".addTranslation; + return "New".addTranslation; } else if (status == "in progress") { return "Status update to In Progress".addTranslation; } else if (status == "closed") { @@ -176,12 +166,3 @@ class AssetDeliveryHistoryLogView extends StatelessWidget { return status; } } - -class HistoryLogModel { - String message; - DateTime date; - String? status; - Color? statusColor; - - HistoryLogModel({required this.message, required this.date, this.status, this.statusColor}); -} diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/asset_delivery_utils.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/asset_delivery_utils.dart new file mode 100644 index 00000000..ffa4a1b4 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/asset_delivery_utils.dart @@ -0,0 +1,18 @@ + + +import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart'; + +class AssetDeliveryUtils{ + ///This is static list for now if change in future backend provide Api as discuss with backend team + static List inspectionChecklist = [ + InspectionChecklistItem(title: 'Physical Inspection As Per Manufacturer Instructions', value: 'flagphysicalInspection'), + InspectionChecklistItem(title: 'Functional Performance As Per Results Of Manufacturer Recommended Check List', value: 'flagFunctionPerformance'), + InspectionChecklistItem(title: 'Grounding Resistance: Ω', value: 'flagGroundingResistance'), + InspectionChecklistItem(title: 'Chassis Leakage Current: µA', value: 'flagChassiss'), + InspectionChecklistItem(title: 'Leads Leakage Current: µA', value: 'flagLeadsLeakage'), + InspectionChecklistItem(title: 'This Device Is Not Subject To Any Alert Or Recall Until The Date Of Preparation Of This Inspection Form', value: 'flagAlert'), + ]; + + + +} \ No newline at end of file diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart new file mode 100644 index 00000000..4344c633 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart @@ -0,0 +1,194 @@ +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/devices_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/device/asset_search.dart'; +import 'package:test_sa/models/device/model_definition.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/technical_inpection_asset_model.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/custom_app_bar.dart'; +import 'package:test_sa/views/widgets/equipment/asset_item_listview.dart'; +import 'package:test_sa/views/widgets/horizontal_list_widget.dart'; +import 'package:test_sa/views/widgets/loaders/lazy_loading.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; + +class TechnicalInspectionSearchAssetView extends StatefulWidget { + /// add on route + static const String id = "search_asset_view"; + final int? lineId; + + const TechnicalInspectionSearchAssetView({ + Key? key, + this.lineId, + }) : super(key: key); + + @override + State createState() => _TechnicalInspectionSearchAssetViewState(); +} + +class _TechnicalInspectionSearchAssetViewState extends State { + int _selectedIndex = 0; + DeviceSearch? search; + late TextEditingController _searchController; + late AssetProvider _deviceProvider; + + //check for this list if not need remove + final List _searchableList = []; + final GlobalKey _formKey = GlobalKey(); + bool _isFirst = true; + + @override + void initState() { + _searchController = TextEditingController(); + super.initState(); + } + + @override + void dispose() { + _searchController.dispose(); + _deviceProvider.searchReset(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + List searchBy = [ + context.translation.assetName, + context.translation.assetNumber, + 'model'.addTranslation, + 'manufacturer'.addTranslation, + // 'assetType'.addTranslation, + // 'assetOrigin'.addTranslation, + ]; + + _deviceProvider = Provider.of(context, listen: false); + + return Scaffold( + resizeToAvoidBottomInset: false, + appBar: CustomAppBar( + title: context.translation.searchAsset, + ), + body: Column( + children: [ + HorizontalListWidget( + list: searchBy, + callBackFunction: (index) { + setState(() { + _selectedIndex = index; + }); + }, + ).paddingOnly(top: 16, bottom: 0), + Form( + key: _formKey, + child: AppTextFormField( + controller: _searchController, + textInputAction: TextInputAction.search, + labelText: "${context.translation.searchBy} ${searchBy[_selectedIndex]}", + onAction: _search, + onChange: (text) { + _searchController.text = text; + _searchController.selection = TextSelection.fromPosition(TextPosition(offset: _searchController.text.length)); + setState(() {}); + }, + onSaved: (value) { + setState(() { + search = DeviceSearch(); + }); + _setValue(value); + }, + suffixIcon: IconButton( + icon: const Icon(Icons.search), + splashColor: Colors.transparent, + onPressed: _searchController.text.isNotEmpty ? _search : null, + color: AppColor.neutral20, + ).paddingOnly(end: 0), + ).paddingOnly(top: 16, start: 16, end: 16, bottom: 8)), + Expanded( + child: _searchableList.isEmpty + ? _isFirst + ? const SizedBox() + : NoDataFound(message: context.translation.noDeviceFound) + : LazyLoading( + nextPage: _deviceProvider.nextPage, + onLazyLoad: () async { + if (_searchController.text.isNotEmpty) { + await _deviceProvider.getAssetsForAssetDelivery(search: search, lineId: widget.lineId, isSearchBy: true); + setState(() { + _searchableList.clear(); + _searchableList.addAll(_deviceProvider.technicalInspectionAsset); + }); + } + }, + child: ListView.separated( + itemCount: _searchableList.length, + separatorBuilder: (listContext, itemIndex) => 8.height, + padding: const EdgeInsets.all(16), + itemBuilder: (listContext, itemIndex) { + return AssetItemListView( + device: Asset( + id: _searchableList[itemIndex].id, + assetNumber: _searchableList[itemIndex].assetNumber, + assetSerialNo: _searchableList[itemIndex].assetNumber, + modelDefinition: ModelDefinition(assetName: _searchableList[itemIndex].assetName, modelName: _searchableList[itemIndex].model), + ), + onPressed: (device) { + Navigator.of(context).pop(device); + }, + ); + }, + ), + ), + ) + ], + )); + } + + void _search({bool loadMore = false}) async { + FocusScope.of(context).unfocus(); + _formKey.currentState?.save(); + _searchableList.clear(); + _deviceProvider.technicalInspectionAsset.clear(); + setState(() {}); + _deviceProvider.searchReset(); + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + await _deviceProvider.getAssetsForAssetDelivery( + search: search, + lineId: widget.lineId, + isSearchBy: true, + ); + + setState(() { + _searchableList.clear(); + _searchableList.addAll(_deviceProvider.technicalInspectionAsset); + _isFirst = false; + }); + + Navigator.pop(context); + } + + _setValue(String? value) { + search ??= DeviceSearch(); + switch (_selectedIndex) { + case 0: + search!.assetName = value; + break; + case 1: + search!.assetNo = value; + break; + case 2: + search!.model = value; + break; + case 3: + search!.manufacturer = value; + break; + } + } +} diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart new file mode 100644 index 00000000..520b51a7 --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart @@ -0,0 +1,137 @@ +import 'dart:developer'; + +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/modules/asset_delivery_module/models/technical_inspection_asset_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/asset_delivery_utils.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.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'; + +class InspectionChecklistBottomSheet extends StatefulWidget { + final List? initialValues; + + const InspectionChecklistBottomSheet({super.key, this.initialValues}); + + @override + State createState() => + _InspectionChecklistBottomSheetState(); +} + +class _InspectionChecklistBottomSheetState + extends State { + late List checklist; + + @override + void initState() { + super.initState(); + + /// Create local copy (no shared mutation) + checklist = AssetDeliveryUtils.inspectionChecklist + .map((e) => InspectionChecklistItem(title: e.title)) + .toList(); + + /// Apply initial values only if provided + if (widget.initialValues != null && widget.initialValues!.isNotEmpty) { + for (final item in checklist) { + final matched = widget.initialValues!.firstWhere( + (e) => e.title == item.title, + orElse: () => InspectionChecklistItem(), + ); + item.status = matched.status; // null-safe + } + } + } + + void updateStatus(int index, String value) { + setState(() { + checklist[index].status = value; + }); + } + + List get selectedValues => + checklist.where((e) => e.status != null).toList(); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColor.white10, + appBar: DefaultAppBar( + title: 'Asset Check List'.addTranslation, + showBackButton: false, + titleStyle: AppTextStyles.heading3.copyWith( + fontWeight: FontWeight.w500, + color: context.isDark + ? AppColor.neutral30 + : AppColor.neutral50, + ), + ), + body: Column( + children: [ + 12.height, + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: checklist.length, + padding: const EdgeInsets.symmetric(horizontal: 12), + itemBuilder: (context, index) { + final item = checklist[index]; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + item.title ?? '', + style: AppTextStyles.heading6.copyWith( + color: context.isDark + ? AppColor.neutral30 + : AppColor.black10, + ), + ), + Row( + children: [ + Expanded( + child: RadioListTile( + title: const Text('Pass'), + value: 'PASS', + groupValue: item.status, + onChanged: (v) => + updateStatus(index, v!), + ), + ), + Expanded( + child: RadioListTile( + title: const Text('Fail'), + value: 'FAIL', + groupValue: item.status, + onChanged: (v) => + updateStatus(index, v!), + ), + ), + ], + ), + ], + ); + }, + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Save'.addTranslation, + maxWidth: true, + onPressed: () { + Navigator.pop(context, selectedValues); + }, + ), + ), + ], + ), + ); + } +} + diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart index 0a4fc871..d5c75e54 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart @@ -1,21 +1,16 @@ import 'dart:developer'; import 'package:flutter/material.dart'; -import 'package:test_sa/common_widgets/lookup_autocomplete_field.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/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart'; class TechnicalInspectionAssetCard extends StatelessWidget { - Asset assetModel; - - ///if include in model skip this + TechnicalInspectionAssetModel assetModel; bool isViewOnly; bool ischild; VoidCallback? editPress; @@ -33,16 +28,15 @@ class TechnicalInspectionAssetCard extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ///Need to give specific colors if (!ischild) ...[ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ StatusLabel( - label: 'Pass', + label: getAssetStatus(), radius: 4, - textColor: AppColor.getPriorityStatusTextColor(context, 1), - backgroundColor: AppColor.getPriorityStatusColor(context, 1), + textColor: getAssetStatusColor(context: context, status: getAssetStatus(), isBackground: false), + backgroundColor: getAssetStatusColor(context: context, status: getAssetStatus()), ), if (!isViewOnly) 'edit_icon'.toSvgAsset().onPress(() { @@ -70,40 +64,67 @@ class TechnicalInspectionAssetCard extends StatelessWidget { }), ], ), + 2.height, ], + Text( + 'Asset Name: ${assetModel.modelDefinition?.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), if (!ischild) Text( 'Asset Number: ${assetModel.assetNumber ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - 'Model: ${assetModel.modelDefinition ?? '-'}', + 'Serial Number: ${assetModel.serialNo ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - 'Serial Number: ${assetModel.assetSerialNo ?? '-'}', + 'System ID: ${assetModel.systemId ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - 'System ID: ${assetModel.systemID ?? '-'}', + 'Medical Department: ${assetModel.department?.name ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Installation Date: ${assetModel.installationDate ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + 'Asset Type: ${assetModel.assetType?.name ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), - if (!ischild) - Text( - 'Medical Department: ${assetModel.department ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - if (!ischild) - Text( - 'Installation Date: ${assetModel.deliveryInspectionDate ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - if (!ischild) - Text( - 'Asset Type: ${assetModel.assetType ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), ], ).toShadowContainer(context, borderRadius: 20, padding: 12); } + + Color getAssetStatusColor({required BuildContext context, required String status, bool? isBackground = true}) { + switch (status) { + case 'PASS': + return isBackground! ? AppColor.green70.withOpacity(0.4) : AppColor.green15; + case 'FAIL': + return isBackground! ? AppColor.red30.withOpacity(0.4) : AppColor.red30; + default: + return Colors.white10; + } + } + + String getAssetStatus() { + final flags = [ + assetModel.flagphysicalInspection, + assetModel.flagFunctionPerformance, + assetModel.flagGroundingResistance, + assetModel.flagChassiss, + assetModel.flagLeadsLeakage, + assetModel.flagAlert, + ]; + if (flags.any((f) => f == false)) { + return 'FAIL'; + } + if (flags.every((f) => f == true)) { + return 'PASS'; + } + return 'FAIL'; + } } diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart index 1470c34e..c9488779 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart @@ -1,25 +1,26 @@ import 'dart:developer'; import 'package:flutter/material.dart'; +import 'package:test_sa/common_widgets/lookup_autocomplete_field.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/modules/asset_delivery_module/models/cost_center_model.dart'; import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; class TechnicalInspectionCostCard extends StatelessWidget { - ///Need to replace with Cost model. - AssetInventoryModel deliveryDetails; - ///if include in model skip this + CostCenterModel costModel; + VoidCallback? editPress; bool isViewOnly; - VoidCallback ?editPress; TechnicalInspectionCostCard({ super.key, - required this.isViewOnly, - required this.deliveryDetails, + required this.costModel, this.editPress, + required this.isViewOnly, }); @override @@ -31,44 +32,24 @@ class TechnicalInspectionCostCard extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - 'Item No: ${deliveryDetails.transactionDate?.toServiceRequestDetailsFormat ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + Flexible( + child: Text( + 'Cost Center Name: ${costModel.costCenterName ?? '-'}', + overflow: TextOverflow.ellipsis, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), ), - if(!isViewOnly) - 'edit_icon'.toSvgAsset().onPress(() { - if(editPress!=null){ - editPress!(); - } - }), + 8.width, + if (!isViewOnly) + 'edit_icon'.toSvgAsset(height: 18, width: 18).onPress(() { + if (editPress != null) { + editPress!(); + } + }), ], ), Text( - 'Cost Center: ${deliveryDetails.assetNumber ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - 'Power Supply Type: ${deliveryDetails.assetName ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - 'Cost Center: ${deliveryDetails.assetName ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - 'Power Reading: ${deliveryDetails.assetName ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - 'Max Current: ${deliveryDetails.assetName ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - 'Voltage: ${deliveryDetails.assetName ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - 'Frequency: ${deliveryDetails.assetName ?? '-'}', + 'Quantity: ${costModel.quantity ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), ], diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart index 82420e30..61e52c87 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart @@ -1,25 +1,38 @@ +import 'dart:developer'; + 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/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart'; -import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import '../../../../new_views/common_widgets/app_filled_button.dart'; import '../../../../new_views/common_widgets/default_app_bar.dart'; class TechnicalInspectionLinesListView extends StatefulWidget { + final AssetDeliveryTableModel deliveryTableModel; + final AssetDeliveryDataModel? requestModel; + TechnicalInspectionLinesListView({ Key? key, + required this.deliveryTableModel, + this.requestModel, }) : super(key: key); @override @@ -29,13 +42,33 @@ class TechnicalInspectionLinesListView extends StatefulWidget { class _TechnicalInspectionLinesListViewState extends State { final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); - bool viewOnly = true; + bool viewOnly = false; + bool isLoading = false; + AssetDeliveryProvider? assetDeliveryProvider; + List technicalInspectionLinesList = []; @override void initState() { + WidgetsBinding.instance.addPostFrameCallback((_) { + getInitialData(); + }); super.initState(); } + void getInitialData() async { + assetDeliveryProvider = Provider.of(context, listen: false); + viewOnly = widget.deliveryTableModel.status?.value != 3; + isLoading = true; + setState(() {}); + technicalInspectionLinesList = await assetDeliveryProvider!.getTechnicalInspectionLinesListById( + //TODO uncommit this after testing @waseem + itemId: widget.deliveryTableModel.id, + // itemId: 2, + ); + isLoading = false; + setState(() {}); + } + @override void dispose() { super.dispose(); @@ -53,20 +86,13 @@ class _TechnicalInspectionLinesListViewState extends State 8.height, - padding: EdgeInsets.zero, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (listContext, itemIndex) { - return AssetDeliveryLineCard( - deliveryDetails: AssetInventoryModel(), - isViewOnly: viewOnly, - editPress: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => UpdateTechnicalInspectionLinesView())); - }, - ); - }, - ), - ], - ); - } + if (isLoading) { + return SizedBox.expand( + child: const CircularProgressIndicator(color: AppColor.primary10).center, + ); + } - Widget inspectionDetailsForm() { - return Column( - children: [ - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: 'Inspected by'.addTranslation, - titleTextColor: AppColor.neutral120, - showShadow: false, - // backgroundColor: AppColor.neutral100, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, - onSelect: (status) { - if (status != null) { - // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; - setState(() {}); - } - }, - ), - 8.height, - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: 'Approved by'.addTranslation, - showShadow: false, - titleTextColor: AppColor.neutral120, - // backgroundColor: AppColor.neutral100, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, - onSelect: (status) { - if (status != null) { - // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; - setState(() {}); - } - }, - ), - 8.height, - ADatePicker( - label: 'Inspected Date/Time From'.addTranslation, - hideShadow: true, - height: 56.toScreenHeight, - backgroundColor: AppColor.fieldBgColor(context), - // date: _pickerStartAt, - // from: widget.pickerFromDate, - formatDateWithTime: true, - onDatePicker: (selectedDate) { - showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - builder: (BuildContext context, Widget? child) { - final ThemeData currentTheme = Theme.of(context); - return Theme( - data: currentTheme.copyWith( - timePickerTheme: TimePickerThemeData( - dialHandColor: AppColor.primary10, - dialBackgroundColor: Colors.grey.withOpacity(0.1), - hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), - dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), - dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), - dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), - entryModeIconColor: AppColor.primary10, - ), - textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), - ), - child: child!, - ); - }, - ).then((selectedTime) { - if (selectedTime != null) { - // _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); - // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { - // "Start time is before the request time.".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } - // if (_pickerStartAt!.isAfter(DateTime.now())) { - // "Start time is after than current time".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } - setState(() {}); - } - }); - }, - ), - 8.height, - ADatePicker( - label: 'Inspected Date/Time To'.addTranslation, - hideShadow: true, - height: 56.toScreenHeight, - backgroundColor: AppColor.fieldBgColor(context), - // date: _pickerStartAt, - // from: widget.pickerFromDate, - formatDateWithTime: true, - onDatePicker: (selectedDate) { - showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - builder: (BuildContext context, Widget? child) { - final ThemeData currentTheme = Theme.of(context); - return Theme( - data: currentTheme.copyWith( - timePickerTheme: TimePickerThemeData( - dialHandColor: AppColor.primary10, - dialBackgroundColor: Colors.grey.withOpacity(0.1), - hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), - dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), - dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), - dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), - entryModeIconColor: AppColor.primary10, - ), - textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), - ), - child: child!, - ); - }, - ).then((selectedTime) { - if (selectedTime != null) { - // _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); - // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { - // "Start time is before the request time.".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } - // if (_pickerStartAt!.isAfter(DateTime.now())) { - // "Start time is after than current time".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } - setState(() {}); - } - }); + if (technicalInspectionLinesList.isEmpty) { + return const NoDataFound().center; + } + + return ListView.separated( + padding: const EdgeInsets.all(16), + itemCount: technicalInspectionLinesList.length + 1, // +1 for the header + separatorBuilder: (_, __) => 8.height, + itemBuilder: (context, index) { + if (index == 0) { + return Text( + "Lines", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ); + } + + final DeliveryLineModel model = technicalInspectionLinesList[index - 1]; + return AssetDeliveryLineCard( + deliveryLineModel: model, + isViewOnly: viewOnly, + isTechnical: true, + editPress: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => UpdateTechnicalInspectionLinesView( + requestModel: widget.requestModel, + deliveryTableModel: widget.deliveryTableModel, + deliveryLineModel: model, + ), + ), + ); }, - ), - ], - ); + ); + }, + ).toShadowContainer(context, borderRadius: 20, padding: 12); } +//May be need to show data. Widget inspectionDetails() { return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -324,13 +215,44 @@ class _TechnicalInspectionLinesListViewState extends State const AppLazyLoading()); + await assetDeliveryProvider?.changeDeliveryStatus(itemId: widget.deliveryTableModel.id).then((status) async { + Navigator.pop(context); + if (status) { + Navigator.pop(context); + await assetDeliveryProvider?.getAssetDeliveryTableListById(requestId: widget.requestModel?.id); + } + }); + } + + void _attachmentTap() async { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AssetDeliveryAttachmentView( + tableItemId: widget.deliveryTableModel.id, + ))); + } - void _cancelTap() async {} + void _cancelTap() async { + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + await assetDeliveryProvider?.changeDeliveryStatusToCancel(itemId: widget.deliveryTableModel.id).then((status) async { + Navigator.pop(context); + if (status) { + Navigator.pop(context); + await assetDeliveryProvider?.getAssetDeliveryTableListById(requestId: widget.requestModel?.id); + } + }); + } void _nextTap() async { - Navigator.push(context, MaterialPageRoute(builder: (context) => EndUserCostCenterLIstView())); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => EndUserCostCenterLIstView( + requestModel: widget.requestModel, + deliveryTableModel: widget.deliveryTableModel, + ))); } - - void _changeStatusTap() async {} } diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart index 2ea5d088..5f6a60c6 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart @@ -1,19 +1,28 @@ - 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/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/modules/asset_delivery_module/models/technical_inspection_asset_model.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import '../../../../new_views/common_widgets/default_app_bar.dart'; class TechnicalInspectionParentAssetListView extends StatefulWidget { + final int? costCenterId; + final int? tableItemId; + final int? lineId; + TechnicalInspectionParentAssetListView({ Key? key, + this.costCenterId, + this.tableItemId, + this.lineId, }) : super(key: key); @override @@ -24,12 +33,35 @@ class _TechnicalInspectionParentAssetListViewState extends State _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); bool viewOnly = false; + AssetDeliveryProvider? assetDeliveryProvider; + List assetList = []; + bool isLoading = false; @override void initState() { + WidgetsBinding.instance.addPostFrameCallback((_) { + getInitialData(); + }); super.initState(); } + void getInitialData() async { + setState(() { + isLoading = true; + }); + assetDeliveryProvider = Provider.of(context, listen: false); + //TODO replace static id's after testing... + assetList = await assetDeliveryProvider!.getParentAssetList( + costCenterId: widget.costCenterId, + tableItemId: widget.tableItemId, + lineId: widget.lineId, + ); + + setState(() { + isLoading = false; + }); + } + @override void dispose() { super.dispose(); @@ -43,45 +75,59 @@ class _TechnicalInspectionParentAssetListViewState extends State 8.height, - padding: EdgeInsets.zero, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (listContext, itemIndex) { - return TechnicalInspectionAssetCard( - assetModel: Asset(), - isViewOnly: viewOnly, - editPress: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => UpdateParentAssetView())); - }, + if (isLoading) { + return SizedBox.expand( + child: const CircularProgressIndicator(color: AppColor.primary10).center, + ); + } + + if (assetList.isEmpty) { + return const NoDataFound().center; + } + + return ListView.separated( + padding: const EdgeInsets.all(16), + itemCount: assetList.length + 1, // +1 for the "Parents" header + separatorBuilder: (_, __) => 8.height, + itemBuilder: (context, index) { + if (index == 0) { + return Text( + "Parents", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ); + } + + final asset = assetList[index - 1]; + return TechnicalInspectionAssetCard( + assetModel: asset, + isViewOnly: viewOnly, + editPress: () async { + bool isRefreshed = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => UpdateParentAssetView( + assetModel: asset, + lineId: widget.lineId, + tableItemId: widget.tableItemId, + costCenterItemId: widget.costCenterId, + ), + ), ); + + if (isRefreshed) { + getInitialData(); + } }, - ), - ], + ); + }, ); } - } diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart index 8733e005..bb0b6ca9 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart @@ -1,46 +1,42 @@ -import 'dart:convert'; import 'dart:developer'; -import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:flutter_advanced_switch/flutter_advanced_switch.dart'; import 'package:provider/provider.dart'; -import 'package:test_sa/common_widgets/lookup_autocomplete_field.dart'; -import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/device/asset.dart'; -import 'package:test_sa/models/generic_attachment_model.dart'; -import 'package:test_sa/models/lookup.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart'; -import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; -import 'package:test_sa/modules/asset_inventory_module/pages/search_asset_view.dart'; -import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; -import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; +import 'package:test_sa/models/new_models/building.dart'; +import 'package:test_sa/models/new_models/floor.dart'; +import 'package:test_sa/models/new_models/site.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/asset_delivery_utils.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; -import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; -import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; +import 'package:test_sa/providers/gas_request_providers/site_provider.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; -import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; -import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; -import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; -import 'package:test_sa/views/widgets/requests/request_status.dart'; +import '../../../../models/new_models/department.dart'; import '../../../../new_views/common_widgets/app_filled_button.dart'; import '../../../../new_views/common_widgets/default_app_bar.dart'; -///convert this to stateless no state needed when impleminting api's +//TODO need to refactor this screen when done ... + class UpdateChildAssetView extends StatefulWidget { - ///Need to pass model here... + final TechnicalInspectionAssetModel assetModel; + final int? lineId; + final int index; + UpdateChildAssetView({ Key? key, + required this.assetModel, + required this.index, + this.lineId, }) : super(key: key); @override @@ -50,15 +46,48 @@ class UpdateChildAssetView extends StatefulWidget { class _UpdateChildAssetViewState extends State { final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); - bool viewOnly = false; + List checkList = []; + late SiteProvider siteProvider; + late AssetDeliveryProvider assetDeliveryProvider; + late TextEditingController assetNumberCtrl; + late TextEditingController serialNoCtrl; + late TextEditingController systemIdCtrl; @override void initState() { + siteProvider = Provider.of(context, listen: false); + assetDeliveryProvider = Provider.of(context, listen: false); + assetNumberCtrl = TextEditingController(); + serialNoCtrl = TextEditingController(); + systemIdCtrl = TextEditingController(); + WidgetsBinding.instance.addPostFrameCallback((_) { + populateForm(); + }); super.initState(); } + void populateForm() async { + assetDeliveryProvider.isChildAssetDataLoading = true; + assetDeliveryProvider.setChildModel(widget.assetModel); + if (widget.assetModel.site != null) { + await assetDeliveryProvider.getSiteData(siteId: widget.assetModel.site?.id, model: assetDeliveryProvider.childFormModel); + } + populateTextFields(model: assetDeliveryProvider.childFormModel); + assetDeliveryProvider.isChildAssetDataLoading = false; + } + + void populateTextFields({required TechnicalInspectionAssetModel model}) { + assetNumberCtrl.text = model.assetNumber ?? ''; + serialNoCtrl.text = model.serialNo ?? ''; + systemIdCtrl.text = model.systemId ?? ''; + setState(() {}); + } + @override void dispose() { + assetNumberCtrl.dispose(); + serialNoCtrl.dispose(); + systemIdCtrl.dispose(); super.dispose(); } @@ -72,74 +101,328 @@ class _UpdateChildAssetViewState extends State { ), body: Form( key: _formKey, - child: Column( - children: [ - SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: 'Asset Number'.addTranslation, - titleTextColor: AppColor.neutral120, - showShadow: false, - // backgroundColor: AppColor.neutral100, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, - onSelect: (status) { - if (status != null) { - // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; - setState(() {}); - } - }, - ), - 8.height, - AppTextFormField( - labelText: 'Model'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), - initialValue: '', - textAlign: TextAlign.center, - labelStyle: AppTextStyles.textFieldLabelStyle, - textInputType: TextInputType.number, - showShadow: false, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - AppTextFormField( - labelText: 'Serial Number'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), - initialValue: '', - textAlign: TextAlign.center, - labelStyle: AppTextStyles.textFieldLabelStyle, - showShadow: false, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - AppTextFormField( - labelText: 'System ID'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), - initialValue: '', - textAlign: TextAlign.center, - labelStyle: AppTextStyles.textFieldLabelStyle, - showShadow: false, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - ], - ).toShadowContainer(context, borderRadius: 20, padding: 12)) - .expanded, - FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), - ], - ), + child: Consumer(builder: (context, provider, child) { + return provider.isChildAssetDataLoading + ? const CircularProgressIndicator(color: AppColor.primary10).center + : Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + inspectionDetailsForm( + lineId: widget.lineId, + provider: provider, + ), + 8.height, + const Divider().defaultStyle(context), + 8.height, + testLines( + context: context, + ) + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12)) + .expanded, + FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), + ], + ); + }), ), ); } + Widget testLines({required BuildContext context}) { + return Row( + children: [ + Text( + "Test List", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.width, + 'web_link_icon'.toSvgAsset().onPress(() { + openInspectionChecklist(context); + }), + ], + ); + } + + /// Need to make reuseable as used in parent and child both. + + Widget inspectionDetailsForm({ + int? lineId, + required AssetDeliveryProvider provider, + }) { + TechnicalInspectionAssetModel model = provider.childFormModel; + return Column( + children: [ + AppTextFormField( + labelText: 'Asset Number'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + controller: assetNumberCtrl, + initialValue: model.assetNumber, + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + textInputType: TextInputType.number, + showShadow: false, + enable: false, + style: Theme.of(context).textTheme.titleMedium, + ).onPress(() async { + var data = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => TechnicalInspectionSearchAssetView( + lineId: lineId, + ))); + if (data != null) { + TechnicalInspectionAssetModel? assetModel = await provider.getAssetDetails(assetId: data?.id); + + if (assetModel != null) { + provider.setChildModel(assetModel); + if (assetModel.site != null) { + await provider.getSiteData(siteId: assetModel.site?.id, model: provider.childFormModel); + } + provider.setParentModel(assetModel); + log('child list length ${assetModel.childAssetList?.length}'); + populateTextFields(model: provider.childFormModel); + } + } + }), + 8.height, + AppTextFormField( + labelText: 'Serial Number'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + controller: serialNoCtrl, + initialValue: model.serialNo ?? '', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + textInputType: TextInputType.number, + showShadow: false, + onSaved: (value) { + model.serialNo = value; + }, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'System ID'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + controller: systemIdCtrl, + initialValue: model.systemId ?? '', + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + onSaved: (value) { + model.systemId = value; + }, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: 'Site', + initialValue: model.site, + loading: provider.isSiteLoading, + showAsBottomSheet: true, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + // enabled: false, + onSelect: (value) { + if (value == null) { + return; + } + model.site = value; + model.building = null; + model.floor = null; + model.department = null; + setState(() {}); + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: 'Building', + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + loading: provider.isSiteLoading, + showShadow: false, + initialValue: model.building, + enabled: model.site?.buildings?.isNotEmpty ?? false, + staticData: model.site?.buildings ?? [], + onSelect: (value) { + if (value == null) { + return; + } + model.building = value; + model.floor = null; + model.department = null; + setState(() {}); + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + showAsBottomSheet: true, + backgroundColor: AppColor.fieldBgColor(context), + loading: provider.isSiteLoading, + showShadow: false, + title: 'Floor', + initialValue: model.floor, + enabled: model.building?.floors?.isNotEmpty ?? false, + staticData: model.building?.floors ?? [], + onSelect: (value) { + if (value == null) { + return; + } + model.floor = value; + model.department = null; + setState(() {}); + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: 'Department', + backgroundColor: AppColor.fieldBgColor(context), + loading: provider.isSiteLoading, + showAsBottomSheet: true, + showShadow: false, + initialValue: model.department, + enabled: model.floor?.departments?.isNotEmpty ?? false, + staticData: model.floor?.departments ?? [], + onSelect: (value) { + if (value == null) { + return; + } + model.department = value; + model.room = null; + setState(() {}); + }, + ), + 8.height, + ADatePicker( + label: 'Installation Date'.addTranslation, + hideShadow: true, + height: 56.toScreenHeight, + backgroundColor: AppColor.fieldBgColor(context), + date: model.installationDate, + // from: widget.pickerFromDate, + formatDateWithTime: true, + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + builder: (BuildContext context, Widget? child) { + final ThemeData currentTheme = Theme.of(context); + return Theme( + data: currentTheme.copyWith( + timePickerTheme: TimePickerThemeData( + dialHandColor: AppColor.primary10, + dialBackgroundColor: Colors.grey.withOpacity(0.1), + hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), + dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), + dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), + dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), + entryModeIconColor: AppColor.primary10, + ), + textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), + ), + child: child!, + ); + }, + ).then((selectedTime) { + if (selectedTime != null) { + model.installationDate = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); + setState(() {}); + } + }); + }, + ), + 8.height, + ], + ); + } + + ///Need to check which details show here... + void _saveTap() async { - AssetInventoryProvider assetInventoryProvider = Provider.of(context, listen: false); _formKey.currentState!.save(); + //Need to check if not auto update. + // assetDeliveryProvider.parentFormModel.childAssetList?[widget.index]= assetDeliveryProvider.childFormModel; + Navigator.pop(context); + } + + Future openInspectionChecklist(BuildContext context) async { + applyInspectionFlagsToChecklist(model: assetDeliveryProvider.childFormModel); + + final result = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => InspectionChecklistBottomSheet( + initialValues: checkList, + ))); + if (result != null) { + checkList = result; + setState(() {}); + } + buildInspectionPayload(checkList); + } + + bool _isPass(List list, String title) { + return list + .firstWhere( + (e) => e.title == title, + orElse: () => InspectionChecklistItem(status: 'FAIL'), + ) + .status == + 'PASS'; + } + + buildInspectionPayload(List checklist) { + assetDeliveryProvider.childFormModel.flagphysicalInspection = _isPass(checklist, 'Physical Inspection As Per Manufacturer Instructions'); + assetDeliveryProvider.childFormModel.flagFunctionPerformance = _isPass(checklist, 'Functional Performance As Per Results Of Manufacturer Recommended Check List'); + assetDeliveryProvider.childFormModel.flagGroundingResistance = _isPass(checklist, 'Grounding Resistance: Ω'); + assetDeliveryProvider.childFormModel.flagChassiss = _isPass(checklist, 'Chassis Leakage Current: µA'); + assetDeliveryProvider.childFormModel.flagLeadsLeakage = _isPass(checklist, 'Leads Leakage Current: µA'); + assetDeliveryProvider.childFormModel.flagAlert = _isPass(checklist, 'This Device Is Not Subject To Any Alert Or Recall Until The Date Of Preparation Of This Inspection Form'); + } + + void applyInspectionFlagsToChecklist({ + required TechnicalInspectionAssetModel model, + }) { + if (checkList.isEmpty) { + checkList = AssetDeliveryUtils.inspectionChecklist; + } + for (final item in checkList) { + switch (item.value) { + case 'flagphysicalInspection': + item.status = _statusFromBool(model.flagphysicalInspection); + break; + + case 'flagFunctionPerformance': + item.status = _statusFromBool(model.flagFunctionPerformance); + break; + + case 'flagGroundingResistance': + item.status = _statusFromBool(model.flagGroundingResistance); + break; + + case 'flagChassiss': + item.status = _statusFromBool(model.flagChassiss); + break; + + case 'flagLeadsLeakage': + item.status = _statusFromBool(model.flagLeadsLeakage); + break; + + case 'flagAlert': + item.status = _statusFromBool(model.flagAlert); + break; + } + } + } + + String _statusFromBool(bool? value) { + return value == true ? 'PASS' :value==false? 'FAIL':''; } } diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart index 4ff14e0a..8bac4319 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart @@ -1,45 +1,47 @@ -import 'dart:convert'; import 'dart:developer'; -import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:flutter_advanced_switch/flutter_advanced_switch.dart'; import 'package:provider/provider.dart'; -import 'package:test_sa/common_widgets/lookup_autocomplete_field.dart'; -import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/device/asset.dart'; -import 'package:test_sa/models/generic_attachment_model.dart'; -import 'package:test_sa/models/lookup.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; +import 'package:test_sa/models/new_models/building.dart'; +import 'package:test_sa/models/new_models/floor.dart'; +import 'package:test_sa/models/new_models/site.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/asset_delivery_utils.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart'; -import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; -import 'package:test_sa/modules/asset_inventory_module/pages/search_asset_view.dart'; -import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; -import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; -import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; +import 'package:test_sa/providers/gas_request_providers/site_provider.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; -import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; -import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; -import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; -import 'package:test_sa/views/widgets/requests/request_status.dart'; +import '../../../../models/new_models/department.dart'; import '../../../../new_views/common_widgets/app_filled_button.dart'; import '../../../../new_views/common_widgets/default_app_bar.dart'; +//TODO need to refactor this screen also add loaders when done ... + class UpdateParentAssetView extends StatefulWidget { + final TechnicalInspectionAssetModel assetModel; + final int? lineId; + final int? tableItemId; + final int? costCenterItemId; + UpdateParentAssetView({ Key? key, + required this.assetModel, + this.lineId, + this.tableItemId, + this.costCenterItemId, }) : super(key: key); @override @@ -49,15 +51,52 @@ class UpdateParentAssetView extends StatefulWidget { class _UpdateParentAssetViewState extends State { final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); - bool viewOnly = false; + List checkList = []; + late SiteProvider siteProvider; + late AssetDeliveryProvider assetDeliveryProvider; + late TextEditingController assetNumberCtrl; + late TextEditingController serialNoCtrl; + late TextEditingController systemIdCtrl; @override void initState() { + siteProvider = Provider.of(context, listen: false); + assetDeliveryProvider = Provider.of(context, listen: false); + assetNumberCtrl = TextEditingController(); + serialNoCtrl = TextEditingController(); + systemIdCtrl = TextEditingController(); + WidgetsBinding.instance.addPostFrameCallback((_) { + populateForm(); + }); super.initState(); } + void populateForm() async { + assetDeliveryProvider.isLoading = true; + assetDeliveryProvider.setParentModel(widget.assetModel); + if (widget.assetModel.site != null) { + await assetDeliveryProvider.getSiteData(siteId: widget.assetModel.site?.id, model: assetDeliveryProvider.parentFormModel); + } else { + if (siteProvider.items.isEmpty) { + await siteProvider.getData(); + } + } + populateTextFields(model: assetDeliveryProvider.parentFormModel); + assetDeliveryProvider.isLoading = false; + } + + void populateTextFields({required TechnicalInspectionAssetModel model}) { + assetNumberCtrl.text = model.assetNumber ?? ''; + serialNoCtrl.text = model.serialNo ?? ''; + systemIdCtrl.text = model.systemId ?? ''; + setState(() {}); + } + @override void dispose() { + assetNumberCtrl.dispose(); + serialNoCtrl.dispose(); + systemIdCtrl.dispose(); super.dispose(); } @@ -71,127 +110,241 @@ class _UpdateParentAssetViewState extends State { ), body: Form( key: _formKey, - child: Column( - children: [ - SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - inspectionDetailsForm(), - 8.height, - const Divider().defaultStyle(context), - 8.height, - childList(context), - ], - ).toShadowContainer(context, borderRadius: 20, padding: 12)) - .expanded, - FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), - ], - ), + child: Consumer(builder: (context, provider, child) { + return provider.isLoading + ? const CircularProgressIndicator(color: AppColor.primary10).center + : Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + inspectionDetailsForm(lineId: widget.lineId, provider: provider), + 8.height, + const Divider().defaultStyle(context), + 8.height, + Row( + children: [ + Text( + "Test List", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.width, + 'web_link_icon'.toSvgAsset().onPress(() { + openInspectionChecklist(context); + }), + ], + ), + 8.height, + childList( + context: context, + provider: provider, + ) + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12)) + .expanded, + FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), + ], + ); + }), ), ); } - Widget childList(BuildContext context) { - final assetDeliveryTableList = ['abc', 'def', 'ghi', 'fhg', 'hjhh']; - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Text( - "Test List", - style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), - ), - 8.width, - 'web_link_icon'.toSvgAsset().onPress((){ - ///Open webview... - }), - ], - ), - 8.height, - ListView.separated( - itemCount: assetDeliveryTableList.length, - separatorBuilder: (_, __) => 8.height, - padding: EdgeInsets.zero, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (listContext, itemIndex) { - return TechnicalInspectionAssetCard( - assetModel: Asset(), - ischild: true, - editPress: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => UpdateChildAssetView())); - }, - isViewOnly: viewOnly, - ); + Widget childList({required BuildContext context, required AssetDeliveryProvider provider}) { + final List assetDeliveryTableList = provider.parentFormModel.childAssetList ?? []; + return ListView.separated( + itemCount: assetDeliveryTableList.length, + separatorBuilder: (_, __) => 8.height, + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (listContext, itemIndex) { + TechnicalInspectionAssetModel model = assetDeliveryTableList[itemIndex]; + return TechnicalInspectionAssetCard( + assetModel: model, + ischild: true, + editPress: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => UpdateChildAssetView( + assetModel: model, + index: itemIndex, + ))); }, - ), - ], + isViewOnly: false, + ); + }, ); } - Widget inspectionDetailsForm() { + /// Need to make reuseable as used in parent and child both. + + Widget inspectionDetailsForm({ + int? lineId, + required AssetDeliveryProvider provider, + }) { + TechnicalInspectionAssetModel model = provider.parentFormModel; return Column( children: [ - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: 'Asset Number'.addTranslation, - titleTextColor: AppColor.neutral120, - showShadow: false, - // backgroundColor: AppColor.neutral100, + //Replace with simple container... + AppTextFormField( + labelText: 'Asset Number'.addTranslation, backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, - onSelect: (status) { - if (status != null) { - // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; - setState(() {}); + controller: assetNumberCtrl, + initialValue: model.assetNumber, + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + textInputType: TextInputType.number, + showShadow: false, + enable: false, + style: Theme.of(context).textTheme.titleMedium, + ).onPress(() async { + var data = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => TechnicalInspectionSearchAssetView( + lineId: lineId, + ))); + if (data != null) { + TechnicalInspectionAssetModel? assetModel = await provider.getAssetDetails(assetId: data?.id); + + if (assetModel != null) { + provider.setParentModel(assetModel); + if (assetModel.site != null) { + await provider.getSiteData(siteId: assetModel.site?.id, model: provider.parentFormModel); + } + assetModel.assetDeliveryInternalDetailAssetId = assetModel.id; + assetModel.id = 0; + provider.setParentModel(assetModel); + log('child list length ${assetModel.childAssetList?.length}'); + populateTextFields(model: provider.parentFormModel); } - }, - ), + } + }), 8.height, AppTextFormField( labelText: 'Serial Number'.addTranslation, backgroundColor: AppColor.fieldBgColor(context), - initialValue: '', + controller: serialNoCtrl, + initialValue: model.serialNo ?? '', textAlign: TextAlign.center, labelStyle: AppTextStyles.textFieldLabelStyle, textInputType: TextInputType.number, showShadow: false, + onSaved: (value) { + model.serialNo = value; + }, style: Theme.of(context).textTheme.titleMedium, ), 8.height, AppTextFormField( labelText: 'System ID'.addTranslation, backgroundColor: AppColor.fieldBgColor(context), - initialValue: '', + controller: systemIdCtrl, + initialValue: model.systemId ?? '', textAlign: TextAlign.center, labelStyle: AppTextStyles.textFieldLabelStyle, showShadow: false, + onSaved: (value) { + model.systemId = value; + }, style: Theme.of(context).textTheme.titleMedium, ), 8.height, - AppTextFormField( - labelText: 'Medical Department'.addTranslation, + SingleItemDropDownMenu( + context: context, + title: 'Site', + initialValue: model.site, + loading: provider.isSiteLoading, + showAsBottomSheet: true, backgroundColor: AppColor.fieldBgColor(context), - initialValue: '', - textAlign: TextAlign.center, - labelStyle: AppTextStyles.textFieldLabelStyle, showShadow: false, - style: Theme.of(context).textTheme.titleMedium, + // enabled: false, + onSelect: (value) { + if (value == null) { + return; + } + model.site = value; + model.building = null; + model.floor = null; + model.department = null; + setState(() {}); + }, ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: 'Building', + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + loading: provider.isSiteLoading, + showShadow: false, + initialValue: model.building, + enabled: model.site?.buildings?.isNotEmpty ?? false, + staticData: model.site?.buildings ?? [], + onSelect: (value) { + if (value == null) { + return; + } + model.building = value; + model.floor = null; + model.department = null; + setState(() {}); + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + showAsBottomSheet: true, + backgroundColor: AppColor.fieldBgColor(context), + loading: provider.isSiteLoading, + showShadow: false, + title: 'Floor', + initialValue: model.floor, + enabled: model.building?.floors?.isNotEmpty ?? false, + staticData: model.building?.floors ?? [], + onSelect: (value) { + if (value == null) { + return; + } + model.floor = value; + model.department = null; + setState(() {}); + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: 'Department', + backgroundColor: AppColor.fieldBgColor(context), + loading: provider.isSiteLoading, + showAsBottomSheet: true, + showShadow: false, + initialValue: model.department, + enabled: model.floor?.departments?.isNotEmpty ?? false, + staticData: model.floor?.departments ?? [], + onSelect: (value) { + if (value == null) { + return; + } + model.department = value; + model.room = null; + setState(() {}); + }, + ), + 8.height, ADatePicker( label: 'Installation Date'.addTranslation, hideShadow: true, height: 56.toScreenHeight, backgroundColor: AppColor.fieldBgColor(context), - // date: _pickerStartAt, - // from: widget.pickerFromDate, + date: model.installationDate, + //Need to check whare the picker start for now start from start of year + from: DateTime(DateTime.now().year, 1, 1), formatDateWithTime: true, onDatePicker: (selectedDate) { showTimePicker( @@ -217,34 +370,13 @@ class _UpdateParentAssetViewState extends State { }, ).then((selectedTime) { if (selectedTime != null) { - // _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); - // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { - // "Start time is before the request time.".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } - // if (_pickerStartAt!.isAfter(DateTime.now())) { - // "Start time is after than current time".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } + model.installationDate = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); setState(() {}); } }); }, ), 8.height, - AppTextFormField( - labelText: 'Asset Type'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), - initialValue: '', - textAlign: TextAlign.center, - labelStyle: AppTextStyles.textFieldLabelStyle, - showShadow: false, - style: Theme.of(context).textTheme.titleMedium, - ), ], ); } @@ -252,7 +384,541 @@ class _UpdateParentAssetViewState extends State { ///Need to check which details show here... void _saveTap() async { - AssetInventoryProvider assetInventoryProvider = Provider.of(context, listen: false); _formKey.currentState!.save(); + assetDeliveryProvider.parentFormModel.lineId = widget.lineId; + + assetDeliveryProvider.parentFormModel.tableItemId = widget.tableItemId; + assetDeliveryProvider.parentFormModel.costCenterId = widget.costCenterItemId; + log('model data ${assetDeliveryProvider.parentFormModel.toJson()}'); + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + await assetDeliveryProvider.saveTechnicalInspectionAssetData(model: assetDeliveryProvider.parentFormModel).then((status) async { + Navigator.pop(context); + if (status) { + Navigator.pop(context, true); + } + }); + } + + Future openInspectionChecklist(BuildContext context) async { + applyInspectionFlagsToChecklist(model: assetDeliveryProvider.parentFormModel); + final result = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => InspectionChecklistBottomSheet( + initialValues: checkList, + ))); + + if (result != null) { + checkList = result; + setState(() {}); + } + buildInspectionPayload(checkList); + if (checkList.isNotEmpty) { + final isPass = checkList.every((e) => e.status == 'PASS'); + log('Final Status: ${isPass ? 'PASS' : 'FAIL'}'); + } + +// call this as bottomsheet. + // final result = await showModalBottomSheet>>( + // context: context, + // isScrollControlled: true, + // backgroundColor: Colors.transparent, + // builder: (_) => const InspectionChecklistBottomSheet(), + // ); + } + + bool _isPass(List list, String title) { + return list + .firstWhere( + (e) => e.title == title, + orElse: () => InspectionChecklistItem(status: 'FAIL'), + ) + .status == + 'PASS'; + } + + buildInspectionPayload(List checklist) { + assetDeliveryProvider.parentFormModel.flagphysicalInspection = _isPass(checklist, 'Physical Inspection As Per Manufacturer Instructions'); + assetDeliveryProvider.parentFormModel.flagFunctionPerformance = _isPass(checklist, 'Functional Performance As Per Results Of Manufacturer Recommended Check List'); + assetDeliveryProvider.parentFormModel.flagGroundingResistance = _isPass(checklist, 'Grounding Resistance: Ω'); + assetDeliveryProvider.parentFormModel.flagChassiss = _isPass(checklist, 'Chassis Leakage Current: µA'); + assetDeliveryProvider.parentFormModel.flagLeadsLeakage = _isPass(checklist, 'Leads Leakage Current: µA'); + assetDeliveryProvider.parentFormModel.flagAlert = _isPass(checklist, 'This Device Is Not Subject To Any Alert Or Recall Until The Date Of Preparation Of This Inspection Form'); + } + + void applyInspectionFlagsToChecklist({ + required TechnicalInspectionAssetModel model, + }) { + if (checkList.isEmpty) { + checkList = AssetDeliveryUtils.inspectionChecklist; + } + for (final item in checkList) { + switch (item.value) { + case 'flagphysicalInspection': + item.status = _statusFromBool(model.flagphysicalInspection); + break; + + case 'flagFunctionPerformance': + item.status = _statusFromBool(model.flagFunctionPerformance); + break; + + case 'flagGroundingResistance': + item.status = _statusFromBool(model.flagGroundingResistance); + break; + + case 'flagChassiss': + item.status = _statusFromBool(model.flagChassiss); + break; + + case 'flagLeadsLeakage': + item.status = _statusFromBool(model.flagLeadsLeakage); + break; + + case 'flagAlert': + item.status = _statusFromBool(model.flagAlert); + break; + } + } + checkList.forEach((item) { + log('items ${item.toJson()}'); + }); + } + + String _statusFromBool(bool? value) { + return value == true ? 'PASS' : 'FAIL'; } } + +// import 'dart:developer'; +// 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/string_extensions.dart'; +// import 'package:test_sa/extensions/text_extensions.dart'; +// import 'package:test_sa/extensions/widget_extensions.dart'; +// import 'package:test_sa/models/new_models/building.dart'; +// import 'package:test_sa/models/new_models/floor.dart'; +// import 'package:test_sa/models/new_models/site.dart'; +// import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart'; +// import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart'; +// import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart'; +// import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart'; +// import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart'; +// import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; +// import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +// import 'package:test_sa/new_views/app_style/app_color.dart'; +// import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +// import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +// import 'package:test_sa/providers/gas_request_providers/site_provider.dart'; +// import 'package:test_sa/providers/loading_list_notifier.dart'; +// import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +// import '../../../../models/new_models/department.dart'; +// import '../../../../new_views/common_widgets/app_filled_button.dart'; +// import '../../../../new_views/common_widgets/default_app_bar.dart'; +// +// //TODO need to refactor this screen when done ... +// +// class UpdateParentAssetView extends StatefulWidget { +// final TechnicalInspectionParentAssetModel assetModel; +// final int? lineId; +// +// UpdateParentAssetView({ +// Key? key, +// required this.assetModel, +// this.lineId, +// }) : super(key: key); +// +// @override +// State createState() => _UpdateParentAssetViewState(); +// } +// +// class _UpdateParentAssetViewState extends State { +// final GlobalKey _formKey = GlobalKey(); +// final GlobalKey _scaffoldKey = GlobalKey(); +// List checkList = []; +// late SiteProvider siteProvider; +// late AssetDeliveryProvider assetDeliveryProvider; +// +// @override +// void initState() { +// siteProvider = Provider.of(context, listen: false); +// assetDeliveryProvider = Provider.of(context, listen: false); +// // WidgetsBinding.instance.addPostFrameCallback((_) { +// populateForm(); +// // }); +// super.initState(); +// } +// +// void populateForm() async { +// // _model = widget.assetModel; +// assetDeliveryProvider.setModel(widget.assetModel); +// applyInspectionFlagsToChecklist(model: widget.assetModel,checklist: checkList); +// if (widget.assetModel.site != null) { +// await assetDeliveryProvider.getSiteData(siteId: widget.assetModel.site?.id, model: _model); +// } +// setState(() {}); +// } +// +// @override +// void dispose() { +// super.dispose(); +// } +// +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// key: _scaffoldKey, +// appBar: DefaultAppBar( +// title: 'Parent Details'.addTranslation, +// titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), +// ), +// body: Form( +// key: _formKey, +// child: Column( +// children: [ +// SingleChildScrollView( +// padding: const EdgeInsets.all(16), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// inspectionDetailsForm(lineId: widget.lineId), +// 8.height, +// const Divider().defaultStyle(context), +// 8.height, +// childList(context), +// ], +// ).toShadowContainer(context, borderRadius: 20, padding: 12)) +// .expanded, +// FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), +// ], +// ), +// ), +// ); +// } +// +// Widget childList(BuildContext context) { +// final assetDeliveryTableList = ['abc', 'def', 'ghi', 'fhg', 'hjhh']; +// return Column( +// mainAxisSize: MainAxisSize.min, +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Row( +// children: [ +// Text( +// "Test List", +// style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), +// ), +// 8.width, +// 'web_link_icon'.toSvgAsset().onPress(() { +// openInspectionChecklist(context); +// }), +// ], +// ), +// 8.height, +// ListView.separated( +// itemCount: assetDeliveryTableList.length, +// separatorBuilder: (_, __) => 8.height, +// padding: EdgeInsets.zero, +// shrinkWrap: true, +// physics: const NeverScrollableScrollPhysics(), +// itemBuilder: (listContext, itemIndex) { +// return TechnicalInspectionAssetCard( +// assetModel: TechnicalInspectionParentAssetModel(), +// ischild: true, +// editPress: () { +// Navigator.push(context, MaterialPageRoute(builder: (context) => UpdateChildAssetView())); +// }, +// isViewOnly: false, +// ); +// }, +// ), +// ], +// ); +// } +// +// Widget inspectionDetailsForm({int? lineId}) { +// return Column( +// children: [ +// //Replace with simple container... +// AppTextFormField( +// labelText: 'Asset Number'.addTranslation, +// backgroundColor: AppColor.fieldBgColor(context), +// initialValue: _model.assetNumber, +// textAlign: TextAlign.center, +// labelStyle: AppTextStyles.textFieldLabelStyle, +// textInputType: TextInputType.number, +// showShadow: false, +// enable: false, +// style: Theme.of(context).textTheme.titleMedium, +// ).onPress(() async { +// var data = await Navigator.push( +// context, +// MaterialPageRoute( +// builder: (context) => TechnicalInspectionSearchAssetView( +// lineId: lineId, +// ))); +// if (data != null) { +// TechnicalInspectionParentAssetModel? assetModel = await assetDeliveryProvider.getAssetDetails(assetId: data?.id); +// +// if (assetModel != null) { +// _model =TechnicalInspectionParentAssetModel(); +// setState(() { +// +// }); +// setState(() { +// _model = assetModel; +// }); +// if (assetModel.site != null) { +// await assetDeliveryProvider.getSiteData(siteId: assetModel.site?.id, model: _model); +// } +// setState(() {}); +// } +// } +// }), +// 8.height, +// AppTextFormField( +// labelText: 'Serial Number'.addTranslation, +// backgroundColor: AppColor.fieldBgColor(context), +// initialValue: _model.serialNo ?? '', +// textAlign: TextAlign.center, +// labelStyle: AppTextStyles.textFieldLabelStyle, +// textInputType: TextInputType.number, +// showShadow: false, +// onSaved: (value) { +// _model.serialNo = value; +// }, +// style: Theme.of(context).textTheme.titleMedium, +// ), +// 8.height, +// AppTextFormField( +// labelText: 'System ID'.addTranslation, +// backgroundColor: AppColor.fieldBgColor(context), +// initialValue: _model.systemId ?? '', +// textAlign: TextAlign.center, +// labelStyle: AppTextStyles.textFieldLabelStyle, +// showShadow: false, +// onSaved: (value) { +// _model.systemId = value; +// }, +// style: Theme.of(context).textTheme.titleMedium, +// ), +// 8.height, +// SingleItemDropDownMenu( +// context: context, +// title: 'Site', +// initialValue: _model.site, +// loading: assetDeliveryProvider.isSiteLoading, +// showAsBottomSheet: true, +// backgroundColor: AppColor.fieldBgColor(context), +// showShadow: false, +// // enabled: false, +// onSelect: (value) { +// if (value == null) { +// return; +// } +// _model.site = value; +// _model.building = null; +// _model.floor = null; +// _model.department = null; +// setState(() {}); +// }, +// ), +// 8.height, +// SingleItemDropDownMenu( +// context: context, +// title: 'Building', +// backgroundColor: AppColor.fieldBgColor(context), +// showAsBottomSheet: true, +// loading: assetDeliveryProvider.isSiteLoading, +// showShadow: false, +// initialValue: _model.building, +// enabled: _model.site?.buildings?.isNotEmpty ?? false, +// staticData: _model.site?.buildings ?? [], +// onSelect: (value) { +// if (value == null) { +// return; +// } +// _model.building = value; +// _model.floor = null; +// _model.department = null; +// setState(() {}); +// }, +// ), +// 8.height, +// SingleItemDropDownMenu( +// context: context, +// showAsBottomSheet: true, +// backgroundColor: AppColor.fieldBgColor(context), +// loading: assetDeliveryProvider.isSiteLoading, +// showShadow: false, +// title: 'Floor', +// initialValue: _model.floor, +// enabled: _model.building?.floors?.isNotEmpty ?? false, +// staticData: _model.building?.floors ?? [], +// onSelect: (value) { +// if (value == null) { +// return; +// } +// _model.floor = value; +// _model.department = null; +// setState(() {}); +// }, +// ), +// 8.height, +// SingleItemDropDownMenu( +// context: context, +// title: 'Department', +// backgroundColor: AppColor.fieldBgColor(context), +// loading: assetDeliveryProvider.isSiteLoading, +// showAsBottomSheet: true, +// showShadow: false, +// initialValue: _model.department, +// enabled: _model.floor?.departments?.isNotEmpty ?? false, +// staticData: _model.floor?.departments ?? [], +// onSelect: (value) { +// if (value == null) { +// return; +// } +// _model.department = value; +// _model.room = null; +// setState(() {}); +// }, +// ), +// +// 8.height, +// ADatePicker( +// label: 'Installation Date'.addTranslation, +// hideShadow: true, +// height: 56.toScreenHeight, +// backgroundColor: AppColor.fieldBgColor(context), +// date: _model.installationDate, +// // from: widget.pickerFromDate, +// formatDateWithTime: true, +// onDatePicker: (selectedDate) { +// showTimePicker( +// context: context, +// initialTime: TimeOfDay.now(), +// builder: (BuildContext context, Widget? child) { +// final ThemeData currentTheme = Theme.of(context); +// return Theme( +// data: currentTheme.copyWith( +// timePickerTheme: TimePickerThemeData( +// dialHandColor: AppColor.primary10, +// dialBackgroundColor: Colors.grey.withOpacity(0.1), +// hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), +// dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), +// dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), +// dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), +// entryModeIconColor: AppColor.primary10, +// ), +// textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), +// ), +// child: child!, +// ); +// }, +// ).then((selectedTime) { +// if (selectedTime != null) { +// _model.installationDate = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); +// setState(() {}); +// } +// }); +// }, +// ), +// 8.height, +// ], +// ); +// } +// +// ///Need to check which details show here... +// +// void _saveTap() async { +// _formKey.currentState!.save(); +// } +// +// Future openInspectionChecklist(BuildContext context) async { +// final result = await Navigator.push( +// context, +// MaterialPageRoute( +// builder: (context) => InspectionChecklistBottomSheet( +// initialValues: checkList, +// ))); +// +// log('result i got is $result'); +// if(result!=null){ +// checkList = result; +// setState(() {}); +// } +// if (checkList.isNotEmpty) { +// final isPass = checkList.every((e) => e.status == 'PASS'); +// log('Final Status: ${isPass ? 'PASS' : 'FAIL'}'); +// } +// final payload = buildInspectionPayload(checkList); +// +// log('API Payload: $payload'); +// // call this as bottomsheet. +// // final result = await showModalBottomSheet>>( +// // context: context, +// // isScrollControlled: true, +// // backgroundColor: Colors.transparent, +// // builder: (_) => const InspectionChecklistBottomSheet(), +// // ); +// } +// +// bool _isPass(List list, String title) { +// return list +// .firstWhere( +// (e) => e.title == title, +// orElse: () => InspectionChecklistItem(status: 'FAIL'), +// ) +// .status == +// 'PASS'; +// } +// +// Map buildInspectionPayload(List checklist) { +// return { +// 'flagphysicalInspection': _isPass(checklist, 'Physical Inspection As Per Manufacturer Instructions'), +// 'flagFunctionPerformance': _isPass(checklist, 'Functional Performance As Per Results Of Manufacturer Recommended Check List'), +// 'flagGroundingResistance': _isPass(checklist, 'Grounding Resistance: Ω'), +// 'flagChassiss': _isPass(checklist, 'Chassis Leakage Current: µA'), +// 'flagLeadsLeakage': _isPass(checklist, 'Leads Leakage Current: µA'), +// 'flagAlert': _isPass(checklist, 'This Device Is Not Subject To Any Alert Or Recall Until The Date Of Preparation Of This Inspection Form'), +// }; +// } +// +// void applyInspectionFlagsToChecklist({ +// required List checklist, +// required TechnicalInspectionParentAssetModel model, +// }) { +// for (final item in checklist) { +// switch (item.title) { +// case 'Physical Inspection As Per Manufacturer Instructions': +// item.status = _statusFromBool(model.flagphysicalInspection); +// break; +// +// case 'Functional Performance As Per Results Of Manufacturer Recommended Check List': +// item.status = _statusFromBool(model.flagFunctionPerformance); +// break; +// +// case 'Grounding Resistance: Ω': +// item.status = _statusFromBool(model.flagGroundingResistance); +// break; +// +// case 'Chassis Leakage Current: µA': +// item.status = _statusFromBool(model.flagChassiss); +// break; +// +// case 'Leads Leakage Current: µA': +// item.status = _statusFromBool(model.flagLeadsLeakage); +// break; +// +// case 'This Device Is Not Subject To Any Alert Or Recall Until The Date Of Preparation Of This Inspection Form': +// item.status = _statusFromBool(model.flagAlert); +// break; +// } +// } +// } +// String _statusFromBool(bool? value) { +// return value == true ? 'PASS' : 'FAIL'; +// } +// } diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart index d13ab6b3..f64f1461 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart @@ -1,44 +1,41 @@ -import 'dart:convert'; import 'dart:developer'; -import 'dart:io'; + import 'package:flutter/material.dart'; -import 'package:flutter_advanced_switch/flutter_advanced_switch.dart'; import 'package:provider/provider.dart'; -import 'package:test_sa/common_widgets/lookup_autocomplete_field.dart'; -import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_form_model.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart'; -import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; -import 'package:test_sa/modules/asset_inventory_module/pages/search_asset_view.dart'; -import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; -import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/power_supply_type_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; -import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; -import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; -import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; -import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; -import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; -import 'package:test_sa/views/widgets/requests/request_status.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import '../../../../new_views/common_widgets/app_filled_button.dart'; import '../../../../new_views/common_widgets/default_app_bar.dart'; class UpdateTechnicalInspectionLinesView extends StatefulWidget { static const String id = "/technical-inspection-form"; + final AssetDeliveryTableModel deliveryTableModel; + final AssetDeliveryDataModel? requestModel; + final DeliveryLineModel? deliveryLineModel; UpdateTechnicalInspectionLinesView({ Key? key, + required this.deliveryTableModel, + this.requestModel, + this.deliveryLineModel, }) : super(key: key); @override @@ -48,9 +45,15 @@ class UpdateTechnicalInspectionLinesView extends StatefulWidget { class _UpdateTechnicalInspectionLinesViewState extends State { final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); + TechnicalInspectionFormModel model = TechnicalInspectionFormModel(); + AssetDeliveryProvider? assetDeliveryProvider; + bool isLoading = false; @override void initState() { + WidgetsBinding.instance.addPostFrameCallback((_) { + getInitialData(); + }); super.initState(); } @@ -59,6 +62,18 @@ class _UpdateTechnicalInspectionLinesViewState extends State(context, listen: false); + isLoading = true; + setState(() {}); + model = await assetDeliveryProvider!.getTechnicalInspectionData( + lineId: widget.deliveryLineModel?.id, + tableId: widget.deliveryTableModel.id, + ); + isLoading = false; + setState(() {}); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -69,53 +84,87 @@ class _UpdateTechnicalInspectionLinesViewState extends State costCenterList = model.costCenters ?? []; + return costCenterList.isEmpty + ? const NoDataFound().center + : ListView.separated( + itemCount: costCenterList.length, + separatorBuilder: (_, __) => 8.height, + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (listContext, itemIndex) { + return TechnicalInspectionCostCard( + costModel: costCenterList[itemIndex], + editPress: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => TechnicalInspectionParentAssetListView( + costCenterId: costCenterList[itemIndex].id, + tableItemId: widget.deliveryTableModel.id, + lineId: widget.deliveryLineModel?.id, + ))); + }, + isViewOnly: false, + ); + }, + ); + } + + Widget itemDetails({required BuildContext context, String? itemNo, String? itemDescription}) { return Column( - mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Cost Centers", - style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + 'Item No'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), ), 8.height, - ListView.separated( - itemCount: assetDeliveryTableList.length, - separatorBuilder: (_, __) => 8.height, - padding: EdgeInsets.zero, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (listContext, itemIndex) { - return TechnicalInspectionCostCard( - deliveryDetails: AssetInventoryModel(), - editPress: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => TechnicalInspectionParentAssetListView())); - }, - isViewOnly: false, - ); - }, + Text( + itemNo ?? '-', + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Item Description'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + itemDescription ?? '-', + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), ), ], ); @@ -124,81 +173,60 @@ class _UpdateTechnicalInspectionLinesViewState extends State( + SingleItemDropDownMenu( context: context, height: 56.toScreenHeight, title: 'Power Supply Type'.addTranslation, titleTextColor: AppColor.neutral120, showShadow: false, - // backgroundColor: AppColor.neutral100, backgroundColor: AppColor.fieldBgColor(context), showAsBottomSheet: true, - // initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus, - onSelect: (status) { - if (status != null) { - // requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status; + initialValue: model.powerSupplyType, + onSelect: (value) { + if (value != null) { + model.powerSupplyType = value; setState(() {}); } }, ), - // 8.height, - // LookUpAutoCompleteField( - // clearAfterPick: false, - // forAssetName: true, - // onChanged: (value) {}, - // initialValue: '', - // label: 'Cost Center'.addTranslation, - // onPick: (value) {}, - // ), 8.height, AppTextFormField( labelText: 'Power Reading'.addTranslation, backgroundColor: AppColor.fieldBgColor(context), - initialValue: '', + initialValue: model.powerReading != null ? model.powerReading.toString() : '', textAlign: TextAlign.center, labelStyle: AppTextStyles.textFieldLabelStyle, textInputType: TextInputType.number, showShadow: false, + onSaved: (value) { + model.powerReading = int.tryParse(value); + }, style: Theme.of(context).textTheme.titleMedium, ), 8.height, AppTextFormField( labelText: 'Max Current'.addTranslation, backgroundColor: AppColor.fieldBgColor(context), - initialValue: '', + initialValue: model.maxCurrent != null ? model.maxCurrent.toString() : '', textAlign: TextAlign.center, labelStyle: AppTextStyles.textFieldLabelStyle, + textInputType: TextInputType.number, showShadow: false, + onSaved: (value) { + model.maxCurrent = int.tryParse(value); + }, style: Theme.of(context).textTheme.titleMedium, ), 8.height, AppTextFormField( labelText: 'Voltage'.addTranslation, backgroundColor: AppColor.fieldBgColor(context), - initialValue: '', + textInputType: TextInputType.number, + initialValue: model.voltage != null ? model.voltage.toString() : '', textAlign: TextAlign.center, + onSaved: (value) { + model.voltage = int.tryParse(value); + }, labelStyle: AppTextStyles.textFieldLabelStyle, showShadow: false, style: Theme.of(context).textTheme.titleMedium, @@ -207,8 +235,12 @@ class _UpdateTechnicalInspectionLinesViewState extends State(context, listen: false); _formKey.currentState!.save(); + model.tableItemId = widget.deliveryTableModel.id; + model.lineId = widget.deliveryLineModel?.id; + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + await assetDeliveryProvider?.saveTechnicalInspection(model: model).then((status) async { + Navigator.pop(context); + if (status) { + Navigator.pop(context); + } + }); } } diff --git a/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart b/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart index b87e092c..a9dedb0d 100644 --- a/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart +++ b/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart @@ -1,294 +1,267 @@ 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/device/asset.dart'; -import 'package:test_sa/models/device/asset_search.dart'; -import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/module_permissions_model.dart'; -import 'package:test_sa/models/service_request/pending_service_request_model.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/service_request_search.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 'package:test_sa/models/timer_model.dart'; -import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; -import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; - -import '../../../models/service_request/search_work_order.dart'; -import '../../../models/service_request/wo_call_request.dart'; -import '../../../models/user.dart'; -import '../../../new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/models/new_models/building.dart'; +import 'package:test_sa/models/new_models/floor.dart'; +import 'package:test_sa/models/new_models/room_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/delivery_inspection_form_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/end_user_asset_details_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/history_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_form_model.dart'; +import '../../../models/new_models/department.dart'; +import '../../../models/new_models/site.dart'; +import '../models/oracle_user_model.dart'; class AssetDeliveryProvider extends ChangeNotifier { final pageItemNumber = 10; final searchPageItemNumber = 10; int pageNo = 1; - List _devices = []; - List _searchDevices = []; - - List get devices => _devices; - - List get searchDevices => _searchDevices; - SessionModel? sessionModel; - - //TODO need to check i think don't need to create this obj - AssetInventoryResponse? assetInventoryResponse; - AssetInventoryResponse? siteFilterAssetResponse; - - List sessionAssetList = []; - List siteFilterAssetList = []; - + AssetDeliveryDataModel? assetDeliveryDataModel; + List assetDeliveryTableList = []; + List deliveryLinesList = []; ModulesPermissionsModel? modelPermission; + TechnicalInspectionAssetModel parentFormModel = TechnicalInspectionAssetModel(); + TechnicalInspectionAssetModel childFormModel = TechnicalInspectionAssetModel(); void reset() { pageNo = 1; - modelPermission = null; - assetInventoryResponse = null; - sessionModel = null; - sessionAssetList = []; stateCode = null; } int? stateCode; bool isDetailLoading = false; bool nextPage = false; - bool isNextPageLoading = false; bool isLoading = false; - bool isAllAssetLoading = false; + bool isSiteLoading = false; + bool isDeliveryTableListLoading = false; + bool isDeliveryLineListLoading = false; + bool isChildAssetDataLoading = false; - void searchReset() { - stateCode = null; - _searchDevices = []; + void setParentModel(TechnicalInspectionAssetModel m) { + parentFormModel = m; + notifyListeners(); + } + + void setChildModel(TechnicalInspectionAssetModel m) { + childFormModel = m; + notifyListeners(); } - Future getSessionById({required int id}) async { + Future getAssetDeliveryDetailById({int? requestId}) async { try { - sessionModel = SessionModel(); + assetDeliveryDataModel = AssetDeliveryDataModel(); isLoading = true; notifyListeners(); - final response = await ApiManager.instance.get(URLs.getAssetInventoryById + "?assetInventoryId=$id"); + final response = await ApiManager.instance.get(URLs.getAssetDeliveryDetailsById + "?Id=$requestId"); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { - sessionModel = SessionModel.fromJson(json.decode(response.body)["data"]); + assetDeliveryDataModel = AssetDeliveryDataModel.fromJson(json.decode(response.body)["data"]); } else { - sessionModel = null; + assetDeliveryDataModel = null; } - isLoading = false; notifyListeners(); + return assetDeliveryDataModel; } catch (e) { - log("getSessionError [error] : $e"); + log("getdelivery details [error] : $e"); isLoading = false; - sessionModel = null; + assetDeliveryDataModel = null; notifyListeners(); - return null; + return assetDeliveryDataModel; } } - Future getAssetsInSession({ - required int sessionId, - bool loadMore = false, - }) async { - if (isLoading || isNextPageLoading) return -2; - if (loadMore) { - isNextPageLoading = true; - pageNo += 1; - } else { - isLoading = true; - pageNo = 1; // reset pagination - } - notifyListeners(); + Future getAssetDeliveryTableListById({int? requestId}) async { try { - final payload = { - "pageSize": pageItemNumber, - "pageNumber": pageNo, - "sessionId": sessionId, - }; - final response = await ApiManager.instance.post(URLs.getAssetsInSession, body: payload); + assetDeliveryTableList.clear(); + isDeliveryTableListLoading = true; + notifyListeners(); + + final response = await ApiManager.instance.get( + "${URLs.getAssetDeliveryTableListById}?assetDeliveryExternalMasterId=$requestId", + ); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { - final Map jsonData = json.decode(response.body); - final newResponse = AssetInventoryResponse.fromJson(jsonData); - - if (loadMore) { - assetInventoryResponse?.assetList?.addAll(newResponse.assetList ?? []); - assetInventoryResponse?.totalRows = newResponse.totalRows; + final jsonData = json.decode(response.body)["data"]; + if (jsonData is List) { + assetDeliveryTableList = jsonData.map((e) => AssetDeliveryTableModel.fromJson(e)).toList(); } else { - assetInventoryResponse = newResponse; + assetDeliveryTableList = []; } - nextPage = (assetInventoryResponse?.assetList?.length ?? 0) < (assetInventoryResponse?.totalRows ?? 0); } else { - nextPage = false; + assetDeliveryTableList = []; } - isLoading = false; - isNextPageLoading = false; + + isDeliveryTableListLoading = false; notifyListeners(); - return response.statusCode; - } catch (error) { - isLoading = false; - isNextPageLoading = false; - stateCode = -1; - nextPage = false; + } catch (e) { + log("get Delivery Table details [error] : $e"); + isDeliveryTableListLoading = false; + assetDeliveryTableList = []; notifyListeners(); - return -1; } } - ///older code - // Future getAssetsInSession({ - // required int sessionId, - // bool loadMore = false, - // }) async { - // // if (isLoading || nextPage) return -2; - // - // if (loadMore) { - // nextPage = true; - // pageNo += 1; - // } else { - // isLoading = true; - // pageNo = 1; // reset pagination - // } - // - // notifyListeners(); - // log('Fetching page: $pageNo'); - // - // try { - // final payload = { - // "pageSize": pageItemNumber, - // "pageNumber": pageNo, - // "sessionId": sessionId, - // }; - // - // final response = await ApiManager.instance.post(URLs.getAssetsInSession, body: payload); - // stateCode = response.statusCode; - // - // if (response.statusCode >= 200 && response.statusCode < 300) { - // final Map jsonData = json.decode(response.body); - // final newResponse = AssetInventoryResponse.fromJson(jsonData); - // - // if (loadMore) { - // assetInventoryResponse?.assetList?.addAll(newResponse.assetList ?? []); - // assetInventoryResponse?.totalRows = newResponse.totalRows; - // } else { - // assetInventoryResponse = newResponse; - // } - // - // nextPage = (assetInventoryResponse?.assetList?.length ?? 0) < (assetInventoryResponse?.totalRows ?? 0); - // } - // - // isLoading = false; - // nextPage = false; - // notifyListeners(); - // return response.statusCode; - // } catch (error) { - // isLoading = false; - // nextPage = false; - // stateCode = -1; - // notifyListeners(); - // return -1; - // } - // } - - Future getInventoryDetailsByFilter({ - required Map payload, - bool loadMore = false, - }) async { - if (isLoading || isNextPageLoading) return -2; - - if (loadMore) { - isNextPageLoading = true; - pageNo += 1; - } else { - isLoading = true; - pageNo = 1; + Future getDeliveryLinesListById({int? itemId}) async { + try { + deliveryLinesList.clear(); + isDeliveryLineListLoading = true; + notifyListeners(); + final response = await ApiManager.instance.get( + "${URLs.getLineFromExternalPo}?assetDeliveryExternalDeliveryId=$itemId", + ); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + final jsonData = json.decode(response.body)["data"]; + if (jsonData is List) { + deliveryLinesList = jsonData.map((e) => DeliveryLineModel.fromJson(e)).toList(); + } else { + deliveryLinesList = []; + } + } else { + deliveryLinesList = []; + } + isDeliveryLineListLoading = false; + notifyListeners(); + } catch (e) { + log("get Delivery Lines List [error] : $e"); + isDeliveryLineListLoading = false; + deliveryLinesList = []; + notifyListeners(); } + } - notifyListeners(); - log('Fetching inventory page: $pageNo'); - + Future> getTechnicalInspectionLinesListById({int? itemId}) async { + List linesList = []; try { - final paginatedPayload = { - ...payload, - "pageSize": pageItemNumber, - "pageNumber": pageNo, - }; - - final response = await ApiManager.instance.post(URLs.getInventoryDetailsByFilter, body: paginatedPayload); + isLoading = true; + notifyListeners(); + final response = await ApiManager.instance.get( + "${URLs.getLineFromTechnicalInspection}?assetDeliveryExternalDeliveryId=$itemId", + ); stateCode = response.statusCode; - if (response.statusCode >= 200 && response.statusCode < 300) { - final Map jsonData = json.decode(response.body); - final newResponse = AssetInventoryResponse.fromJson(jsonData); - - if (loadMore) { - siteFilterAssetList.addAll(newResponse.assetList ?? []); - siteFilterAssetResponse?.totalRows = newResponse.totalRows; + final jsonData = json.decode(response.body)["data"]; + if (jsonData is List) { + linesList = jsonData.map((e) => DeliveryLineModel.fromJson(e)).toList(); } else { - siteFilterAssetResponse = newResponse; - siteFilterAssetList = newResponse.assetList ?? []; + assetDeliveryTableList = []; } - nextPage = (siteFilterAssetList.length) < (siteFilterAssetResponse?.totalRows ?? 0); } else { - siteFilterAssetList = []; - nextPage = false; + linesList = []; } + isLoading = false; + notifyListeners(); + return linesList; + } catch (e) { + log("get Delivery Lines List [error] : $e"); + isLoading = false; + linesList = []; + notifyListeners(); + return linesList; + } + } + Future> getAssetDeliveryCostCenterListForLines({int? lineId, int? tableItemId}) async { + List costCenterList = []; + try { + isLoading = true; + notifyListeners(); + final response = await ApiManager.instance.get( + "${URLs.getCostCenterListToLineDeliveryInspection}?AssetDeliveryExternalDetailId=$lineId&AssetDeliveryExternalDeliveryId=$tableItemId", + ); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + final jsonData = json.decode(response.body)["data"]; + if (jsonData is List) { + costCenterList = jsonData.map((e) => CostCenterModel.fromJson(e)).toList(); + } + } else { + costCenterList = []; + } isLoading = false; - isNextPageLoading = false; notifyListeners(); - return response.statusCode; - } catch (error) { + return costCenterList; + } catch (e) { + log("get Delivery Lines List [error] : $e"); isLoading = false; - isNextPageLoading = false; - nextPage = false; - stateCode = -1; + costCenterList = []; notifyListeners(); - return -1; + return costCenterList; } } - Future searchAsset({ - required Map payload, + Future addNewDelivery({ + int? requestId, + }) async { + isDeliveryTableListLoading = true; + Map payload = { + 'assetDeliveryExternalMasterId': requestId, + }; + try { + final response = await ApiManager.instance.post(URLs.addNewDelivery, body: payload); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + isDeliveryTableListLoading = false; + notifyListeners(); + return true; + } else { + isDeliveryTableListLoading = false; + notifyListeners(); + return false; + } + } catch (error) { + isDeliveryTableListLoading = false; + notifyListeners(); + return false; + } + } + + Future saveTechnicalInspection({ + required TechnicalInspectionFormModel model, }) async { isLoading = true; try { - final response = await ApiManager.instance.post(URLs.searchAsset, body: payload); + final response = await ApiManager.instance.post(URLs.saveTechnicalInspection, body: model.toJson()); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { - final Map jsonData = json.decode(response.body)["data"]; - AssetInventoryModel model = AssetInventoryModel.fromJson(jsonData); - log('model json ${model.toJson()}'); isLoading = false; notifyListeners(); - return model; + return true; } else { isLoading = false; notifyListeners(); - return null; + return false; } } catch (error) { isLoading = false; - stateCode = -1; notifyListeners(); - return null; + return false; } } - Future saveAssetInSession({ - AssetInventoryModel? model, + Future saveCostCenterToLineDeliveryInspection({ + int? tableItemId, + int? lineId, + List? list, }) async { isLoading = true; + Map payload = { + "assetDeliveryExternalDeliveryId": tableItemId, + "assetDeliveryExternalDetailId": lineId, + "costCenters": list?.map((x) => x.toJson()).toList(), + }; try { - final response = await ApiManager.instance.post(URLs.saveAssetInSession, body: model?.toJson() ?? {}); + final response = await ApiManager.instance.post(URLs.saveCostCenterToLineDeliveryInspection, body: payload); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { isLoading = false; @@ -306,151 +279,435 @@ class AssetDeliveryProvider extends ChangeNotifier { } } - Future getClassification({ - required Map payload, - }) async { + Future changeDeliveryStatusToCancel({int? itemId}) async { isLoading = true; - String? classification; try { - final response = await ApiManager.instance.post(URLs.getClassification, body: payload); + final response = await ApiManager.instance.get( + "${URLs.changeDeliveryStatusToCancel}?assetDeliveryExternalDeliveryId=$itemId", + ); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { - log('classifcation on response ${json.decode(response.body)["data"]['classification']}'); - classification = json.decode(response.body)["data"]['classification']; isLoading = false; notifyListeners(); - return classification; + return true; } else { isLoading = false; notifyListeners(); - return classification; + return false; } } catch (error) { isLoading = false; notifyListeners(); - return classification; + return false; } } - Future deleteAssetISession({required num id}) async { + Future changeDeliveryStatus({ + int? itemId, + Map? requestPayload, + }) async { + isLoading = true; + Map payload = { + 'assetDeliveryExternalDeliveryId': itemId, + }; try { - isLoading = true; - notifyListeners(); - final response = await ApiManager.instance.get(URLs.deleteAssetInSession + "?id=$id"); + final response = await ApiManager.instance.post(URLs.changeDeliveryStatus, body: requestPayload ?? payload); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { isLoading = false; notifyListeners(); return true; + } else { + isLoading = false; + notifyListeners(); + return false; } + } catch (error) { isLoading = false; notifyListeners(); return false; + } + } + + Future getAssetDeliveryInspectionData({int? itemId}) async { + isLoading = true; + DeliveryInspectionFormModel deliveryInspectionFormModel = DeliveryInspectionFormModel(); + try { + final response = await ApiManager.instance.get( + "${URLs.getAssetDeliveryInspectionData}?assetDeliveryExternalDeliveryId=$itemId", + ); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + deliveryInspectionFormModel = DeliveryInspectionFormModel.fromJson(json.decode(response.body)["data"]); + } + isLoading = false; + notifyListeners(); + return deliveryInspectionFormModel; } catch (e) { - log("Delete Asset [error] : $e"); + log("getAssetDeliveryInspectionData details [error] : $e"); isLoading = false; notifyListeners(); - return false; + return deliveryInspectionFormModel; } } - Future> getAutoCompleteDetails({ - bool? isManufacturer, - String? query, - int type = 0, - }) async { + Future getTechnicalInspectionData({int? lineId, int? tableId}) async { + isLoading = true; + TechnicalInspectionFormModel technicalInspectionFormModel = TechnicalInspectionFormModel(); try { - String url = ''; - switch (type) { - //for model and manufacturer.. - case 0: - url = URLs.getManufacturerOrModelAutoComplete; - break; - //for asset name.. - case 1: - url = URLs.searchAssetName; - break; - //for supplier... - case 2: - url = URLs.getSuppliersAutoCompleteInventory; - break; - default: - url = URLs.getManufacturerOrModelAutoComplete; - } - final queryParams = {}; - if (isManufacturer != null && type == 0) { - queryParams['isManufacturer'] = isManufacturer.toString(); + final response = await ApiManager.instance.get( + "${URLs.getTechnicalInspectionByDetailId}?assetDeliveryExternalDetailId=$lineId&assetDeliveryExternalDeliveryId=$tableId", + ); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + technicalInspectionFormModel = TechnicalInspectionFormModel.fromJson(json.decode(response.body)["data"]); } - if (query != null && query.isNotEmpty) { - queryParams['searchText'] = query; + isLoading = false; + notifyListeners(); + return technicalInspectionFormModel; + } catch (e) { + log("getTechnicalInspectionByDetailId details [error] : $e"); + isLoading = false; + notifyListeners(); + return technicalInspectionFormModel; + } + } + + Future getDeliveryHistories({int? itemId}) async { + isLoading = true; + DeliveryInspectionFormModel deliveryInspectionFormModel = DeliveryInspectionFormModel(); + try { + final response = await ApiManager.instance.get( + "${URLs.getAssetDeliveryInspectionData}?assetDeliveryExternalDeliveryId=$itemId", + ); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + deliveryInspectionFormModel = DeliveryInspectionFormModel.fromJson(json.decode(response.body)["data"]); } - if (queryParams.isNotEmpty) { - url += '?${Uri(queryParameters: queryParams).query}'; + isLoading = false; + notifyListeners(); + return deliveryInspectionFormModel; + } catch (e) { + log("getAssetDeliveryInspectionData details [error] : $e"); + isLoading = false; + notifyListeners(); + return deliveryInspectionFormModel; + } + } + + Future> getOracleUserAutoCompleteDetails({ + String? query, + }) async { + try { + isLoading = true; + final response = await ApiManager.instance.post(URLs.getOracleUserList, body: {'employeeName': query}); + List list = []; + if (response.statusCode >= 200 && response.statusCode < 300) { + isLoading = false; + notifyListeners(); + final data = json.decode(response.body)["data"]; + list = (data as List).map((e) => OracleUserModel.fromJson(e)).toList(); } - final response = await ApiManager.instance.get(url); + isLoading = false; + notifyListeners(); + return list; + } catch (error) { + log('error $error'); + isLoading = false; + notifyListeners(); + return []; + } + } - List list = []; + Future> getAttachments({ + num? tableItemId, + }) async { + try { + isLoading = true; + final response = await ApiManager.instance.get("${URLs.getAttachments}?assetDeliveryExternalDeliveryId=$tableItemId"); + List list = []; if (response.statusCode >= 200 && response.statusCode < 300) { + isLoading = false; + notifyListeners(); final data = json.decode(response.body)["data"]; - list = (data as List).map((e) => Lookup.fromJson(e)).toList(); + list = (data as List).map((e) => GenericAttachmentModel.fromJson(e)).toList(); } + isLoading = false; + notifyListeners(); return list; } catch (error) { log('error $error'); + isLoading = false; + notifyListeners(); return []; } } - Future getAssets({DeviceSearch? search, bool isQr = false, bool isSearchBy = false, num? sessionId}) async { - if (isLoading == true) return -2; + Future> getParentAssetList({int? costCenterId, int? tableItemId, int? lineId}) async { + List parentAssetList = []; + try { + isLoading = true; + notifyListeners(); + final response = await ApiManager.instance.get( + "${URLs.getTechnicalInspectionParentData}?assetDeliveryExternalDeliveryId=$tableItemId&assetDeliveryExternalDetailId=$lineId&costCenterId=$costCenterId", + ); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + final jsonData = json.decode(response.body)["data"]; + if (jsonData is List) { + parentAssetList = jsonData.map((e) => TechnicalInspectionAssetModel.fromJson(e)).toList(); + } + } else { + parentAssetList = []; + } + isLoading = false; + notifyListeners(); + return parentAssetList; + } catch (e) { + log("get parent List [error] : $e"); + isLoading = false; + parentAssetList = []; + notifyListeners(); + return parentAssetList; + } + } + + Future getSiteData({ + required num? siteId, + required TechnicalInspectionAssetModel model, + }) async { + isSiteLoading = true; + notifyListeners(); + + try { + final response = await ApiManager.instance.get( + "${URLs.getSiteAutoCompleteWithoutConditionSites}?id=$siteId", + ); + + stateCode = response.statusCode; + + if (response.statusCode >= 200 && response.statusCode < 300) { + final List? siteData = json.decode(response.body)["data"]; + + if (siteData != null && siteData.isNotEmpty) { + model.site = Site.fromJson(siteData.first); + } + + model.building = model.site?.buildings?.firstWhere( + (e) => e.value == model.building?.value, + orElse: () => Building(), + ); + + model.floor = model.building?.floors?.firstWhere( + (e) => e.value == model.floor?.value, + orElse: () => Floor(), + ); + + model.department = model.floor?.departments?.firstWhere( + (e) => e.departmentName == model.department?.departmentName, + orElse: () => Department(), + ); + + model.room = model.department?.rooms?.firstWhere( + (e) => e.value == model.room?.value, + orElse: () => Rooms(), + ); + } + + isSiteLoading = false; + notifyListeners(); + return model; + } catch (e) { + isSiteLoading = false; + stateCode = -1; + notifyListeners(); + return model; + } + } + + Future getAssetDetails({required num? assetId}) async { isLoading = true; notifyListeners(); - late Response response; try { - final Map body = { - "pageSize": isSearchBy ? searchPageItemNumber : pageItemNumber, - "pageNumber": isSearchBy ? (searchDevices.length / searchPageItemNumber).ceil() + 1 : devices.length ~/ pageItemNumber + 1, - "sessionId": sessionId ?? 0, - "assetSerialNo": search?.assetSerialNumber ?? '', - "assetName": search?.assetName ?? '', - "model": search?.model ?? '', - "manufacturer": search?.manufacturer ?? '', - "supplier": search?.supplier ?? '', - "siteName": search?.site ?? '', - // "buildingName":search?.??'', - // "floorName": search?.f??'', - "departmentName": search?.department ?? '', - // "roomName": search?.room - }; - // if (search != null) body.addAll(search.toJson()); - response = await ApiManager.instance.post(URLs.getAssetsTemp, body: body); + Response response = await ApiManager.instance.get(URLs.getAssetDetailsByAssetId + "?AssetDeliveryInternalDetailAssetId=$assetId"); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + final data = json.decode(response.body)["data"]; + TechnicalInspectionAssetModel assetModel = TechnicalInspectionAssetModel.fromJson(data); + isLoading = false; + notifyListeners(); + return assetModel; + } else { + return null; + } } catch (error) { isLoading = false; stateCode = -1; notifyListeners(); - return -1; + return null; } - stateCode = response.statusCode; - if (response.statusCode >= 200 && response.statusCode < 300) { - // client's request was successfully received - List equipmentListJson = json.decode(response.body)["data"]; - var dList = equipmentListJson.map((asset) => AssetInventoryModel.fromJson(asset)).toList() ?? []; - isSearchBy ? _searchDevices.addAll(dList) : _devices.addAll(dList); - nextPage = true; - } else { - nextPage = false; + } + + Future saveTechnicalInspectionAssetData({ + required TechnicalInspectionAssetModel model, + }) async { + isLoading = true; + try { + final response = await ApiManager.instance.post(URLs.saveTechnicalInspectionAsset, body: model.toJson()); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + isLoading = false; + notifyListeners(); + return true; + } else { + isLoading = false; + notifyListeners(); + return false; + } + } catch (error) { + isLoading = false; + notifyListeners(); + return false; } - isLoading = false; - notifyListeners(); - return response.statusCode; } - Future markAsComplete({ + Future saveAttachment({ required Map payload, }) async { isLoading = true; try { - final response = await ApiManager.instance.post(URLs.convertDetailToComplete, body: payload); + final response = await ApiManager.instance.post(URLs.saveAttachments, body: payload); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + isLoading = false; + notifyListeners(); + return true; + } else { + isLoading = false; + notifyListeners(); + return false; + } + } catch (error) { + isLoading = false; + notifyListeners(); + return false; + } + } + + Future> getHistory({ + num? tableItemId, + }) async { + try { + isLoading = true; + notifyListeners(); + final response = await ApiManager.instance.get("${URLs.getDeliveryHistories}?assetDeliveryExternalDeliveryId=$tableItemId"); + List list = []; + if (response.statusCode >= 200 && response.statusCode < 300) { + isLoading = false; + notifyListeners(); + final data = json.decode(response.body)["data"]; + list = (data as List).map((e) => AssetDeliveryHistoryModel.fromJson(e)).toList(); + } + isLoading = false; + notifyListeners(); + return list; + } catch (error) { + log('error $error'); + isLoading = false; + notifyListeners(); + return []; + } + } + + //End user + + Future> getEndUserCostCenterList({int? tableItemId}) async { + List costCenterList = []; + try { + isLoading = true; + notifyListeners(); + final response = await ApiManager.instance.get( + "${URLs.getEndUserAcceptanceCostCenter}?assetDeliveryExternalDeliveryId=$tableItemId", + ); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + final jsonData = json.decode(response.body)["data"]; + if (jsonData is List) { + costCenterList = jsonData.map((e) => CostCenterModel.fromJson(e)).toList(); + } + } else { + costCenterList = []; + } + isLoading = false; + notifyListeners(); + return costCenterList; + } catch (e) { + log("get costCenter for End user [error] : $e"); + isLoading = false; + costCenterList = []; + notifyListeners(); + return costCenterList; + } + } + + Future> getEndUserAssetList({int? tableItemId, String? costCenterName}) async { + List assetList = []; + try { + isLoading = true; + notifyListeners(); + final response = await ApiManager.instance.get( + "${URLs.getCostCenterAssetList}?assetDeliveryExternalDeliveryId=$tableItemId&costCenterName=$costCenterName", + ); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + final jsonData = json.decode(response.body)["data"]; + if (jsonData is List) { + assetList = jsonData.map((e) => EndUserAssetDetailsModel.fromJson(e)).toList(); + } + } else { + assetList = []; + } + isLoading = false; + notifyListeners(); + return assetList; + } catch (e) { + log("get End User AssetList [error] : $e"); + isLoading = false; + assetList = []; + notifyListeners(); + return assetList; + } + } + + Future saveEndUserFormData({ + required CostCenterModel model, + }) async { + isLoading = true; + try { + final response = await ApiManager.instance.post(URLs.saveEndUserFormData, body: model.toEndUserAcceptanceFormJson()); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + isLoading = false; + notifyListeners(); + return true; + } else { + isLoading = false; + notifyListeners(); + return false; + } + } catch (error) { + isLoading = false; + notifyListeners(); + return false; + } + } + + Future saveEndUserAssetDataData({ + required EndUserAssetDetailsModel model, + }) async { + isLoading = true; + try { + final response = await ApiManager.instance.post(URLs.saveEndUserAssetData, body: model.toJson()); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { isLoading = false; diff --git a/lib/modules/asset_delivery_module/provider/cost_center_provider.dart b/lib/modules/asset_delivery_module/provider/cost_center_provider.dart new file mode 100644 index 00000000..80cac313 --- /dev/null +++ b/lib/modules/asset_delivery_module/provider/cost_center_provider.dart @@ -0,0 +1,45 @@ +import 'dart:convert'; +import 'dart:developer'; + +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/models/lookup.dart'; +import 'package:test_sa/modules/loan_module/models/medical_department_model.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +class CostCenterProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading) return; + loading = true; + notifyListeners(); + try { + final response = await ApiManager.instance.get( + URLs.getCostCenterToPo + "?assetDeliveryExternalMasterId=$id", + ); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + final List list = json.decode(response.body)['data']; + final Set seenNames = {}; + int index = 0; + items = + list.where((e) => e is Map && e['name'] != null && e['name'].toString().trim().isNotEmpty).map((e) => e['name'].toString().trim()).where((name) => seenNames.add(name)).map((name) { + final lookup = Lookup( + id: index, + value: index + 1, + name: name, + ); + index++; + return lookup; + }).toList(); + } + } catch (e, s) { + log('getData error', error: e, stackTrace: s); + stateCode = -1; + } finally { + loading = false; + notifyListeners(); + } + } +} diff --git a/lib/modules/asset_delivery_module/provider/end_user_rejection_reason_lookup_provider.dart b/lib/modules/asset_delivery_module/provider/end_user_rejection_reason_lookup_provider.dart new file mode 100644 index 00000000..f560e57e --- /dev/null +++ b/lib/modules/asset_delivery_module/provider/end_user_rejection_reason_lookup_provider.dart @@ -0,0 +1,33 @@ +import 'dart:convert'; +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/models/lookup.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +class EndUserRejectionReasonLookupProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading == true) return -2; + loading = true; + notifyListeners(); + loading = true; + notifyListeners(); + try { + Response response = await ApiManager.instance.get(URLs.endUserRejectionReasonLookup); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List categoriesListJson = json.decode(response.body)["data"]; + items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } +} diff --git a/lib/modules/asset_delivery_module/provider/end_user_status_lookup_provider.dart b/lib/modules/asset_delivery_module/provider/end_user_status_lookup_provider.dart new file mode 100644 index 00000000..866cc600 --- /dev/null +++ b/lib/modules/asset_delivery_module/provider/end_user_status_lookup_provider.dart @@ -0,0 +1,33 @@ +import 'dart:convert'; +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/models/lookup.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +class EndUserStatusLookupProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading == true) return -2; + loading = true; + notifyListeners(); + loading = true; + notifyListeners(); + try { + Response response = await ApiManager.instance.get(URLs.endUserStatusLookup); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List categoriesListJson = json.decode(response.body)["data"]; + items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } +} diff --git a/lib/modules/asset_delivery_module/provider/power_supply_type_provider.dart b/lib/modules/asset_delivery_module/provider/power_supply_type_provider.dart new file mode 100644 index 00000000..353b3ae2 --- /dev/null +++ b/lib/modules/asset_delivery_module/provider/power_supply_type_provider.dart @@ -0,0 +1,33 @@ +import 'dart:convert'; +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/models/lookup.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +class PowerSupplyTypeProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading == true) return -2; + loading = true; + notifyListeners(); + loading = true; + notifyListeners(); + try { + Response response = await ApiManager.instance.get(URLs.powerSupplyTypeLookUp); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List categoriesListJson = json.decode(response.body)["data"]; + items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } +} diff --git a/lib/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart b/lib/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart index 95e1d3ce..f149de8a 100644 --- a/lib/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart +++ b/lib/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart @@ -385,7 +385,7 @@ class ServiceRequestBottomSheet { ], ); }, - ).toShimmer(isShow: snapshot.loading,context: context); + ).toShimmer(isShow: snapshot.loading, context: context); }); } @@ -645,7 +645,7 @@ class ServiceRequestBottomSheet { borderRadius: BorderRadius.circular(14), // Circular border radius ), // color: AppColor.neutral80, - color: AppColor.background(context), + color: AppColor.background(context), child: Row( crossAxisAlignment: CrossAxisAlignment.start, // Align items at the top children: [ @@ -1191,30 +1191,26 @@ class ServiceRequestBottomSheet { 10.height, StatefulBuilder( builder: (context, setState) { - return Column( - children: [ - ESignature( - title: '', - oldSignature: '', - newSignature: newSignature, - backgroundColor: AppColor.neutral100, - showShadow: false, - onChange: (signature) { - if (signature.isEmpty) return; - setState(() { - newSignature = signature; - nurseSignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; - }); - }, - onSaved: (signature) { - if (signature == null || signature.isEmpty) return; - setState(() { - newSignature = signature; - nurseSignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; - }); - }, - ), - ], + return ESignature( + title: '', + oldSignature: '', + newSignature: newSignature, + backgroundColor: AppColor.neutral100, + showShadow: false, + onChange: (signature) { + if (signature.isEmpty) return; + setState(() { + newSignature = signature; + nurseSignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; + }); + }, + onSaved: (signature) { + if (signature == null || signature.isEmpty) return; + setState(() { + newSignature = signature; + nurseSignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; + }); + }, ); }, ), diff --git a/lib/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart b/lib/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart index fccf0af5..43601cec 100644 --- a/lib/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart +++ b/lib/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart @@ -69,7 +69,7 @@ class _RecurrentWorkOrderViewState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ RecurrentTaskInfoWidget(model: requestProvider.recurrentWoData), - requestProvider.recurrentWoData!.planRecurrentMedicalTaskRooms!.isNotEmpty + requestProvider.recurrentWoData!.planRecurrentMedicalTaskRooms != null && requestProvider.recurrentWoData!.planRecurrentMedicalTaskRooms!.isNotEmpty ? Column( children: [ 8.height, diff --git a/lib/new_views/common_widgets/default_app_bar.dart b/lib/new_views/common_widgets/default_app_bar.dart index faaca183..3b3fcf3f 100644 --- a/lib/new_views/common_widgets/default_app_bar.dart +++ b/lib/new_views/common_widgets/default_app_bar.dart @@ -13,10 +13,11 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget { final List? actions; final Function? onBackPress; final bool showHomeActionButton; + final bool showBackButton; final VoidCallback? onWillPopScope; final TextStyle? titleStyle; - const DefaultAppBar({this.title, this.onBackPress, this.onWillPopScope, this.actions,this.titleStyle, this.showHomeActionButton = false, Key? key}) : super(key: key); + const DefaultAppBar({this.title, this.onBackPress, this.onWillPopScope, this.actions,this.titleStyle, this.showHomeActionButton = false, this.showBackButton = true, Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -42,6 +43,7 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget { titleSpacing: 16, title: Row( children: [ + if(showBackButton) const Icon(Icons.arrow_back_ios).onPress(() { if (onWillPopScope != null) { showDialog( diff --git a/lib/new_views/common_widgets/single_item_drop_down_menu.dart b/lib/new_views/common_widgets/single_item_drop_down_menu.dart index 5ea85f7c..ce7f7838 100644 --- a/lib/new_views/common_widgets/single_item_drop_down_menu.dart +++ b/lib/new_views/common_widgets/single_item_drop_down_menu.dart @@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/enum_extensions.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/new_views/app_style/app_text_style.dart'; @@ -32,6 +33,7 @@ class SingleItemDropDownMenu exte final int? requestById; final String? Function(T?)? validator; final AutovalidateMode? autovalidateMode; + final DropDownMatchType matchBy; /// To use a static data (without calling API) /// just send [NullableLoadingProvider] as generic data type and fill the [staticData] @@ -55,6 +57,7 @@ class SingleItemDropDownMenu exte this.requestById, this.validator, this.autovalidateMode, + this.matchBy = DropDownMatchType.identifier, }) : super(key: key); @override @@ -67,41 +70,97 @@ class _SingleItemDropDownMenuState(widget.context); } - if (widget.initialValue != null) { - final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier); - if (result?.isNotEmpty ?? false) _selectedItem = result!.first as T?; - if (widget.onSelect != null && (widget.initialValue?.identifier ?? "") != (_selectedItem?.identifier ?? "")) { - widget.onSelect!(_selectedItem); // Non-null assertion after null check - } + if (widget.initialValue == null) return; + final List? items = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.cast(); + + if (items == null || items.isEmpty) return; + final Iterable matches = items.where((e) => _isSameItem(e, widget.initialValue!)); + + if (matches.isNotEmpty) { + _selectedItem = matches.first; + } else { + _selectedItem = null; + } + if (widget.onSelect != null && !_isSameItem(widget.initialValue!, _selectedItem ?? widget.initialValue!)) { + widget.onSelect!(_selectedItem); } - super.initState(); } + // @override + // void initState() { + // if (X != NullableLoadingProvider) { + // provider = Provider.of(widget.context); + // } + // if (widget.initialValue != null) { + // final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier); + // if (result?.isNotEmpty ?? false) _selectedItem = result!.first as T?; + // if (widget.onSelect != null && (widget.initialValue?.identifier ?? "") != (_selectedItem?.identifier ?? "")) { + // widget.onSelect!(_selectedItem); // Non-null assertion after null check + // } + // } + // super.initState(); + // } + @override void setState(VoidCallback fn) { if (mounted) super.setState(fn); } + bool _isSameItem(Base a, Base b) { + switch (widget.matchBy) { + case DropDownMatchType.name: + return (a.name ?? '') == (b.name ?? ''); + case DropDownMatchType.identifier: + default: + return (a.identifier ?? '') == (b.identifier ?? ''); + } + } + + // @override + // void didUpdateWidget(covariant SingleItemDropDownMenu oldWidget) { + // if (widget.initialValue != null) { + // final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier); + // + // if (result?.isNotEmpty ?? false) { + // _selectedItem = result?.first as T?; + // } else { + // _selectedItem = null; + // } + // if (widget.onSelect != null && (widget.initialValue?.identifier ?? "") != (_selectedItem?.identifier ?? "")) { + // widget.onSelect!(_selectedItem); // Non-null assertion after null check + // } + // } else { + // _selectedItem = null; + // } + // super.didUpdateWidget(oldWidget); + // } @override void didUpdateWidget(covariant SingleItemDropDownMenu oldWidget) { - if (widget.initialValue != null) { - final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier); + super.didUpdateWidget(oldWidget); - if (result?.isNotEmpty ?? false) { - _selectedItem = result?.first as T?; - } else { - _selectedItem = null; - } - if (widget.onSelect != null && (widget.initialValue?.identifier ?? "") != (_selectedItem?.identifier ?? "")) { - widget.onSelect!(_selectedItem); // Non-null assertion after null check - } - } else { + if (oldWidget.initialValue == widget.initialValue) return; + + if (widget.initialValue == null) { _selectedItem = null; + return; + } + final List? items = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.cast(); + + T? matchedItem; + + if (items != null && items.isNotEmpty) { + final Iterable matches = items.where((e) => _isSameItem(e, widget.initialValue!)); + + if (matches.isNotEmpty) matchedItem = matches.first; + } + _selectedItem = matchedItem; + if (widget.onSelect != null && !_isSameItem(widget.initialValue!, _selectedItem ?? widget.initialValue!)) { + widget.onSelect!(_selectedItem); } - super.didUpdateWidget(oldWidget); } @override @@ -148,11 +207,7 @@ class _SingleItemDropDownMenuState( value: _selectedItem, diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index 70327c4c..d482356e 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -68,7 +68,8 @@ class _MyRequestsPageState extends State { if (context.userProvider.isEngineer) { requestsList.add(Request(10, 'Equipment Internal Audit')); requestsList.add(Request(11, 'System Internal Audit')); - requestsList.add(Request(12, "Asset Delivery")); + //Need to be added for new user role commissioning engineer + requestsList.add(Request(13, "Asset Delivery")); } requestsList.add(Request(12, "Loan Equipment")); diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart index 8fc1a0f5..946cb7ba 100644 --- a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart +++ b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart @@ -70,11 +70,10 @@ class RequestItemViewList extends StatelessWidget { return EquipmentInternalAuditItemView(requestDetails: list[index]); case 11: return SystemInternalAuditItemView(requestDetails: list[index]); - //Need to use correct value .... - case 12: - return AssetDeliveryItemView(requestDetails: list[index]); case 12: return LoanEquipmentItemView(requestDetails: list[index]); + case 13: + return AssetDeliveryItemView(requestDetails: list[index]); default: Container( diff --git a/lib/views/widgets/requests/request_status.dart b/lib/views/widgets/requests/request_status.dart index 272ddf42..ab7a40e5 100644 --- a/lib/views/widgets/requests/request_status.dart +++ b/lib/views/widgets/requests/request_status.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/text_extensions.dart'; From 6d6be40b9e4949b677868d992610996cdc079cf9 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 25 Dec 2025 11:34:41 +0300 Subject: [PATCH 04/26] chat notification redirection added. --- .../firebase_notification_manger.dart | 39 +++++++++++++++++++ lib/main.dart | 1 + .../cx_module/chat/chat_api_client.dart | 2 +- .../tasks_wo/task_request_detail_view.dart | 24 +++++++----- 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/lib/controllers/notification/firebase_notification_manger.dart b/lib/controllers/notification/firebase_notification_manger.dart index 5d3117ba..cc32e159 100644 --- a/lib/controllers/notification/firebase_notification_manger.dart +++ b/lib/controllers/notification/firebase_notification_manger.dart @@ -12,6 +12,7 @@ import 'package:test_sa/modules/cm_module/views/service_request_detail_main_view import 'package:test_sa/modules/cx_module/survey/survey_page.dart'; import 'package:test_sa/modules/pm_module/ppm_wo/ppm_details_page.dart'; import 'package:test_sa/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart'; +import 'package:test_sa/modules/tm_module/tasks_wo/task_request_detail_view.dart'; import 'package:test_sa/views/pages/device_transfer/device_transfer_details.dart'; import 'package:test_sa/views/pages/user/gas_refill/gas_refill_details.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; @@ -88,6 +89,44 @@ class FirebaseNotificationManger { String? transactionType = messageData["transactionType"]?.toString(); + if (transactionType == null) { + return; + } else if (transactionType == "17" && messageData["requestType"] == "chat") { + int moduleId = int.parse(messageData["moduleId"].toString()); + int requestNumber = int.parse(messageData["requestNumber"].toString()); + + switch (moduleId) { + case 1: // cm + serviceClass = ServiceRequestDetailMain(requestId: requestNumber, moduleId: moduleId); + break; + case 2: // gas refill + serviceClass = GasRefillDetailsPage( + priority: messageData["priority"], + date: messageData["createdOn"], + moduleId: moduleId, + model: GasRefillModel(id: requestNumber), + ); + break; + case 3: //transfer + serviceClass = DeviceTransferDetails(model: DeviceTransfer(id: requestNumber), moduleId: moduleId); + break; + case 6: // task + serviceClass = TaskRequestDetailsView( + taskId: requestNumber, + moduleId: moduleId, + // requestDetails: RequestsDetails(nameOfType: requestData?.nameOfType, status: requestData?.statusName, priority: requestData?.priorityName, date: requestData?.transactionDate, ), + ); + ServiceRequestDetailMain(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1); + break; + + default: + serviceClass = const Scaffold(body: Center(child: NoDataFound())); + } + + Navigator.of(context).push(MaterialPageRoute(builder: (_) => serviceClass!)); + return; + } + // PPM=1, // ServiceRequestEngineer = 3, // AssetTransfer=7, diff --git a/lib/main.dart b/lib/main.dart index 8855155a..0d138e27 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -126,6 +126,7 @@ import 'providers/service_request_providers/reject_reason_provider.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); + SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); // HttpOverrides.global = MyHttpOverrides(); // for later use. _configureLocalTimeZone(); NotificationManger.initialisation((notificationDetails) {}, (id, title, body, payload) async {}); diff --git a/lib/modules/cx_module/chat/chat_api_client.dart b/lib/modules/cx_module/chat/chat_api_client.dart index b859e305..a98cac23 100644 --- a/lib/modules/cx_module/chat/chat_api_client.dart +++ b/lib/modules/cx_module/chat/chat_api_client.dart @@ -82,7 +82,7 @@ class ChatApiClient { Future loadParticipants(int moduleId, int referenceId, String? assigneeEmployeeNumber) async { Response response = - await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId?assigneeEmployeeNumber=$assigneeEmployeeNumber", token: chatLoginResponse!.token); + await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId?assigneeEmployeeNumber=$assigneeEmployeeNumber&requestType=chat&transactionType=17", token: chatLoginResponse!.token); if (!kReleaseMode) { // logger.i("login-res: " + response.body); diff --git a/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart b/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart index 330ce2f2..e4777fec 100644 --- a/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart +++ b/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart @@ -75,16 +75,20 @@ class _TaskRequestDetailsViewState extends State { selector: (_, myModel) => myModel.taskRequestModel, // Selects only the userName builder: (_, _taskReqModel, __) { if (_taskReqModel == null) return const SizedBox(); - - return ChatWidget( - moduleId: widget.moduleId, - isShow: _taskReqModel.taskJobStatus!.value! != 1, - isReadOnly: _taskReqModel.taskJobStatus!.value! != 2, - requestId: widget.taskId.toInt(), - assigneeEmployeeNumber: _taskReqModel.assignedEngineer?.employeeId!, - myLoginUserID: context.userProvider.user!.username!, - contactEmployeeINumber: _taskReqModel.taskJobContactPersons!.first.user?.employeeId, - ); + if ((context.userProvider.isEngineer || context.userProvider.isNurse) && + _taskReqModel.assignedEngineer?.employeeId != null && + (_taskReqModel.taskJobContactPersons?.isNotEmpty ?? false)) { + return ChatWidget( + moduleId: widget.moduleId, + isShow: _taskReqModel.taskJobStatus!.value! != 1, + isReadOnly: _taskReqModel.taskJobStatus!.value! != 2, + requestId: widget.taskId.toInt(), + assigneeEmployeeNumber: _taskReqModel.assignedEngineer?.employeeId!, + myLoginUserID: context.userProvider.user!.username!, + contactEmployeeINumber: _taskReqModel.taskJobContactPersons!.first.user?.employeeId, + ); + } else + return const SizedBox(); }) ], ), From a7c206e6f40ca1752031dedad55456bcc986066e Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 25 Dec 2025 11:36:01 +0300 Subject: [PATCH 05/26] chat notification redirection added. --- lib/modules/cx_module/chat/chat_api_client.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/modules/cx_module/chat/chat_api_client.dart b/lib/modules/cx_module/chat/chat_api_client.dart index a98cac23..29d9239a 100644 --- a/lib/modules/cx_module/chat/chat_api_client.dart +++ b/lib/modules/cx_module/chat/chat_api_client.dart @@ -81,8 +81,9 @@ class ChatApiClient { } Future loadParticipants(int moduleId, int referenceId, String? assigneeEmployeeNumber) async { - Response response = - await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId?assigneeEmployeeNumber=$assigneeEmployeeNumber&requestType=chat&transactionType=17", token: chatLoginResponse!.token); + Response response = await ApiClient().getJsonForResponse( + "${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId?assigneeEmployeeNumber=$assigneeEmployeeNumber&requestType=chat&transactionType=17", + token: chatLoginResponse!.token); if (!kReleaseMode) { // logger.i("login-res: " + response.body); From c2068544dbaa49c8a239aafd68b53db1efdf10e1 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Thu, 25 Dec 2025 11:37:24 +0300 Subject: [PATCH 06/26] Medical Gas Inspection completed --- lib/controllers/api_routes/urls.dart | 16 +- lib/main.dart | 10 + lib/models/new_models/dashboard_detail.dart | 3 + .../delivery_inspection_form_view.dart | 2 +- .../update_child_asset_view.dart | 12 +- .../create_medical_gas_request_page.dart | 295 ++++++++++++++++++ .../medical_gas_inspection_detail_page.dart | 152 +++++++++ .../medical_gas_inspection_item_view.dart | 130 ++++++++ .../medical_gas_item_list_view.dart | 94 ++++++ .../models/delivery_notes_form_model.dart | 92 ++++++ .../models/medical_gas_data_model.dart | 169 ++++++++++ .../models/medical_gas_form_model.dart | 87 ++++++ .../models/medical_gas_supplier_model.dart | 72 +++++ .../providers/item_type_provider.dart | 33 ++ .../medical_gas_inspection_provider.dart | 119 +++++++ .../medical_gas_supplier_provider.dart | 34 ++ .../providers/order_type_provider.dart | 33 ++ .../update_delivery_notes_page.dart | 288 +++++++++++++++++ lib/new_views/app_style/app_color.dart | 16 + .../create_request_type_bottom_sheet.dart | 6 + .../my_request/my_requests_page.dart | 1 + .../requests/request_paginated_listview.dart | 3 + .../widgets/request_item_view_list.dart | 3 + 23 files changed, 1661 insertions(+), 9 deletions(-) create mode 100644 lib/modules/medical_gas_inspection/create_medical_gas_request_page.dart create mode 100644 lib/modules/medical_gas_inspection/medical_gas_inspection_detail_page.dart create mode 100644 lib/modules/medical_gas_inspection/medical_gas_inspection_item_view.dart create mode 100644 lib/modules/medical_gas_inspection/medical_gas_item_list_view.dart create mode 100644 lib/modules/medical_gas_inspection/models/delivery_notes_form_model.dart create mode 100644 lib/modules/medical_gas_inspection/models/medical_gas_data_model.dart create mode 100644 lib/modules/medical_gas_inspection/models/medical_gas_form_model.dart create mode 100644 lib/modules/medical_gas_inspection/models/medical_gas_supplier_model.dart create mode 100644 lib/modules/medical_gas_inspection/providers/item_type_provider.dart create mode 100644 lib/modules/medical_gas_inspection/providers/medical_gas_inspection_provider.dart create mode 100644 lib/modules/medical_gas_inspection/providers/medical_gas_supplier_provider.dart create mode 100644 lib/modules/medical_gas_inspection/providers/order_type_provider.dart create mode 100644 lib/modules/medical_gas_inspection/update_delivery_notes_page.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index aac9b8b5..39818fc7 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -11,7 +11,7 @@ class URLs { // static String _baseUrl = "$_host/mobile"; // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis - static final String _baseUrl = "$_host/v6/mobile"; // for asset delivery module + static final String _baseUrl = "$_host/v3/mobile"; // for asset delivery module // static final String _baseUrl = "$_host/mobile"; // host local UAT and for internal audit dev // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM // static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation @@ -394,7 +394,6 @@ class URLs { static get addLoan => '$_baseUrl/Loan/AddLoan'; //Asset Delivery Module - //AssetDeliveryExternal/GetAssetDeliveryExternalById static get getAssetDeliveryDetailsById => '$_baseUrl/AssetDeliveryExternal/GetAssetDeliveryExternalById'; static get getAssetDeliveryTableListById => '$_baseUrl/AssetDeliveryExternalDelivery/GetDeliveriesByMasterId'; @@ -432,4 +431,17 @@ class URLs { static get saveEndUserAssetData => "$_baseUrl/AssetDeliveryEndUserAcceptance/SaveDetail"; static get endUserStatusLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=534"; static get endUserRejectionReasonLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=5007"; + + //Medical Gas Request.. +// 4004 + static get orderTypeLookUp => "$_baseUrl/Lookups/GetLookup?lookupEnum=4004"; + static get itemTypeLookUp => "$_baseUrl/Lookups/GetLookup?lookupEnum=4005"; + static get getMedicalGasSupplierList => "$_baseUrl/MedicalGas/GetMedicalGasSupplierAsync"; + static get getMedicalGasInfoBySupplier => "$_baseUrl/MedicalGas/GetMedicalGasInfoBySupplierAsync"; + static get addMedicalGasRequest => "$_baseUrl/MedicalGas/AddUpdateMedicalGasRequestAsync"; + static get getMedicalGasById => "$_baseUrl/MedicalGas/GetMedicalGasRequestByIdAsync"; + static get updateDeliveryNote => "$_baseUrl/MedicalGas/MedicalGasRequestDeliveryNotesAsync"; + + + } diff --git a/lib/main.dart b/lib/main.dart index ceff381d..6592c495 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -46,6 +46,10 @@ import 'package:test_sa/modules/loan_module/pages/create_loan_request_page.dart' import 'package:test_sa/modules/loan_module/provider/loan_period_provider.dart'; import 'package:test_sa/modules/loan_module/provider/loan_provider.dart'; import 'package:test_sa/modules/loan_module/provider/medical_department_provider.dart'; +import 'package:test_sa/modules/medical_gas_inspection/create_medical_gas_request_page.dart'; +import 'package:test_sa/modules/medical_gas_inspection/providers/item_type_provider.dart'; +import 'package:test_sa/modules/medical_gas_inspection/providers/medical_gas_inspection_provider.dart'; +import 'package:test_sa/modules/medical_gas_inspection/providers/order_type_provider.dart'; import 'package:test_sa/modules/tm_module/gas_refill/create_gas_refill_request.dart'; import 'package:test_sa/modules/tm_module/gas_refill/update_gas_refill_request.dart'; import 'package:test_sa/modules/traf_module/create_traf_request_page.dart'; @@ -114,6 +118,7 @@ import 'dashboard_latest/dashboard_provider.dart'; import 'modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart'; import 'modules/internal_audit_module/provider/internal_audit_checklist_provider.dart'; import 'modules/cx_module/survey/survey_provider.dart'; +import 'modules/medical_gas_inspection/providers/medical_gas_supplier_provider.dart'; import 'modules/tm_module/device_transfer/create_device_transfer_request.dart'; import 'modules/tm_module/device_transfer/device_filter_screen.dart'; import 'modules/tm_module/device_transfer/device_search_screen.dart'; @@ -326,6 +331,10 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => PowerSupplyTypeProvider()), ChangeNotifierProvider(create: (_) => EndUserStatusLookupProvider()), ChangeNotifierProvider(create: (_) => EndUserRejectionReasonLookupProvider()), + ChangeNotifierProvider(create: (_) => MedicalGasOrderTypeProvider()), + ChangeNotifierProvider(create: (_) => MedicalGasItemTypeProvider()), + ChangeNotifierProvider(create: (_) => MedicalGasInspectionProvider()), + ChangeNotifierProvider(create: (_) => MedicalGasSupplierProvider()), ], child: GestureDetector( onTap: () { @@ -393,6 +402,7 @@ class MyApp extends StatelessWidget { UpdateEquipmentInternalAuditPage.id: (_) => UpdateEquipmentInternalAuditPage(), UpdateSystemInternalAuditPage.id: (_) => UpdateSystemInternalAuditPage(), CreateLoanRequestPage.id: (_) => CreateLoanRequestPage(), + CreateMedicalGasRequestPage.id: (_) => CreateMedicalGasRequestPage(), // SwipeSuccessView.routeName: (_) => const SwipeSuccessView(), // SwipeHistoryView.routeName: (_) => const SwipeHistoryView(), }, diff --git a/lib/models/new_models/dashboard_detail.dart b/lib/models/new_models/dashboard_detail.dart index 7c39d4ce..93c868a1 100644 --- a/lib/models/new_models/dashboard_detail.dart +++ b/lib/models/new_models/dashboard_detail.dart @@ -55,6 +55,7 @@ class Data { String? assetNumber; String? requestTypeName; String? requestNo; + String? requestType; String? poInternal; String? poExternal; int? transactionNo; @@ -77,6 +78,7 @@ class Data { this.assetNumber, this.requestTypeName, this.requestNo, + this.requestType, this.poExternal, this.poInternal, this.transactionNo}); @@ -90,6 +92,7 @@ class Data { isHighPriority = json['isHighPriority']; assetName = json['assetName']; sessionType = json['sessionType']; + requestType = json['requestType']; numberOfSites = json['numberOfSites']; numberOfAssets = json['numberOfAssets']; assetNumber = json['assetNumber']; diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart index 40a4f61c..36faf4bf 100644 --- a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart @@ -161,7 +161,7 @@ class _DeliveryInspectionFormViewState extends State return Consumer(builder: (context, provider, child) { List linesList = provider.deliveryLinesList; return provider.isDeliveryLineListLoading - ? SizedBox(height: 200.toScreenHeight, child: const CircularProgressIndicator(color: AppColor.primary10).center) + ? SizedBox.expand(child: const CircularProgressIndicator(color: AppColor.primary10).center) : linesList.isEmpty ? const NoDataFound().center : ListView.separated( diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart index bb0b6ca9..c95dd194 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart @@ -330,12 +330,12 @@ class _UpdateChildAssetViewState extends State { child: child!, ); }, - ).then((selectedTime) { - if (selectedTime != null) { - model.installationDate = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); - setState(() {}); - } - }); + ).then((selectedTime) { + if (selectedTime != null) { + model.installationDate = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); + setState(() {}); + } + }); }, ), 8.height, diff --git a/lib/modules/medical_gas_inspection/create_medical_gas_request_page.dart b/lib/modules/medical_gas_inspection/create_medical_gas_request_page.dart new file mode 100644 index 00000000..d8c017ff --- /dev/null +++ b/lib/modules/medical_gas_inspection/create_medical_gas_request_page.dart @@ -0,0 +1,295 @@ + +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/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/new_models/site.dart'; +import 'package:test_sa/models/new_models/task_request/task_type_model.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/medical_gas_inspection/models/medical_gas_data_model.dart'; +import 'package:test_sa/modules/medical_gas_inspection/models/medical_gas_form_model.dart'; +import 'package:test_sa/modules/medical_gas_inspection/models/medical_gas_supplier_model.dart'; +import 'package:test_sa/modules/medical_gas_inspection/providers/item_type_provider.dart'; +import 'package:test_sa/modules/medical_gas_inspection/providers/medical_gas_inspection_provider.dart'; +import 'package:test_sa/modules/medical_gas_inspection/providers/medical_gas_supplier_provider.dart'; +import 'package:test_sa/modules/medical_gas_inspection/providers/order_type_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/gas_request_providers/site_provider.dart'; +import '../../../../../../new_views/common_widgets/default_app_bar.dart'; + +class CreateMedicalGasRequestPage extends StatefulWidget { + static const String id = "/create-medical-gas"; + final MedicalGasDataModel? dataModel; + + CreateMedicalGasRequestPage({Key? key, this.dataModel}) : super(key: key); + + @override + _CreateMedicalGasRequestPageState createState() => _CreateMedicalGasRequestPageState(); +} + +class _CreateMedicalGasRequestPageState extends State with TickerProviderStateMixin { + final List attachments = []; + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + TaskType? selectedType; + MedicalGasFormModel _medicalGasFormModel = MedicalGasFormModel(); + MedicalGasSupplierModel? medicalGasInfo; + late MedicalGasInspectionProvider medicalGasInspectionProvider; + bool isGasInfoLoading = false; + + @override + void initState() { + super.initState(); + // Provider.of(context, listen: false).reset(); + medicalGasInspectionProvider = Provider.of(context, listen: false); + _populateFormData(); + } + + _populateFormData() { + if (widget.dataModel != null) { + MedicalGasDataModel dataModel = widget.dataModel!; + _medicalGasFormModel = MedicalGasFormModel( + id: dataModel.id, + orderType: Lookup(id: dataModel.requestOrderTypeId, name: dataModel.requestOrderType), + itemType: Lookup(id: dataModel.itemTypeId, name: dataModel.itemType), + site: Site(id: dataModel.siteId, custName: dataModel.site), + supplier: MedicalGasSupplierModel(id: dataModel.supplierId, supplier: dataModel.supplier), + ); + List attributeInfo = []; + dataModel.requestDetailDtos.forEach((v) { + attributeInfo.add(AttributeInfo.fromJson(v.toJson())); + }); + medicalGasInfo = MedicalGasSupplierModel( + supplierContact: dataModel.contact, + supplierEmail: dataModel.email, + attributeInfo: attributeInfo, + ); + setState(() {}); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar(title: 'Medical Gas Inspection'.addTranslation), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + SingleItemDropDownMenu( + context: context, + title: "Order Type", + validator: (value) { + if (value == null) return "Mandatory"; + return null; + }, + initialValue: _medicalGasFormModel.orderType, + showShadow: false, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + onSelect: (value) { + _medicalGasFormModel.orderType = value; + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: "Item Type", + validator: (value) { + if (value == null) return "Mandatory"; + return null; + }, + initialValue: _medicalGasFormModel.itemType, + showShadow: false, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + onSelect: (value) { + _medicalGasFormModel.itemType = value; + setState(() {}); + setGasInfo(); + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.site, + initialValue: _medicalGasFormModel.site, + showShadow: false, + validator: (value) { + if (value == null) return "Please select a site"; + return null; + }, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + onSelect: (value) { + _medicalGasFormModel.site = value; + setState(() {}); + setGasInfo(); + }, + ), + 8.height, + // 8.height, + // SingleItemDropDownMenu( + // context: context, + // title: context.translation.department, + // showShadow: false, + // validator: (value) { + // if (value == null) return "Please select a department"; + // return null; + // }, + // showAsBottomSheet: true, + // initialValue: _medicalGasFormModel.department, + // requestById: context.userProvider.user?.clientId, + // backgroundColor: AppColor.fieldBgColor(context), + // onSelect: (value) { + // _medicalGasFormModel.department = value; + // setState(() {}); + // }, + // ), + // 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.supplier, + initialValue: _medicalGasFormModel.supplier, + showAsBottomSheet: true, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + onSelect: (value) { + setState(() { + _medicalGasFormModel.supplier = value; + }); + setGasInfo(); + }, + ), + + if (medicalGasInfo != null) medicalGasInfoWidget(), + ], + ).toShadowContainer(context, borderRadius: 20), + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: Row( + children: [ + AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Save'.addTranslation, + onPressed: () { + _update(isSubmitted: false); + }, + // buttonColor: AppColor.primary10, + ).expanded, + 8.width, + AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Submit'.addTranslation, + onPressed: () { + _update(isSubmitted: true); + }, + // buttonColor: AppColor.primary10, + ).expanded, + ], + ), + ), + ], + ), + ), + ); + } + + void setGasInfo() async { + if (_medicalGasFormModel.itemType != null && _medicalGasFormModel.site != null && _medicalGasFormModel.supplier != null) { + setState(() { + isGasInfoLoading = true; + }); + medicalGasInfo = + await medicalGasInspectionProvider.getMedicalGasInfo(itemTypeId: _medicalGasFormModel.itemType!.id, supplierId: _medicalGasFormModel.supplier!.id, siteId: _medicalGasFormModel.site!.id); + setState(() { + isGasInfoLoading = false; + }); + } + } + + Widget medicalGasInfoWidget() { + return isGasInfoLoading + ? const CircularProgressIndicator(color: AppColor.primary10).center + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 8.height, + 'Supplier Contact: ${medicalGasInfo?.supplierContact ?? "-"}'.bodyText(context).custom(color: AppColor.black10), + 8.height, + 'Supplier Email: ${medicalGasInfo?.supplierEmail ?? "-"}'.bodyText(context).custom(color: AppColor.black10), + 8.height, + 'Items'.addTranslation.bodyText(context).custom(color: AppColor.textColor(context)), + 8.height, + // MedicalGasItemsListView( + // itemsList: medicalGasInfo?.attributeInfo ?? [], + // ), + if (medicalGasInfo!.attributeInfo!.isNotEmpty) + ListView.separated( + separatorBuilder: (_, __) => 12.height, + itemCount: medicalGasInfo!.attributeInfo!.length, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + AttributeInfo model = medicalGasInfo!.attributeInfo![index]; + return AppTextFormField( + labelText: model.itemName, + hintText: 'Enter Quantity'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.requestedQuantity != null ? model.requestedQuantity.toString() : '', + textAlign: TextAlign.center, + enable: true, + textInputType: TextInputType.number, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + onChange: (value) { + if (value.isNotEmpty) { + model.requestedQuantity = int.tryParse(value); + } + }, + style: Theme.of(context).textTheme.titleMedium, + ); + }, + ) + ], + ); + } + + Future _update({bool isSubmitted = false}) async { + if (medicalGasInfo != null && medicalGasInfo!.attributeInfo!.isNotEmpty) { + _medicalGasFormModel.gasRequestDetail = []; + for (var item in medicalGasInfo!.attributeInfo!) { + _medicalGasFormModel.gasRequestDetail?.add(MedicalGasFormDetailModel( + id: widget.dataModel != null ? item.id : 0, + medicalGasAttributeId: item.medicalGasAttributeId ?? item.id, + requestedQuantity: item.requestedQuantity, + )); + } + } + _medicalGasFormModel.isSubmitted = isSubmitted; + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + await medicalGasInspectionProvider.saveMedicalGas(model: _medicalGasFormModel).then((status) async { + Navigator.pop(context); + if (status) { + Navigator.pop(context, true); + } + }); + } +} diff --git a/lib/modules/medical_gas_inspection/medical_gas_inspection_detail_page.dart b/lib/modules/medical_gas_inspection/medical_gas_inspection_detail_page.dart new file mode 100644 index 00000000..e55e3274 --- /dev/null +++ b/lib/modules/medical_gas_inspection/medical_gas_inspection_detail_page.dart @@ -0,0 +1,152 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/api_routes/urls.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/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/medical_gas_inspection/create_medical_gas_request_page.dart'; +import 'package:test_sa/modules/medical_gas_inspection/models/medical_gas_data_model.dart'; +import 'package:test_sa/modules/medical_gas_inspection/providers/medical_gas_inspection_provider.dart'; +import 'package:test_sa/modules/medical_gas_inspection/update_delivery_notes_page.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/views/widgets/images/files_list.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class MedicalGasInspectionDetailPage extends StatefulWidget { + static const String id = "/medical-gas-inspection-detail-page"; + final int inspectionId; + final String? prority; + + MedicalGasInspectionDetailPage({Key? key, required this.inspectionId, this.prority}) : super(key: key); + + @override + State createState() => _MedicalGasInspectionDetailPageState(); +} + +class _MedicalGasInspectionDetailPageState extends State { + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + _loadData(); + }); + } + + MedicalGasDataModel? model; + bool _isLoading = true; + + Future _loadData() async { + final result = await context.read().getMedicalGasById(requestId: widget.inspectionId); + setState(() { + model = result; + _isLoading = false; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: const DefaultAppBar(title: "Request Details"), + body: SafeArea( + child: _isLoading + ? SizedBox.expand(child: const CircularProgressIndicator(color: AppColor.primary10).center) + : model == null + ? const NoDataFound().center + : Column( + children: [ + ListView( + padding: const EdgeInsets.all(16), + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + //Need to return the status form api backend + Row( + children: [ + if (widget.prority != null) ...[ + StatusLabel( + label: widget.prority, + textColor: AppColor.getRequestStatusTextColorByName(context, widget.prority), + backgroundColor: AppColor.getRequestStatusColorByName(context, widget.prority), + ), + 8.width, + ], + StatusLabel( + label: model?.requestStatus?.name, + textColor: AppColor.getHistoryLogStatusTextColorByName(model?.requestStatus?.name ?? ''), + backgroundColor: AppColor.getHistoryLogStatusColorByName(model?.requestStatus?.name ?? ''), + ), + 1.width.expanded, + Text(model!.requestedDate!.toServiceRequestCardFormat, + textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50)) + ], + ), + 8.height, + Text("Request Details", style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), + '${context.translation.requestNo}: ${model?.requestNumber ?? '-'}'.bodyText(context), + 'Order Type: ${model?.requestOrderType ?? '-'}'.bodyText(context), + 'Item Type: ${model?.itemType ?? '-'}'.bodyText(context), + 'Site: ${model?.site ?? '-'}'.bodyText(context), + 'Supplier Name: ${model?.supplier ?? '-'}'.bodyText(context), + 'Supplier Contact: ${model?.contact ?? '-'}'.bodyText(context), + 'Supplier Email: ${model?.email ?? '-'}'.bodyText(context), + if (model!.deliveryNoteAttachmentDto.isNotEmpty) ...[ + const Divider().defaultStyle(context), + Text( + "Attachments".addTranslation, + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + FilesList(images: model!.deliveryNoteAttachmentDto.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), + ], + ], + ).toShadowContainer(context, padding: 12), + ], + ).expanded, + if (model?.requestStatus?.value != null && model!.requestStatus!.value! < 3) + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: model?.isSubmitted == true ? "Upload Delivery Note" : 'Update', + onPressed: () async { + if (model?.isSubmitted == true) { + bool? isRefresh = await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdateDeliveryNotes(dataModel: model))); + if (isRefresh == true) { + _loadData(); + } + return; + } + bool? isRefresh = await Navigator.of(context).push(MaterialPageRoute( + builder: (_) => CreateMedicalGasRequestPage( + dataModel: model, + ))); + if (isRefresh == true) { + _loadData(); + } + }), + ), + ], + ), + )); + } + + Widget labelValueText(BuildContext context, String label, String? value) { + if (value == null || value.isEmpty) return const SizedBox.shrink(); + + return Padding( + padding: const EdgeInsets.only(bottom: 4), + child: Text( + '$label: $value', + style: AppTextStyles.bodyText.copyWith( + color: context.isDark ? AppColor.neutral30 : AppColor.neutral120, + ), + ), + ); + } +} diff --git a/lib/modules/medical_gas_inspection/medical_gas_inspection_item_view.dart b/lib/modules/medical_gas_inspection/medical_gas_inspection_item_view.dart new file mode 100644 index 00000000..e03fc500 --- /dev/null +++ b/lib/modules/medical_gas_inspection/medical_gas_inspection_item_view.dart @@ -0,0 +1,130 @@ +import 'dart:developer'; + +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/models/all_requests_and_count_model.dart'; +import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/medical_gas_inspection/medical_gas_inspection_detail_page.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class MedicalGasInspectionItemView extends StatelessWidget { + final Data? requestData; + final RequestsDetails? requestDetails; + final bool showShadow; + + const MedicalGasInspectionItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); + + @override + Widget build(BuildContext context) { + if (requestData != null) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (requestData!.priorityName != null) ...[ + StatusLabel( + label: requestData!.priorityName!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.priorityName!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.priorityName!), + ), + 8.width, + ], + StatusLabel( + label: requestData!.statusName!, + textColor: AppColor.getHistoryLogStatusTextColorByName(requestData!.statusName!), + backgroundColor: AppColor.getHistoryLogStatusColorByName(requestData!.statusName!), + ), + 1.width.expanded, + Text(requestData!.transactionDate!.toServiceRequestCardFormat, + textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50)), + ], + ), + (requestData?.typeTransaction ?? 'Medical Gas Request').heading5(context), + infoWidget(label: 'Request Number'.addTranslation, value: requestData?.requestNo ?? '-', context: context), + infoWidget(label: 'Request Type'.addTranslation, value: requestData?.requestType ?? '-', context: context), + // infoWidget(label: 'Site'.addTranslation, value: requestData?.si ?? '-', context: context), + // infoWidget(label: 'Gas Type'.addTranslation, value: requestDetails?.gasType ?? '-', context: context), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.of(context).push(MaterialPageRoute( + builder: (_) => MedicalGasInspectionDetailPage( + inspectionId: requestData!.id!, + prority: requestData?.priorityName, + ))); + }); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (requestDetails!.priority != null) ...[ + StatusLabel( + label: requestDetails!.priority!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails!.priority!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails!.priority!), + ), + 8.width, + ], + StatusLabel( + label: requestDetails!.status!, + textColor: AppColor.getHistoryLogStatusTextColorByName(requestDetails!.status!), + backgroundColor: AppColor.getHistoryLogStatusColorByName(requestDetails!.status!), + ), + 1.width.expanded, + Text(requestDetails!.date!.toServiceRequestCardFormat, textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50)), + ], + ), + (requestDetails?.nameOfType ?? 'Medical Gas Request').heading5(context), + infoWidget(label: 'Request Number'.addTranslation, value: requestDetails?.requestNo ?? '-', context: context), + infoWidget(label: 'Request Type'.addTranslation, value: requestDetails?.requestType ?? '-', context: context), + infoWidget(label: 'Site'.addTranslation, value: requestDetails?.site ?? '-', context: context), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.of(context).push(MaterialPageRoute( + builder: (_) => MedicalGasInspectionDetailPage( + inspectionId: requestDetails!.id!, + prority: requestDetails?.priority, + ))); + }); + } + + Widget infoWidget({required String label, String? value, required BuildContext context}) { + if (value != null && value.isNotEmpty) { + return '$label: $value'.bodyText(context); + } + return const SizedBox(); + } +} diff --git a/lib/modules/medical_gas_inspection/medical_gas_item_list_view.dart b/lib/modules/medical_gas_inspection/medical_gas_item_list_view.dart new file mode 100644 index 00000000..7b399233 --- /dev/null +++ b/lib/modules/medical_gas_inspection/medical_gas_item_list_view.dart @@ -0,0 +1,94 @@ +// import 'dart:developer'; +// +// import 'package:flutter/material.dart'; +// import 'package:provider/provider.dart'; +// import 'package:test_sa/extensions/context_extension.dart'; +// import 'package:test_sa/extensions/enum_extensions.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/lookup.dart'; +// import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; +// import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; +// import 'package:test_sa/modules/asset_delivery_module/provider/cost_center_provider.dart'; +// import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +// import 'package:test_sa/modules/medical_gas_inspection/models/medical_gas_supplier_model.dart'; +// import 'package:test_sa/new_views/app_style/app_color.dart'; +// import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +// import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +// import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +// import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +// import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +// +// class MedicalGasItemsListView extends StatelessWidget { +// final List itemsList; +// +// MedicalGasItemsListView({ +// super.key, +// required this.itemsList, +// }); +// +// late AssetDeliveryProvider assetDeliveryProvider; +// +// @override +// Widget build(BuildContext context) { +// // return ListView.separated( +// // separatorBuilder: (_, __) => 12.height, +// // itemCount: itemsList.length, +// // shrinkWrap: true, +// // itemBuilder: (context, index) { +// // AttributeInfo model = itemsList[index]; +// // return AppTextFormField( +// // labelText: model.itemName, +// // hintText: 'Enter Quantity'.addTranslation, +// // backgroundColor: AppColor.fieldBgColor(context), +// // initialValue: model.requestedQuantity != null ? model.requestedQuantity.toString() : '', +// // textAlign: TextAlign.center, +// // enable: true, +// // textInputType: TextInputType.number, +// // labelStyle: AppTextStyles.textFieldLabelStyle, +// // showShadow: false, +// // onChange: (value) { +// // if (value.isNotEmpty) { +// // model.requestedQuantity = int.tryParse(value); +// // } +// // }, +// // style: Theme.of(context).textTheme.titleMedium, +// // ); +// // }, +// // ); +// } +// } +// +// // class ItemCard extends StatelessWidget { +// // final AttributeInfo model; +// // final int index; +// // +// // const ItemCard({ +// // super.key, +// // required this.model, +// // required this.index, +// // }); +// // +// // @override +// // Widget build(BuildContext context) { +// // return AppTextFormField( +// // labelText: model.itemName, +// // hintText: 'Enter Quantity'.addTranslation, +// // backgroundColor: AppColor.fieldBgColor(context), +// // initialValue: model.requestedQuantity != null ? model.requestedQuantity.toString() : '', +// // textAlign: TextAlign.center, +// // enable: true, +// // textInputType: TextInputType.number, +// // labelStyle: AppTextStyles.textFieldLabelStyle, +// // showShadow: false, +// // onChange: (value) { +// // if (value.isNotEmpty) { +// // model.requestedQuantity = int.tryParse(value); +// // } +// // }, +// // style: Theme.of(context).textTheme.titleMedium, +// // ); +// // } +// // } diff --git a/lib/modules/medical_gas_inspection/models/delivery_notes_form_model.dart b/lib/modules/medical_gas_inspection/models/delivery_notes_form_model.dart new file mode 100644 index 00000000..5b86859c --- /dev/null +++ b/lib/modules/medical_gas_inspection/models/delivery_notes_form_model.dart @@ -0,0 +1,92 @@ +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/modules/medical_gas_inspection/models/medical_gas_data_model.dart'; + +class DeliveryNotesFormModel { + int? id; + DateTime? deliveredDate; + String? deliveryNoteNumber; + bool? isPressureChecked; + bool? isInspectedGasLeak; + bool? isSubmitted; + + List gasDeliveredQuantityDtos = []; + List deliveredItemList = []; + List attachments = []; + + DeliveryNotesFormModel({ + this.id, + this.deliveredDate, + this.deliveryNoteNumber, + this.isPressureChecked, + this.isInspectedGasLeak, + this.isSubmitted, + List? gasDeliveredQuantityDtos, + List? deliveredItemList, + List? attachments, + }) { + this.gasDeliveredQuantityDtos = gasDeliveredQuantityDtos ?? []; + this.deliveredItemList = deliveredItemList ?? []; + this.attachments = attachments ?? []; + } + + DeliveryNotesFormModel.fromJson(Map json) { + id = json['id']; + deliveredDate = json['deliveredDate'] != null ? DateTime.parse(json['deliveredDate']) : null; + deliveryNoteNumber = json['deliveryNoteNumber']; + isPressureChecked = json['isPressureChecked']; + isInspectedGasLeak = json['isInspectedGasLeak']; + isSubmitted = json['isSubmitted']; + if (json['gasDeliveredQuantityDtos'] != null) { + gasDeliveredQuantityDtos = []; + json['gasDeliveredQuantityDtos'].forEach((v) { + gasDeliveredQuantityDtos.add(GasDeliveredQuantityModel.fromJson(v)); + }); + } + + if (json['cUMedicalGasDeliveryNoteAttachmentDtos'] != null) { + attachments = []; + json['cUMedicalGasDeliveryNoteAttachmentDtos'].forEach((v) { + attachments.add(GenericAttachmentModel.fromJson(v)); + }); + } + } + + Map toJson() { + return { + 'id': id, + 'deliveredDate': deliveredDate?.toIso8601String(), + 'deliveryNoteNumber': deliveryNoteNumber, + 'isPressureChecked': isPressureChecked, + 'isInspectedGasLeak': isInspectedGasLeak, + 'isSubmitted': isSubmitted, + 'gasDeliveredQuantityDtos': gasDeliveredQuantityDtos.map((e) => e.toJson()).toList(), + 'cUMedicalGasDeliveryNoteAttachmentDtos': attachments.map((e) => e.toJson()).toList(), + }; + } +} + +class GasDeliveredQuantityModel { + int? id; + num? medicalGasAttributeId; + num? deliveredQuantity; + + GasDeliveredQuantityModel({ + this.id, + this.medicalGasAttributeId, + this.deliveredQuantity, + }); + + GasDeliveredQuantityModel.fromJson(Map json) { + id = json['id']; + medicalGasAttributeId = json['medicalGasAttributeId']; + deliveredQuantity = json['deliveredQuantity']; + } + + Map toJson() { + return { + 'id': id, + 'medicalGasAttributeId': medicalGasAttributeId, + 'deliveredQuantity': deliveredQuantity, + }; + } +} diff --git a/lib/modules/medical_gas_inspection/models/medical_gas_data_model.dart b/lib/modules/medical_gas_inspection/models/medical_gas_data_model.dart new file mode 100644 index 00000000..01dc4a7b --- /dev/null +++ b/lib/modules/medical_gas_inspection/models/medical_gas_data_model.dart @@ -0,0 +1,169 @@ +import 'package:test_sa/models/base.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/lookup.dart'; + +class MedicalGasDataModel { + int? id; + String? requestNumber; + String? requestedBy; + String? requestedDate; + int? requestOrderTypeId; + String? requestOrderType; + int? itemTypeId; + String? itemType; + int? siteId; + String? site; + int? supplierId; + String? supplier; + String? contact; + String? email; + bool? isSubmitted; + String? requestOrderStatus; + bool? isPressureChecked; + bool? isInspectedGasLeak; + Lookup? requestStatus; + DateTime? deliveredDate; + String? deliveryNote; + + /// ✅ non-nullable lists + List requestDetailDtos = []; + List deliveryNoteAttachmentDto = []; + + MedicalGasDataModel({ + this.id, + this.requestNumber, + this.requestedBy, + this.requestedDate, + this.requestOrderTypeId, + this.requestOrderType, + this.itemTypeId, + this.itemType, + this.siteId, + this.site, + this.requestStatus, + this.supplierId, + this.supplier, + this.contact, + this.email, + this.isSubmitted, + this.requestOrderStatus, + this.isPressureChecked, + this.isInspectedGasLeak, + this.deliveredDate, + this.deliveryNote, + List? requestDetailDtos, + List? deliveryNoteAttachmentDto, + }) { + this.requestDetailDtos = requestDetailDtos ?? []; + this.deliveryNoteAttachmentDto = deliveryNoteAttachmentDto ?? []; + } + + MedicalGasDataModel.fromJson(Map json) { + id = json['id']; + requestNumber = json['requestNumber']; + requestedBy = json['requestedBy']; + requestedDate = json['requestedDate']; + requestOrderTypeId = json['requestOrderTypeId']; + requestOrderType = json['requestOrderType']; + itemTypeId = json['itemTypeId']; + itemType = json['itemType']; + siteId = json['siteId']; + site = json['site']; + supplierId = json['supplierId']; + supplier = json['supplier']; + contact = json['contact']; + email = json['email']; + isSubmitted = json['isSubmitted']; + deliveryNote = json['deliveryNote']; + requestOrderStatus = json['requestOrderStatus']; + isPressureChecked = json['isPressureChecked']; + isInspectedGasLeak = json['isInspectedGasLeak']; + deliveredDate = json['deliveredDate'] != null ? DateTime.parse(json['deliveredDate']) : null; + requestStatus = json['requestOrderStatusDto'] != null ? Lookup.fromJson(json['requestOrderStatusDto']) : null; + if (json['requestDetailDtos'] != null) { + requestDetailDtos = []; + json['requestDetailDtos'].forEach((v) { + requestDetailDtos.add(MedicalGasRequestDetailModel.fromJson(v)); + }); + } + + if (json['deliveryNoteAttachmentDto'] != null) { + deliveryNoteAttachmentDto = []; + json['deliveryNoteAttachmentDto'].forEach((v) { + deliveryNoteAttachmentDto.add(GenericAttachmentModel.fromJson(v)); + }); + } + } + + Map toJson() { + return { + 'id': id, + 'requestNumber': requestNumber, + 'requestedBy': requestedBy, + 'requestedDate': requestedDate, + 'requestOrderTypeId': requestOrderTypeId, + 'requestOrderType': requestOrderType, + 'itemTypeId': itemTypeId, + 'itemType': itemType, + 'siteId': siteId, + 'site': site, + 'supplierId': supplierId, + 'deliveryNote': deliveryNote, + 'supplier': supplier, + 'contact': contact, + 'email': email, + 'isSubmitted': isSubmitted, + 'requestOrderStatus': requestOrderStatus, + 'isPressureChecked': isPressureChecked, + 'isInspectedGasLeak': isInspectedGasLeak, + 'deliveredDate': deliveredDate?.toIso8601String(), + 'requestDetailDtos': requestDetailDtos.map((e) => e.toJson()).toList(), + 'requestOrderStatusDto': requestStatus?.toJson(), + 'deliveryNoteAttachmentDto': deliveryNoteAttachmentDto.map((e) => e.toJson()).toList(), + }; + } +} + +class MedicalGasRequestDetailModel extends Base { + int? id; + int? medicalGasAttributeId; + String? itemName; + String? oracleName; + String? oracleCode; + num? requestedQuantity; + num? deliveredQuantity; + + MedicalGasRequestDetailModel({ + this.id, + this.medicalGasAttributeId, + this.itemName, + this.oracleName, + this.oracleCode, + this.requestedQuantity, + this.deliveredQuantity, + }) : super(identifier: id?.toString(), name: itemName); + + MedicalGasRequestDetailModel.fromJson(Map json) { + id = json['id']; + medicalGasAttributeId = json['medicalGasAttributeId']; + itemName = json['itemName']; + identifier = id.toString(); + name = itemName; + oracleName = json['oracleName']; + oracleCode = json['oracleCode']; + requestedQuantity = json['requestedQuantity']; + deliveredQuantity = json['deliveredQuantity']; + } + + Map toJson() { + return { + 'id': id, + 'medicalGasAttributeId': medicalGasAttributeId, + 'itemName': itemName, + 'oracleName': oracleName, + 'oracleCode': oracleCode, + 'requestedQuantity': requestedQuantity, + 'deliveredQuantity': deliveredQuantity, + }; + } +} diff --git a/lib/modules/medical_gas_inspection/models/medical_gas_form_model.dart b/lib/modules/medical_gas_inspection/models/medical_gas_form_model.dart new file mode 100644 index 00000000..a3f08ac1 --- /dev/null +++ b/lib/modules/medical_gas_inspection/models/medical_gas_form_model.dart @@ -0,0 +1,87 @@ +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/new_models/site.dart'; +import 'package:test_sa/modules/loan_module/models/medical_department_model.dart'; +import 'package:test_sa/modules/medical_gas_inspection/models/medical_gas_supplier_model.dart'; + +class MedicalGasFormModel { + int? id; + int? requestOrderTypeId; + Lookup? orderType; + Lookup? itemType; + int? itemTypeId; + int? siteId; + Site? site; + MedicalDepartmentModel? department; + MedicalGasSupplierModel? supplier; + int? supplierId; + bool? isSubmitted; + List? gasRequestDetail; + + MedicalGasFormModel({ + this.id, + this.requestOrderTypeId, + this.itemTypeId, + this.siteId, + this.supplierId, + this.supplier, + this.isSubmitted, + this.orderType, + this.itemType, + this.site, + this.department, + this.gasRequestDetail, + }); + + MedicalGasFormModel.fromJson(Map json) { + id = json['id']; + requestOrderTypeId = json['requestOrderTypeId']; + itemTypeId = json['itemTypeId']; + siteId = json['siteId']; + supplierId = json['supplierId']; + isSubmitted = json['isSubmitted']; + if (json['gasRequestDetailDtos'] != null) { + gasRequestDetail = []; + json['gasRequestDetailDtos'].forEach((v) { + gasRequestDetail!.add(MedicalGasFormDetailModel.fromJson(v)); + }); + } + } + + Map toJson() { + return { + 'id': id ?? 0, + 'requestOrderTypeId': orderType?.id, + 'itemTypeId': itemType?.id, + 'siteId': site?.id, + 'supplierId': supplier?.id, + 'isSubmitted': isSubmitted, + 'gasRequestDetailDtos': gasRequestDetail?.map((e) => e.toJson()).toList(), + }; + } +} + +class MedicalGasFormDetailModel { + int? id; + int? medicalGasAttributeId; + num? requestedQuantity; + + MedicalGasFormDetailModel({ + this.id, + this.medicalGasAttributeId, + this.requestedQuantity, + }); + + MedicalGasFormDetailModel.fromJson(Map json) { + id = json['id']; + medicalGasAttributeId = json['medicalGasAttributeId']; + requestedQuantity = json['requestedQuantity']; + } + + Map toJson() { + return { + 'id': id, + 'medicalGasAttributeId': medicalGasAttributeId, + 'requestedQuantity': requestedQuantity??0, + }; + } +} diff --git a/lib/modules/medical_gas_inspection/models/medical_gas_supplier_model.dart b/lib/modules/medical_gas_inspection/models/medical_gas_supplier_model.dart new file mode 100644 index 00000000..17ca804f --- /dev/null +++ b/lib/modules/medical_gas_inspection/models/medical_gas_supplier_model.dart @@ -0,0 +1,72 @@ + + +import 'package:test_sa/models/base.dart'; + +class MedicalGasSupplierModel extends Base { + int? id; + String? supplier; + String? supplierEmail; + String? supplierContact; + List? attributeInfo; + + MedicalGasSupplierModel({this.id, this.supplier, this.supplierContact, this.supplierEmail, this.attributeInfo}) : super(identifier: id?.toString() ?? '', name: supplier); + + MedicalGasSupplierModel.fromJson(Map json) { + id = json['id']; + identifier = id?.toString() ?? ''; + supplier = json['supplier']; + name=supplier; + supplierEmail = json['supplierEmail']; + supplierContact = json['supplierContact']; + if (json['attributeInfoDtos'] != null) { + attributeInfo = []; + json['attributeInfoDtos'].forEach((v) { + attributeInfo!.add(AttributeInfo.fromJson(v)); + }); + } + } + + Map toJson() { + return { + 'id': id, + 'supplier': supplier, + 'supplierEmail': supplierEmail, + 'supplierContact': supplierContact, + 'attributeInfoDtos': attributeInfo?.map((e) => e.toJson()).toList(), + }; + } +} + +class AttributeInfo { + int? id; + int? medicalGasAttributeId; + num? requestedQuantity; + String? itemName; + String? oracleName; + String? oracleCode; + + AttributeInfo({this.id, this.medicalGasAttributeId, this.requestedQuantity, this.itemName, this.oracleName, this.oracleCode}); + + AttributeInfo.fromJson(Map json) { + id = json['id']; + medicalGasAttributeId = json['medicalGasAttributeId']; + requestedQuantity = json['requestedQuantity']; + itemName = json['itemName']; + oracleName = json['oracleName']; + oracleCode = json['oracleCode']; + } + + Map toJson() { + //{ + // "id": 0, + // "medicalGasAttributeId": 0, + // "requestedQuantity": 0 + // } + return { + 'id': id, + 'medicalGasAttributeId': medicalGasAttributeId, + 'requestedQuantity': requestedQuantity, + // 'oracleCode': oracleCode, + }; + } +} diff --git a/lib/modules/medical_gas_inspection/providers/item_type_provider.dart b/lib/modules/medical_gas_inspection/providers/item_type_provider.dart new file mode 100644 index 00000000..e7c38208 --- /dev/null +++ b/lib/modules/medical_gas_inspection/providers/item_type_provider.dart @@ -0,0 +1,33 @@ +import 'dart:convert'; +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/models/lookup.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +class MedicalGasItemTypeProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading == true) return -2; + loading = true; + notifyListeners(); + loading = true; + notifyListeners(); + try { + Response response = await ApiManager.instance.get(URLs.itemTypeLookUp); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List categoriesListJson = json.decode(response.body)["data"]; + items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } +} diff --git a/lib/modules/medical_gas_inspection/providers/medical_gas_inspection_provider.dart b/lib/modules/medical_gas_inspection/providers/medical_gas_inspection_provider.dart new file mode 100644 index 00000000..a28c76ee --- /dev/null +++ b/lib/modules/medical_gas_inspection/providers/medical_gas_inspection_provider.dart @@ -0,0 +1,119 @@ +import 'dart:convert'; +import 'dart:developer'; +import 'package:flutter/material.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/modules/medical_gas_inspection/models/delivery_notes_form_model.dart'; +import 'package:test_sa/modules/medical_gas_inspection/models/medical_gas_data_model.dart'; +import 'package:test_sa/modules/medical_gas_inspection/models/medical_gas_form_model.dart'; +import 'package:test_sa/modules/medical_gas_inspection/models/medical_gas_supplier_model.dart'; + +class MedicalGasInspectionProvider extends ChangeNotifier { + final pageItemNumber = 10; + final searchPageItemNumber = 10; + int pageNo = 1; + + void reset() { + pageNo = 1; + stateCode = null; + } + + int? stateCode; + bool isDetailLoading = false; + bool nextPage = false; + bool isLoading = false; + bool isGasInfoLoading = false; + + Future getMedicalGasById({int? requestId}) async { + MedicalGasDataModel? assetDeliveryDataModel = MedicalGasDataModel(); + + try { + isLoading = true; + notifyListeners(); + final response = await ApiManager.instance.get(URLs.getMedicalGasById + "?medicalGasRequestId=$requestId"); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + assetDeliveryDataModel = MedicalGasDataModel.fromJson(json.decode(response.body)["data"]); + } else { + assetDeliveryDataModel = null; + } + isLoading = false; + notifyListeners(); + return assetDeliveryDataModel; + } catch (e) { + log("getMedicalGas details [error] : $e"); + isLoading = false; + assetDeliveryDataModel = null; + notifyListeners(); + return assetDeliveryDataModel; + } + } + + Future saveMedicalGas({ + required MedicalGasFormModel model, + }) async { + isLoading = true; + try { + final response = await ApiManager.instance.post(URLs.addMedicalGasRequest, body: model.toJson()); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + isLoading = false; + notifyListeners(); + return true; + } else { + isLoading = false; + notifyListeners(); + return false; + } + } catch (error) { + isLoading = false; + notifyListeners(); + return false; + } + } + + Future getMedicalGasInfo({int? supplierId, int? itemTypeId, num? siteId}) async { + MedicalGasSupplierModel? supplierInfo; + Map payload = {"supplierId": supplierId, "itemTypeId": itemTypeId, "siteId": siteId}; + try { + isGasInfoLoading = true; + notifyListeners(); + final response = await ApiManager.instance.post("${URLs.getMedicalGasInfoBySupplier}", body: payload); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + final jsonData = json.decode(response.body)["data"]; + supplierInfo = MedicalGasSupplierModel.fromJson(jsonData); + } + isGasInfoLoading = false; + notifyListeners(); + return supplierInfo; + } catch (e) { + log("get Supplier List [error] : $e"); + isGasInfoLoading = false; + notifyListeners(); + return supplierInfo; + } + } + Future updatedDeliveryNotes({ + required DeliveryNotesFormModel model, + }) async { + isLoading = true; + try { + final response = await ApiManager.instance.post(URLs.updateDeliveryNote, body: model.toJson()); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + isLoading = false; + notifyListeners(); + return true; + } else { + isLoading = false; + notifyListeners(); + return false; + } + } catch (error) { + isLoading = false; + notifyListeners(); + return false; + } + } +} diff --git a/lib/modules/medical_gas_inspection/providers/medical_gas_supplier_provider.dart b/lib/modules/medical_gas_inspection/providers/medical_gas_supplier_provider.dart new file mode 100644 index 00000000..d7127726 --- /dev/null +++ b/lib/modules/medical_gas_inspection/providers/medical_gas_supplier_provider.dart @@ -0,0 +1,34 @@ +import 'dart:convert'; +import 'dart:developer'; + +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/models/lookup.dart'; +import 'package:test_sa/modules/medical_gas_inspection/models/medical_gas_supplier_model.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +class MedicalGasSupplierProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + loading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.get(URLs.getMedicalGasSupplierList); + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List listJson = json.decode(response.body)["data"]; + items = listJson.map((supplier) => MedicalGasSupplierModel.fromJson(supplier)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } +} diff --git a/lib/modules/medical_gas_inspection/providers/order_type_provider.dart b/lib/modules/medical_gas_inspection/providers/order_type_provider.dart new file mode 100644 index 00000000..32d19716 --- /dev/null +++ b/lib/modules/medical_gas_inspection/providers/order_type_provider.dart @@ -0,0 +1,33 @@ +import 'dart:convert'; +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/models/lookup.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +class MedicalGasOrderTypeProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading == true) return -2; + loading = true; + notifyListeners(); + loading = true; + notifyListeners(); + try { + Response response = await ApiManager.instance.get(URLs.orderTypeLookUp); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List categoriesListJson = json.decode(response.body)["data"]; + items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } +} diff --git a/lib/modules/medical_gas_inspection/update_delivery_notes_page.dart b/lib/modules/medical_gas_inspection/update_delivery_notes_page.dart new file mode 100644 index 00000000..c87e511e --- /dev/null +++ b/lib/modules/medical_gas_inspection/update_delivery_notes_page.dart @@ -0,0 +1,288 @@ +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/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/medical_gas_inspection/models/delivery_notes_form_model.dart'; +import 'package:test_sa/modules/medical_gas_inspection/models/medical_gas_data_model.dart'; +import 'package:test_sa/modules/medical_gas_inspection/providers/medical_gas_inspection_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/new_views/common_widgets/multiple_item_drop_down_menu.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; + +class UpdateDeliveryNotes extends StatefulWidget { + final MedicalGasDataModel? dataModel; + + UpdateDeliveryNotes({Key? key, required this.dataModel}) : super(key: key); + + @override + _UpdateDeliveryNotesState createState() { + return _UpdateDeliveryNotesState(); + } +} + +class _UpdateDeliveryNotesState extends State { + DeliveryNotesFormModel formModel = DeliveryNotesFormModel(); + late MedicalGasInspectionProvider medicalGasInspectionProvider; + bool pressureTestAcknowledgement = false; + bool leakTestAcknowledgement = false; + List selectedItemList = []; + + @override + void initState() { + super.initState(); + medicalGasInspectionProvider = Provider.of(context, listen: false); + _populateFormData(); + } + + @override + void dispose() { + super.dispose(); + } + + _populateFormData() { + if (widget.dataModel != null) { + MedicalGasDataModel dataModel = widget.dataModel!; + formModel = DeliveryNotesFormModel( + id: dataModel.id, + deliveredItemList: dataModel.requestDetailDtos, + isInspectedGasLeak: dataModel.isInspectedGasLeak, + isPressureChecked: dataModel.isPressureChecked, + deliveredDate: dataModel.deliveredDate, + attachments: dataModel.deliveryNoteAttachmentDto, + isSubmitted: dataModel.isSubmitted, + deliveryNoteNumber: dataModel.deliveryNote); + //Need to Confirm this condition + selectedItemList = dataModel.requestDetailDtos.where((item) => item.deliveredQuantity != null && item.deliveredQuantity! > 0).toList(); + setState(() {}); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: const DefaultAppBar( + title: "Upload Delivery Note", + // onWillPopScope: () { + // _update(context: context); + // }, + ), + body: SafeArea( + child: Column( + children: [ + ListView( + padding: const EdgeInsets.all(16), + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ADatePicker( + label: "Delivered Date", + hideShadow: true, + backgroundColor: AppColor.fieldBgColor(context), + from: DateTime.now().subtract(const Duration(days: 365 * 3)), + date: formModel.deliveredDate, + formatDateWithTime: true, + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + if (selectedTime != null) { + formModel.deliveredDate = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); + setState(() {}); + } + }); + }, + ), + 16.height, + MultipleItemDropDownMenu( + context: context, + showAsBottomSheet: true, + backgroundColor: AppColor.neutral100, + showShadow: false, + showCancel: true, + requestById: context.userProvider.user?.clientId, + title: 'Delivered Items'.addTranslation, + staticData: formModel.deliveredItemList, + initialValue: selectedItemList, + onSelect: (value) { + if ((value ?? []).isNotEmpty) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; + setState(() { + selectedItemList = value ?? []; + }); + }); + } + }, + ), + if (selectedItemList.isNotEmpty) ...[ + 8.height, + ListView.separated( + separatorBuilder: (_, __) => 12.height, + itemCount: selectedItemList.length, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + MedicalGasRequestDetailModel model = selectedItemList[index]; + return AppTextFormField( + labelText: '${model.name} (Req Qty =${model.requestedQuantity})', + hintText: 'Enter Delivered Quantity'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.deliveredQuantity != null ? model.deliveredQuantity?.toInt().toString() : '', + textAlign: TextAlign.center, + enable: true, + textInputType: TextInputType.number, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + onChange: (value) { + if (value.isNotEmpty) { + model.deliveredQuantity = double.tryParse(value); + } + }, + style: Theme.of(context).textTheme.titleMedium, + ); + }, + ) + ], + 16.height, + AppTextFormField( + initialValue: formModel.deliveryNoteNumber, + labelText: "Delivery Notes", + validator: (value) { + if ((value ?? "").isEmpty) return "Mandatory"; + return null; + }, + backgroundColor: AppColor.fieldBgColor(context), + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + floatingLabelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + showShadow: false, + textInputType: TextInputType.multiline, + makeMultiLinesNull: true, + onChange: (value) { + formModel.deliveryNoteNumber = value; + }, + ), + 16.height, + AttachmentPicker( + label: 'Upload Attachment', + attachment: formModel.attachments, + buttonColor: AppColor.primary10, + // showAsListView: true, + onlyImages: false, + buttonIcon: 'attachment_icon'.toSvgAsset( + color: AppColor.primary10, + ), + ), + 16.height, + //should create a reusable widget. + Row( + children: [ + Checkbox( + value: formModel.isPressureChecked, + visualDensity: const VisualDensity(horizontal: -4.0, vertical: -4.0), + activeColor: AppColor.blueStatus(context), + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + onChanged: (value) { + setState(() { + formModel.isPressureChecked = value!; + }); + }), + 12.width, + "I Acknowledge that the received medical gases cylinders have been tested for pressure." + .addTranslation + .bodyText(context) + .custom(color: context.isDark ? AppColor.primary50 : AppColor.neutral120) + .expanded, + ], + ), + 8.height, + Row( + // mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Checkbox( + value: formModel.isInspectedGasLeak, + visualDensity: const VisualDensity(horizontal: -4.0, vertical: -4.0), + activeColor: AppColor.blueStatus(context), + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + onChanged: (value) { + setState(() { + formModel.isInspectedGasLeak = value!; + }); + }), + 12.width, + "I Acknowledge that the received medical gases cylinders have been inspected for leak test." + .addTranslation + .bodyText(context) + .custom(color: context.isDark ? AppColor.primary50 : AppColor.neutral120) + .expanded, + ], + ), + ], + ).toShadowContainer(context, padding: 12), + ], + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: Row( + children: [ + AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Save'.addTranslation, + onPressed: () { + _update(context: context); + }, + // buttonColor: AppColor.primary10, + ).expanded, + 8.width, + AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Submit'.addTranslation, + onPressed: () { + _update(context: context, isSubmitted: true); + }, + // buttonColor: AppColor.primary10, + ).expanded, + ], + ), + ), + ], + ), + )); + // .handlePopScope( + // cxt: context, + // onSave: () { + // _update(context: context); + // }); + } + + void _update({required BuildContext context, bool isSubmitted = false}) async { + formModel.gasDeliveredQuantityDtos = []; + formModel.isSubmitted = isSubmitted; + for (var item in selectedItemList) { + formModel.gasDeliveredQuantityDtos.add(GasDeliveredQuantityModel( + id: widget.dataModel != null ? item.id : 0, + medicalGasAttributeId: item.medicalGasAttributeId ?? item.id, + deliveredQuantity: item.deliveredQuantity, + )); + } + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + await medicalGasInspectionProvider.updatedDeliveryNotes(model: formModel).then((status) async { + Navigator.pop(context); + if (status) { + Navigator.pop(context, true); + } + }); + } +} diff --git a/lib/new_views/app_style/app_color.dart b/lib/new_views/app_style/app_color.dart index 8adc321d..8f2ab1c6 100644 --- a/lib/new_views/app_style/app_color.dart +++ b/lib/new_views/app_style/app_color.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:test_sa/extensions/context_extension.dart'; @@ -119,6 +121,8 @@ class AppColor { return orange60; case "high priority": return white10; + case "emergency": + return white10; case "yes": return white10; case "low priority": @@ -134,6 +138,8 @@ class AppColor { switch ((status).toLowerCase()) { case "in progress": return white936; + case "waiting for delivery": + return white936; case "new": return primary63; case "open": @@ -193,6 +199,14 @@ class AppColor { return red30; case "returned": return red30; + case "waiting for delivery": + return orange30; + case "waiting for medical gas specialist review": + return orange30; + case "reviewed": + return orange30; + case "returned for correction": + return orange30; default: return Colors.white; } @@ -210,6 +224,8 @@ class AppColor { return greenStatus(context); case "high priority": return redStatus(context); + case "emergency": + return redStatus(context); case "yes": return redStatus(context); case "low priority": diff --git a/lib/new_views/pages/land_page/create_request_type_bottom_sheet.dart b/lib/new_views/pages/land_page/create_request_type_bottom_sheet.dart index 030b2895..0bd10a54 100644 --- a/lib/new_views/pages/land_page/create_request_type_bottom_sheet.dart +++ b/lib/new_views/pages/land_page/create_request_type_bottom_sheet.dart @@ -13,6 +13,7 @@ import 'package:test_sa/modules/cm_module/create_cm_request.dart'; import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart'; import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart'; import 'package:test_sa/modules/loan_module/pages/create_loan_request_page.dart'; +import 'package:test_sa/modules/medical_gas_inspection/create_medical_gas_request_page.dart'; import 'package:test_sa/modules/tm_module/device_transfer/create_device_transfer_request.dart'; import 'package:test_sa/modules/tm_module/tasks/create_task_view.dart'; import 'package:test_sa/modules/traf_module/create_traf_request_page.dart'; @@ -121,8 +122,13 @@ class CreateRequestModel { if (Provider.of(context, listen: false).engineerCanCreateCM) { list.add(CreateRequestModel(context.translation.correctiveMaintenance, "add_icon", CreateCMRequest.id)); } + //TODO uncommit this to enable task. list.add(CreateRequestModel(context.translation.task, "add_icon", CreateTaskView.id)); + //Need to add check from permission Api. + // if (Provider.of(context, listen: false).engineerCanCreateCM) { + list.add(CreateRequestModel('Medical Gas'.addTranslation, "add_icon", CreateMedicalGasRequestPage.id)); + // } } else { list.add(CreateRequestModel(context.translation.correctiveMaintenance, "add_icon", CreateCMRequest.id)); list.add(CreateRequestModel(context.translation.gasRefill, "add_icon", GasRefillRequestForm.routeName)); diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index d482356e..1823b10a 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -70,6 +70,7 @@ class _MyRequestsPageState extends State { requestsList.add(Request(11, 'System Internal Audit')); //Need to be added for new user role commissioning engineer requestsList.add(Request(13, "Asset Delivery")); + requestsList.add(Request(14, "Medical Gas Inspection")); } requestsList.add(Request(12, "Loan Equipment")); diff --git a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart index 62580009..f4d83656 100644 --- a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart +++ b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart @@ -6,6 +6,7 @@ import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_a import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart'; import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart'; import 'package:test_sa/modules/loan_module/pages/loan_equipment_item_view.dart'; +import 'package:test_sa/modules/medical_gas_inspection/medical_gas_inspection_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks/task_request_item_view.dart'; import 'package:test_sa/modules/traf_module/traf_request_item_view.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; @@ -78,6 +79,8 @@ class RequestPaginatedListview extends StatelessWidget { return LoanEquipmentItemView(requestData: request); case 13: return AssetDeliveryItemView(requestData: request); + case 14: + return MedicalGasInspectionItemView(requestData: request); default: return Container( height: 100, diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart index 946cb7ba..10339da7 100644 --- a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart +++ b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart @@ -11,6 +11,7 @@ import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_a import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart'; import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart'; import 'package:test_sa/modules/loan_module/pages/loan_equipment_item_view.dart'; +import 'package:test_sa/modules/medical_gas_inspection/medical_gas_inspection_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks/task_request_item_view.dart'; import 'package:test_sa/modules/traf_module/traf_request_item_view.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; @@ -74,6 +75,8 @@ class RequestItemViewList extends StatelessWidget { return LoanEquipmentItemView(requestDetails: list[index]); case 13: return AssetDeliveryItemView(requestDetails: list[index]); + case 14: + return MedicalGasInspectionItemView(requestDetails: list[index]); default: Container( From ab6b14376342e9e0e4dbac32d7e260d9ceb6630c Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 25 Dec 2025 12:41:02 +0300 Subject: [PATCH 07/26] improvements --- lib/extensions/context_extension.dart | 4 +- .../pages/asset_delivery_page.dart | 102 ++++++------ .../pages/attachment_view.dart | 9 +- .../pages/change_status_bottomsheet.dart | 33 ++-- .../cost_center_form_view.dart | 88 +++++----- .../delivery_inspection_form_view.dart | 37 ++--- .../end_user_cost_center_list_view.dart | 36 ++-- .../technical_inspection_lines_list_view.dart | 155 +++++++++--------- 8 files changed, 229 insertions(+), 235 deletions(-) diff --git a/lib/extensions/context_extension.dart b/lib/extensions/context_extension.dart index f85af74c..96e79211 100644 --- a/lib/extensions/context_extension.dart +++ b/lib/extensions/context_extension.dart @@ -29,11 +29,9 @@ extension BuildContextExtension on BuildContext { return isTablet; } - - void showConfirmDialog(String message, {String? title, VoidCallback? onTap, String? okTitle}) => showDialog( context: this, - builder: (BuildContext cxt) => ConfirmDialog(message: message, onTap: onTap, title: title,okTitle: okTitle), + builder: (BuildContext cxt) => ConfirmDialog(message: message, onTap: onTap, title: title, okTitle: okTitle), ); Future showBottomSheet(Widget childWidget, {bool? isDismissible, String? title}) => showModalBottomSheet( diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart index aad1d276..b3a3174b 100644 --- a/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart +++ b/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart @@ -74,60 +74,58 @@ class _AssetDeliveryPageState extends State { if (dataModel == null) { return const NoDataFound().center; } - return ListView( - padding: const EdgeInsets.all(12), - children: [ - requestDetailCard(context), - const Divider().defaultStyle(context), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Asset Delivery Table", - style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), - ), - Row( - children: [ - Container( - height: 24, - width: 24, - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: AppColor.primary10, // or AppColor.blueStatus(context) - ), - alignment: Alignment.center, - child: const Icon( - Icons.add, - color: Colors.white, - size: 16, + return SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + requestDetailCard(context), + const Divider().defaultStyle(context), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Asset Delivery Table", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + Row( + children: [ + Container( + height: 24, + width: 24, + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: AppColor.primary10, // or AppColor.blueStatus(context) + ), + alignment: Alignment.center, + child: const Icon( + Icons.add, + color: Colors.white, + size: 16, + ), ), - ), - 4.width, - Text( - "Add more", - style: AppTextStyles.bodyText.copyWith( - color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, - decoration: TextDecoration.underline, + 4.width, + Text( + "Add more", + style: AppTextStyles.bodyText.copyWith( + color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, + decoration: TextDecoration.underline, + ), ), - ), - ], - ).onPress(() async { - await assetDeliveryProvider?.addNewDelivery(requestId: widget.requestId).then((status) async { - if (status) { - await assetDeliveryProvider?.getAssetDeliveryTableListById(requestId: widget.requestId); - } - }); - }), - ], - ), - 8.height, - assetDeliveryTableList(context: context, assetDeliveryProvider: provider), - ], - ).toShadowContainer( - context, - borderRadius: 20, - padding: 0, - margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + ], + ).onPress(() async { + await assetDeliveryProvider?.addNewDelivery(requestId: widget.requestId).then((status) async { + if (status) { + await assetDeliveryProvider?.getAssetDeliveryTableListById(requestId: widget.requestId); + } + }); + }), + ], + ), + 8.height, + assetDeliveryTableList(context: context, assetDeliveryProvider: provider), + ], + ).toShadowContainer(context, borderRadius: 20), ); }, ), diff --git a/lib/modules/asset_delivery_module/pages/attachment_view.dart b/lib/modules/asset_delivery_module/pages/attachment_view.dart index 0c22772e..a8834fcc 100644 --- a/lib/modules/asset_delivery_module/pages/attachment_view.dart +++ b/lib/modules/asset_delivery_module/pages/attachment_view.dart @@ -78,6 +78,7 @@ class _AssetDeliveryAttachmentViewState extends State attachement = []; for (var item in _attachments) { String fileName = - CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; + CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; attachement.add(GenericAttachmentModel(id: item.id ?? 0, name: fileName)); } showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - Map payLoad ={ + Map payLoad = { 'assetDeliveryExternalDeliveryId': widget.tableItemId, - 'attachments':attachement, + 'attachments': attachement, }; - await assetDeliveryProvider.saveAttachment(payload:payLoad).then((status) async { + await assetDeliveryProvider.saveAttachment(payload: payLoad).then((status) async { Navigator.pop(context); if (status) { ///Need to verify need to stay on this page and refresh or go back.. diff --git a/lib/modules/asset_delivery_module/pages/change_status_bottomsheet.dart b/lib/modules/asset_delivery_module/pages/change_status_bottomsheet.dart index 696207bf..1eb16c9c 100644 --- a/lib/modules/asset_delivery_module/pages/change_status_bottomsheet.dart +++ b/lib/modules/asset_delivery_module/pages/change_status_bottomsheet.dart @@ -1,5 +1,3 @@ - - import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; @@ -21,7 +19,7 @@ class AssetDeliveryBottomSheet { ); } - static Future changeStatusBottomSheet({required BuildContext context,required VoidCallback cancelStatusTap,required VoidCallback statusChangeTap}) { + static Future changeStatusBottomSheet({required BuildContext context, required VoidCallback cancelStatusTap, required VoidCallback statusChangeTap}) { return buildBottomSheetParent( context: context, childWidget: Column( @@ -31,14 +29,17 @@ class AssetDeliveryBottomSheet { 8.height, Align( alignment: AlignmentDirectional.centerStart, - child: Text('Change Status'.addTranslation,style: TextStyle( - fontSize: 21.toScreenWidth, - fontWeight: FontWeight.w500, - fontStyle: FontStyle.normal, - decoration: TextDecoration.none, - ),), + child: Text( + 'Change Status'.addTranslation, + style: TextStyle( + fontSize: 21.toScreenWidth, + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + decoration: TextDecoration.none, + ), + ), ), - 10.height, + 16.height, Row( children: [ AppFilledButton( @@ -50,14 +51,16 @@ class AssetDeliveryBottomSheet { showBorder: true, onPressed: () async { cancelStatusTap(); - }, ).expanded, 12.width, - AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: () { - statusChangeTap(); - - }).expanded, + AppFilledButton( + buttonColor: AppColor.green70, + label: 'Change Status'.addTranslation, + maxWidth: true, + onPressed: () { + statusChangeTap(); + }).expanded, ], ), ], diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart index 4dec60db..3cc0497b 100644 --- a/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart @@ -1,4 +1,3 @@ - import 'dart:developer'; import 'package:flutter/material.dart'; @@ -103,32 +102,30 @@ class _CostCenterFormViewState extends State { backgroundColor: Theme.of(context).scaffoldBackgroundColor, appBar: DefaultAppBar( title: 'Cost Center for Item'.addTranslation, - onBackPress: () { - Navigator.pop(context); - }, + // onBackPress: () { + // Navigator.pop(context); + // }, ), body: Consumer(builder: (context, provider, child) { - return Column( - children: [ - itemDetails(context: context, itemNo: widget.itemNo, itemDescription: widget.itemDescription), - provider.isLoading - ? const CircularProgressIndicator(color: AppColor.primary10).center - : ListView.builder( + return provider.isLoading + ? const CircularProgressIndicator(color: AppColor.primary10).center + : Column( + children: [ + itemDetails(context: context, itemNo: widget.itemNo, itemDescription: widget.itemDescription), + ListView.builder( itemCount: _list.length + 1, shrinkWrap: true, - padding: EdgeInsets.all(widget.cardPadding ?? 16), + padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8), itemBuilder: (context, index) { if (index == _list.length) { - return Visibility( - child: AppFilledButton( - label: "Add Cost Center".addTranslation, - maxWidth: true, - textColor: AppColor.textColor(context), - buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, - icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), - showIcon: true, - onPressed: _addNewEntry, - ), + return AppFilledButton( + label: "Add Cost Center".addTranslation, + maxWidth: true, + textColor: AppColor.textColor(context), + buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, + icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), + showIcon: true, + onPressed: _addNewEntry, ); } return CostCenterItemCard( @@ -142,28 +139,27 @@ class _CostCenterFormViewState extends State { ); }, ).expanded, - 8.height, - FooterActionButton.footerContainer( - context: context, - child: AppFilledButton( - buttonColor: AppColor.primary10, - label: 'Save'.addTranslation, - maxWidth: true, - onPressed: () async { - showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - await assetDeliveryProvider.saveCostCenterToLineDeliveryInspection(tableItemId: widget.tableItemId, lineId: widget.lineId, list: _list).then((status) async { - Navigator.pop(context); - if (status) { - Navigator.pop(context); - assetDeliveryProvider.getDeliveryLinesListById( - itemId: widget.tableItemId, - ); - } - }); - }), - ), - ], - ); + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Save'.addTranslation, + maxWidth: true, + onPressed: () async { + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + await assetDeliveryProvider.saveCostCenterToLineDeliveryInspection(tableItemId: widget.tableItemId, lineId: widget.lineId, list: _list).then((status) async { + Navigator.pop(context); + if (status) { + Navigator.pop(context); + assetDeliveryProvider.getDeliveryLinesListById( + itemId: widget.tableItemId, + ); + } + }); + }), + ), + ], + ); }), ); } @@ -172,6 +168,7 @@ class _CostCenterFormViewState extends State { Widget itemDetails({required BuildContext context, String? itemNo, String? itemDescription}) { return Column( crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, children: [ Text( 'Item No'.addTranslation, @@ -197,7 +194,8 @@ Widget itemDetails({required BuildContext context, String? itemNo, String? itemD context, borderRadius: 20, padding: 12, - margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + showShadow: false, + margin: const EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 8), ); } @@ -293,6 +291,6 @@ class CostCenterItemCard extends StatelessWidget { ], ) ], - ).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16, vertical: 12)).paddingOnly(bottom: 12); + ).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 12, vertical: 12)).paddingOnly(bottom: 12); } } diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart index 40a4f61c..3ef8c0a0 100644 --- a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart @@ -124,29 +124,28 @@ class _DeliveryInspectionFormViewState extends State ], ).toShadowContainer(context, borderRadius: 20, padding: 12)) .expanded, - if (!viewOnly) ...[ - FooterActionButton.footerContainer( - context: context, - child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap), - ), - 8.height, - ], FooterActionButton.footerContainer( context: context, child: !viewOnly - ? Row( + ? Column( children: [ - AppFilledButton( - label: 'Cancel'.addTranslation, - maxWidth: true, - buttonColor: AppColor.background(context), - // textColor: context.isDark ? AppColor.neutral30 : Colors.white, - textColor: AppColor.red30, - showBorder: true, - onPressed: _cancelTap, - ).expanded, - 12.width, - AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded, + AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap), + 16.height, + Row( + children: [ + AppFilledButton( + label: 'Cancel'.addTranslation, + maxWidth: true, + buttonColor: AppColor.background(context), + // textColor: context.isDark ? AppColor.neutral30 : Colors.white, + textColor: AppColor.red30, + showBorder: true, + onPressed: _cancelTap, + ).expanded, + 12.width, + AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded, + ], + ), ], ) : AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap), diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart index 3711f237..5accb0ae 100644 --- a/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart @@ -83,28 +83,28 @@ class _EndUserCostCenterLIstViewState extends State { children: [ //Refactor this SingleChildScrollView(padding: const EdgeInsets.all(16), child: linesList(context).toShadowContainer(context, borderRadius: 20, padding: 12)).expanded, - if (!viewOnly) ...[ - FooterActionButton.footerContainer( - context: context, - child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap), - ), - 8.height, - ], + !viewOnly ? FooterActionButton.footerContainer( context: context, - child: Row( + child: Column( children: [ - AppFilledButton( - label: 'Cancel'.addTranslation, - maxWidth: true, - buttonColor: AppColor.background(context), - textColor: AppColor.red30, - showBorder: true, - onPressed: _cancelTap, - ).expanded, - 12.width, - AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded, + AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap), + 16.height, + Row( + children: [ + AppFilledButton( + label: 'Cancel'.addTranslation, + maxWidth: true, + buttonColor: AppColor.background(context), + textColor: AppColor.red30, + showBorder: true, + onPressed: _cancelTap, + ).expanded, + 12.width, + AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded, + ], + ), ], )) : const SizedBox(), diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart index 61e52c87..11105480 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart @@ -84,89 +84,86 @@ class _TechnicalInspectionLinesListViewState extends State 8.height, + itemBuilder: (context, index) { + if (index == 0) { + return Text( + "Lines", + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ); + } + + final DeliveryLineModel model = technicalInspectionLinesList[index - 1]; + return AssetDeliveryLineCard( + deliveryLineModel: model, + isViewOnly: viewOnly, + isTechnical: true, + editPress: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => UpdateTechnicalInspectionLinesView( + requestModel: widget.requestModel, + deliveryTableModel: widget.deliveryTableModel, + deliveryLineModel: model, + ), + ), + ); + }, + ); + }, + ).toShadowContainer(context, borderRadius: 20, padding: 12), + ], + ), + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: !viewOnly + ? Column( + children: [ + AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap), + 16.height, + Row( + children: [ + AppFilledButton( + label: 'Cancel'.addTranslation, + maxWidth: true, + buttonColor: AppColor.background(context), + // textColor: context.isDark ? AppColor.neutral30 : Colors.white, + textColor: AppColor.red30, + showBorder: true, + onPressed: _cancelTap, + ).expanded, + 12.width, + AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded, + ], + ), + ], + ) + : AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap), + ), + ], + ), ), ); } - Widget linesList(BuildContext context) { - if (isLoading) { - return SizedBox.expand( - child: const CircularProgressIndicator(color: AppColor.primary10).center, - ); - } - - if (technicalInspectionLinesList.isEmpty) { - return const NoDataFound().center; - } - - return ListView.separated( - padding: const EdgeInsets.all(16), - itemCount: technicalInspectionLinesList.length + 1, // +1 for the header - separatorBuilder: (_, __) => 8.height, - itemBuilder: (context, index) { - if (index == 0) { - return Text( - "Lines", - style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), - ); - } - - final DeliveryLineModel model = technicalInspectionLinesList[index - 1]; - return AssetDeliveryLineCard( - deliveryLineModel: model, - isViewOnly: viewOnly, - isTechnical: true, - editPress: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => UpdateTechnicalInspectionLinesView( - requestModel: widget.requestModel, - deliveryTableModel: widget.deliveryTableModel, - deliveryLineModel: model, - ), - ), - ); - }, - ); - }, - ).toShadowContainer(context, borderRadius: 20, padding: 12); - } - //May be need to show data. Widget inspectionDetails() { return Column( From 2425c78cf934578dd5cd5cb19895774adf076b84 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Sun, 28 Dec 2025 11:10:17 +0300 Subject: [PATCH 08/26] chat count implemented --- lib/modules/cx_module/chat/chat_widget.dart | 46 +++-- .../chat/model/chat_participant_model.dart | 39 +++-- .../common_widgets/custom_badge.dart | 157 +++++++++++++++++- 3 files changed, 201 insertions(+), 41 deletions(-) diff --git a/lib/modules/cx_module/chat/chat_widget.dart b/lib/modules/cx_module/chat/chat_widget.dart index 4d428abb..f84c7032 100644 --- a/lib/modules/cx_module/chat/chat_widget.dart +++ b/lib/modules/cx_module/chat/chat_widget.dart @@ -1,9 +1,12 @@ +import 'dart:developer'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; +import 'package:test_sa/new_views/common_widgets/custom_badge.dart'; import 'chat_page.dart'; import 'chat_provider.dart'; @@ -74,24 +77,31 @@ class _ChatWidgetState extends State { @override Widget build(BuildContext context) { return widget.isShow - ? Consumer(builder: (pContext, requestProvider, _) { - return IconButton( - icon: const Icon(Icons.chat_bubble), - onPressed: () { - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => ChatPage( - moduleId: widget.moduleId, - requestId: widget.requestId, - title: widget.title, - readOnly: widget.isReadOnly, - assigneeEmployeeNumber: widget.assigneeEmployeeNumber, - contactEmployeeINumber: widget.contactEmployeeINumber, - myLoginUserID: widget.myLoginUserID, - ))); - }, - ).toShimmer(context: context, isShow: requestProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30); + ? Consumer(builder: (pContext, chatProvider, _) { + final int unreadCount = (!chatProvider.chatLoginTokenLoading && (chatProvider.chatParticipantModel?.unreadCount ?? 0) > 0) ? chatProvider.chatParticipantModel!.unreadCount! : 0; + return CustomBadge2( + value: unreadCount, + top: 2, + right: 2, + minSize: 18, + child: IconButton( + icon: const Icon(Icons.chat_bubble), + onPressed: () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => ChatPage( + moduleId: widget.moduleId, + requestId: widget.requestId, + title: widget.title, + readOnly: widget.isReadOnly, + assigneeEmployeeNumber: widget.assigneeEmployeeNumber, + contactEmployeeINumber: widget.contactEmployeeINumber, + myLoginUserID: widget.myLoginUserID, + ))); + }, + ).toShimmer(context: context, isShow: chatProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30), + ); }) : const SizedBox(); } diff --git a/lib/modules/cx_module/chat/model/chat_participant_model.dart b/lib/modules/cx_module/chat/model/chat_participant_model.dart index 6ef1d4e4..671bc4c4 100644 --- a/lib/modules/cx_module/chat/model/chat_participant_model.dart +++ b/lib/modules/cx_module/chat/model/chat_participant_model.dart @@ -1,12 +1,15 @@ +import 'dart:developer'; + class ChatParticipantModel { int? id; String? title; String? conversationType; List? participants; - String? lastMessage; + // String? lastMessage; String? createdAt; + int? unreadCount; - ChatParticipantModel({this.id, this.title, this.conversationType, this.participants, this.lastMessage, this.createdAt}); + ChatParticipantModel({this.id, this.title, this.conversationType, this.participants, this.createdAt, this.unreadCount}); ChatParticipantModel.fromJson(Map json) { id = json['id']; @@ -18,20 +21,22 @@ class ChatParticipantModel { participants!.add(new Participants.fromJson(v)); }); } - lastMessage = json['lastMessage']; + // lastMessage = json['lastMessage']; createdAt = json['createdAt']; + unreadCount = json['unreadCount']; } Map toJson() { - final Map data = new Map(); - data['id'] = this.id; - data['title'] = this.title; - data['conversationType'] = this.conversationType; - if (this.participants != null) { - data['participants'] = this.participants!.map((v) => v.toJson()).toList(); + final Map data = {}; + data['id'] = id; + data['title'] = title; + data['conversationType'] = conversationType; + if (participants != null) { + data['participants'] = participants!.map((v) => v.toJson()).toList(); } - data['lastMessage'] = this.lastMessage; - data['createdAt'] = this.createdAt; + // data['lastMessage'] = lastMessage; + data['createdAt'] = createdAt; + data['unreadCount'] = unreadCount; return data; } } @@ -54,12 +59,12 @@ class Participants { } Map toJson() { - final Map data = new Map(); - data['userId'] = this.userId; - data['userName'] = this.userName; - data['employeeNumber'] = this.employeeNumber; - data['role'] = this.role; - data['userStatus'] = this.userStatus; + final Map data = {}; + data['userId'] = userId; + data['userName'] = userName; + data['employeeNumber'] = employeeNumber; + data['role'] = role; + data['userStatus'] = userStatus; return data; } } diff --git a/lib/new_views/common_widgets/custom_badge.dart b/lib/new_views/common_widgets/custom_badge.dart index 654304ec..a048877f 100644 --- a/lib/new_views/common_widgets/custom_badge.dart +++ b/lib/new_views/common_widgets/custom_badge.dart @@ -5,12 +5,20 @@ import 'package:test_sa/new_views/app_style/app_color.dart'; class CustomBadge extends StatelessWidget { final Widget child; // The widget that the badge will be overlaid on. final int value; // The value or text to be displayed in the badge. - final Color color; // The background color of the badge. + final Color color; + final double? positionR; + final double? positionT; + final double? height; + final double? width; - const CustomBadge({ + CustomBadge({ Key? key, required this.child, required this.value, + this.height, + this.width, + this.positionR, + this.positionT, this.color = AppColor.red30, // Default color is red }) : super(key: key); @@ -22,13 +30,14 @@ class CustomBadge extends StatelessWidget { child, // The main widget // if (value > 0) Positioned( - right: -6, - top: -6, + right: positionR ?? -6, + top: positionT ?? -6, + //Need to check why opacity he used here this is not correct need to make this total dynamic and responsive child: Opacity( opacity: value > 0 ? 1 : 0, child: Container( - height: 23, - constraints: const BoxConstraints(minWidth: 23), + height: height ?? 23, + constraints: BoxConstraints(minWidth: width ?? 23), padding: const EdgeInsets.all(3), alignment: Alignment.center, decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(30)), @@ -43,3 +52,139 @@ class CustomBadge extends StatelessWidget { ); } } + +//Need to use this badge every where.. +class CustomBadge2 extends StatelessWidget { + final Widget child; + final int value; + final double top; + final double right; + final double left; + final double bottom; + final double minSize; + final Color backgroundColor; + final Color textColor; + final TextStyle? textStyle; + final int maxValue; + final Duration animationDuration; + + const CustomBadge2({ + super.key, + required this.child, + required this.value, + this.top = -6, + this.right = -6, + this.left = double.nan, + this.bottom = double.nan, + this.minSize = 18, + this.backgroundColor = AppColor.red30, + this.textColor = AppColor.white10, + this.textStyle, + this.maxValue = 99, + this.animationDuration = const Duration(milliseconds: 200), + }); + + bool get _isVisible => value > 0; + + @override + Widget build(BuildContext context) { + return Stack( + clipBehavior: Clip.none, + children: [ + child, + if (_isVisible) + Positioned( + top: top.isNaN ? null : top, + right: right.isNaN ? null : right, + left: left.isNaN ? null : left, + bottom: bottom.isNaN ? null : bottom, + child: AnimatedScale( + scale: _isVisible ? 1 : 0, + duration: animationDuration, + curve: Curves.easeOutBack, + child: AnimatedOpacity( + opacity: _isVisible ? 1 : 0, + duration: animationDuration, + child: _Badge( + value: value, + maxValue: maxValue, + minSize: minSize, + backgroundColor: backgroundColor, + textColor: textColor, + textStyle: textStyle ?? + Theme.of(context).textTheme.labelSmall?.copyWith( + fontWeight: FontWeight.w700, + ), + ), + ), + ), + ), + ], + ); + } +} + +class _Badge extends StatelessWidget { + final int value; + final int maxValue; + final double minSize; + final Color backgroundColor; + final Color textColor; + final TextStyle? textStyle; + + const _Badge({ + required this.value, + required this.maxValue, + required this.minSize, + required this.backgroundColor, + required this.textColor, + this.textStyle, + }); + + bool get _isOverflow => value > maxValue; + + @override + Widget build(BuildContext context) { + final TextStyle baseStyle = (textStyle ?? Theme.of(context).textTheme.labelMedium)!.copyWith( + color: textColor, + fontWeight: FontWeight.w700, + ); + + final double badgeSize = minSize; + + return IgnorePointer( + child: SizedBox( + width: badgeSize, + height: badgeSize, + child: DecoratedBox( + decoration: const BoxDecoration( + shape: BoxShape.circle, + ), + child: DecoratedBox( + decoration: BoxDecoration( + color: backgroundColor, + shape: BoxShape.circle, + ), + child: Center( + child: _isOverflow + ? FittedBox( + child: Text( + '$maxValue+', + style: baseStyle.copyWith( + fontSize: badgeSize * 0.45, + ), + ), + ) + : CounterAnimatedText( + value: value, + style: baseStyle.copyWith( + fontSize: badgeSize * 0.6, + ), + ), + ), + ), + ), + ), + ); + } +} From 077095502e7d5f92bb09d2a06f9b984638a7ea9b Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Mon, 29 Dec 2025 08:56:20 +0300 Subject: [PATCH 09/26] chat count implemented --- .../notification/firebase_notification_manger.dart | 4 +++- .../cm_module/views/service_request_detail_main_view.dart | 2 +- lib/modules/cx_module/chat/helper/chat_file_viewer.dart | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/controllers/notification/firebase_notification_manger.dart b/lib/controllers/notification/firebase_notification_manger.dart index cc32e159..7b6dd5cd 100644 --- a/lib/controllers/notification/firebase_notification_manger.dart +++ b/lib/controllers/notification/firebase_notification_manger.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:developer'; import 'dart:io'; import 'package:firebase_messaging/firebase_messaging.dart'; @@ -84,6 +85,7 @@ class FirebaseNotificationManger { } static void handleMessage(context, Map messageData) { + log('message data is ${messageData}'); if (messageData["requestType"] != null && messageData["requestNumber"] != null) { Widget? serviceClass; @@ -116,7 +118,7 @@ class FirebaseNotificationManger { moduleId: moduleId, // requestDetails: RequestsDetails(nameOfType: requestData?.nameOfType, status: requestData?.statusName, priority: requestData?.priorityName, date: requestData?.transactionDate, ), ); - ServiceRequestDetailMain(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1); + // ServiceRequestDetailMain(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1); break; default: diff --git a/lib/modules/cm_module/views/service_request_detail_main_view.dart b/lib/modules/cm_module/views/service_request_detail_main_view.dart index 3e2fab9c..332a7b49 100644 --- a/lib/modules/cm_module/views/service_request_detail_main_view.dart +++ b/lib/modules/cm_module/views/service_request_detail_main_view.dart @@ -41,6 +41,7 @@ class _ServiceRequestDetailMainState extends State { @override void initState() { super.initState(); + _requestProvider = Provider.of(context, listen: false); WidgetsBinding.instance.addPostFrameCallback((_) { Provider.of(context, listen: false).reset(); getInitialData(); @@ -49,7 +50,6 @@ class _ServiceRequestDetailMainState extends State { Future getInitialData() async { bool isNurse = (Provider.of(context, listen: false).user?.type) == UsersTypes.normal_user; - _requestProvider = Provider.of(context, listen: false); await _requestProvider.getWorkOrderById(id: widget.requestId); if (isNurse && (_requestProvider.currentWorkOrder?.data?.nextStep?.workOrderNextStepEnum == WorkOrderNextStepEnum.waitingForRequesterToConfirm)) { ServiceRequestBottomSheet.nurseVerifyArrivalBottomSheet(context: context); diff --git a/lib/modules/cx_module/chat/helper/chat_file_viewer.dart b/lib/modules/cx_module/chat/helper/chat_file_viewer.dart index 04fba4a1..6d9c99d9 100644 --- a/lib/modules/cx_module/chat/helper/chat_file_viewer.dart +++ b/lib/modules/cx_module/chat/helper/chat_file_viewer.dart @@ -24,6 +24,7 @@ class ChatFileViewer extends StatelessWidget { @override Widget build(BuildContext context) { + return FutureBuilder( future: checkFileInLocalStorage(), builder: (BuildContext context, AsyncSnapshot snapshot) { From 66b77c51a61567cd021dc979e6d82ce0c9545148 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Tue, 30 Dec 2025 09:22:51 +0300 Subject: [PATCH 10/26] loan site bug fixes --- .../loan_module/models/loan_form_model.dart | 8 +++++--- .../pages/create_loan_request_page.dart | 15 ++++----------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lib/modules/loan_module/models/loan_form_model.dart b/lib/modules/loan_module/models/loan_form_model.dart index b31df2e6..a60b93ef 100644 --- a/lib/modules/loan_module/models/loan_form_model.dart +++ b/lib/modules/loan_module/models/loan_form_model.dart @@ -1,7 +1,5 @@ import 'package:test_sa/models/lookup.dart'; -import 'package:test_sa/models/new_models/building.dart'; -import 'package:test_sa/models/new_models/department.dart'; -import 'package:test_sa/models/new_models/floor.dart'; +import 'package:test_sa/models/new_models/mapped_sites.dart'; import 'package:test_sa/models/new_models/site.dart'; import 'package:test_sa/modules/loan_module/models/medical_department_model.dart'; @@ -21,6 +19,8 @@ class LoanFormModel { Site? site; MedicalDepartmentModel? department; List? loanAttachment; + MappedSite? mappedSite; + MappedDepartment? mappedDepartment; LoanFormModel({ this.docName, @@ -38,6 +38,8 @@ class LoanFormModel { this.loanAttachment, this.site, this.department, + this.mappedSite, + this.mappedDepartment, }); //{ diff --git a/lib/modules/loan_module/pages/create_loan_request_page.dart b/lib/modules/loan_module/pages/create_loan_request_page.dart index fe76e39b..c257622f 100644 --- a/lib/modules/loan_module/pages/create_loan_request_page.dart +++ b/lib/modules/loan_module/pages/create_loan_request_page.dart @@ -1,22 +1,17 @@ import 'dart:convert'; import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:test_sa/controllers/providers/api/device_transfer_provider.dart'; import 'package:test_sa/controllers/validator/validator.dart'; -import 'package:test_sa/dashboard_latest/dashboard_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/helper/utils.dart'; -import 'package:test_sa/models/device/asset.dart'; -import 'package:test_sa/models/enums/user_types.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; -import 'package:test_sa/models/new_models/site.dart'; +import 'package:test_sa/models/new_models/mapped_sites.dart'; import 'package:test_sa/models/new_models/task_request/task_type_model.dart'; import 'package:test_sa/models/new_models/work_order_detail_model.dart'; import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; @@ -25,13 +20,11 @@ import 'package:test_sa/modules/loan_module/models/loan_form_model.dart'; import 'package:test_sa/modules/loan_module/models/medical_department_model.dart'; import 'package:test_sa/modules/loan_module/provider/loan_period_provider.dart'; import 'package:test_sa/modules/loan_module/provider/loan_provider.dart'; -import 'package:test_sa/modules/loan_module/provider/loan_provider.dart'; import 'package:test_sa/modules/loan_module/provider/medical_department_provider.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/department_provider.dart'; import 'package:test_sa/providers/gas_request_providers/site_provider.dart'; import 'package:test_sa/providers/loading_list_notifier.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; @@ -275,10 +268,10 @@ class _CreateLoanRequestPageState extends State with Tick return [ 'Item Details'.addTranslation.bodyText(context).custom(color: AppColor.black10), 8.height, - SingleItemDropDownMenu( + SingleItemDropDownMenu( context: context, title: context.translation.site, - initialValue: _loanFormModel.site, + initialValue: _loanFormModel.mappedSite, showShadow: false, validator: (value) { if (value == null) return "Please select a site"; @@ -287,7 +280,7 @@ class _CreateLoanRequestPageState extends State with Tick backgroundColor: AppColor.fieldBgColor(context), showAsBottomSheet: true, onSelect: (value) { - _loanFormModel.site = value; + _loanFormModel.mappedSite = value; setState(() {}); }, ), From e303b4e099485e6dc60e553f87c9c3e7d7812642 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Tue, 30 Dec 2025 13:56:00 +0300 Subject: [PATCH 11/26] chat bug fixes --- lib/controllers/api_routes/urls.dart | 1 + .../cx_module/chat/chat_api_client.dart | 44 +++++++++++++++++++ lib/modules/cx_module/chat/chat_page.dart | 6 ++- lib/modules/cx_module/chat/chat_provider.dart | 31 ++++++++++++- lib/modules/cx_module/chat/chat_widget.dart | 6 ++- .../chat/helper/chat_file_picker.dart | 1 + .../chat/model/chat_participant_model.dart | 6 +-- 7 files changed, 88 insertions(+), 7 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index bd3e73e6..2897df0d 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -17,6 +17,7 @@ class URLs { static const String chatHubUrlApi = "$chatHubUrl/api"; // new V2 apis static const String chatHubUrlChat = "$chatHubUrl/hubs/chat"; // new V2 apis + static const String resetMessageCount = "$chatHubUrlApi/userChatHistory/AckMessages"; // new V2 apis static const String chatApiKey = "f53a98286f82798d588f67a7f0db19f7aebc839e"; // new V2 apis static String _host = host1; diff --git a/lib/modules/cx_module/chat/chat_api_client.dart b/lib/modules/cx_module/chat/chat_api_client.dart index 29d9239a..77770e83 100644 --- a/lib/modules/cx_module/chat/chat_api_client.dart +++ b/lib/modules/cx_module/chat/chat_api_client.dart @@ -95,6 +95,50 @@ class ChatApiClient { } } + Future resetCountApi(int moduleCode, int referenceNumber, String? employeeNumber) async { + final Map payload = { + 'moduleCode': moduleCode, + 'ReferenceNumber': referenceNumber, + }; + + // final headers = chatAckHeaders( + // apiKey: URLs.chatApiKey, + // employeeNumber: employeeNumber.toString(), + // origin: 'http://localhost:4400', + // referer: 'http://localhost:4400/', + // userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)', + // ); + + final Response response = await ApiClient().postJsonForResponse( + URLs.resetMessageCount, + payload, + token: chatLoginResponse!.token, + // headers: headers, + ); + // Response response = await ApiClient().postJsonForResponse( + // "${URLs.resetMessageCount}?moduleCode=$moduleCode&ReferenceNumber=$referenceNumber", {"moduleCode": moduleCode.toString(), "ReferenceNumber": referenceNumber.toString()}, + // token: chatLoginResponse!.token); + + + return response.statusCode == 200; + } + + Map chatAckHeaders({ + required String apiKey, + required String employeeNumber, + required String origin, + required String referer, + required String userAgent, + String acceptLanguage = 'en-US,en;q=0.9', + }) { + return { + 'Accept': 'application/json, text/plain, */*', + 'Content-Type': 'application/json', + // 'X-API-Key': apiKey, + // 'X-Employee-Number': employeeNumber, + }; + } + Future> viewAllDocuments(int moduleId, int referenceId) async { Response response = await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/attachments/conversation?referenceId=$referenceId&moduleCode=$moduleId", token: chatLoginResponse!.token); diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart index f84b4e23..d4b44721 100644 --- a/lib/modules/cx_module/chat/chat_page.dart +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -75,7 +75,7 @@ class _ChatPageState extends State { }); } - void loadChatHistory() { + void loadChatHistory() async { // // String assigneeEmployeeNumber = Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; // // String myEmployeeId = context.userProvider.user!.username!; // // @@ -99,7 +99,9 @@ class _ChatPageState extends State { ? Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderCreatedBy!.employeeId! : Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId!)) : ""); - Provider.of(context, listen: false).connectToHub(widget.moduleId, widget.requestId, myEmployeeId, receiver, widget.readOnly, isMounted: mounted); + ChatProvider chatProvider = Provider.of(context, listen: false); + chatProvider.connectToHub(widget.moduleId, widget.requestId, myEmployeeId, receiver, widget.readOnly, isMounted: mounted); + } @override diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index 136dd28b..84282a64 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -40,6 +40,7 @@ import 'package:path_provider/path_provider.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:signalr_netcore/hub_connection.dart'; import 'package:signalr_netcore/signalr_client.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/string_extensions.dart'; import 'package:test_sa/modules/cx_module/chat/model/chat_login_response_model.dart'; @@ -370,9 +371,37 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // } } } - // notifyListeners(); } + Future resetCount({ + required int moduleId, + required int referenceNo, + String ?userId , + }) async { + try { + return await ChatApiClient().resetCountApi(moduleId, referenceNo,userId); + } catch (e, stack) { + debugPrint('resetCount error: $e'); + rethrow; + } + } + + // Future resetCount({ required int moduleId, + // required int referenceNo}) async { + // Response response; + // try { + // response = await ApiManager.instance.post("${URLs.resetMessageCount}?moduleCode=$moduleId&ReferenceNumber=$referenceNo", body: {}); + // notifyListeners(); + // if (response.statusCode == 200) { + // return true; + // } + // return false; + // } catch (error) { + // notifyListeners(); + // return false; + // } + // } + void updateUserChatHistoryStatusAsync(List data) { try { chatHubConnection!.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); diff --git a/lib/modules/cx_module/chat/chat_widget.dart b/lib/modules/cx_module/chat/chat_widget.dart index f84c7032..788f470b 100644 --- a/lib/modules/cx_module/chat/chat_widget.dart +++ b/lib/modules/cx_module/chat/chat_widget.dart @@ -86,7 +86,11 @@ class _ChatWidgetState extends State { minSize: 18, child: IconButton( icon: const Icon(Icons.chat_bubble), - onPressed: () { + onPressed: () async { + bool readStatus = await chatProvider.resetCount(moduleId: widget.moduleId, referenceNo: widget.requestId, userId: context.userProvider.user?.id); + if (readStatus) { + chatProvider.chatParticipantModel?.unreadCount = 0; + } Navigator.push( context, CupertinoPageRoute( diff --git a/lib/modules/cx_module/chat/helper/chat_file_picker.dart b/lib/modules/cx_module/chat/helper/chat_file_picker.dart index 1070e3db..f080cd20 100644 --- a/lib/modules/cx_module/chat/helper/chat_file_picker.dart +++ b/lib/modules/cx_module/chat/helper/chat_file_picker.dart @@ -46,6 +46,7 @@ class ChatFilePicker extends StatelessWidget { fromMediaPicker(BuildContext context, ImageSource imageSource) async { XFile? pickedFile = await ImagePicker().pickImage(source: imageSource, imageQuality: 70, maxWidth: 800, maxHeight: 800); if (pickedFile != null) { + //Has UI issues here top buttons not clickable smoothly CroppedFile? croppedFile = await ImageCropper().cropImage( sourcePath: pickedFile.path, // aspectRatio: CropAspectRatio(ratioX: 1, ratioY: 1), diff --git a/lib/modules/cx_module/chat/model/chat_participant_model.dart b/lib/modules/cx_module/chat/model/chat_participant_model.dart index 671bc4c4..80c6bfc4 100644 --- a/lib/modules/cx_module/chat/model/chat_participant_model.dart +++ b/lib/modules/cx_module/chat/model/chat_participant_model.dart @@ -5,7 +5,7 @@ class ChatParticipantModel { String? title; String? conversationType; List? participants; - // String? lastMessage; + dynamic lastMessage; String? createdAt; int? unreadCount; @@ -21,7 +21,7 @@ class ChatParticipantModel { participants!.add(new Participants.fromJson(v)); }); } - // lastMessage = json['lastMessage']; + lastMessage = json['lastMessage']; createdAt = json['createdAt']; unreadCount = json['unreadCount']; } @@ -34,7 +34,7 @@ class ChatParticipantModel { if (participants != null) { data['participants'] = participants!.map((v) => v.toJson()).toList(); } - // data['lastMessage'] = lastMessage; + data['lastMessage'] = lastMessage; data['createdAt'] = createdAt; data['unreadCount'] = unreadCount; return data; From d57348dd92fb3c32392f4593f542736d0c96176c Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Tue, 30 Dec 2025 14:58:21 +0300 Subject: [PATCH 12/26] bug fixes for site and department previously it was showing all sites not related to that specif user --- lib/modules/loan_module/models/loan_form_model.dart | 9 ++++++--- .../loan_module/pages/create_loan_request_page.dart | 9 +++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/modules/loan_module/models/loan_form_model.dart b/lib/modules/loan_module/models/loan_form_model.dart index a60b93ef..79d459ca 100644 --- a/lib/modules/loan_module/models/loan_form_model.dart +++ b/lib/modules/loan_module/models/loan_form_model.dart @@ -1,6 +1,7 @@ import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/new_models/mapped_sites.dart'; import 'package:test_sa/models/new_models/site.dart'; +import 'package:test_sa/models/new_models/traf_department.dart'; import 'package:test_sa/modules/loan_module/models/medical_department_model.dart'; class LoanFormModel { @@ -20,7 +21,7 @@ class LoanFormModel { MedicalDepartmentModel? department; List? loanAttachment; MappedSite? mappedSite; - MappedDepartment? mappedDepartment; + TrafDepartment? mappedDepartment; LoanFormModel({ this.docName, @@ -93,8 +94,10 @@ class LoanFormModel { "vendorNumber": vendorNumber, "vendorContact": vendorNumber, "vendorEmail": vendorEmail, - 'siteId': site?.id, - 'departmentId': department?.id, + // 'siteId': site?.id, + 'siteId': mappedSite?.id, + // 'departmentId': department?.id, + 'departmentId': mappedDepartment?.id, "loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toJson()).toList() : [], }; } diff --git a/lib/modules/loan_module/pages/create_loan_request_page.dart b/lib/modules/loan_module/pages/create_loan_request_page.dart index c257622f..b5107f85 100644 --- a/lib/modules/loan_module/pages/create_loan_request_page.dart +++ b/lib/modules/loan_module/pages/create_loan_request_page.dart @@ -13,11 +13,11 @@ import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/new_models/mapped_sites.dart'; import 'package:test_sa/models/new_models/task_request/task_type_model.dart'; +import 'package:test_sa/models/new_models/traf_department.dart'; import 'package:test_sa/models/new_models/work_order_detail_model.dart'; import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/loan_module/models/loan_form_model.dart'; -import 'package:test_sa/modules/loan_module/models/medical_department_model.dart'; import 'package:test_sa/modules/loan_module/provider/loan_period_provider.dart'; import 'package:test_sa/modules/loan_module/provider/loan_provider.dart'; import 'package:test_sa/modules/loan_module/provider/medical_department_provider.dart'; @@ -27,6 +27,7 @@ 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/gas_request_providers/site_provider.dart'; import 'package:test_sa/providers/loading_list_notifier.dart'; +import 'package:test_sa/providers/lookups/department_lookup_provider.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import '../../../../../../new_views/common_widgets/default_app_bar.dart'; @@ -285,7 +286,7 @@ class _CreateLoanRequestPageState extends State with Tick }, ), 8.height, - SingleItemDropDownMenu( + SingleItemDropDownMenu( context: context, title: context.translation.department, showShadow: false, @@ -294,11 +295,11 @@ class _CreateLoanRequestPageState extends State with Tick return null; }, showAsBottomSheet: true, - initialValue: _loanFormModel.department, + initialValue: _loanFormModel.mappedDepartment, requestById: context.userProvider.user?.clientId, backgroundColor: AppColor.fieldBgColor(context), onSelect: (value) { - _loanFormModel.department = value; + _loanFormModel.mappedDepartment = value; setState(() {}); }, ), From af6ae868d7fe816b8732faab3bc7569e3d0970b9 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 30 Dec 2025 16:23:44 +0300 Subject: [PATCH 13/26] improvements --- .../loan_module/pages/create_loan_request_page.dart | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/modules/loan_module/pages/create_loan_request_page.dart b/lib/modules/loan_module/pages/create_loan_request_page.dart index b5107f85..32616761 100644 --- a/lib/modules/loan_module/pages/create_loan_request_page.dart +++ b/lib/modules/loan_module/pages/create_loan_request_page.dart @@ -281,8 +281,13 @@ class _CreateLoanRequestPageState extends State with Tick backgroundColor: AppColor.fieldBgColor(context), showAsBottomSheet: true, onSelect: (value) { - _loanFormModel.mappedSite = value; - setState(() {}); + if(value!=null){ + _loanFormModel.mappedSite = value; + _loanFormModel.mappedDepartment = null; + Provider.of(context,listen:false).getData(id:_loanFormModel.mappedSite?.id); + setState(() {}); + } + }, ), 8.height, From e598f3b5ad71d5c840129a46f260ff74d62baced Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Wed, 31 Dec 2025 09:39:36 +0300 Subject: [PATCH 14/26] chat bug fixes --- .../cx_module/chat/chat_api_client.dart | 35 ++----------------- lib/modules/cx_module/chat/chat_page.dart | 14 +++++--- lib/modules/cx_module/chat/chat_provider.dart | 18 ++-------- lib/modules/cx_module/chat/chat_widget.dart | 14 ++++---- 4 files changed, 21 insertions(+), 60 deletions(-) diff --git a/lib/modules/cx_module/chat/chat_api_client.dart b/lib/modules/cx_module/chat/chat_api_client.dart index 77770e83..639849a3 100644 --- a/lib/modules/cx_module/chat/chat_api_client.dart +++ b/lib/modules/cx_module/chat/chat_api_client.dart @@ -35,6 +35,7 @@ import 'model/user_chat_history_model.dart'; // import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as user; // import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav; +//Need to refector this remove unused code. class ChatApiClient { static final ChatApiClient _instance = ChatApiClient._internal(); @@ -97,47 +98,17 @@ class ChatApiClient { Future resetCountApi(int moduleCode, int referenceNumber, String? employeeNumber) async { final Map payload = { - 'moduleCode': moduleCode, - 'ReferenceNumber': referenceNumber, + 'moduleCode': "$moduleCode", + 'ReferenceNumber': "$referenceNumber", }; - - // final headers = chatAckHeaders( - // apiKey: URLs.chatApiKey, - // employeeNumber: employeeNumber.toString(), - // origin: 'http://localhost:4400', - // referer: 'http://localhost:4400/', - // userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)', - // ); - final Response response = await ApiClient().postJsonForResponse( URLs.resetMessageCount, payload, token: chatLoginResponse!.token, - // headers: headers, ); - // Response response = await ApiClient().postJsonForResponse( - // "${URLs.resetMessageCount}?moduleCode=$moduleCode&ReferenceNumber=$referenceNumber", {"moduleCode": moduleCode.toString(), "ReferenceNumber": referenceNumber.toString()}, - // token: chatLoginResponse!.token); - - return response.statusCode == 200; } - Map chatAckHeaders({ - required String apiKey, - required String employeeNumber, - required String origin, - required String referer, - required String userAgent, - String acceptLanguage = 'en-US,en;q=0.9', - }) { - return { - 'Accept': 'application/json, text/plain, */*', - 'Content-Type': 'application/json', - // 'X-API-Key': apiKey, - // 'X-Employee-Number': employeeNumber, - }; - } Future> viewAllDocuments(int moduleId, int referenceId) async { Response response = await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/attachments/conversation?referenceId=$referenceId&moduleCode=$moduleId", token: chatLoginResponse!.token); diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart index d4b44721..060bd52b 100644 --- a/lib/modules/cx_module/chat/chat_page.dart +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -28,7 +28,7 @@ import 'helper/chat_file_picker.dart'; import 'helper/chat_file_viewer.dart'; import 'model/get_single_user_chat_list_model.dart'; import 'model/user_chat_history_model.dart'; - +//Need to refactor this ... enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted } class ChatPage extends StatefulWidget { @@ -66,7 +66,10 @@ class _ChatPageState extends State { @override void initState() { super.initState(); - loadChatHistory(); + WidgetsBinding.instance.addPostFrameCallback((_) { + loadChatHistory(); + }); + playerController.addListener(() async { // if (playerController.playerState == PlayerState.playing && playerController.maxDuration == await playerController.getDuration()) { // await playerController.stopPlayer(); @@ -99,9 +102,12 @@ class _ChatPageState extends State { ? Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderCreatedBy!.employeeId! : Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId!)) : ""); - ChatProvider chatProvider = Provider.of(context, listen: false); + final chatProvider = context.read(); chatProvider.connectToHub(widget.moduleId, widget.requestId, myEmployeeId, receiver, widget.readOnly, isMounted: mounted); - + bool readStatus = await chatProvider.resetCount(moduleId: widget.moduleId, referenceNo: widget.requestId, userId: context.userProvider.user?.id); + if (readStatus) { + chatProvider.chatParticipantModel?.unreadCount = 0; + } } @override diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index 84282a64..46ba0d3c 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -55,6 +55,8 @@ import 'model/get_single_user_chat_list_model.dart'; import 'model/user_chat_history_model.dart'; // import 'get_single_user_chat_list_model.dart'; +//Need to refactor this remove unused code. + HubConnection? chatHubConnection; class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { @@ -386,22 +388,6 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { } } - // Future resetCount({ required int moduleId, - // required int referenceNo}) async { - // Response response; - // try { - // response = await ApiManager.instance.post("${URLs.resetMessageCount}?moduleCode=$moduleId&ReferenceNumber=$referenceNo", body: {}); - // notifyListeners(); - // if (response.statusCode == 200) { - // return true; - // } - // return false; - // } catch (error) { - // notifyListeners(); - // return false; - // } - // } - void updateUserChatHistoryStatusAsync(List data) { try { chatHubConnection!.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); diff --git a/lib/modules/cx_module/chat/chat_widget.dart b/lib/modules/cx_module/chat/chat_widget.dart index 788f470b..43c5d5fc 100644 --- a/lib/modules/cx_module/chat/chat_widget.dart +++ b/lib/modules/cx_module/chat/chat_widget.dart @@ -1,4 +1,4 @@ -import 'dart:developer'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -43,8 +43,10 @@ class _ChatWidgetState extends State { @override void initState() { super.initState(); - Provider.of(context, listen: false).reset(); - getChatToken(); + WidgetsBinding.instance.addPostFrameCallback((_) { + Provider.of(context, listen: false).reset(); + getChatToken(); + }); } void getChatToken() { @@ -86,11 +88,7 @@ class _ChatWidgetState extends State { minSize: 18, child: IconButton( icon: const Icon(Icons.chat_bubble), - onPressed: () async { - bool readStatus = await chatProvider.resetCount(moduleId: widget.moduleId, referenceNo: widget.requestId, userId: context.userProvider.user?.id); - if (readStatus) { - chatProvider.chatParticipantModel?.unreadCount = 0; - } + onPressed: () { Navigator.push( context, CupertinoPageRoute( From 45d736a64ee098506510bfc487dabd1ff671d925 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 1 Jan 2026 09:24:39 +0300 Subject: [PATCH 15/26] app release v1.5.0+32 to stores --- lib/controllers/api_routes/urls.dart | 10 +-- .../service_request_detail_main_view.dart | 2 +- lib/modules/cx_module/chat/chat_page.dart | 10 ++- lib/modules/cx_module/chat/chat_provider.dart | 68 ++++++++++++++++++- .../tasks_wo/task_request_detail_view.dart | 2 +- .../create_request-type_bottomsheet.dart | 12 ++-- .../my_request/all_requests_filter_page.dart | 24 +++---- .../my_request/my_requests_page.dart | 15 ++-- .../device_transfer_details.dart | 4 +- .../user/gas_refill/gas_refill_details.dart | 2 +- .../widgets/equipment/asset_detail_page.dart | 2 +- 11 files changed, 112 insertions(+), 39 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 2897df0d..c1b7f5ef 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -1,16 +1,16 @@ class URLs { URLs._(); - static const String appReleaseBuildNumber = "31"; + static const String appReleaseBuildNumber = "32"; - // static const host1 = "https://atomsm.hmg.com"; // production url + static const host1 = "https://atomsm.hmg.com"; // production url // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static final String _baseUrl = "$_host/mobile"; // host local UAT - static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis + // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis // static final String _baseUrl = "$_host/mobile"; // host local UAT and for internal audit dev - // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM + static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM // static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation static const String chatHubUrl = "https://apiderichat.hmg.com/chathub"; diff --git a/lib/modules/cm_module/views/service_request_detail_main_view.dart b/lib/modules/cm_module/views/service_request_detail_main_view.dart index 332a7b49..f59b49e1 100644 --- a/lib/modules/cm_module/views/service_request_detail_main_view.dart +++ b/lib/modules/cm_module/views/service_request_detail_main_view.dart @@ -102,7 +102,7 @@ class _ServiceRequestDetailMainState extends State { (provider.currentWorkOrder?.data?.workOrderContactPerson?.isNotEmpty ?? false)) { return ChatWidget( moduleId: widget.moduleId, - isShow: (context.userProvider.isEngineer || context.userProvider.isNurse) && provider.currentWorkOrder?.data?.assignedEmployee != null, + isShow: context.settingProvider.isUserFlowMedical && (context.userProvider.isEngineer || context.userProvider.isNurse) && provider.currentWorkOrder?.data?.assignedEmployee != null, isReadOnly: _requestProvider.isReadOnlyRequest, requestId: widget.requestId.toInt(), assigneeEmployeeNumber: provider.currentWorkOrder?.data?.assignedEmployee!.employeeId!, diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart index 060bd52b..0cbc72be 100644 --- a/lib/modules/cx_module/chat/chat_page.dart +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:developer'; import 'dart:io'; import 'package:audio_waveforms/audio_waveforms.dart'; @@ -28,6 +29,7 @@ import 'helper/chat_file_picker.dart'; import 'helper/chat_file_viewer.dart'; import 'model/get_single_user_chat_list_model.dart'; import 'model/user_chat_history_model.dart'; + //Need to refactor this ... enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted } @@ -103,7 +105,9 @@ class _ChatPageState extends State { : Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId!)) : ""); final chatProvider = context.read(); + // final chatProvider = Provider.of { } return Column(mainAxisSize: MainAxisSize.min, children: [ if (showDateHeader) dateCard(currentMessage.createdDate?.toString().chatMsgDateWithYear ?? ""), - isSender ? senderMsgCard(showSenderName, chatProvider.chatResponseList[index]) : recipientMsgCard(showSenderName, chatProvider.chatResponseList[index]) + isSender + ? senderMsgCard(showSenderName, chatProvider.chatResponseList[index], index: index) + : recipientMsgCard(showSenderName, chatProvider.chatResponseList[index]) ]); }, itemCount: chatProvider.chatResponseList.length)) @@ -615,7 +621,7 @@ class _ChatPageState extends State { .center; } - Widget senderMsgCard(bool showHeader, SingleUserChatModel? chatResponse, {bool loading = false, String msg = ""}) { + Widget senderMsgCard(bool showHeader, SingleUserChatModel? chatResponse, {bool loading = false, String msg = "", int index = 0}) { Widget senderHeader = Row( mainAxisSize: MainAxisSize.min, children: [ diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index 46ba0d3c..8d56bcf2 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:developer'; import 'dart:io'; import 'dart:typed_data'; import 'package:audio_waveforms/audio_waveforms.dart'; @@ -251,6 +252,9 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { chatHubConnection!.on("OnSubmitChatAsync", OnSubmitChatAsync); chatHubConnection!.on("OnTypingAsync", OnTypingAsync); chatHubConnection!.on("OnStopTypingAsync", OnStopTypingAsync); + //Need by Chat Backend for seen and un seen. + chatHubConnection!.on("OnSeenChatUserAsync", onSeenUserChatAsync); + chatHubConnection!.on("OnAckSeenAsync", onAckSeenAsync); //group On message @@ -378,10 +382,10 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { Future resetCount({ required int moduleId, required int referenceNo, - String ?userId , + String? userId, }) async { try { - return await ChatApiClient().resetCountApi(moduleId, referenceNo,userId); + return await ChatApiClient().resetCountApi(moduleId, referenceNo, userId); } catch (e, stack) { debugPrint('resetCount error: $e'); rethrow; @@ -468,6 +472,15 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { print(args); } + Future markMessageAsRead(int messageId) async { + final senderId = sender?.userId; + if (senderId == null) return; + chatHubConnection?.invoke( + "SendMessageReadAsync", + args: [messageId, senderId], + ); + } + void onChatSeen(List? args) { dynamic items = args!.toList(); // for (var user in searchedChats!) { @@ -574,6 +587,57 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); } + Future onSeenUserChatAsync(List? parameters) async { + try { + if (parameters == null || parameters.isEmpty) { + log('onSeenUserChatAsync: parameters are null or empty'); + return; + } + final parm = parameters.first; + if (parm is! List || parm.isEmpty) { + log('onSeenUserChatAsync: parm is not a valid list'); + return; + } + final firstItem = parm.first; + if (firstItem is! Map) { + log('onSeenUserChatAsync: firstItem is not a Map'); + return; + } + await chatHubConnection!.invoke( + "AckSeenAsync", + args: [ + firstItem['currentUserId'], + [firstItem['userChatHistoryId']], + ], + ); + } catch (e, stackTrace) { + log('onSeenUserChatAsync error: $e'); + log('StackTrace: $stackTrace'); + } + } + + + Future onAckSeenAsync(List? parameters) async { + try { + if (parameters == null || parameters.isEmpty) { + log('onAckSeenAsync: parameters are null or empty'); + return; + } + final parm = parameters.first; + log('parm onAckSeenAsync $parm'); + if (chatResponseList.isEmpty) { + log('onAckSeenAsync: chatResponseList is empty'); + return; + } + log('last list item id ${chatResponseList.first.toJson()}'); + chatResponseList.first.isSeen = true; + notifyListeners(); + } catch (e, stackTrace) { + log('onAckSeenAsync error: $e'); + log('StackTrace: $stackTrace'); + } + } + // Future OnSubmitChatAsync(List? parameters) async { // // List data = jsonDecode(parameters!.first!.toString()); // diff --git a/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart b/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart index e4777fec..bf3aa96f 100644 --- a/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart +++ b/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart @@ -80,7 +80,7 @@ class _TaskRequestDetailsViewState extends State { (_taskReqModel.taskJobContactPersons?.isNotEmpty ?? false)) { return ChatWidget( moduleId: widget.moduleId, - isShow: _taskReqModel.taskJobStatus!.value! != 1, + isShow: context.settingProvider.isUserFlowMedical&& _taskReqModel.taskJobStatus!.value! != 1, isReadOnly: _taskReqModel.taskJobStatus!.value! != 2, requestId: widget.taskId.toInt(), assigneeEmployeeNumber: _taskReqModel.assignedEngineer?.employeeId!, diff --git a/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart b/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart index a8d9155c..77439b73 100644 --- a/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart +++ b/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart @@ -110,12 +110,14 @@ class CreateRequestModel { // list.add(CreateRequestModel(module.module!.name!, "add_icon", CreateTaskView.id)); // } // }); - if (context.userProvider.isQualityUser) { + if (context.userProvider.isQualityUser && context.settingProvider.isUserFlowMedical) { list.add(CreateRequestModel("Equipment Internal Audit Checklist".addTranslation, "add_icon", CreateEquipmentInternalAuditForm.id)); list.add(CreateRequestModel("System Internal Audit Checklist".addTranslation, "add_icon", CreateSystemInternalAuditForm.id)); - } else if (context.userProvider.isAssessor) { - list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id)); - } else if (context.userProvider.isEngineer) { + } + // else if (context.userProvider.isAssessor) { + // list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id)); + // } + else if (context.userProvider.isEngineer) { if (Provider.of(context, listen: false).engineerCanCreateCM) { list.add(CreateRequestModel(context.translation.correctiveMaintenance, "add_icon", CreateNewRequest.id)); } @@ -127,7 +129,7 @@ class CreateRequestModel { list.add(CreateRequestModel(context.translation.transferAsset, "add_icon", CreateDeviceTransferRequest.id)); //TODO uncommit this to enable task. list.add(CreateRequestModel(context.translation.task, "add_icon", CreateTaskView.id)); - list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id)); + // list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id)); } return list; } diff --git a/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart b/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart index 155babc9..ea79339f 100644 --- a/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart +++ b/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart @@ -78,8 +78,8 @@ class _AllRequestsFilterPageState extends State { if (isEngineer) { types[context.translation.recurrentWo] = 5; - types["Equipment Internal Audit".addTranslation] = 10; - types["System Internal Audit".addTranslation] = 11; + if (context.settingProvider.isUserFlowMedical) types["Equipment Internal Audit".addTranslation] = 10; + if (context.settingProvider.isUserFlowMedical) types["System Internal Audit".addTranslation] = 11; } if (context.settingProvider.isUserFlowMedical && isEngineer) { @@ -92,18 +92,18 @@ class _AllRequestsFilterPageState extends State { types[module.module!.name!] = module.module!.value!; } }); - - if (!isEngineer) { - types['TRAF'] = 9; - } - - if (context.userProvider.isAssessor) { - types = {"TRAF": 9}; - } +//Hide traf + // if (!isEngineer) { + // types['TRAF'] = 9; + // } + + // if (context.userProvider.isAssessor) { + // types = {"TRAF": 9}; + // } if (context.userProvider.isQualityUser) { if (context.settingProvider.isUserFlowMedical) types = {'Recall and Alert': 7}; - types['Equipment Internal Audit'] = 10; - types['System Internal Audit'] = 11; + if (context.settingProvider.isUserFlowMedical) types['Equipment Internal Audit'] = 10; + if (context.settingProvider.isUserFlowMedical) types['System Internal Audit'] = 11; } final statuses = { diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index a39cc687..30ba4c19 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -61,10 +61,11 @@ class _MyRequestsPageState extends State { requestsList.add(Request(module.module!.value!, module.module!.name!.addTranslation)); } }); - if (context.userProvider.user!.type == UsersTypes.normal_user) { - requestsList.add(Request(9, 'TRAF')); - } - if (context.userProvider.isEngineer) { + //Hide TRAF. + // if (context.userProvider.user!.type == UsersTypes.normal_user) { + // requestsList.add(Request(9, 'TRAF')); + // } + if (context.userProvider.isEngineer &&context.settingProvider.isUserFlowMedical) { requestsList.add(Request(10, 'Equipment Internal Audit')); requestsList.add(Request(11, 'System Internal Audit')); } @@ -72,15 +73,15 @@ class _MyRequestsPageState extends State { if (context.userProvider.isAssessor) { requestsList = [ Request(null, context.translation.allWorkOrder), - Request(9, 'TRAF'), + // Request(9, 'TRAF'), ]; } if (context.userProvider.isQualityUser) { requestsList = [ Request(null, context.translation.allWorkOrder), if (context.settingProvider.isUserFlowMedical) Request(7, 'Recall and Alert'), - Request(10, 'Equipment Internal Audit'), - Request(11, 'System Internal Audit'), + if (context.settingProvider.isUserFlowMedical) Request(10, 'Equipment Internal Audit'), + if (context.settingProvider.isUserFlowMedical) Request(11, 'System Internal Audit'), ]; } diff --git a/lib/views/pages/device_transfer/device_transfer_details.dart b/lib/views/pages/device_transfer/device_transfer_details.dart index 03b04961..e0ad05bc 100644 --- a/lib/views/pages/device_transfer/device_transfer_details.dart +++ b/lib/views/pages/device_transfer/device_transfer_details.dart @@ -223,7 +223,7 @@ class _DeviceTransferDetailsState extends State { if (context.userProvider.isEngineer || context.userProvider.isNurse) ChatWidget( moduleId: widget.moduleId, - isShow: _model!.senderMachineStatusValue! != 4, + isShow: context.settingProvider.isUserFlowMedical && _model!.senderMachineStatusValue! != 4, isReadOnly: _model!.senderMachineStatusValue! != 1, requestId: widget.model.id!.toInt(), assigneeEmployeeNumber: _model!.senderAssignedEmployeeNumber, @@ -284,7 +284,7 @@ class _DeviceTransferDetailsState extends State { if (context.userProvider.isEngineer || context.userProvider.isNurse) ChatWidget( moduleId: widget.moduleId, - isShow: (isSender ? _deviceTransfer.senderMachineStatusValue! : _deviceTransfer.receiverMachineStatusValue!) != 0, + isShow: context.settingProvider.isUserFlowMedical && (isSender ? _deviceTransfer.senderMachineStatusValue! : _deviceTransfer.receiverMachineStatusValue!) != 0, isReadOnly: (isSender ? _deviceTransfer.senderMachineStatusValue! : _deviceTransfer.receiverMachineStatusValue) != 1, requestId: widget.model.id!.toInt(), assigneeEmployeeNumber: isSender ? _deviceTransfer.senderAssignedEmployeeNumber! : _deviceTransfer.receiverAssignedEmployeeNumber!, diff --git a/lib/views/pages/user/gas_refill/gas_refill_details.dart b/lib/views/pages/user/gas_refill/gas_refill_details.dart index 57f81d36..74f4287e 100644 --- a/lib/views/pages/user/gas_refill/gas_refill_details.dart +++ b/lib/views/pages/user/gas_refill/gas_refill_details.dart @@ -68,7 +68,7 @@ class _GasRefillDetailsPageState extends State { return ChatWidget( moduleId: widget.moduleId, - isShow: _gasRefillModel.status!.value! != 0, + isShow: context.settingProvider.isUserFlowMedical && _gasRefillModel.status!.value! != 0, isReadOnly: _gasRefillModel.status!.value! != 1, requestId: widget.model.id!.toInt(), assigneeEmployeeNumber: _gasRefillModel.assignedEmployee?.employeeId!, diff --git a/lib/views/widgets/equipment/asset_detail_page.dart b/lib/views/widgets/equipment/asset_detail_page.dart index f34f834c..f0b095fb 100644 --- a/lib/views/widgets/equipment/asset_detail_page.dart +++ b/lib/views/widgets/equipment/asset_detail_page.dart @@ -122,7 +122,7 @@ class _AssetDetailPageState extends State { "${context.translation.building}: ${assetModel.building?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context), "${context.translation.floor}: ${assetModel.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context), "${context.translation.md}: ${assetModel.department?.departmentName?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context), - "${context.translation.room}: ${assetModel.room?.value ?? "-"}".bodyText(context), + "${context.translation.room}: ${assetModel.room?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context), ], ).expanded, ], From 45eaa0eeed76547d609ce4bab4dc2040e3b82bf9 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Mon, 5 Jan 2026 16:19:54 +0300 Subject: [PATCH 16/26] app release v1.5.0+32 to stores --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 4efdf850..ec7b7255 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.4.0+31 +version: 1.5.0+32 environment: sdk: ">=3.5.0 <4.0.0" From 3944a549b229149dda8da4cceddf47623f9ad587 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Wed, 14 Jan 2026 09:20:32 +0300 Subject: [PATCH 17/26] requested changes done --- lib/controllers/api_routes/urls.dart | 9 +- .../providers/api/all_requests_provider.dart | 6 +- .../providers/api/user_provider.dart | 1 + lib/dashboard_latest/dashboard_provider.dart | 92 ++++-- lib/extensions/enum_extensions.dart | 6 + lib/main.dart | 2 + lib/models/enums/user_types.dart | 3 +- lib/models/user.dart | 3 + .../helper_function.dart | 72 +++++ .../models/cost_center_model.dart | 5 - .../cost_center_serial_no_form_model.dart | 53 +++ .../delivery_inspection_form_model.dart | 30 +- .../models/inspection_person_model.dart | 15 + .../pages/attachment_view.dart | 133 ++++---- .../cost_center_form_view.dart | 305 +++++++++++++----- .../delivery_inspection_form_view.dart | 274 ++++++++++++---- .../inpection_bottomsheet.dart | 152 +++++++++ .../end_user_cost_center_list_view.dart | 8 +- .../technical_inspection_lines_list_view.dart | 14 +- .../provider/asset_delivery_provider.dart | 38 ++- .../provider/attachment_type_provider.dart | 33 ++ .../my_request/all_requests_filter_page.dart | 6 + .../my_request/my_requests_page.dart | 9 +- 23 files changed, 1017 insertions(+), 252 deletions(-) create mode 100644 lib/modules/asset_delivery_module/helper_function.dart create mode 100644 lib/modules/asset_delivery_module/models/cost_center_serial_no_form_model.dart create mode 100644 lib/modules/asset_delivery_module/models/inspection_person_model.dart create mode 100644 lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart create mode 100644 lib/modules/asset_delivery_module/provider/attachment_type_provider.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index bacf721a..2c8c2a6b 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -68,9 +68,11 @@ class URLs { //service request new flow urls. static get nurseDashboardCountUrl => '$_baseUrl/ServiceRequest/GetDashboardNurseCount'; static get qaAuditorCount => '$_baseUrl/ServiceRequest/GetDashboardQAAuditorCount'; + static get commissioningEngineerCount => '$_baseUrl/ServiceRequest/GetDashboardCommissioningEngineerCount'; static get nurseDashboardDetailsUrl => '$_baseUrl/ServiceRequest/GetDashboardNurseDetails'; static get qaAuditorDetails => '$_baseUrl/ServiceRequest/GetDashboardQAAuditorDetails'; + static get commissioningEngineerDetails => '$_baseUrl/ServiceRequest/GetDashboardCommissioningEngineerDetails'; static get nurseRejectUrl => '$_baseUrl/ServiceRequest/NurseReject'; @@ -413,8 +415,10 @@ class URLs { static get getLineFromExternalPo => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetLineFromExternalPo'; static get getCostCenterListToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetCostCenterToLineDeliveryInspection'; + static get getCostCenterAndSerialNoToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetCostCenterAndSerialNoToLineDeliveryInspection'; static get getCostCenterToPo => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetCostCenterToPo'; static get saveCostCenterToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/SaveCostCenterToLineDeliveryInspection'; + static get saveCostCenterAndSerialNoToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/SaveCostCenterAndSerialNoToLineDeliveryInspection'; static get getDeliveryHistories => '$_baseUrl/AssetDeliveryExternalDelivery/GetDeliveryHistories'; //Technical Inscption... static get getLineFromTechnicalInspection => '$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetLineFromDeliveryInspection'; @@ -425,7 +429,7 @@ class URLs { static get getAssetFromInternalTechnicalInspection => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetAssetFromInternal"; static get getAssetDetailsByAssetId => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetAssetByIdFromInternal"; static get saveTechnicalInspectionAsset => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/SaveTechnicalInspectionItem"; - static get getAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/GetAttachments"; + static get getAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/GetAttachmentsBasedOnType"; static get saveAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/Save"; //End user Acceptance... static get getEndUserAcceptanceCostCenter => "$_baseUrl/AssetDeliveryEndUserAcceptance/GetEndUserAcceptanceCostCenter"; @@ -433,5 +437,6 @@ class URLs { static get saveEndUserFormData => "$_baseUrl/AssetDeliveryEndUserAcceptance/SaveMaster"; static get saveEndUserAssetData => "$_baseUrl/AssetDeliveryEndUserAcceptance/SaveDetail"; static get endUserStatusLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=534"; - static get endUserRejectionReasonLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=5007"; + static get endUserRejectionReasonLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=415"; + static get attachmentTypeLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=5009"; } diff --git a/lib/controllers/providers/api/all_requests_provider.dart b/lib/controllers/providers/api/all_requests_provider.dart index 5036ea9c..86579328 100644 --- a/lib/controllers/providers/api/all_requests_provider.dart +++ b/lib/controllers/providers/api/all_requests_provider.dart @@ -166,7 +166,11 @@ class AllRequestsProvider extends ChangeNotifier { if (context.userProvider.isNurse) { list.add(9); // } - list.add(12); // loan module + list.add(12); + if (context.userProvider.isCommissioningEngineer) { + list = [13]; + } + // loan module return list; } diff --git a/lib/controllers/providers/api/user_provider.dart b/lib/controllers/providers/api/user_provider.dart index ad64c8b8..d82a6b2d 100644 --- a/lib/controllers/providers/api/user_provider.dart +++ b/lib/controllers/providers/api/user_provider.dart @@ -47,6 +47,7 @@ class UserProvider extends ChangeNotifier { bool get isAssessor => user!.type == UsersTypes.assessor || user!.type == UsersTypes.assessorTl; bool get isQualityUser => user!.type == UsersTypes.qualityUser; + bool get isCommissioningEngineer => user!.type == UsersTypes.commissioningEngineer; VerifyOtpModel _verifyOtpModel = VerifyOtpModel(); SwipeTransaction _swipeTransactionModel = SwipeTransaction(); diff --git a/lib/dashboard_latest/dashboard_provider.dart b/lib/dashboard_latest/dashboard_provider.dart index f1a92f54..cc39807f 100644 --- a/lib/dashboard_latest/dashboard_provider.dart +++ b/lib/dashboard_latest/dashboard_provider.dart @@ -106,13 +106,22 @@ class DashBoardProvider extends ChangeNotifier { isAllCountLoading = true; notifyListeners(); String url = ''; - if (usersType == UsersTypes.qualityUser) { - url = URLs.qaAuditorCount; - } else if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) { - url = URLs.engineerDashboardCountUrl; - } else { - url = URLs.nurseDashboardCountUrl; - } + + // if (usersType == UsersTypes.qualityUser) { + // url = URLs.qaAuditorCount; + // } else if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) { + // url = URLs.engineerDashboardCountUrl; + // } else { + // url = URLs.nurseDashboardCountUrl; + // } + final urlMap = { + UsersTypes.qualityUser: URLs.qaAuditorCount, + UsersTypes.commissioningEngineer: URLs.commissioningEngineerCount, + UsersTypes.engineer: URLs.engineerDashboardCountUrl, + UsersTypes.assessor: URLs.engineerDashboardCountUrl, + UsersTypes.assessorTl: URLs.engineerDashboardCountUrl, + }; + url = urlMap[usersType] ?? URLs.nurseDashboardCountUrl; Response response; try { response = await ApiManager.instance.post(url, body: {}); @@ -235,6 +244,32 @@ class DashBoardProvider extends ChangeNotifier { } } + String getDashboardUrl({ + required UsersTypes usersType, + int? status, + int? tabId, + }) { + switch (usersType) { + case UsersTypes.qualityUser: + return URLs.qaAuditorDetails; + case UsersTypes.commissioningEngineer: + return URLs.commissioningEngineerDetails; + case UsersTypes.engineer: + case UsersTypes.assessor: + case UsersTypes.assessorTl: + if (status == 0) { + return URLs.engineerDashboardUpcoming; + } else if (status == 1 && tabId == 1) { + return URLs.engineerDashboardNotAssignDetails; + } else { + // status == 1 && tabId == 2 OR any other case + return URLs.engineerDashboardDetailsUrl; + } + default: + return URLs.nurseDashboardDetailsUrl; + } + } + Future getRequestDetail({bool showLoader = true, required UsersTypes usersType, int? status, bool isHighPriority = false, bool isOverdue = false, String? date, int? tabId}) async { if (showLoader) { isDetailLoading = showLoader; @@ -243,25 +278,26 @@ class DashBoardProvider extends ChangeNotifier { Response response; String url = ''; + // if (usersType == UsersTypes.qualityUser) { + // url = URLs.qaAuditorDetails; + // } else if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) { + // //need to check pagination for not assigned task @waseem. + // + // //these checks are to call different apis for dashboard for engineer... + // if (status == 0) { + // url = URLs.engineerDashboardUpcoming; + // } else if (status == 1 && tabId == 1) { + // url = URLs.engineerDashboardNotAssignDetails; + // } else if (status == 1 && tabId == 2) { + // url = URLs.engineerDashboardDetailsUrl; + // } else { + // url = URLs.engineerDashboardDetailsUrl; + // } + // } else { + // url = URLs.nurseDashboardDetailsUrl; + // } + url = getDashboardUrl(usersType: usersType, status: status, tabId: tabId); - if (usersType == UsersTypes.qualityUser) { - url = URLs.qaAuditorDetails; - } else if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) { - //need to check pagination for not assigned task @waseem. - - //these checks are to call different apis for dashboard for engineer... - if (status == 0) { - url = URLs.engineerDashboardUpcoming; - } else if (status == 1 && tabId == 1) { - url = URLs.engineerDashboardNotAssignDetails; - } else if (status == 1 && tabId == 2) { - url = URLs.engineerDashboardDetailsUrl; - } else { - url = URLs.engineerDashboardDetailsUrl; - } - } else { - url = URLs.nurseDashboardDetailsUrl; - } try { Map body = {"pageNumber": pageNum, "pageSize": pageItemNumber}; @@ -383,6 +419,12 @@ class CategoryTabs { tabs.add(CategoryTabs(label: 'Closed', tag: 3, id: 4)); return tabs; } + if (userType == UsersTypes.commissioningEngineer) { + tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2)); + tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3)); + tabs.add(CategoryTabs(label: 'Closed', tag: 3, id: 4)); + return tabs; + } tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2)); tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3)); diff --git a/lib/extensions/enum_extensions.dart b/lib/extensions/enum_extensions.dart index 747e2080..991a0f81 100644 --- a/lib/extensions/enum_extensions.dart +++ b/lib/extensions/enum_extensions.dart @@ -125,3 +125,9 @@ enum DropDownMatchType { identifier, name, } + + +enum CostCenterType { + costCenter, + serialNumber, +} diff --git a/lib/main.dart b/lib/main.dart index ceff381d..ed84e486 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -28,6 +28,7 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/report/servic import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_repair_location_provider.dart'; import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/attachment_type_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/cost_center_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/end_user_rejection_reason_lookup_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/end_user_status_lookup_provider.dart'; @@ -326,6 +327,7 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => PowerSupplyTypeProvider()), ChangeNotifierProvider(create: (_) => EndUserStatusLookupProvider()), ChangeNotifierProvider(create: (_) => EndUserRejectionReasonLookupProvider()), + ChangeNotifierProvider(create: (_) => AttachmentTypeLookupProvider()), ], child: GestureDetector( onTap: () { diff --git a/lib/models/enums/user_types.dart b/lib/models/enums/user_types.dart index cd6b5f13..13238d83 100644 --- a/lib/models/enums/user_types.dart +++ b/lib/models/enums/user_types.dart @@ -4,5 +4,6 @@ enum UsersTypes { nurse, // 1 assessor, assessorTl, - qualityUser + qualityUser, + commissioningEngineer } diff --git a/lib/models/user.dart b/lib/models/user.dart index 5eac8486..a18b67c5 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -108,10 +108,13 @@ class User { return UsersTypes.assessor; case "R-19": // Head Nurse Role return UsersTypes.assessorTl; + //TODO need to confirm why repeat. case "R-3": // Quality User return UsersTypes.qualityUser; case "R-58": // Quality User return UsersTypes.qualityUser; + case "R-201": // Quality User + return UsersTypes.commissioningEngineer; default: return null; } diff --git a/lib/modules/asset_delivery_module/helper_function.dart b/lib/modules/asset_delivery_module/helper_function.dart new file mode 100644 index 00000000..b34a749c --- /dev/null +++ b/lib/modules/asset_delivery_module/helper_function.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/attachment_type_provider.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; + +class HelperFunction { + static void attachmentTap({required BuildContext context, required AssetDeliveryProvider assetDeliveryProvider, required dynamic deliveryTableItemId}) async { + Lookup? result; + result = await showAttachmentTypeBottomSheet(context); + List list = []; + + if (result != null) { + showDialog( + context: context, + barrierDismissible: false, + builder: (_) => const AppLazyLoading(), + ); + list = await assetDeliveryProvider.getAttachments(tableItemId: deliveryTableItemId, attachmentType: result.value); + Navigator.pop(context); + // if (list.isNotEmpty) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AssetDeliveryAttachmentView( + tableItemId: deliveryTableItemId, + attachmentType: result!.value, + attachmentList: list, + ))); + // } + } + } + + static Future showAttachmentTypeBottomSheet(BuildContext context) { + return showModalBottomSheet( + context: context, + isScrollControlled: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(20)), + ), + builder: (_) { + return SafeArea( + top: false, + child: Padding( + padding: const EdgeInsets.only( + top: 16, + left: 16, + right: 16, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SingleItemDropDownMenu( + context: context, + title: context.translation.reason, + onSelect: (value) { + Navigator.pop(context, value); + }, + ), + ], + ), + ), + ); + }, + ); + } +} diff --git a/lib/modules/asset_delivery_module/models/cost_center_model.dart b/lib/modules/asset_delivery_module/models/cost_center_model.dart index 4bbfe9aa..0cacd34a 100644 --- a/lib/modules/asset_delivery_module/models/cost_center_model.dart +++ b/lib/modules/asset_delivery_module/models/cost_center_model.dart @@ -40,11 +40,6 @@ class CostCenterModel { data['id'] = id ?? 0; data['qty'] = quantity; - // data['costCenter'] = costCenter; - // data['acceptedBy'] = acceptedBy; - // data['acceptanceDate'] = acceptanceDate; - // data['acceptedByEmail'] = acceptedByEmail; - // data['acceptedBySignature'] = acceptedBySignature; data['costCenter'] = costCenterName; return data; } diff --git a/lib/modules/asset_delivery_module/models/cost_center_serial_no_form_model.dart b/lib/modules/asset_delivery_module/models/cost_center_serial_no_form_model.dart new file mode 100644 index 00000000..049abaa4 --- /dev/null +++ b/lib/modules/asset_delivery_module/models/cost_center_serial_no_form_model.dart @@ -0,0 +1,53 @@ +import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; + +class CostCenterSerialNoFormModel { + List? costCenters; + List? serialNos; + + CostCenterSerialNoFormModel({ + this.costCenters, + this.serialNos, + }); + + // From JSON + CostCenterSerialNoFormModel.fromJson(Map json) { + if (json['costCenters'] != null) { + costCenters = List.from((json['costCenters'] as List).map((e) => CostCenterModel.fromJson(e))); + } + + if (json['serialNos'] != null) { + serialNos = List.from((json['serialNos'] as List).map((e) => SerialNoModel.fromJson(e))); + } + } + + // To JSON + Map toJson() { + return { + 'costCenters': costCenters?.map((e) => e.toJson()).toList() ?? [], + 'serialNos': serialNos?.map((e) => e.toJson()).toList() ?? [], + }; + } +} + + +class SerialNoModel { + int? id; + String? serialNo; + SerialNoModel({ + this.id, + this.serialNo, + }); + SerialNoModel.fromJson(Map json) { + id = json['id'] ?? json['costCenterId']; + serialNo = json['serialNo']; + } + Map toJson() { + final Map data = {}; + data['id'] = id ?? 0; + data['serialNo'] = serialNo; + return data; + } +} + + + diff --git a/lib/modules/asset_delivery_module/models/delivery_inspection_form_model.dart b/lib/modules/asset_delivery_module/models/delivery_inspection_form_model.dart index 10b45d4f..4d73b496 100644 --- a/lib/modules/asset_delivery_module/models/delivery_inspection_form_model.dart +++ b/lib/modules/asset_delivery_module/models/delivery_inspection_form_model.dart @@ -1,6 +1,11 @@ +import 'package:test_sa/modules/asset_delivery_module/models/inspection_person_model.dart'; + class DeliveryInspectionFormModel { int? assetDeliveryExternalDeliveryId; String? deliveryInspectionInspectedBy; + InspectionPersonModel? inspectedByModel; + InspectionPersonModel? approvedByModel; + InspectionPersonModel? thirdApprovalModel; DateTime? deliveryInspectionInspectedDateFrom; DateTime? deliveryInspectionInspectedDateTo; num? totalTime; @@ -9,6 +14,9 @@ class DeliveryInspectionFormModel { DeliveryInspectionFormModel({ this.assetDeliveryExternalDeliveryId, this.deliveryInspectionInspectedBy, + this.inspectedByModel, + this.approvedByModel, + this.thirdApprovalModel, this.deliveryInspectionInspectedDateFrom, this.deliveryInspectionInspectedDateTo, this.totalTime, @@ -18,20 +26,32 @@ class DeliveryInspectionFormModel { DeliveryInspectionFormModel.fromJson(Map json) { assetDeliveryExternalDeliveryId = json['assetDeliveryExternalDeliveryId']; deliveryInspectionInspectedBy = json['deliveryInspectionInspectedBy']; - deliveryInspectionInspectedDateFrom = json['deliveryInspectionInspectedDateFrom']!=null?DateTime.tryParse(json['deliveryInspectionInspectedDateFrom']):null; - deliveryInspectionInspectedDateTo = json['deliveryInspectionInspectedDateTo']!=null?DateTime.tryParse(json['deliveryInspectionInspectedDateTo']):null; + inspectedByModel = InspectionPersonModel(name: json['deliveryInspectionInspectedBy'], email: json['deliveryInspectionInspectedByEmail'], signature: json['deliveryInspectionInspectedBySignature']); + approvedByModel = InspectionPersonModel(name: json['deliveryInspectionApprovedBy'], email: json['deliveryInspectionApprovedByEmail'], signature: json['deliveryInspectionApprovedBySignature']); + thirdApprovalModel = + InspectionPersonModel(name: json['deliveryInspectionThirdApproverBy'], email: json['deliveryInspectionThirdApproverByEmail'], signature: json['deliveryInspectionThirdApproverBySignature']); + deliveryInspectionInspectedDateFrom = json['deliveryInspectionInspectedDateFrom'] != null ? DateTime.tryParse(json['deliveryInspectionInspectedDateFrom']) : null; + deliveryInspectionInspectedDateTo = json['deliveryInspectionInspectedDateTo'] != null ? DateTime.tryParse(json['deliveryInspectionInspectedDateTo']) : null; totalTime = json['totalTime']; deliveryInspectionApprovedBy = json['deliveryInspectionApprovedBy']; } +//TODO need to set payload.. Map toJson() { return { 'assetDeliveryExternalDeliveryId': assetDeliveryExternalDeliveryId, - 'deliveryInspectionInspectedBy': deliveryInspectionInspectedBy, - 'deliveryInspectionInspectedDateFrom': deliveryInspectionInspectedDateFrom?.toIso8601String(), + 'deliveryInspectionInspectedDateFrom': deliveryInspectionInspectedDateFrom?.toIso8601String(), 'deliveryInspectionInspectedDateTo': deliveryInspectionInspectedDateTo?.toIso8601String(), 'totalTime': totalTime, - 'deliveryInspectionApprovedBy': deliveryInspectionApprovedBy, + 'deliveryInspectionInspectedBy': inspectedByModel?.name, + "deliveryInspectionInspectedBySignature": inspectedByModel?.signature, + "deliveryInspectionInspectedByEmail": inspectedByModel?.email, + 'deliveryInspectionApprovedBy': approvedByModel?.name, + "deliveryInspectionApprovedBySignature": approvedByModel?.signature, + "deliveryInspectionApprovedByEmail": approvedByModel?.email, + "deliveryInspectionThirdApproverBy": thirdApprovalModel?.name, + "deliveryInspectionThirdApproverBySignature": thirdApprovalModel?.signature, + "deliveryInspectionThirdApproverByEmail": thirdApprovalModel?.email, }; } } diff --git a/lib/modules/asset_delivery_module/models/inspection_person_model.dart b/lib/modules/asset_delivery_module/models/inspection_person_model.dart new file mode 100644 index 00000000..8c00357d --- /dev/null +++ b/lib/modules/asset_delivery_module/models/inspection_person_model.dart @@ -0,0 +1,15 @@ +import 'package:flutter/services.dart'; + +class InspectionPersonModel { + String? name; + String? email; + String? signature; + Uint8List? localSignature; + + InspectionPersonModel({ + this.name, + this.email, + this.signature, + this.localSignature, + }); +} diff --git a/lib/modules/asset_delivery_module/pages/attachment_view.dart b/lib/modules/asset_delivery_module/pages/attachment_view.dart index a8834fcc..e98ab0af 100644 --- a/lib/modules/asset_delivery_module/pages/attachment_view.dart +++ b/lib/modules/asset_delivery_module/pages/attachment_view.dart @@ -1,8 +1,10 @@ import 'dart:convert'; +import 'dart:developer'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:provider/provider.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/extensions/text_extensions.dart'; @@ -15,21 +17,20 @@ import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; class AssetDeliveryAttachmentView extends StatefulWidget { - ///Need to check which parm need here. - final int? lineId; final int? tableItemId; - final int? requestId; - final bool? isHmg; + final int? attachmentType; + final List attachmentList; const AssetDeliveryAttachmentView({ super.key, - this.lineId, - this.requestId, + required this.attachmentList, + this.attachmentType, this.tableItemId, - this.isHmg, }); @override @@ -52,15 +53,17 @@ class _AssetDeliveryAttachmentViewState extends State URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []).toShadowContainer( + context, + borderRadius: 20, + padding: 12, + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + ), + ], + ), + ), FooterActionButton.footerContainer( context: context, child: AppFilledButton( - buttonColor: AppColor.primary10, - label: 'Save'.addTranslation, - maxWidth: true, - onPressed: () async { - List attachement = []; - for (var item in _attachments) { - String fileName = - CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - attachement.add(GenericAttachmentModel(id: item.id ?? 0, name: fileName)); - } - showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - Map payLoad = { - 'assetDeliveryExternalDeliveryId': widget.tableItemId, - 'attachments': attachement, - }; - await assetDeliveryProvider.saveAttachment(payload: payLoad).then((status) async { - Navigator.pop(context); - if (status) { - ///Need to verify need to stay on this page and refresh or go back.. - Navigator.pop(context); - // assetDeliveryProvider.getDeliveryLinesListById( - // itemId: widget.tableItemId, - // ); - } - }); - }), + buttonColor: AppColor.primary10, + label: 'Save'.addTranslation, + maxWidth: true, + onPressed: _onSavePressed, + ), ), ], ), ); } + + Future _onSavePressed() async { + final List attachmentPayload = _attachments.map((item) { + final String name = CMRequestUtils.isLocalUrl(item.name ?? '') ? '${item.name?.split("/").last}|${base64Encode(File(item.name!).readAsBytesSync())}' : item.name ?? ''; + + return GenericAttachmentModel( + id: item.id ?? 0, + name: name, + ); + }).toList(); + + showDialog( + context: context, + barrierDismissible: false, + builder: (_) => const AppLazyLoading(), + ); + + final payload = { + 'assetDeliveryExternalDeliveryId': widget.tableItemId, + 'attachments': attachmentPayload, + }; + + final status = await assetDeliveryProvider.saveAttachment(payload: payload); + + Navigator.pop(context); + + if (status) { + Navigator.pop(context); + } + } } diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart index 3cc0497b..2fdfe356 100644 --- a/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart @@ -1,5 +1,3 @@ -import 'dart:developer'; - import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; @@ -10,6 +8,7 @@ import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/cost_center_serial_no_form_model.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/cost_center_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; @@ -47,8 +46,9 @@ class CostCenterFormView extends StatefulWidget { } class _CostCenterFormViewState extends State { - List _list = []; + CostCenterSerialNoFormModel formModel = CostCenterSerialNoFormModel(costCenters: [], serialNos: []); late AssetDeliveryProvider assetDeliveryProvider; + CostCenterType _selectedType = CostCenterType.costCenter; @override void initState() { @@ -60,15 +60,20 @@ class _CostCenterFormViewState extends State { } void getInitialData() async { - _list = await assetDeliveryProvider.getAssetDeliveryCostCenterListForLines( + formModel = await assetDeliveryProvider.getAssetDeliveryCostCenterListForLines( lineId: widget.lineId, tableItemId: widget.tableItemId, ); - if (_list.isEmpty) { - _list.add(CostCenterModel( + if (formModel.costCenters!.isEmpty) { + formModel.costCenters!.add(CostCenterModel( id: 0, )); } + // if (formModel.serialNos!.isEmpty) { + // formModel.serialNos!.add(SerialNoModel( + // id: 0, + // )); + // } if (widget.isHmg == true) { CostCenterProvider costCenterProvider = Provider.of(context, listen: false); if (costCenterProvider.items.isEmpty) { @@ -78,21 +83,21 @@ class _CostCenterFormViewState extends State { setState(() {}); } - void _addNewEntry() { + void addItem(List list, T Function() creator) { setState(() { - _list.add(CostCenterModel(costCenter: Lookup())); + list.add(creator()); }); } - void _removeEntry(int index) { + void removeItem(List list, int index) { setState(() { - _list.removeAt(index); + list.removeAt(index); }); } - void _updateModel(int index, void Function(CostCenterModel model) updateList) { + void updateItem(List list, int index, void Function(T item) updater) { setState(() { - updateList(_list[index]); + updater(list[index]); }); } @@ -111,34 +116,9 @@ class _CostCenterFormViewState extends State { ? const CircularProgressIndicator(color: AppColor.primary10).center : Column( children: [ - itemDetails(context: context, itemNo: widget.itemNo, itemDescription: widget.itemDescription), - ListView.builder( - itemCount: _list.length + 1, - shrinkWrap: true, - padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8), - itemBuilder: (context, index) { - if (index == _list.length) { - return AppFilledButton( - label: "Add Cost Center".addTranslation, - maxWidth: true, - textColor: AppColor.textColor(context), - buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, - icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), - showIcon: true, - onPressed: _addNewEntry, - ); - } - return CostCenterItemCard( - model: _list[index], - index: index, - isReadOnly: false, - isHmg: widget.isHmg, - requestId: widget.requestId, - onUpdate: (updateList) => _updateModel(index, updateList), - onRemove: () => _removeEntry(index), - ); - }, - ).expanded, + itemDetails(), + selectionButton(), + _selectedType == CostCenterType.costCenter ? _buildCostCenterList() : _buildSerialNumberList(), FooterActionButton.footerContainer( context: context, child: AppFilledButton( @@ -147,7 +127,9 @@ class _CostCenterFormViewState extends State { maxWidth: true, onPressed: () async { showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - await assetDeliveryProvider.saveCostCenterToLineDeliveryInspection(tableItemId: widget.tableItemId, lineId: widget.lineId, list: _list).then((status) async { + await assetDeliveryProvider + .saveCostCenterToLineDeliveryInspection(tableItemId: widget.tableItemId, lineId: widget.lineId, list: formModel.costCenters, serialNoList: formModel.serialNos) + .then((status) async { Navigator.pop(context); if (status) { Navigator.pop(context); @@ -163,40 +145,169 @@ class _CostCenterFormViewState extends State { }), ); } -} -Widget itemDetails({required BuildContext context, String? itemNo, String? itemDescription}) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - 'Item No'.addTranslation, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), - ), - 8.height, - Text( - itemNo ?? '-', - style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), - ), - 8.height, - Text( - 'Item Description'.addTranslation, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + Widget _buildCostCenterList() { + return ListView.builder( + itemCount: formModel.costCenters!.length + 1, + shrinkWrap: true, + padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8), + itemBuilder: (context, index) { + if (index == formModel.costCenters!.length) { + return AppFilledButton( + label: "Add Cost Center".addTranslation, + maxWidth: true, + textColor: AppColor.textColor(context), + buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, + icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), + showIcon: true, + onPressed: () { + addItem(formModel.costCenters!, () => CostCenterModel(costCenter: Lookup())); + }, + ); + } + + return CostCenterItemCard( + model: formModel.costCenters![index], + index: index, + isReadOnly: false, + isHmg: widget.isHmg, + requestId: widget.requestId, + onUpdate: (update) { + updateItem(formModel.costCenters!, index, update); + }, + onRemove: () { + removeItem(formModel.costCenters!, index); + }, + ); + }, + ).expanded; + } + + Widget _buildSerialNumberList() { + return ListView.builder( + itemCount: formModel.serialNos!.length + 1, + shrinkWrap: true, + padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8), + itemBuilder: (context, index) { + if (index == formModel.serialNos!.length) { + return AppFilledButton( + label: "Add Serial Number".addTranslation, + maxWidth: true, + textColor: AppColor.textColor(context), + buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, + icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), + showIcon: true, + onPressed: () { + addItem(formModel.serialNos!, () => SerialNoModel()); + }, + ); + } + + return SerialNumberItemCard( + model: formModel.serialNos![index], + onUpdate: (update) { + updateItem(formModel.serialNos!, index, update); + }, + onRemove: () { + removeItem(formModel.serialNos!, index); + }, + ); + }, + ).expanded; + } + + Widget selectionButton() { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Row( + children: [ + Expanded( + child: _radioItem( + value: CostCenterType.costCenter, + groupValue: _selectedType, + title: 'Cost Center', + onTap: () { + setState(() { + _selectedType = CostCenterType.costCenter; + }); + }, + ), + ), + Expanded( + child: _radioItem( + value: CostCenterType.serialNumber, + groupValue: _selectedType, + title: 'Serial Number', + onTap: () { + setState(() { + _selectedType = CostCenterType.serialNumber; + }); + }, + ), + ), + ], ), - 8.height, - Text( - itemDescription ?? '-', - style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ); + } + + Widget _radioItem({ + required CostCenterType value, + required CostCenterType groupValue, + required String title, + required VoidCallback onTap, + }) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: onTap, + child: Row( + children: [ + Radio( + value: value, + groupValue: groupValue, + onChanged: (_) => onTap(), + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: VisualDensity.compact, + ), + 4.width, + title.addTranslation.bodyText(context), + ], ), - ], - ).toShadowContainer( - context, - borderRadius: 20, - padding: 12, - showShadow: false, - margin: const EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 8), - ); + ); + } + + Widget itemDetails() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Item No'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + widget.itemNo ?? '-', + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Item Description'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + widget.itemDescription ?? '-', + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + ], + ).toShadowContainer( + context, + borderRadius: 20, + padding: 12, + showShadow: false, + margin: const EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 8), + ); + } } class CostCenterItemCard extends StatelessWidget { @@ -294,3 +405,53 @@ class CostCenterItemCard extends StatelessWidget { ).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 12, vertical: 12)).paddingOnly(bottom: 12); } } + +class SerialNumberItemCard extends StatelessWidget { + final SerialNoModel model; + final VoidCallback onRemove; + final void Function(void Function(SerialNoModel model)) onUpdate; + + const SerialNumberItemCard({ + super.key, + required this.model, + required this.onRemove, + required this.onUpdate, + }); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + 'Serial Number'.addTranslation.bodyText(context), + Container( + height: 28, + width: 28, + padding: const EdgeInsets.all(6), + child: "trash".toSvgAsset(height: 20, width: 20), + ).onPress(onRemove), + ], + ), + 8.height, + AppTextFormField( + labelText: 'Serial Number'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.serialNo ?? '', + textAlign: TextAlign.center, + showShadow: false, + onChange: (value) { + model.serialNo = value; + }, + style: Theme.of(context).textTheme.titleMedium, + ), + ], + ) + .toShadowContainer( + context, + paddingObject: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), + ) + .paddingOnly(bottom: 12); + } +} diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart index 3ef8c0a0..c6918f74 100644 --- a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart @@ -1,5 +1,5 @@ -import 'dart:developer'; - +import 'dart:convert'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; @@ -7,21 +7,26 @@ 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/generic_attachment_model.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/helper_function.dart'; import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/delivery_inspection_form_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/inspection_person_model.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/attachment_type_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; -import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import '../../../../new_views/common_widgets/app_filled_button.dart'; @@ -129,7 +134,13 @@ class _DeliveryInspectionFormViewState extends State child: !viewOnly ? Column( children: [ - AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap), + AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Attachments'.addTranslation, + maxWidth: true, + onPressed: () { + HelperFunction.attachmentTap(context: context, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id); + }), 16.height, Row( children: [ @@ -207,56 +218,109 @@ class _DeliveryInspectionFormViewState extends State Widget inspectionDetailsForm() { return Column( children: [ - if (widget.requestModel?.isHMG == true) ...[ - OracleUserAutoCompleteField( - clearAfterPick: false, - initialValue: model.deliveryInspectionInspectedBy ?? '', - label: 'Inspected by'.addTranslation, - onPick: (value) { - model.deliveryInspectionInspectedBy = value.fullName; - setState(() {}); - }, - onChanged: (value) {}, - ), - 8.height, - OracleUserAutoCompleteField( - clearAfterPick: false, - initialValue: model.deliveryInspectionApprovedBy ?? '', - label: 'Approved by'.addTranslation, - onChanged: (value) {}, - onPick: (value) { - model.deliveryInspectionApprovedBy = value.fullName; - setState(() {}); - }, - ), - ] //No HMG user free text insted of dropdown ... - else ...[ - AppTextFormField( - labelText: 'Inspected by'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), - initialValue: model.deliveryInspectionInspectedBy ?? '', - textAlign: TextAlign.center, - labelStyle: AppTextStyles.textFieldLabelStyle, - showShadow: false, - onChange: (value) { - model.deliveryInspectionInspectedBy = value; - }, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - AppTextFormField( - labelText: 'Approved by'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), - initialValue: model.deliveryInspectionApprovedBy ?? '', - textAlign: TextAlign.center, - labelStyle: AppTextStyles.textFieldLabelStyle, - showShadow: false, - onChange: (value) { - model.deliveryInspectionApprovedBy = value; + _inspectionTile( + title: 'Inspected by'.addTranslation, + model: model.inspectedByModel, + isHmg: widget.requestModel?.isHMG == true, + onTap: () async { + final result = await showInspectionBottomSheet( + context, + title: 'Inspected by'.addTranslation, + isHmg: widget.requestModel?.isHMG == true, + initialModel: model.inspectedByModel ?? InspectionPersonModel(), + ); + if (result != null) { + setState(() => model.inspectedByModel = result); + } + }, + ), + + 8.height, + _inspectionTile( + title: 'Approved by'.addTranslation, + model: model.approvedByModel, + isHmg: widget.requestModel?.isHMG == true, + onTap: () async { + final result = await showInspectionBottomSheet( + context, + title: 'Approved by'.addTranslation, + isHmg: widget.requestModel?.isHMG == true, + initialModel: model.approvedByModel ?? InspectionPersonModel(), + ); + if (result != null) { + setState(() => model.approvedByModel = result); + } + }, + ), + if (widget.requestModel?.paymentTerm?.value == 2) ...[ + _inspectionTile( + title: 'Third Approved by'.addTranslation, + model: model.thirdApprovalModel, + isHmg: widget.requestModel?.isHMG == true, + onTap: () async { + final result = await showInspectionBottomSheet( + context, + title: 'Third Approved by'.addTranslation, + isHmg: widget.requestModel?.isHMG == true, + initialModel: model.thirdApprovalModel ?? InspectionPersonModel(), + ); + if (result != null) { + setState(() => model.thirdApprovalModel = result); + } }, - style: Theme.of(context).textTheme.titleMedium, ), ], + + // if (widget.requestModel?.isHMG == true) ...[ + // OracleUserAutoCompleteField( + // clearAfterPick: false, + // initialValue: model.deliveryInspectionInspectedBy ?? '', + // label: 'Inspected by'.addTranslation, + // onPick: (value) { + // model.deliveryInspectionInspectedBy = value.fullName; + // setState(() {}); + // }, + // onChanged: (value) {}, + // ), + // 8.height, + // OracleUserAutoCompleteField( + // clearAfterPick: false, + // initialValue: model.deliveryInspectionApprovedBy ?? '', + // label: 'Approved by'.addTranslation, + // onChanged: (value) {}, + // onPick: (value) { + // model.deliveryInspectionApprovedBy = value.fullName; + // setState(() {}); + // }, + // ), + // ] //No HMG user free text insted of dropdown ... + // else ...[ + // AppTextFormField( + // labelText: 'Inspected by'.addTranslation, + // backgroundColor: AppColor.fieldBgColor(context), + // initialValue: model.deliveryInspectionInspectedBy ?? '', + // textAlign: TextAlign.center, + // labelStyle: AppTextStyles.textFieldLabelStyle, + // showShadow: false, + // onChange: (value) { + // model.deliveryInspectionInspectedBy = value; + // }, + // style: Theme.of(context).textTheme.titleMedium, + // ), + // 8.height, + // AppTextFormField( + // labelText: 'Approved by'.addTranslation, + // backgroundColor: AppColor.fieldBgColor(context), + // initialValue: model.deliveryInspectionApprovedBy ?? '', + // textAlign: TextAlign.center, + // labelStyle: AppTextStyles.textFieldLabelStyle, + // showShadow: false, + // onChange: (value) { + // model.deliveryInspectionApprovedBy = value; + // }, + // style: Theme.of(context).textTheme.titleMedium, + // ), + // ], 8.height, ADatePicker( label: 'Inspected Date/Time From'.addTranslation, @@ -417,13 +481,69 @@ class _DeliveryInspectionFormViewState extends State ); } - void _attachmentTap() async { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AssetDeliveryAttachmentView( - tableItemId: widget.deliveryTableModel.id, - ))); + Widget _inspectionTile({ + required String title, + InspectionPersonModel? model, + required bool isHmg, + required VoidCallback onTap, + }) { + return InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(12), + child: Container( + padding: const EdgeInsets.all(14), + decoration: BoxDecoration( + color: AppColor.fieldBgColor(context), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title, style: AppTextStyles.textFieldLabelStyle), + 6.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + model?.name?.isNotEmpty == true ? model!.name! : 'Tap to add'.addTranslation, + style: AppTextStyles.bodyText, + ), + + ///Need to display other info as well + // Text( + // model?.email?.isNotEmpty == true + // ? model!.email! + // : '', + // style: AppTextStyles.bodyText, + // ), + ], + ), + ], + ), + ], + ), + ), + ); + } + + Future showAttachmentTypePicker() { + return showDialog( + context: context, + builder: (_) { + return AlertDialog( + content: SingleItemDropDownMenu( + context: context, + title: context.translation.reason, + showAsFullScreenDialog: false, + onSelect: (value) { + Navigator.pop(context, value); + }, + ), + ); + }, + ); } void _cancelTap() async { @@ -469,4 +589,40 @@ class _DeliveryInspectionFormViewState extends State } }); } + + Future showInspectionBottomSheet( + BuildContext context, { + required String title, + required bool isHmg, + required InspectionPersonModel initialModel, + }) { + return showModalBottomSheet( + context: context, + isScrollControlled: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(20)), + ), + builder: (_) { + if (initialModel.localSignature == null && initialModel.signature != null) { + initialModel.localSignature = signatureFromString(initialModel.signature); + } + return InspectionPersonBottomSheet( + title: title, + isHmg: isHmg, + model: InspectionPersonModel( + name: initialModel.name, + email: initialModel.email, + signature: initialModel.signature, + localSignature: initialModel.localSignature, + ), + ); + }, + ); + } + + Uint8List? signatureFromString(String? value) { + if (value == null || !value.contains('|')) return null; + final base64Part = value.split('|').last; + return base64Decode(base64Part); + } } diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart new file mode 100644 index 00000000..bd81f92a --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart @@ -0,0 +1,152 @@ +import 'dart:convert'; +import 'dart:developer'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.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/modules/asset_delivery_module/models/inspection_person_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.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/views/widgets/e_signature/e_signature.dart'; + +class InspectionPersonBottomSheet extends StatefulWidget { + final String title; + bool isHmg; + final InspectionPersonModel model; + + InspectionPersonBottomSheet({ + super.key, + required this.title, + required this.isHmg, + required this.model, + }); + + @override + State createState() => _InspectionPersonBottomSheetState(); +} + +class _InspectionPersonBottomSheetState extends State { + late InspectionPersonModel _model; + + late TextEditingController nameController; + late TextEditingController emailController; + + @override + void initState() { + super.initState(); + + _model = InspectionPersonModel(name: widget.model.name, email: widget.model.email, signature: widget.model.signature, localSignature: widget.model.localSignature); + nameController = TextEditingController(text: _model.name ?? ''); + emailController = TextEditingController(text: _model.email ?? ''); + widget.isHmg = true; + log('isHmg = ${widget.isHmg}'); + } + + @override + void dispose() { + nameController.dispose(); + emailController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return SafeArea( + top: false, + child: Padding( + padding: EdgeInsets.only( + top: 16, + left: 16, + right: 16, + bottom: MediaQuery.of(context).viewInsets.bottom, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(widget.title, style: Theme.of(context).textTheme.titleLarge), + 16.height, + if (widget.isHmg) + OracleUserAutoCompleteField( + clearAfterPick: false, + initialValue: _model.name ?? '', + label: 'Name'.addTranslation, + onPick: (value) { + _model.name = value.fullName; + nameController.text = value.fullName ?? ''; + setState(() {}); + }, + ) + else + AppTextFormField( + labelText: 'Name'.addTranslation, + controller: nameController, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + style: Theme.of(context).textTheme.titleMedium, + onChange: (v) { + _model.name = v; + setState(() {}); + }, + ), + 12.height, + AppTextFormField( + labelText: 'Email'.addTranslation, + controller: emailController, + textInputType: TextInputType.emailAddress, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + style: Theme.of(context).textTheme.titleMedium, + onChange: (v) { + setState(() { + _model.email = v; + }); + }, + ), + 12.height, + ESignature( + title: '', + oldSignature: _model.localSignature == null ? _model.signature : null, + newSignature: _model.localSignature, + backgroundColor: AppColor.neutral100, + showShadow: false, + onChange: (signature) { + if (signature.isEmpty) return; + setState(() { + _model.localSignature = signature; + _model.signature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; + }); + }, + onSaved: (signature) { + if (signature == null || signature.isEmpty) return; + setState(() { + _model.localSignature = signature; + _model.signature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; + }); + }, + ), + 20.height, + AppFilledButton( + label: context.translation.save, + maxWidth: true, + buttonColor: AppColor.primary10, + onPressed: () async { + _model.name = nameController.text.trim(); + _model.email = emailController.text.trim(); + Navigator.pop(context, _model); + }, + ), + ], + ), + ), + ); + } +} diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart index 5accb0ae..92979620 100644 --- a/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart @@ -5,6 +5,7 @@ import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/asset_delivery_module/helper_function.dart'; import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart'; @@ -156,12 +157,7 @@ class _EndUserCostCenterLIstViewState extends State { } void _attachmentTap() async { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AssetDeliveryAttachmentView( - tableItemId: widget.deliveryTableModel.id, - ))); + HelperFunction.attachmentTap(context: context, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id); } void _cancelTap() async { diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart index 11105480..b4c6d505 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart @@ -8,6 +8,7 @@ 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/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/helper_function.dart'; import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; @@ -224,12 +225,13 @@ class _TechnicalInspectionLinesListViewState extends State AssetDeliveryAttachmentView( - tableItemId: widget.deliveryTableModel.id, - ))); + HelperFunction.attachmentTap(context: context, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id); + // Navigator.push( + // context, + // MaterialPageRoute( + // builder: (context) => AssetDeliveryAttachmentView( + // tableItemId: widget.deliveryTableModel.id, + // ))); } void _cancelTap() async { diff --git a/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart b/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart index a9dedb0d..c01a4c2c 100644 --- a/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart +++ b/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart @@ -11,6 +11,7 @@ import 'package:test_sa/models/new_models/floor.dart'; import 'package:test_sa/models/new_models/room_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/cost_center_serial_no_form_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/delivery_inspection_form_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/end_user_asset_details_model.dart'; @@ -171,33 +172,38 @@ class AssetDeliveryProvider extends ChangeNotifier { } } - Future> getAssetDeliveryCostCenterListForLines({int? lineId, int? tableItemId}) async { - List costCenterList = []; + Future getAssetDeliveryCostCenterListForLines({ + int? lineId, + int? tableItemId, + }) async { + CostCenterSerialNoFormModel costCenterSerialNoFormModel = CostCenterSerialNoFormModel(); try { isLoading = true; notifyListeners(); + final response = await ApiManager.instance.get( - "${URLs.getCostCenterListToLineDeliveryInspection}?AssetDeliveryExternalDetailId=$lineId&AssetDeliveryExternalDeliveryId=$tableItemId", + "${URLs.getCostCenterAndSerialNoToLineDeliveryInspection}?AssetDeliveryExternalDetailId=$lineId&AssetDeliveryExternalDeliveryId=$tableItemId", ); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { final jsonData = json.decode(response.body)["data"]; - if (jsonData is List) { - costCenterList = jsonData.map((e) => CostCenterModel.fromJson(e)).toList(); - } + costCenterSerialNoFormModel = CostCenterSerialNoFormModel.fromJson(jsonData); } else { - costCenterList = []; + costCenterSerialNoFormModel.costCenters = []; + costCenterSerialNoFormModel.serialNos = []; } - isLoading = false; - notifyListeners(); - return costCenterList; } catch (e) { log("get Delivery Lines List [error] : $e"); + costCenterSerialNoFormModel.costCenters = []; + costCenterSerialNoFormModel.serialNos = []; + } finally { isLoading = false; - costCenterList = []; notifyListeners(); - return costCenterList; } + + return costCenterSerialNoFormModel; } Future addNewDelivery({ @@ -253,15 +259,18 @@ class AssetDeliveryProvider extends ChangeNotifier { int? tableItemId, int? lineId, List? list, + List? serialNoList, }) async { isLoading = true; Map payload = { "assetDeliveryExternalDeliveryId": tableItemId, "assetDeliveryExternalDetailId": lineId, "costCenters": list?.map((x) => x.toJson()).toList(), + if (serialNoList != null && serialNoList.isNotEmpty) + "serialNos": serialNoList.map((x) => x.toJson()).toList(), }; try { - final response = await ApiManager.instance.post(URLs.saveCostCenterToLineDeliveryInspection, body: payload); + final response = await ApiManager.instance.post(URLs.saveCostCenterAndSerialNoToLineDeliveryInspection, body: payload); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { isLoading = false; @@ -421,10 +430,11 @@ class AssetDeliveryProvider extends ChangeNotifier { Future> getAttachments({ num? tableItemId, + num? attachmentType, }) async { try { isLoading = true; - final response = await ApiManager.instance.get("${URLs.getAttachments}?assetDeliveryExternalDeliveryId=$tableItemId"); + final response = await ApiManager.instance.get("${URLs.getAttachments}?attachmentDocTypeValue=$attachmentType&assetDeliveryExternalDeliveryId=$tableItemId"); List list = []; if (response.statusCode >= 200 && response.statusCode < 300) { isLoading = false; diff --git a/lib/modules/asset_delivery_module/provider/attachment_type_provider.dart b/lib/modules/asset_delivery_module/provider/attachment_type_provider.dart new file mode 100644 index 00000000..2ef16d0b --- /dev/null +++ b/lib/modules/asset_delivery_module/provider/attachment_type_provider.dart @@ -0,0 +1,33 @@ +import 'dart:convert'; +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/models/lookup.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +class AttachmentTypeLookupProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading == true) return -2; + loading = true; + notifyListeners(); + loading = true; + notifyListeners(); + try { + Response response = await ApiManager.instance.get(URLs.attachmentTypeLookup); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List categoriesListJson = json.decode(response.body)["data"]; + items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } +} diff --git a/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart b/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart index ea9963d2..06482a0f 100644 --- a/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart +++ b/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart @@ -106,6 +106,12 @@ class _AllRequestsFilterPageState extends State { types['Equipment Internal Audit'] = 10; types['System Internal Audit'] = 11; } + if (context.userProvider.isCommissioningEngineer) { + ///TODO need to check what other requests type needed here. + types = { + 'Asset Delivery': 13, + }; + } final statuses = { "All WO": 0, diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index 0a31b856..52c35338 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -69,7 +69,7 @@ class _MyRequestsPageState extends State { requestsList.add(Request(10, 'Equipment Internal Audit')); requestsList.add(Request(11, 'System Internal Audit')); //Need to be added for new user role commissioning engineer - requestsList.add(Request(13, "Asset Delivery")); + // requestsList.add(Request(13, "Asset Delivery")); } requestsList.add(Request(12, "Loan Equipment")); @@ -80,6 +80,13 @@ class _MyRequestsPageState extends State { Request(9, 'TRAF'), ]; } + if (context.userProvider.isCommissioningEngineer) { + ///TODO need to show only allowed ids for all workOrder + requestsList = [ + Request(null, context.translation.allWorkOrder), + Request(13, "Asset Delivery"), + ]; + } if (context.userProvider.isQualityUser) { requestsList = [ Request(null, context.translation.allWorkOrder), From 3c9688fdcbded397eb861e8b94b6305dcfe84db9 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Wed, 14 Jan 2026 16:16:27 +0300 Subject: [PATCH 18/26] delivery notes item design updated --- lib/controllers/api_routes/urls.dart | 8 +- .../create_medical_gas_request_page.dart | 4 + .../medical_gas_inspection_detail_page.dart | 1 + .../update_delivery_notes_page.dart | 191 +++++++++++++----- .../my_request/all_requests_filter_page.dart | 1 + 5 files changed, 150 insertions(+), 55 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 39818fc7..522b7853 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -4,14 +4,14 @@ class URLs { static const String appReleaseBuildNumber = "28"; // static const host1 = "https://atomsm.hmg.com"; // production url - static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url + static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url // static String _baseUrl = "$_host/mobile"; - // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis - static final String _baseUrl = "$_host/v3/mobile"; // for asset delivery module + static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis + // static final String _baseUrl = "$_host/v3/mobile"; // for asset delivery module // static final String _baseUrl = "$_host/mobile"; // host local UAT and for internal audit dev // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM // static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation diff --git a/lib/modules/medical_gas_inspection/create_medical_gas_request_page.dart b/lib/modules/medical_gas_inspection/create_medical_gas_request_page.dart index d8c017ff..0bbd9e66 100644 --- a/lib/modules/medical_gas_inspection/create_medical_gas_request_page.dart +++ b/lib/modules/medical_gas_inspection/create_medical_gas_request_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; @@ -289,6 +290,9 @@ class _CreateMedicalGasRequestPageState extends State { }, ), 16.height, - MultipleItemDropDownMenu( - context: context, - showAsBottomSheet: true, - backgroundColor: AppColor.neutral100, - showShadow: false, - showCancel: true, - requestById: context.userProvider.user?.clientId, - title: 'Delivered Items'.addTranslation, - staticData: formModel.deliveredItemList, - initialValue: selectedItemList, - onSelect: (value) { - if ((value ?? []).isNotEmpty) { - WidgetsBinding.instance.addPostFrameCallback((_) { - if (!mounted) return; - setState(() { - selectedItemList = value ?? []; - }); - }); - } - }, - ), - if (selectedItemList.isNotEmpty) ...[ - 8.height, - ListView.separated( - separatorBuilder: (_, __) => 12.height, - itemCount: selectedItemList.length, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) { - MedicalGasRequestDetailModel model = selectedItemList[index]; - return AppTextFormField( - labelText: '${model.name} (Req Qty =${model.requestedQuantity})', - hintText: 'Enter Delivered Quantity'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), - initialValue: model.deliveredQuantity != null ? model.deliveredQuantity?.toInt().toString() : '', - textAlign: TextAlign.center, - enable: true, - textInputType: TextInputType.number, - labelStyle: AppTextStyles.textFieldLabelStyle, - showShadow: false, - onChange: (value) { - if (value.isNotEmpty) { - model.deliveredQuantity = double.tryParse(value); - } - }, - style: Theme.of(context).textTheme.titleMedium, - ); - }, - ) - ], - 16.height, AppTextFormField( initialValue: formModel.deliveryNoteNumber, labelText: "Delivery Notes", @@ -174,6 +123,77 @@ class _UpdateDeliveryNotesState extends State { }, ), 16.height, + + //Older design code + // MultipleItemDropDownMenu( + // context: context, + // showAsBottomSheet: true, + // backgroundColor: AppColor.neutral100, + // showShadow: false, + // showCancel: true, + // requestById: context.userProvider.user?.clientId, + // title: 'Delivered Items'.addTranslation, + // staticData: formModel.deliveredItemList, + // initialValue: selectedItemList, + // onSelect: (value) { + // if ((value ?? []).isNotEmpty) { + // WidgetsBinding.instance.addPostFrameCallback((_) { + // if (!mounted) return; + // setState(() { + // selectedItemList = value ?? []; + // }); + // }); + // } + // }, + // ), + // if (selectedItemList.isNotEmpty) ...[ + // 8.height, + // ListView.separated( + // separatorBuilder: (_, __) => 12.height, + // itemCount: selectedItemList.length, + // shrinkWrap: true, + // physics: const NeverScrollableScrollPhysics(), + // itemBuilder: (context, index) { + // MedicalGasRequestDetailModel model = selectedItemList[index]; + // return AppTextFormField( + // labelText: '${model.name} (Req Qty =${model.requestedQuantity})', + // hintText: 'Enter Delivered Quantity'.addTranslation, + // backgroundColor: AppColor.fieldBgColor(context), + // initialValue: model.deliveredQuantity != null ? model.deliveredQuantity?.toInt().toString() : '', + // textAlign: TextAlign.center, + // enable: true, + // textInputType: TextInputType.number, + // labelStyle: AppTextStyles.textFieldLabelStyle, + // showShadow: false, + // onChange: (value) { + // if (value.isNotEmpty) { + // model.deliveredQuantity = double.tryParse(value); + // } + // }, + // style: Theme.of(context).textTheme.titleMedium, + // ); + // }, + // ) + // ], + if (formModel.deliveredItemList.isNotEmpty) ...[ + _ItemRowLayout( + left: 'Items'.addTranslation.bodyText(context).custom(color: AppColor.textColor(context)), + right: 'Delivered Qty'.addTranslation.bodyText(context).custom(color: AppColor.textColor(context)), + ), + 8.height, + ListView.separated( + separatorBuilder: (_, __) => 12.height, + itemCount: formModel.deliveredItemList.length, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + MedicalGasRequestDetailModel model = formModel.deliveredItemList[index]; + return itemQuantityFieldWidget(index: index, model: model, context: context); + }, + ) + ], + 16.height, + AttachmentPicker( label: 'Upload Attachment', attachment: formModel.attachments, @@ -285,4 +305,73 @@ class _UpdateDeliveryNotesState extends State { } }); } + + Widget itemQuantityFieldWidget({ + required int index, + required MedicalGasRequestDetailModel model, + required BuildContext context, + }) { + final border = OutlineInputBorder( + borderRadius: BorderRadius.circular(4), + borderSide: const BorderSide(color: AppColor.white70, width: 0), + ); + + return _ItemRowLayout( + left: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + model.itemName!.bodyText2(context).custom( + color: context.isDark ? Colors.white : AppColor.white936, + fontWeight: FontWeight.w500, + ), + 'Req Qty ${model.requestedQuantity}'.bodyText2(context).custom( + color: context.isDark ? Colors.white : AppColor.white936, + fontWeight: FontWeight.w500, + ), + ], + ), + right: TextFormField( + keyboardType: TextInputType.number, + initialValue: model.deliveredQuantity != null ? model.deliveredQuantity.toString() : '', + decoration: InputDecoration( + contentPadding: EdgeInsets.symmetric(horizontal: 5.toScreenWidth), + filled: true, + fillColor: AppColor.fieldBgColor(context), + constraints: BoxConstraints( + maxHeight: 30.toScreenHeight, + ), + border: border, + enabledBorder: border, + focusedBorder: border, + ), + onChanged: (value) { + model.deliveredQuantity = int.tryParse(value); + }, + ), + ); + } +} + +class _ItemRowLayout extends StatelessWidget { + final Widget left; + final Widget right; + + const _ItemRowLayout({ + required this.left, + required this.right, + }); + + @override + Widget build(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded(child: left), // Items column + SizedBox( + width: 100.toScreenWidth, // Delivered Qty column + child: right, + ), + ], + ); + } } diff --git a/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart b/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart index 26076417..c134fecd 100644 --- a/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart +++ b/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart @@ -81,6 +81,7 @@ class _AllRequestsFilterPageState extends State { types[context.translation.recurrentWo] = 5; types["Equipment Internal Audit".addTranslation] = 10; types["System Internal Audit".addTranslation] = 11; + types["Medical Gas Inspection".addTranslation] = 14; } if (context.settingProvider.isUserFlowMedical && isEngineer) { From ac50236aa261eba33e950e133908e7712d2a9433 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Thu, 15 Jan 2026 15:52:44 +0300 Subject: [PATCH 19/26] bugs fixes --- lib/controllers/api_routes/urls.dart | 8 +- .../widgets/request_category_list.dart | 3 + .../models/asset_delivery_data_model.dart | 6 +- .../technical_inspection_asset_model.dart | 2 +- .../delivery_inspection_form_view.dart | 219 +++++--- .../inpection_bottomsheet.dart | 6 +- .../end_user_asset_detail_card.dart | 10 +- .../update_end_user_asset_details_view.dart | 505 ++++++++++++++---- ...ate_end_user_cost_center_details_view.dart | 70 ++- .../update_child_asset_view.dart | 39 +- .../update_parent_asset_view.dart | 44 +- .../provider/asset_delivery_provider.dart | 3 +- 12 files changed, 676 insertions(+), 239 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 2c8c2a6b..0930ace5 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -4,14 +4,14 @@ class URLs { static const String appReleaseBuildNumber = "31"; // static const host1 = "https://atomsm.hmg.com"; // production url - static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url + static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url // static String _baseUrl = "$_host/mobile"; - // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis - static final String _baseUrl = "$_host/v6/mobile"; // for asset delivery module + static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis + // static final String _baseUrl = "$_host/v6/mobile"; // for asset delivery module // static final String _baseUrl = "$_host/mobile"; // host local UAT and for internal audit dev // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM // static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation diff --git a/lib/dashboard_latest/widgets/request_category_list.dart b/lib/dashboard_latest/widgets/request_category_list.dart index d0e5d156..9ae0e6ce 100644 --- a/lib/dashboard_latest/widgets/request_category_list.dart +++ b/lib/dashboard_latest/widgets/request_category_list.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_item_view.dart'; import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart'; import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks/task_request_item_view.dart'; @@ -62,6 +63,8 @@ class RequestCategoryList extends StatelessWidget { return EquipmentInternalAuditItemView(requestData: request); case 11: return EquipmentInternalAuditItemView(requestData: request); + case 13: + return AssetDeliveryItemView(requestData: request); default: return Container( height: 100, diff --git a/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart b/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart index 08de3111..cde76346 100644 --- a/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart +++ b/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart @@ -241,7 +241,7 @@ class AssetDeliveryInternalDetail { num? qtyCancelled; num? unitPrice; num? unitPriceWithTax; - String? itemCategory; + Lookup? itemCategory; num? totalAssets; num? childPerAsset; @@ -259,7 +259,9 @@ class AssetDeliveryInternalDetail { qtyCancelled = json['qtyCancelled']; unitPrice = json['unitPrice']; unitPriceWithTax = json['unitPriceWithTax']; - itemCategory = json['itemCategory']; + itemCategory = json['itemCategory'] != null + ? Lookup.fromJson(json['itemCategory']) + : null; totalAssets = json['totalAssets']; childPerAsset = json['childPerAsset']; } diff --git a/lib/modules/asset_delivery_module/models/technical_inspection_asset_model.dart b/lib/modules/asset_delivery_module/models/technical_inspection_asset_model.dart index 64671b11..fafcc277 100644 --- a/lib/modules/asset_delivery_module/models/technical_inspection_asset_model.dart +++ b/lib/modules/asset_delivery_module/models/technical_inspection_asset_model.dart @@ -136,7 +136,7 @@ class TechnicalInspectionAssetModel { Map toChildJson() { final Map data = {}; - data['id'] = id; + data['id'] = id ?? 0; data['assetDeliveryInternalDetailAssetChildId'] = assetDeliveryInternalDetailAssetChildId; data['assetNumber'] = assetNumber; data['assetOriginId'] = assetOrigin?.id; diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart index c6918f74..cdb4d5e9 100644 --- a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart @@ -7,7 +7,6 @@ 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/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/modules/asset_delivery_module/helper_function.dart'; import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; @@ -15,7 +14,6 @@ import 'package:test_sa/modules/asset_delivery_module/models/delivery_inspection import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/inspection_person_model.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart'; @@ -205,13 +203,22 @@ class _DeliveryInspectionFormViewState extends State } void calculateTotalTime() { - if (model.deliveryInspectionInspectedDateFrom == null || model.deliveryInspectionInspectedDateTo == null) { + final from = model.deliveryInspectionInspectedDateFrom; + final to = model.deliveryInspectionInspectedDateTo; + + if (from == null || to == null) { model.totalTime = null; return; } - final fromDate = model.deliveryInspectionInspectedDateFrom!; - final toDate = model.deliveryInspectionInspectedDateTo!; - final hours = toDate.difference(fromDate).inSeconds / 3600.0; + + final diffInSeconds = to.difference(from).inSeconds; + + if (diffInSeconds < 0) { + model.totalTime = null; + return; + } + + final hours = diffInSeconds / 3600; model.totalTime = num.parse(hours.toStringAsFixed(3)); } @@ -253,6 +260,7 @@ class _DeliveryInspectionFormViewState extends State }, ), if (widget.requestModel?.paymentTerm?.value == 2) ...[ + 8.height, _inspectionTile( title: 'Third Approved by'.addTranslation, model: model.thirdApprovalModel, @@ -330,52 +338,31 @@ class _DeliveryInspectionFormViewState extends State date: model.deliveryInspectionInspectedDateFrom, from: DateTime(DateTime.now().year, 1, 1), formatDateWithTime: true, - onDatePicker: (selectedDate) { - showTimePicker( + onDatePicker: (selectedDate) async { + final selectedTime = await showTimePicker( context: context, initialTime: TimeOfDay.now(), - builder: (BuildContext context, Widget? child) { - final ThemeData currentTheme = Theme.of(context); - return Theme( - data: currentTheme.copyWith( - timePickerTheme: TimePickerThemeData( - dialHandColor: AppColor.primary10, - dialBackgroundColor: Colors.grey.withOpacity(0.1), - hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), - dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), - dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), - dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), - entryModeIconColor: AppColor.primary10, - ), - textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), - ), - child: child!, - ); - }, - ).then((selectedTime) { - if (selectedTime != null) { - model.deliveryInspectionInspectedDateFrom = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); - // calculateTotalTime(); - - ///need to check if need validation or not. - // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { - // "Start time is before the request time.".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } - if (model.deliveryInspectionInspectedDateFrom!.isAfter(DateTime.now())) { - "Start time is after than current time".showToast; - model.deliveryInspectionInspectedDateFrom = null; - selectedTime = null; - return; - } - - setState(() {}); - } - }); + builder: _timePickerThemeBuilder, + ); + if (selectedTime == null) return; + + final fromDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + + if (!_validateInspectionDates(from: fromDateTime, to: model.deliveryInspectionInspectedDateTo)) { + return; // invalid, do not assign + } + + model.deliveryInspectionInspectedDateFrom = fromDateTime; + setState(() {}); }, ), + 8.height, ADatePicker( label: 'Inspected Date/Time To'.addTranslation, @@ -385,55 +372,109 @@ class _DeliveryInspectionFormViewState extends State date: model.deliveryInspectionInspectedDateTo, from: model.deliveryInspectionInspectedDateFrom, formatDateWithTime: true, - onDatePicker: (selectedDate) { - showTimePicker( + onDatePicker: (selectedDate) async { + if (model.deliveryInspectionInspectedDateFrom == null) { + "Please select time to first".showToast; + return; + } + + final selectedTime = await showTimePicker( context: context, initialTime: TimeOfDay.now(), - builder: (BuildContext context, Widget? child) { - final ThemeData currentTheme = Theme.of(context); - return Theme( - data: currentTheme.copyWith( - timePickerTheme: TimePickerThemeData( - dialHandColor: AppColor.primary10, - dialBackgroundColor: Colors.grey.withOpacity(0.1), - hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), - dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), - dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), - dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), - entryModeIconColor: AppColor.primary10, - ), - textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), - ), - child: child!, - ); - }, - ).then((selectedTime) { - if (selectedTime != null) { - model.deliveryInspectionInspectedDateTo = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); - calculateTotalTime(); - - ///Need to check need validation or not.. - // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { - // "Start time is before the request time.".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } - if (model.deliveryInspectionInspectedDateTo!.isAfter(DateTime.now())) { - "End time is after than current time".showToast; - model.deliveryInspectionInspectedDateTo = null; - selectedTime = null; - return; - } - setState(() {}); - } - }); + builder: _timePickerThemeBuilder, + ); + if (selectedTime == null) return; + + final toDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + + if (!_validateInspectionDates(from: model.deliveryInspectionInspectedDateFrom, to: toDateTime)) { + return; // invalid, do not assign + } + + model.deliveryInspectionInspectedDateTo = toDateTime; + setState(() {}); }, ), ], ); } + bool _validateInspectionDates({DateTime? from, DateTime? to}) { + if (from == null && to == null) return true; + if (from != null) { + if (from.isAfter(DateTime.now())) { + "Start time cannot be in the future".showToast; + return false; + } + if (to != null && from.isAfter(to)) { + "Start time cannot be after end time".showToast; + return false; + } + } + if (to != null) { + if (to.isAfter(DateTime.now())) { + "End time cannot be in the future".showToast; + return false; + } + if (from != null && to.isBefore(from)) { + "End time cannot be before start time".showToast; + return false; + } + } + + if (from != null && to != null) { + final diffInSeconds = to.difference(from).inSeconds; + if (diffInSeconds < 0) { + model.totalTime = null; + return false; + } + final hours = diffInSeconds / 3600.0; + model.totalTime = num.parse(hours.toStringAsFixed(3)); + } else { + model.totalTime = null; + } + + return true; + } + + Widget _timePickerThemeBuilder(BuildContext context, Widget? child) { + final ThemeData currentTheme = Theme.of(context); + + return Theme( + data: currentTheme.copyWith( + timePickerTheme: TimePickerThemeData( + dialHandColor: AppColor.primary10, + dialBackgroundColor: Colors.grey.withOpacity(0.1), + hourMinuteColor: MaterialStateColor.resolveWith( + (states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1), + ), + dayPeriodColor: MaterialStateColor.resolveWith( + (states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent, + ), + dayPeriodTextColor: MaterialStateColor.resolveWith( + (states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10, + ), + dayPeriodBorderSide: BorderSide( + color: Colors.grey.withOpacity(0.2), + ), + entryModeIconColor: AppColor.primary10, + ), + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + foregroundColor: AppColor.primary10, + ), + ), + ), + child: child!, + ); + } + Widget inspectionDetails() { return Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart index bd81f92a..106b3a97 100644 --- a/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart @@ -15,10 +15,10 @@ import 'package:test_sa/views/widgets/e_signature/e_signature.dart'; class InspectionPersonBottomSheet extends StatefulWidget { final String title; - bool isHmg; + bool isHmg; final InspectionPersonModel model; - InspectionPersonBottomSheet({ + InspectionPersonBottomSheet({ super.key, required this.title, required this.isHmg, @@ -42,8 +42,6 @@ class _InspectionPersonBottomSheetState extends State createState() => _UpdateEndUserAssetDetailsViewState(); +// } +// +// class _UpdateEndUserAssetDetailsViewState extends State { +// final GlobalKey _formKey = GlobalKey(); +// final GlobalKey _scaffoldKey = GlobalKey(); +// bool viewOnly = false; +// late AssetDeliveryProvider assetDeliveryProvider; +// EndUserAssetDetailsModel model = EndUserAssetDetailsModel(); +// late TextEditingController quantityController; +// late TextEditingController descriptionController; +// +// @override +// void initState() { +// quantityController = TextEditingController(); +// descriptionController = TextEditingController(); +// WidgetsBinding.instance.addPostFrameCallback((_) { +// getInitialData(); +// }); +// super.initState(); +// } +// +// @override +// void dispose() { +// super.dispose(); +// } +// +// void getInitialData() async { +// assetDeliveryProvider = Provider.of(context, listen: false); +// if (widget.assetDetailsModel != null) { +// model = EndUserAssetDetailsModel.fromJson(widget.assetDetailsModel!.toJson()); +// model.costCenterName = widget.costCenterName; +// model.assetDeliveryExternalDeliveryId = widget.tableId; +// model.status = widget.assetDetailsModel?.status; +// model.rejectionReason = widget.assetDetailsModel?.rejectionReason; +// } +// quantityController.text = model.rejectedQty != null ? model.rejectedQty.toString() : ''; +// descriptionController.text = model.description ?? ''; +// model.type = 'Accessory'; +// setState(() {}); +// } +// +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// key: _scaffoldKey, +// appBar: DefaultAppBar( +// title: 'Item Details'.addTranslation, +// titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), +// ), +// body: Form( +// key: _formKey, +// child: Column( +// children: [ +// SingleChildScrollView( +// padding: const EdgeInsets.all(16), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// SingleItemDropDownMenu( +// context: context, +// height: 56.toScreenHeight, +// title: 'Status'.addTranslation, +// titleTextColor: AppColor.neutral120, +// showShadow: false, +// validator: (value) { +// if (value == null) return "Please select status"; +// return null; +// }, +// backgroundColor: AppColor.fieldBgColor(context), +// showAsBottomSheet: true, +// initialValue: model.status, +// onSelect: (status) { +// if (status != null) { +// model.status = status; +// setState(() {}); +// } +// }, +// ), +// 8.height, +// if (model.type == 'Accessory') ...[ +// AppTextFormField( +// labelText: 'Rejected Quantity'.addTranslation, +// controller: quantityController, +// backgroundColor: AppColor.fieldBgColor(context), +// textAlign: TextAlign.center, +// labelStyle: AppTextStyles.textFieldLabelStyle, +// textInputType: TextInputType.number, +// showShadow: false, +// validator: (value) { +// if ((value ?? "").isEmpty) return "Mandatory"; +// return null; +// }, +// onChange: (value) { +// if (value.isNotEmpty) { +// model.rejectedQty = model.rejectedQty = num.tryParse(value); +// setState(() {}); +// } +// }, +// style: Theme.of(context).textTheme.titleMedium, +// ), +// 8.height, +// if (model.status?.value == 1 && (model.rejectedQty != null && quantityController.text.isNotEmpty && model.rejectedQty! > 0)) +// SingleItemDropDownMenu( +// context: context, +// height: 56.toScreenHeight, +// title: 'Rejection Reason '.addTranslation, +// validator: (value) { +// if (value == null) return "Please select rejection reason"; +// return null; +// }, +// titleTextColor: AppColor.neutral120, +// showShadow: false, +// backgroundColor: AppColor.fieldBgColor(context), +// showAsBottomSheet: true, +// initialValue: model.rejectionReason, +// onSelect: (reason) { +// if (reason != null) { +// model.rejectionReason = reason; +// setState(() {}); +// } +// }, +// ), +// 8.height, +// ], +// if (model.status != null && model.status!.value == 2) ...[ +// SingleItemDropDownMenu( +// context: context, +// height: 56.toScreenHeight, +// title: 'Rejection Reason '.addTranslation, +// validator: (value) { +// if (value == null) return "Please select rejection reason"; +// return null; +// }, +// titleTextColor: AppColor.neutral120, +// showShadow: false, +// backgroundColor: AppColor.fieldBgColor(context), +// showAsBottomSheet: true, +// initialValue: model.rejectionReason, +// onSelect: (reason) { +// if (reason != null) { +// model.rejectionReason = reason; +// setState(() {}); +// } +// }, +// ), +// 8.height, +// ], +// AppTextFormField( +// controller: descriptionController, +// labelText: 'Description'.addTranslation, +// backgroundColor: AppColor.fieldBgColor(context), +// showShadow: false, +// labelStyle: AppTextStyles.textFieldLabelStyle, +// alignLabelWithHint: true, +// textInputType: TextInputType.multiline, +// onChange: (value) { +// model.description = value; +// }, +// onSaved: (value) { +// model.description = value; +// }, +// ), +// 8.height, +// ], +// ).toShadowContainer(context, borderRadius: 20, padding: 12)) +// .expanded, +// FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), +// ], +// ), +// ), +// ); +// } +// +// ///Need to check which details show here... +// +// void _saveTap() async { +// if (!_formKey.currentState!.validate()) { +// return; +// } +// _formKey.currentState!.save(); +// log('payload ${model.toJson()}'); +// return; +// showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); +// await assetDeliveryProvider.saveEndUserAssetDataData(model: model).then((status) async { +// Navigator.pop(context); +// if (status) { +// Navigator.pop(context, true); +// } +// }); +// } +// } + import 'dart:developer'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; @@ -22,11 +245,16 @@ import '../../../../new_views/common_widgets/app_filled_button.dart'; import '../../../../new_views/common_widgets/default_app_bar.dart'; class UpdateEndUserAssetDetailsView extends StatefulWidget { - EndUserAssetDetailsModel? assetDetailsModel; - String? costCenterName; - int? tableId; + final EndUserAssetDetailsModel? assetDetailsModel; + final String? costCenterName; + final int? tableId; - UpdateEndUserAssetDetailsView({Key? key, this.assetDetailsModel, this.costCenterName, this.tableId}) : super(key: key); + const UpdateEndUserAssetDetailsView({ + Key? key, + this.assetDetailsModel, + this.costCenterName, + this.tableId, + }) : super(key: key); @override State createState() => _UpdateEndUserAssetDetailsViewState(); @@ -34,147 +262,220 @@ class UpdateEndUserAssetDetailsView extends StatefulWidget { class _UpdateEndUserAssetDetailsViewState extends State { final GlobalKey _formKey = GlobalKey(); - final GlobalKey _scaffoldKey = GlobalKey(); - bool viewOnly = false; + late AssetDeliveryProvider assetDeliveryProvider; EndUserAssetDetailsModel model = EndUserAssetDetailsModel(); + late TextEditingController quantityController; late TextEditingController descriptionController; @override void initState() { + super.initState(); quantityController = TextEditingController(); descriptionController = TextEditingController(); + WidgetsBinding.instance.addPostFrameCallback((_) { - getInitialData(); + _loadInitialData(); }); - super.initState(); } - @override - void dispose() { - super.dispose(); - } - - void getInitialData() async { + void _loadInitialData() { assetDeliveryProvider = Provider.of(context, listen: false); + if (widget.assetDetailsModel != null) { - model = EndUserAssetDetailsModel.fromJson(widget.assetDetailsModel!.toJson()); + model = EndUserAssetDetailsModel.fromJson( + widget.assetDetailsModel!.toJson(), + ); model.costCenterName = widget.costCenterName; model.assetDeliveryExternalDeliveryId = widget.tableId; model.status = widget.assetDetailsModel?.status; model.rejectionReason = widget.assetDetailsModel?.rejectionReason; } + quantityController.text = model.rejectedQty != null ? model.rejectedQty.toString() : ''; descriptionController.text = model.description ?? ''; setState(() {}); } + bool get _isAccessory => model.type == 'Accessory'; + + bool get _isAccepted => model.status?.value == 1; + + bool get _isRejected => model.status?.value == 2; + + bool get _showRejectedQty { + if (_isAccessory) return true; + return false; + } + + bool get _showRejectionReason { + if (_isAccessory) { + if (_isRejected) return true; + if (_isAccepted && (model.rejectedQty ?? 0) > 0) return true; + return false; + } + if (_isRejected) return true; + return false; + } + @override Widget build(BuildContext context) { return Scaffold( - key: _scaffoldKey, appBar: DefaultAppBar( title: 'Item Details'.addTranslation, - titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + titleStyle: AppTextStyles.heading3.copyWith( + fontWeight: FontWeight.w500, + color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, + ), ), body: Form( key: _formKey, child: Column( children: [ SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: 'Status'.addTranslation, - titleTextColor: AppColor.neutral120, - showShadow: false, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - initialValue: model.status, - onSelect: (status) { - if (status != null) { - model.status = status; - setState(() {}); - } - }, - ), - 8.height, - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: 'Rejection Reason '.addTranslation, - titleTextColor: AppColor.neutral120, - showShadow: false, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - initialValue: model.rejectionReason, - onSelect: (reason) { - if (reason != null) { - model.rejectionReason = reason; - setState(() {}); - } - }, - ), - 8.height, - if (model.type == 'Accessory') ...[ - AppTextFormField( - labelText: 'Rejected Quantity'.addTranslation, - controller: quantityController, - backgroundColor: AppColor.fieldBgColor(context), - textAlign: TextAlign.center, - labelStyle: AppTextStyles.textFieldLabelStyle, - textInputType: TextInputType.number, - showShadow: false, - onChange: (value) { - if (value.isNotEmpty) { - model.rejectedQty = model.rejectedQty = num.tryParse(value); - } - }, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - ], - AppTextFormField( - controller: descriptionController, - labelText: 'Description'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), - showShadow: false, - labelStyle: AppTextStyles.textFieldLabelStyle, - alignLabelWithHint: true, - textInputType: TextInputType.multiline, - onChange: (value) { - model.description = value; - }, - onSaved: (value) { - model.description = value; - }, - ), - 8.height, - ], - ).toShadowContainer(context, borderRadius: 20, padding: 12)) - .expanded, - FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), + padding: const EdgeInsets.all(16), + child: _formBody(context), + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Save'.addTranslation, + maxWidth: true, + onPressed: _saveTap, + ), + ), ], ), ), ); } - ///Need to check which details show here... + Widget _formBody(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _statusDropdown(), + 8.height, + if (_showRejectedQty) ...[ + _rejectedQtyField(), + 8.height, + ], + if (_showRejectionReason) ...[ + _rejectionReasonDropdown(), + 8.height, + ], + _descriptionField(), + 8.height, + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12); + } + + Widget _statusDropdown() { + return SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Status'.addTranslation, + titleTextColor: AppColor.neutral120, + showShadow: false, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + initialValue: model.status, + validator: (value) { + if (value == null) return 'Please select status'; + return null; + }, + onSelect: (status) { + if (status != null) { + model.status = status; + model.rejectionReason = null; + setState(() {}); + } + }, + ); + } + + Widget _rejectedQtyField() { + return AppTextFormField( + labelText: 'Rejected Quantity'.addTranslation, + controller: quantityController, + backgroundColor: AppColor.fieldBgColor(context), + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + textInputType: TextInputType.number, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + validator: (value) { + if (!_showRejectedQty) return null; + if ((value ?? '').isEmpty) return 'Mandatory'; + final qty = num.tryParse(value!); + if (qty == null || qty <= 0) return 'Enter valid quantity'; + return null; + }, + onChange: (value) { + model.rejectedQty = value.isNotEmpty ? num.tryParse(value) : null; + setState(() {}); + }, + ); + } + + Widget _rejectionReasonDropdown() { + return SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Rejection Reason'.addTranslation, + titleTextColor: AppColor.neutral120, + showShadow: false, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + initialValue: model.rejectionReason, + validator: (value) { + if (!_showRejectionReason) return null; + if (value == null) return 'Please select rejection reason'; + return null; + }, + onSelect: (reason) { + if (reason != null) { + model.rejectionReason = reason; + setState(() {}); + } + }, + ); + } + + Widget _descriptionField() { + return AppTextFormField( + controller: descriptionController, + labelText: 'Description'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + onChange: (value) => model.description = value, + onSaved: (value) => model.description = value, + ); + } void _saveTap() async { + if (!_formKey.currentState!.validate()) return; + _formKey.currentState!.save(); - showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - await assetDeliveryProvider.saveEndUserAssetDataData(model: model).then((status) async { - Navigator.pop(context); - if (status) { - Navigator.pop(context, true); - } - }); + log('payload ${model.toJson()}'); + + showDialog( + context: context, + barrierDismissible: false, + builder: (_) => const AppLazyLoading(), + ); + + final status = await assetDeliveryProvider.saveEndUserAssetDataData(model: model); + + Navigator.pop(context); + + if (status) { + Navigator.pop(context, true); + } } } diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart index 3b98beaa..1234a018 100644 --- a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart @@ -235,16 +235,6 @@ class _UpdateEndUserCostCenterDetailsViewState extends State const AppLazyLoading()); model.assetDeliveryExternalDetailId = widget.tableItemId; diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart index bb0b6ca9..be67dd74 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart @@ -189,6 +189,39 @@ class _UpdateChildAssetViewState extends State { } }), 8.height, + AppTextFormField( + labelText: 'Asset Name'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.modelDefinition?.assetName, + textAlign: TextAlign.center, + enable: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Model'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.modelDefinition?.model, + textAlign: TextAlign.center, + enable: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Manufacturer'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.modelDefinition?.manufacturer ?? '', + textAlign: TextAlign.center, + enable: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, AppTextFormField( labelText: 'Serial Number'.addTranslation, backgroundColor: AppColor.fieldBgColor(context), @@ -423,6 +456,10 @@ class _UpdateChildAssetViewState extends State { } String _statusFromBool(bool? value) { - return value == true ? 'PASS' :value==false? 'FAIL':''; + return value == true + ? 'PASS' + : value == false + ? 'FAIL' + : ''; } } diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart index 8bac4319..52a14cda 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart @@ -216,15 +216,55 @@ class _UpdateParentAssetViewState extends State { if (assetModel.site != null) { await provider.getSiteData(siteId: assetModel.site?.id, model: provider.parentFormModel); } - assetModel.assetDeliveryInternalDetailAssetId = assetModel.id; - assetModel.id = 0; + assetModel.assetDeliveryInternalDetailAssetId = assetModel.id; + assetModel.id = 0; + if (assetModel.childAssetList != null && assetModel.childAssetList!.isNotEmpty) { + for (var asset in assetModel.childAssetList!) { + asset.assetDeliveryInternalDetailAssetChildId = asset.id; + asset.id = 0; + } + } provider.setParentModel(assetModel); log('child list length ${assetModel.childAssetList?.length}'); + populateTextFields(model: provider.parentFormModel); } } }), 8.height, + AppTextFormField( + labelText: 'Asset Name'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.modelDefinition?.assetName, + textAlign: TextAlign.center, + enable: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Model'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.modelDefinition?.model, + textAlign: TextAlign.center, + enable: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Manufacturer'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.modelDefinition?.manufacturer ?? '', + textAlign: TextAlign.center, + enable: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, AppTextFormField( labelText: 'Serial Number'.addTranslation, backgroundColor: AppColor.fieldBgColor(context), diff --git a/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart b/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart index c01a4c2c..6516b500 100644 --- a/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart +++ b/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart @@ -266,8 +266,7 @@ class AssetDeliveryProvider extends ChangeNotifier { "assetDeliveryExternalDeliveryId": tableItemId, "assetDeliveryExternalDetailId": lineId, "costCenters": list?.map((x) => x.toJson()).toList(), - if (serialNoList != null && serialNoList.isNotEmpty) - "serialNos": serialNoList.map((x) => x.toJson()).toList(), + if (serialNoList != null && serialNoList.isNotEmpty) "serialNos": serialNoList.map((x) => x.toJson()).toList(), }; try { final response = await ApiManager.instance.post(URLs.saveCostCenterAndSerialNoToLineDeliveryInspection, body: payload); From 1c86fe71a2a7ca441c5a7fdd51c70527483275f1 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Thu, 15 Jan 2026 16:55:13 +0300 Subject: [PATCH 20/26] improvements and added modifiedBy details --- lib/controllers/api_routes/urls.dart | 3 ++- .../medical_gas_inspection_detail_page.dart | 2 ++ .../models/medical_gas_data_model.dart | 5 +++++ .../update_delivery_notes_page.dart | 15 +++++++++++---- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 522b7853..d51fb77c 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -435,7 +435,8 @@ class URLs { //Medical Gas Request.. // 4004 static get orderTypeLookUp => "$_baseUrl/Lookups/GetLookup?lookupEnum=4004"; - static get itemTypeLookUp => "$_baseUrl/Lookups/GetLookup?lookupEnum=4005"; + // static get itemTypeLookUp => "$_baseUrl/Lookups/GetLookup?lookupEnum=4005"; + static get itemTypeLookUp => "$_baseUrl/MedicalGas/GetItemTypeLookup?lookupEnum=4002"; static get getMedicalGasSupplierList => "$_baseUrl/MedicalGas/GetMedicalGasSupplierAsync"; static get getMedicalGasInfoBySupplier => "$_baseUrl/MedicalGas/GetMedicalGasInfoBySupplierAsync"; static get addMedicalGasRequest => "$_baseUrl/MedicalGas/AddUpdateMedicalGasRequestAsync"; diff --git a/lib/modules/medical_gas_inspection/medical_gas_inspection_detail_page.dart b/lib/modules/medical_gas_inspection/medical_gas_inspection_detail_page.dart index 46d990b1..023af466 100644 --- a/lib/modules/medical_gas_inspection/medical_gas_inspection_detail_page.dart +++ b/lib/modules/medical_gas_inspection/medical_gas_inspection_detail_page.dart @@ -91,6 +91,8 @@ class _MedicalGasInspectionDetailPageState extends State requestDetailDtos = []; @@ -51,6 +52,7 @@ class MedicalGasDataModel { this.isInspectedGasLeak, this.deliveredDate, this.deliveryNote, + this.lastModifiedBy, List? requestDetailDtos, List? deliveryNoteAttachmentDto, }) { @@ -75,9 +77,11 @@ class MedicalGasDataModel { email = json['email']; isSubmitted = json['isSubmitted']; deliveryNote = json['deliveryNote']; + lastModifiedBy = json['lastModifiedBy']; requestOrderStatus = json['requestOrderStatus']; isPressureChecked = json['isPressureChecked']; isInspectedGasLeak = json['isInspectedGasLeak']; + deliveredDate = json['deliveredDate'] != null ? DateTime.parse(json['deliveredDate']) : null; requestStatus = json['requestOrderStatusDto'] != null ? Lookup.fromJson(json['requestOrderStatusDto']) : null; if (json['requestDetailDtos'] != null) { @@ -109,6 +113,7 @@ class MedicalGasDataModel { 'site': site, 'supplierId': supplierId, 'deliveryNote': deliveryNote, + 'lastModifiedBy': lastModifiedBy, 'supplier': supplier, 'contact': contact, 'email': email, diff --git a/lib/modules/medical_gas_inspection/update_delivery_notes_page.dart b/lib/modules/medical_gas_inspection/update_delivery_notes_page.dart index 56744d4d..925f5193 100644 --- a/lib/modules/medical_gas_inspection/update_delivery_notes_page.dart +++ b/lib/modules/medical_gas_inspection/update_delivery_notes_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; @@ -35,7 +36,8 @@ class _UpdateDeliveryNotesState extends State { late MedicalGasInspectionProvider medicalGasInspectionProvider; bool pressureTestAcknowledgement = false; bool leakTestAcknowledgement = false; - List selectedItemList = []; + + // List selectedItemList = []; @override void initState() { @@ -62,7 +64,7 @@ class _UpdateDeliveryNotesState extends State { isSubmitted: dataModel.isSubmitted, deliveryNoteNumber: dataModel.deliveryNote); //Need to Confirm this condition - selectedItemList = dataModel.requestDetailDtos.where((item) => item.deliveredQuantity != null && item.deliveredQuantity! > 0).toList(); + // selectedItemList = dataModel.requestDetailDtos.where((item) => item.deliveredQuantity != null && item.deliveredQuantity! > 0).toList(); setState(() {}); } } @@ -290,7 +292,7 @@ class _UpdateDeliveryNotesState extends State { void _update({required BuildContext context, bool isSubmitted = false}) async { formModel.gasDeliveredQuantityDtos = []; formModel.isSubmitted = isSubmitted; - for (var item in selectedItemList) { + for (var item in formModel.deliveredItemList) { formModel.gasDeliveredQuantityDtos.add(GasDeliveredQuantityModel( id: widget.dataModel != null ? item.id : 0, medicalGasAttributeId: item.medicalGasAttributeId ?? item.id, @@ -302,6 +304,11 @@ class _UpdateDeliveryNotesState extends State { Navigator.pop(context); if (status) { Navigator.pop(context, true); + if (formModel.isSubmitted == true) { + AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); + allRequestsProvider.reset(); + await allRequestsProvider.getAllRequests(context, typeTransaction: 14); + } } }); } @@ -332,7 +339,7 @@ class _UpdateDeliveryNotesState extends State { ), right: TextFormField( keyboardType: TextInputType.number, - initialValue: model.deliveredQuantity != null ? model.deliveredQuantity.toString() : '', + initialValue: model.deliveredQuantity != null ? model.deliveredQuantity?.toStringAsFixed(0) : '', decoration: InputDecoration( contentPadding: EdgeInsets.symmetric(horizontal: 5.toScreenWidth), filled: true, From b78d10af468cc3e6e4442f2f54f6a182b1249d10 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 15 Jan 2026 18:20:38 +0300 Subject: [PATCH 21/26] current user employee id for chat. --- lib/models/user.dart | 4 ++++ .../cm_module/views/service_request_detail_main_view.dart | 2 +- lib/modules/tm_module/tasks_wo/task_request_detail_view.dart | 4 ++-- lib/views/pages/device_transfer/device_transfer_details.dart | 4 ++-- lib/views/pages/user/gas_refill/gas_refill_details.dart | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/models/user.dart b/lib/models/user.dart index 5eac8486..747f221b 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -12,6 +12,7 @@ class User { List? departmentName; String? message; String? username; + String? employeeId; String? userID; String? email; String? password; @@ -53,6 +54,7 @@ class User { this.departmentName, this.message, this.username, + this.employeeId, this.userID, this.email, this.password, @@ -148,6 +150,7 @@ class User { map['message'] = message; map['username'] = username; map['userID'] = userID; + map['employeeId'] = employeeId; map['email'] = email; map['password'] = password; map['token'] = token; @@ -209,6 +212,7 @@ class User { message = json['message']; username = json['username']; userID = json['userID']; + employeeId = json['employeeId']; email = json['email']; password = json['password']; token = json['token']; diff --git a/lib/modules/cm_module/views/service_request_detail_main_view.dart b/lib/modules/cm_module/views/service_request_detail_main_view.dart index f59b49e1..36d5e8bf 100644 --- a/lib/modules/cm_module/views/service_request_detail_main_view.dart +++ b/lib/modules/cm_module/views/service_request_detail_main_view.dart @@ -106,7 +106,7 @@ class _ServiceRequestDetailMainState extends State { isReadOnly: _requestProvider.isReadOnlyRequest, requestId: widget.requestId.toInt(), assigneeEmployeeNumber: provider.currentWorkOrder?.data?.assignedEmployee!.employeeId!, - myLoginUserID: context.userProvider.user!.username!, + myLoginUserID: context.userProvider.user!.employeeId ?? context.userProvider.user!.username!, contactEmployeeINumber: provider.currentWorkOrder?.data?.workOrderContactPerson.first.employeeId, ); } diff --git a/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart b/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart index bf3aa96f..514d8055 100644 --- a/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart +++ b/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart @@ -80,11 +80,11 @@ class _TaskRequestDetailsViewState extends State { (_taskReqModel.taskJobContactPersons?.isNotEmpty ?? false)) { return ChatWidget( moduleId: widget.moduleId, - isShow: context.settingProvider.isUserFlowMedical&& _taskReqModel.taskJobStatus!.value! != 1, + isShow: context.settingProvider.isUserFlowMedical && _taskReqModel.taskJobStatus!.value! != 1, isReadOnly: _taskReqModel.taskJobStatus!.value! != 2, requestId: widget.taskId.toInt(), assigneeEmployeeNumber: _taskReqModel.assignedEngineer?.employeeId!, - myLoginUserID: context.userProvider.user!.username!, + myLoginUserID: context.userProvider.user!.employeeId ?? context.userProvider.user!.username!, contactEmployeeINumber: _taskReqModel.taskJobContactPersons!.first.user?.employeeId, ); } else diff --git a/lib/views/pages/device_transfer/device_transfer_details.dart b/lib/views/pages/device_transfer/device_transfer_details.dart index e0ad05bc..49b58057 100644 --- a/lib/views/pages/device_transfer/device_transfer_details.dart +++ b/lib/views/pages/device_transfer/device_transfer_details.dart @@ -227,7 +227,7 @@ class _DeviceTransferDetailsState extends State { isReadOnly: _model!.senderMachineStatusValue! != 1, requestId: widget.model.id!.toInt(), assigneeEmployeeNumber: _model!.senderAssignedEmployeeNumber, - myLoginUserID: context.userProvider.user!.username!, + myLoginUserID: context.userProvider.user!.employeeId ?? context.userProvider.user!.username!, contactEmployeeINumber: _model!.assetTransferContactPersons!.first.employeeNumber, ), if ((_userProvider!.user?.type == UsersTypes.engineer)) @@ -288,7 +288,7 @@ class _DeviceTransferDetailsState extends State { isReadOnly: (isSender ? _deviceTransfer.senderMachineStatusValue! : _deviceTransfer.receiverMachineStatusValue) != 1, requestId: widget.model.id!.toInt(), assigneeEmployeeNumber: isSender ? _deviceTransfer.senderAssignedEmployeeNumber! : _deviceTransfer.receiverAssignedEmployeeNumber!, - myLoginUserID: context.userProvider.user!.username!, + myLoginUserID: context.userProvider.user!.employeeId ?? context.userProvider.user!.username!, contactEmployeeINumber: _deviceTransfer.assetTransferContactPersons!.first.employeeNumber, ), if ((_userProvider!.user?.type == UsersTypes.engineer)) diff --git a/lib/views/pages/user/gas_refill/gas_refill_details.dart b/lib/views/pages/user/gas_refill/gas_refill_details.dart index 74f4287e..45d3c128 100644 --- a/lib/views/pages/user/gas_refill/gas_refill_details.dart +++ b/lib/views/pages/user/gas_refill/gas_refill_details.dart @@ -72,7 +72,7 @@ class _GasRefillDetailsPageState extends State { isReadOnly: _gasRefillModel.status!.value! != 1, requestId: widget.model.id!.toInt(), assigneeEmployeeNumber: _gasRefillModel.assignedEmployee?.employeeId!, - myLoginUserID: context.userProvider.user!.username!, + myLoginUserID: context.userProvider.user!.employeeId ?? context.userProvider.user!.username!, contactEmployeeINumber: _gasRefillModel.gasRefillContactPerson!.first.employeeCode!, ); }) From 415bdf18f198231cfd426f42c72bd08ef69a414b Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Thu, 15 Jan 2026 18:31:01 +0300 Subject: [PATCH 22/26] improvements --- .../update_end_user_asset_details_view.dart | 42 ++++++++++++++++++- .../update_child_asset_view.dart | 6 +-- .../update_parent_asset_view.dart | 6 +-- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart index e760abca..2918d5b2 100644 --- a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart @@ -282,7 +282,6 @@ class _UpdateEndUserAssetDetailsViewState extends State(context, listen: false); - if (widget.assetDetailsModel != null) { model = EndUserAssetDetailsModel.fromJson( widget.assetDetailsModel!.toJson(), @@ -291,7 +290,9 @@ class _UpdateEndUserAssetDetailsViewState extends State( context: context, diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart index be67dd74..9bbc97cb 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart @@ -191,7 +191,7 @@ class _UpdateChildAssetViewState extends State { 8.height, AppTextFormField( labelText: 'Asset Name'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), + // backgroundColor: AppColor.fieldBgColor(context), initialValue: model.modelDefinition?.assetName, textAlign: TextAlign.center, enable: false, @@ -202,7 +202,7 @@ class _UpdateChildAssetViewState extends State { 8.height, AppTextFormField( labelText: 'Model'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), + // backgroundColor: AppColor.fieldBgColor(context), initialValue: model.modelDefinition?.model, textAlign: TextAlign.center, enable: false, @@ -213,7 +213,7 @@ class _UpdateChildAssetViewState extends State { 8.height, AppTextFormField( labelText: 'Manufacturer'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), + // backgroundColor: AppColor.fieldBgColor(context), initialValue: model.modelDefinition?.manufacturer ?? '', textAlign: TextAlign.center, enable: false, diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart index 52a14cda..024dfe5f 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart @@ -234,7 +234,7 @@ class _UpdateParentAssetViewState extends State { 8.height, AppTextFormField( labelText: 'Asset Name'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), + // backgroundColor: AppColor.fieldBgColor(context), initialValue: model.modelDefinition?.assetName, textAlign: TextAlign.center, enable: false, @@ -245,7 +245,7 @@ class _UpdateParentAssetViewState extends State { 8.height, AppTextFormField( labelText: 'Model'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), + // backgroundColor: AppColor.fieldBgColor(context), initialValue: model.modelDefinition?.model, textAlign: TextAlign.center, enable: false, @@ -256,7 +256,7 @@ class _UpdateParentAssetViewState extends State { 8.height, AppTextFormField( labelText: 'Manufacturer'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), + // backgroundColor: AppColor.fieldBgColor(context), initialValue: model.modelDefinition?.manufacturer ?? '', textAlign: TextAlign.center, enable: false, From 73ee12cba4a04de386cf6e0afd03e9a0a4aa59b6 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Sun, 18 Jan 2026 15:02:53 +0300 Subject: [PATCH 23/26] Atoms-1743,1745,1748 fixes --- .../asset_delivery_utils.dart | 0 .../delivery_inspection_form_view.dart | 30 +++++++++++++++---- .../inpection_bottomsheet.dart | 2 ++ .../oracle_user_autocomplete_field.dart | 27 +++++++++-------- .../update_end_user_asset_details_view.dart | 6 ++-- .../status_checklist_view.dart | 2 +- .../technical_inpection_asset_card_view.dart | 8 +++++ .../update_child_asset_view.dart | 12 +++++++- .../update_parent_asset_view.dart | 11 ++++++- ...pdate_technical_inspection_lines_view.dart | 21 +++++++++++++ .../common_widgets/app_bottom_nav_bar.dart | 5 ++-- 11 files changed, 97 insertions(+), 27 deletions(-) rename lib/modules/asset_delivery_module/pages/{technical_inpection => }/asset_delivery_utils.dart (100%) diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/asset_delivery_utils.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_utils.dart similarity index 100% rename from lib/modules/asset_delivery_module/pages/technical_inpection/asset_delivery_utils.dart rename to lib/modules/asset_delivery_module/pages/asset_delivery_utils.dart diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart index cdb4d5e9..9d589023 100644 --- a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart @@ -113,9 +113,16 @@ class _DeliveryInspectionFormViewState extends State ), 8.height, Text( - model.totalTime != null ? '${model.totalTime.toString()} hours' : '-', - style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + formatInspectionDuration(model.totalTime), + style: AppTextStyles.bodyText2.copyWith( + color: context.isDark ? AppColor.neutral30 : AppColor.neutral120, + ), ), + + // Text( + // model.totalTime != null ? '${model.totalTime.toString()} hours' : '-', + // style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + // ), 8.height, const Divider().defaultStyle(context), Text( @@ -409,21 +416,21 @@ class _DeliveryInspectionFormViewState extends State if (from == null && to == null) return true; if (from != null) { if (from.isAfter(DateTime.now())) { - "Start time cannot be in the future".showToast; + "Time From cannot be in the future".showToast; return false; } if (to != null && from.isAfter(to)) { - "Start time cannot be after end time".showToast; + "Time To cannot be after Time From".showToast; return false; } } if (to != null) { if (to.isAfter(DateTime.now())) { - "End time cannot be in the future".showToast; + "Time To cannot be in the future".showToast; return false; } if (from != null && to.isBefore(from)) { - "End time cannot be before start time".showToast; + "Timer To cannot be before from time".showToast; return false; } } @@ -443,6 +450,17 @@ class _DeliveryInspectionFormViewState extends State return true; } + String formatInspectionDuration(num? hours) { + if (hours == null) return '-'; + + if (hours < 1) { + final minutes = (hours * 60).round(); + return '$minutes minutes'; + } + + return '${hours.toStringAsFixed(2)} hours'; + } + Widget _timePickerThemeBuilder(BuildContext context, Widget? child) { final ThemeData currentTheme = Theme.of(context); diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart index 106b3a97..434f3382 100644 --- a/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart @@ -76,6 +76,7 @@ class _InspectionPersonBottomSheetState extends State { AssetDeliveryProvider? assetDeliveryProvider; - late TextEditingController _controller; + + // late TextEditingController _controller; @override void initState() { - _controller = TextEditingController(text: widget.initialValue); + // _controller = TextEditingController(text: widget.initialValue); super.initState(); } @override void didUpdateWidget(covariant OracleUserAutoCompleteField oldWidget) { - if (widget.initialValue != oldWidget.initialValue) { - _controller = TextEditingController(text: widget.initialValue); - } + // if (widget.initialValue != oldWidget.initialValue) { + // _controller = TextEditingController(text: widget.initialValue); + // } super.didUpdateWidget(oldWidget); } @override void dispose() { - _controller.dispose(); + // _controller.dispose(); super.dispose(); } @@ -59,16 +60,18 @@ class _AutoCompletePartsFieldState extends State { // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], ), child: Autocomplete( + key: ValueKey(widget.initialValue), optionsBuilder: (TextEditingValue textEditingValue) async { if (textEditingValue.text.isEmpty) { return const Iterable.empty(); } return await assetDeliveryProvider!.getOracleUserAutoCompleteDetails(query: textEditingValue.text); }, + initialValue: TextEditingValue(text: widget.initialValue), displayStringForOption: (OracleUserModel option) => option.fullName ?? "", fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) { return TextField( - controller: _controller, + controller: fieldTextEditingController, focusNode: fieldFocusNode, style: AppTextStyles.bodyText.copyWith(color: AppColor.black10), textAlign: TextAlign.start, @@ -101,11 +104,11 @@ class _AutoCompletePartsFieldState extends State { ); }, onSelected: (OracleUserModel selection) { - if (widget.clearAfterPick) { - _controller.clear(); - } else { - _controller.text = selection.fullName ?? ''; - } + // if (widget.clearAfterPick) { + // fieldTextEditingController.clear(); + // } else { + // _controller.text = selection.fullName ?? ''; + // } widget.onPick(selection); }, ), diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart index 2918d5b2..ecccc451 100644 --- a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart @@ -431,12 +431,12 @@ class _UpdateEndUserAssetDetailsViewState extends State { backgroundColor: AppColor.fieldBgColor(context), controller: serialNoCtrl, initialValue: model.serialNo ?? '', + validator: (value) { + if ((value ?? "").isEmpty) return "Mandatory"; + return null; + }, textAlign: TextAlign.center, labelStyle: AppTextStyles.textFieldLabelStyle, textInputType: TextInputType.number, @@ -379,7 +383,13 @@ class _UpdateChildAssetViewState extends State { ///Need to check which details show here... void _saveTap() async { + if(!_formKey.currentState!.validate()) return; + if(assetDeliveryProvider.childFormModel.installationDate==null){ + "Installation Date is Required".showToast; + return; + } _formKey.currentState!.save(); + //Need to check if not auto update. // assetDeliveryProvider.parentFormModel.childAssetList?[widget.index]= assetDeliveryProvider.childFormModel; Navigator.pop(context); diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart index 024dfe5f..14944824 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart @@ -10,7 +10,7 @@ import 'package:test_sa/models/new_models/building.dart'; import 'package:test_sa/models/new_models/floor.dart'; import 'package:test_sa/models/new_models/site.dart'; import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/asset_delivery_utils.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_utils.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart'; @@ -270,6 +270,10 @@ class _UpdateParentAssetViewState extends State { backgroundColor: AppColor.fieldBgColor(context), controller: serialNoCtrl, initialValue: model.serialNo ?? '', + validator: (value) { + if ((value ?? "").isEmpty) return "Mandatory"; + return null; + }, textAlign: TextAlign.center, labelStyle: AppTextStyles.textFieldLabelStyle, textInputType: TextInputType.number, @@ -424,6 +428,11 @@ class _UpdateParentAssetViewState extends State { ///Need to check which details show here... void _saveTap() async { + if (!_formKey.currentState!.validate()) return; + if (assetDeliveryProvider.parentFormModel.installationDate == null) { + "Installation Date is Required".showToast; + return; + } _formKey.currentState!.save(); assetDeliveryProvider.parentFormModel.lineId = widget.lineId; diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart index f64f1461..035fffe3 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart @@ -179,6 +179,10 @@ class _UpdateTechnicalInspectionLinesViewState extends State(context, listen: false).user?.type) == UsersTypes.engineer; bool isUserFMS = Provider.of(context, listen: false).isUserFMS; + bool commissioningEng = context.userProvider.isCommissioningEngineer; List navItems = [ NavItemModel(0, "overview", context.translation.overview), NavItemModel(1, "request_icon", context.translation.workOrder), - //TODO unCommit this to disable task - // if (!isEngineer||isUserFMS) - NavItemModel(2, "add_icon", context.translation.calendar, showLabel: false), + if (!commissioningEng) NavItemModel(2, "add_icon", context.translation.calendar, showLabel: false), NavItemModel(3, "assets", context.translation.assets), NavItemModel(4, "contact", context.translation.contact), ]; From 520e7af640694ab5e59c156ac04a4b9f0a326039 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Sun, 18 Jan 2026 15:05:47 +0300 Subject: [PATCH 24/26] fcm initialization changed to landing page --- lib/dashboard_latest/dashboard_view.dart | 16 ++++++++-------- lib/new_views/pages/land_page/land_page.dart | 12 +++++++++++- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/dashboard_latest/dashboard_view.dart b/lib/dashboard_latest/dashboard_view.dart index 987e76cd..bf9b5a71 100644 --- a/lib/dashboard_latest/dashboard_view.dart +++ b/lib/dashboard_latest/dashboard_view.dart @@ -73,14 +73,14 @@ class _DashboardViewState extends State { // await requestDetailProvider.engineerRejectWorkOrder(id: '3', feedBack: 'Abcdef'); // await dashBoardProvider.getDashBoardCount(usersType: user.type!); // await getAllRequests(); - if (isFCM) { - FirebaseNotificationManger.initialized(context); - NotificationManger.initialisation((notificationDetails) { - FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload!)); - }, (id, title, body, payload) async {}); - - isFCM = false; - } + // if (isFCM) { + // FirebaseNotificationManger.initialized(context); + // NotificationManger.initialisation((notificationDetails) { + // FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload!)); + // }, (id, title, body, payload) async {}); + // + // isFCM = false; + // } }); } diff --git a/lib/new_views/pages/land_page/land_page.dart b/lib/new_views/pages/land_page/land_page.dart index b28b6eb2..ea07c085 100644 --- a/lib/new_views/pages/land_page/land_page.dart +++ b/lib/new_views/pages/land_page/land_page.dart @@ -1,8 +1,11 @@ +import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; +import 'package:test_sa/controllers/notification/notification_manger.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/settings/app_settings.dart'; import 'package:test_sa/dashboard_latest/dashboard_view.dart'; @@ -42,7 +45,7 @@ class _LandPageState extends State { bool showAppbar = true; late List _pages; UserProvider? _userProvider; - + bool isFCM = true; @override void initState() { _pages = []; @@ -123,7 +126,14 @@ class _LandPageState extends State { // if (_userProvider!.user!.type != UsersTypes.engineer) const CalendarPage(), const MyAssetsPage(fromBottomBar: true), ]; + if (isFCM) { + FirebaseNotificationManger.initialized(context); + NotificationManger.initialisation((notificationDetails) { + FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload!)); + }, (id, title, body, payload) async {}); + isFCM = false; + } checkLocalAuth(); } From a0a084803d658c0c48192f7a5dc2ce3e44b30bb1 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Tue, 20 Jan 2026 10:01:46 +0300 Subject: [PATCH 25/26] UI improvements --- lib/extensions/enum_extensions.dart | 24 + lib/models/lookup.dart | 6 +- .../helper_function.dart | 3 +- .../models/asset_delivery_data_model.dart | 1 + .../pages/asset_delivery_page.dart | 48 +- .../pages/asset_delivery_stage_tab_page.dart | 90 ++++ .../pages/asset_delivery_table_card_view.dart | 47 +- .../pages/attachment_view.dart | 6 +- .../delivery_inspection_form_view.dart | 65 ++- .../end_user_cost_center_list_view.dart | 20 +- .../update_end_user_asset_details_view.dart | 1 - .../pages/history_log_view.dart | 12 +- .../status_checklist_view.dart | 216 ++++++--- .../technical_inspection_lines_list_view.dart | 43 +- .../update_child_asset_view.dart | 9 +- .../update_parent_asset_view.dart | 454 +----------------- 16 files changed, 444 insertions(+), 601 deletions(-) create mode 100644 lib/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart diff --git a/lib/extensions/enum_extensions.dart b/lib/extensions/enum_extensions.dart index 991a0f81..24d0a479 100644 --- a/lib/extensions/enum_extensions.dart +++ b/lib/extensions/enum_extensions.dart @@ -121,6 +121,24 @@ extension StringExtensionsRecurrentTaskInpesctionDataType on String { } } } + + +extension IntExtensionsAssetDeliveryStage on int { + AssetDeliveryStageEnum toAssetDeliveryStageEnum() { + switch (this) { + case 2: + return AssetDeliveryStageEnum.deliveryInspection; + case 3: + return AssetDeliveryStageEnum.technicalInspection; + case 4: + return AssetDeliveryStageEnum.endUserAcceptance; + default: + return AssetDeliveryStageEnum.other; + } + } +} + + enum DropDownMatchType { identifier, name, @@ -131,3 +149,9 @@ enum CostCenterType { costCenter, serialNumber, } +enum AssetDeliveryStageEnum { + deliveryInspection, + technicalInspection, + endUserAcceptance, + other, +} diff --git a/lib/models/lookup.dart b/lib/models/lookup.dart index 844e46df..1af16028 100644 --- a/lib/models/lookup.dart +++ b/lib/models/lookup.dart @@ -7,9 +7,10 @@ class Lookup extends Base { int? id; // Now nullable int? value; // Now nullable WorkOrderNextStepEnum? workOrderNextStepEnum; // Now nullable + AssetDeliveryStageEnum? assetDeliveryStageEnum; // Now nullable String? name; // Now nullable - Lookup({this.id, this.value, this.name, this.workOrderNextStepEnum}) : super(identifier: id?.toString(), name: name); + Lookup({this.id, this.value, this.name, this.workOrderNextStepEnum, this.assetDeliveryStageEnum}) : super(identifier: id?.toString(), name: name); @override bool operator ==(Object other) => identical(this, other) || other is Lookup && ((value != null && value == other.value) || (id != null && id == other.id)); @@ -38,10 +39,11 @@ class Lookup extends Base { // } factory Lookup.fromJson(Map? parsedJson) { - if(parsedJson==null) return Lookup(); + if (parsedJson == null) return Lookup(); return Lookup( name: parsedJson["name"], workOrderNextStepEnum: parsedJson["value"] == null ? null : (parsedJson["value"] as int).toWorkOrderNextStepEnum(), + assetDeliveryStageEnum: parsedJson["value"] == null ? null : (parsedJson["value"] as int).toAssetDeliveryStageEnum(), id: parsedJson["id"], value: parsedJson["value"], ); diff --git a/lib/modules/asset_delivery_module/helper_function.dart b/lib/modules/asset_delivery_module/helper_function.dart index b34a749c..0cfb122e 100644 --- a/lib/modules/asset_delivery_module/helper_function.dart +++ b/lib/modules/asset_delivery_module/helper_function.dart @@ -10,7 +10,7 @@ import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; class HelperFunction { - static void attachmentTap({required BuildContext context, required AssetDeliveryProvider assetDeliveryProvider, required dynamic deliveryTableItemId}) async { + static void attachmentTap({required BuildContext context, bool viewOnly = false, required AssetDeliveryProvider assetDeliveryProvider, required dynamic deliveryTableItemId}) async { Lookup? result; result = await showAttachmentTypeBottomSheet(context); List list = []; @@ -30,6 +30,7 @@ class HelperFunction { builder: (context) => AssetDeliveryAttachmentView( tableItemId: deliveryTableItemId, attachmentType: result!.value, + viewOnly: viewOnly, attachmentList: list, ))); // } diff --git a/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart b/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart index cde76346..15ece8ca 100644 --- a/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart +++ b/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart @@ -305,6 +305,7 @@ class AssetDeliveryTableModel { status = json['status'] != null ? Lookup.fromJson(json['status']) : null; + } Map toJson() { diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart index b3a3174b..a4ce0983 100644 --- a/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart +++ b/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart @@ -6,6 +6,7 @@ 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/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/change_status_bottomsheet.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart'; @@ -35,6 +36,7 @@ class AssetDeliveryPage extends StatefulWidget { class _AssetDeliveryPageState extends State { AssetDeliveryDataModel? dataModel; AssetDeliveryProvider? assetDeliveryProvider; + bool loading = false; @override void initState() { @@ -46,12 +48,18 @@ class _AssetDeliveryPageState extends State { } Future getDetailsById() async { + setState(() { + loading = true; + }); final futures = [ assetDeliveryProvider!.getAssetDeliveryDetailById(requestId: widget.requestId).then((value) => dataModel = value), assetDeliveryProvider!.getAssetDeliveryTableListById(requestId: widget.requestId), ]; await Future.wait(futures); + setState(() { + loading = false; + }); } @override @@ -68,7 +76,7 @@ class _AssetDeliveryPageState extends State { body: Consumer( builder: (context, provider, child) { final dataModel = provider.assetDeliveryDataModel; - if (provider.isLoading) { + if (loading) { return const CircularProgressIndicator(color: AppColor.primary10).center; } if (dataModel == null) { @@ -246,16 +254,17 @@ class _AssetDeliveryPageState extends State { style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), ), 8.height, - Text( - 'EDD (Estimated Delivery Date)'.addTranslation, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), - ), - 8.height, - Text( - dataModel?.edd != null ? dataModel!.edd!.toAssetDetailsFormat : '-', - style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), - ), - 8.height, + //Removed as request by Ahmed backend... + // Text( + // 'EDD (Estimated Delivery Date)'.addTranslation, + // style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + // ), + // 8.height, + // Text( + // dataModel?.edd != null ? dataModel!.edd!.toAssetDetailsFormat : '-', + // style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + // ), + // 8.height, Text( 'Total'.addTranslation, style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), @@ -321,10 +330,21 @@ class _AssetDeliveryPageState extends State { }); }); } else { + // Navigator.of(context).push(MaterialPageRoute( + // builder: (_) => + // DeliveryInspectionFormView( + // deliveryTableModel: model, + // requestModel: dataModel, + // ), + // )); Navigator.of(context).push(MaterialPageRoute( - builder: (_) => DeliveryInspectionFormView( - deliveryTableModel: model, - requestModel: dataModel, + builder: (_) => AssetDeliveryStageTabPage( + title: 'Delivery Inspection'.addTranslation, + detailWidget: DeliveryInspectionFormView( + deliveryTableModel: model, + requestModel: dataModel, + ), + tableId: model.id, ), )); } diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart new file mode 100644 index 00000000..959beffc --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/enum_extensions.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/modules/asset_delivery_module/pages/history_log_view.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; + +class AssetDeliveryStageTabPage extends StatefulWidget { + String title; + Widget detailWidget; + int? tableId; + + AssetDeliveryStageTabPage({ + Key? key, + required this.title, + required this.detailWidget, + this.tableId, + }) : super(key: key); + + @override + _AssetDeliveryStageTabPageState createState() { + return _AssetDeliveryStageTabPageState(); + } +} + +class _AssetDeliveryStageTabPageState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + appBar: DefaultAppBar( + title: widget.title, + ), + 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, + indicatorSize: TabBarIndicatorSize.tab, + dividerColor: Colors.transparent, + indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)), + tabs: [ + Tab(text: context.translation.details, height: 57.toScreenHeight), + Tab(text: context.translation.historyLogs, height: 57.toScreenHeight), + ], + ), + ), + // 12.height, + TabBarView( + children: [ + widget.detailWidget, + AssetDeliveryHistoryLogView( + tableItemId: widget.tableId, + ), + ], + ).expanded, + ], + ), + )); + } + + + String getPageTitle({AssetDeliveryStageEnum? deliveryStage}) { + if (deliveryStage == AssetDeliveryStageEnum.deliveryInspection) { + return 'Delivery Inspection'.addTranslation; + } + if (deliveryStage == AssetDeliveryStageEnum.technicalInspection) { + return 'Technical Inspection'.addTranslation; + } + if (deliveryStage == AssetDeliveryStageEnum.endUserAcceptance) { + return 'End-User Acceptance'.addTranslation; + } else { + return 'Details'.addTranslation; + } + } +} diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart index 0d906d49..e7a41d96 100644 --- a/lib/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart +++ b/lib/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart @@ -26,28 +26,33 @@ class AssetDeliveryTableCard extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - StatusLabel( - label: deliveryTableModel.status?.name, - textColor: AppColor.neutral50, - backgroundColor: AppColor.orange30, - ), - Row( - children: [ - 'history_icon'.toSvgAsset(height: 14, width: 14), - 8.width, - Text( - 'View History'.addTranslation, - style: AppTextStyles.bodyText.copyWith(color: AppColor.primary10), - ), - ], - ).onPress(() { - onViewHistoryTap(); - }), - ], + StatusLabel( + label: deliveryTableModel.status?.name, + textColor: AppColor.neutral50, + backgroundColor: AppColor.orange30, ), + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // StatusLabel( + // label: deliveryTableModel.status?.name, + // textColor: AppColor.neutral50, + // backgroundColor: AppColor.orange30, + // ), + // Row( + // children: [ + // 'history_icon'.toSvgAsset(height: 14, width: 14), + // 8.width, + // Text( + // 'View History'.addTranslation, + // style: AppTextStyles.bodyText.copyWith(color: AppColor.primary10), + // ), + // ], + // ).onPress(() { + // onViewHistoryTap(); + // }), + // ], + // ), 8.height, Text( 'Delivery Number: ${deliveryTableModel.number ?? '-'}', diff --git a/lib/modules/asset_delivery_module/pages/attachment_view.dart b/lib/modules/asset_delivery_module/pages/attachment_view.dart index e98ab0af..2f4020e7 100644 --- a/lib/modules/asset_delivery_module/pages/attachment_view.dart +++ b/lib/modules/asset_delivery_module/pages/attachment_view.dart @@ -24,11 +24,13 @@ import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; class AssetDeliveryAttachmentView extends StatefulWidget { final int? tableItemId; final int? attachmentType; + bool viewOnly = false; final List attachmentList; - const AssetDeliveryAttachmentView({ + AssetDeliveryAttachmentView({ super.key, required this.attachmentList, + this.viewOnly=false, this.attachmentType, this.tableItemId, }); @@ -80,7 +82,7 @@ class _AssetDeliveryAttachmentViewState extends State Widget build(BuildContext context) { return Scaffold( backgroundColor: Theme.of(context).scaffoldBackgroundColor, - appBar: DefaultAppBar( - title: 'Delivery Inspection'.addTranslation, - onBackPress: () { - Navigator.pop(context); - }, - ), + // appBar: DefaultAppBar( + // title: 'Delivery Inspection'.addTranslation, + // onBackPress: () { + // Navigator.pop(context); + // }, + // ), body: isLoading ? const CircularProgressIndicator(color: AppColor.primary10).center : Form( @@ -164,7 +167,20 @@ class _DeliveryInspectionFormViewState extends State ), ], ) - : AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap), + : Row( + children: [ + AppFilledButton( + buttonColor: AppColor.white60, + label: 'Attachments'.addTranslation, + maxWidth: true, + textColor: AppColor.black10, + onPressed: () { + HelperFunction.attachmentTap(context: context, viewOnly: true, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id); + }).expanded, + 8.width, + AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap).expanded, + ], + ), ), ], ), @@ -618,21 +634,44 @@ class _DeliveryInspectionFormViewState extends State void _nextTap() { if (widget.deliveryTableModel.isContainsTechnicalInspection == true) { + // Navigator.push( + // context, + // MaterialPageRoute( + // builder: (context) => TechnicalInspectionLinesListView( + // deliveryTableModel: widget.deliveryTableModel, + // requestModel: widget.requestModel, + // )) + // ); Navigator.push( context, MaterialPageRoute( - builder: (context) => TechnicalInspectionLinesListView( - deliveryTableModel: widget.deliveryTableModel, - requestModel: widget.requestModel, + builder: (context) => AssetDeliveryStageTabPage( + title: 'Technical Inspection'.addTranslation, + detailWidget: TechnicalInspectionLinesListView( + deliveryTableModel: widget.deliveryTableModel, + requestModel: widget.requestModel, + ), + tableId: widget.deliveryTableModel.id, ))); } else { Navigator.push( context, MaterialPageRoute( - builder: (context) => EndUserCostCenterLIstView( - deliveryTableModel: widget.deliveryTableModel, - requestModel: widget.requestModel, + builder: (context) => AssetDeliveryStageTabPage( + title: 'End-User Acceptance'.addTranslation, + detailWidget: EndUserCostCenterLIstView( + deliveryTableModel: widget.deliveryTableModel, + requestModel: widget.requestModel, + ), + tableId: widget.deliveryTableModel.id, ))); + // Navigator.push( + // context, + // MaterialPageRoute( + // builder: (context) => EndUserCostCenterLIstView( + // deliveryTableModel: widget.deliveryTableModel, + // requestModel: widget.requestModel, + // ))); } } diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart index 92979620..f032d75a 100644 --- a/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart @@ -72,10 +72,10 @@ class _EndUserCostCenterLIstViewState extends State { Widget build(BuildContext context) { return Scaffold( key: _scaffoldKey, - appBar: DefaultAppBar( - title: 'End-User Acceptance'.addTranslation, - titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), - ), + // appBar: DefaultAppBar( + // title: 'End-User Acceptance'.addTranslation, + // titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + // ), body: Form( key: _formKey, child: isLoading @@ -108,7 +108,17 @@ class _EndUserCostCenterLIstViewState extends State { ), ], )) - : const SizedBox(), + : FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.white60, + label: 'Attachments'.addTranslation, + maxWidth: true, + textColor: AppColor.black10, + onPressed: () { + HelperFunction.attachmentTap(context: context, viewOnly: true, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id); + }), + ), ], ), ), diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart index ecccc451..834b96b3 100644 --- a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart @@ -292,7 +292,6 @@ class _UpdateEndUserAssetDetailsViewState extends State(builder: (context, provider, _) { return provider.isLoading ? const CircularProgressIndicator(color: AppColor.primary10).center diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart index 9a574d69..e98c1213 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart @@ -13,34 +13,27 @@ 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'; -class InspectionChecklistBottomSheet extends StatefulWidget { +class InspectionCheckListView extends StatefulWidget { final List? initialValues; - const InspectionChecklistBottomSheet({super.key, this.initialValues}); + const InspectionCheckListView({super.key, this.initialValues}); @override - State createState() => - _InspectionChecklistBottomSheetState(); + State createState() => _InspectionCheckListViewState(); } -class _InspectionChecklistBottomSheetState - extends State { +class _InspectionCheckListViewState extends State { late List checklist; @override void initState() { super.initState(); + checklist = AssetDeliveryUtils.inspectionChecklist.map((e) => InspectionChecklistItem(title: e.title)).toList(); - /// Create local copy (no shared mutation) - checklist = AssetDeliveryUtils.inspectionChecklist - .map((e) => InspectionChecklistItem(title: e.title)) - .toList(); - - /// Apply initial values only if provided if (widget.initialValues != null && widget.initialValues!.isNotEmpty) { for (final item in checklist) { final matched = widget.initialValues!.firstWhere( - (e) => e.title == item.title, + (e) => e.title == item.title, orElse: () => InspectionChecklistItem(), ); item.status = matched.status; // null-safe @@ -54,70 +47,36 @@ class _InspectionChecklistBottomSheetState }); } - List get selectedValues => - checklist.where((e) => e.status != null).toList(); + List get selectedValues => checklist.where((e) => e.status != null).toList(); @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: AppColor.white10, appBar: DefaultAppBar( title: 'Asset Check List'.addTranslation, - showBackButton: false, - titleStyle: AppTextStyles.heading3.copyWith( - fontWeight: FontWeight.w500, - color: context.isDark - ? AppColor.neutral30 - : AppColor.neutral50, - ), ), body: Column( children: [ - 12.height, - ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: checklist.length, - padding: const EdgeInsets.symmetric(horizontal: 12), - itemBuilder: (context, index) { - final item = checklist[index]; - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - item.title ?? '', - style: AppTextStyles.heading6.copyWith( - color: context.isDark - ? AppColor.neutral30 - : AppColor.black10, - ), - ), - Row( - children: [ - Expanded( - child: RadioListTile( - title: const Text('Pass'), - value: 'PASS', - groupValue: item.status, - onChanged: (v) => - updateStatus(index, v!), - ), - ), - Expanded( - child: RadioListTile( - title: const Text('Fail'), - value: 'FAIL', - groupValue: item.status, - onChanged: (v) => - updateStatus(index, v!), - ), - ), - ], - ), - ], - ); - }, - ).expanded, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: List.generate( + checklist.length, + (index) { + final model = checklist[index]; + return inspectionStatusRadioWidget( + model: model, + index: index, + context: context, + ); + }, + ), + ).toShadowContainer( + context, + borderRadius: 20, + margin: const EdgeInsets.only(top: 12, left: 12, right: 12), + ), + const Spacer(), FooterActionButton.footerContainer( context: context, child: AppFilledButton( @@ -133,5 +92,124 @@ class _InspectionChecklistBottomSheetState ), ); } -} + Widget inspectionStatusRadioWidget({required int index, required InspectionChecklistItem model, required BuildContext context}) { + bool status = (model.status == null || model.status == null) ? true : (model.status != null ? (model.status == 'true' ? true : false) : false); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model.title ?? '', + overflow: TextOverflow.ellipsis, + maxLines: 1, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? Colors.white : AppColor.white936), + ), + 14.height, + // Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // + // (status ? 'Pass' : 'Fail').bodyText2(context).custom(color: AppColor.neutral120, fontWeight: FontWeight.w500), + // ], + // ).expanded, + GestureDetector( + onTap: () { + setState(() { + status = !status; + model.status = status.toString(); + }); + }, + child: Container( + width: 99.toScreenWidth, + height: 40.toScreenHeight, + padding: EdgeInsetsDirectional.all(4.toScreenHeight), + decoration: BoxDecoration( + color: AppColor.fieldBgColor(context), + borderRadius: BorderRadius.circular(5), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + buildToggleOption( + label: "PASS", + isActive: status, + activeColor: AppColor.green20, + inactiveColor: Colors.transparent, + textColor: status + ? AppColor.green50 + : context.isDark + ? Colors.white + : AppColor.black20, + ), + buildToggleOption( + label: "FAIL", + isActive: !status, + activeColor: AppColor.red20, + inactiveColor: Colors.transparent, + textColor: status + ? context.isDark + ? Colors.white + : AppColor.black20 + : AppColor.red30, + ), + ], + ), + ), + ), + ], + ).paddingOnly(top: 4, bottom: 4); + } + + Widget buildToggleOption({ + required String label, + required bool isActive, + required Color activeColor, + required Color inactiveColor, + required Color textColor, + }) { + return Container( + width: 44.toScreenWidth, + height: 30.toScreenHeight, + alignment: Alignment.center, + decoration: BoxDecoration( + color: isActive ? activeColor : inactiveColor, + borderRadius: BorderRadius.circular(3), + ), + child: label.bodyText2(context).custom(color: textColor), + ); + } + +//older widget ... +// return Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Text( +// item.title ?? '', +// style: AppTextStyles.heading6.copyWith( +// color: context.isDark ? AppColor.neutral30 : AppColor.black10, +// ), +// ), +// Row( +// children: [ +// Expanded( +// child: RadioListTile( +// title: const Text('Pass'), +// value: 'PASS', +// groupValue: item.status, +// onChanged: (v) => updateStatus(index, v!), +// ), +// ), +// Expanded( +// child: RadioListTile( +// title: const Text('Fail'), +// value: 'FAIL', +// groupValue: item.status, +// onChanged: (v) => updateStatus(index, v!), +// ), +// ), +// ], +// ), +// ], +// ); +} diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart index b4c6d505..e2c05093 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart @@ -12,6 +12,7 @@ import 'package:test_sa/modules/asset_delivery_module/helper_function.dart'; import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart'; @@ -79,10 +80,10 @@ class _TechnicalInspectionLinesListViewState extends State EndUserCostCenterLIstView( + // requestModel: widget.requestModel, + // deliveryTableModel: widget.deliveryTableModel, + // ))); + Navigator.push( context, MaterialPageRoute( - builder: (context) => EndUserCostCenterLIstView( - requestModel: widget.requestModel, - deliveryTableModel: widget.deliveryTableModel, + builder: (context) => AssetDeliveryStageTabPage( + title: 'End-User Acceptance'.addTranslation, + detailWidget: EndUserCostCenterLIstView( + deliveryTableModel: widget.deliveryTableModel, + requestModel: widget.requestModel, + ), + tableId: widget.deliveryTableModel.id, ))); } } diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart index 07c7450d..3e151cb9 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart @@ -25,8 +25,6 @@ import '../../../../models/new_models/department.dart'; import '../../../../new_views/common_widgets/app_filled_button.dart'; import '../../../../new_views/common_widgets/default_app_bar.dart'; -//TODO need to refactor this screen when done ... - class UpdateChildAssetView extends StatefulWidget { final TechnicalInspectionAssetModel assetModel; final int? lineId; @@ -183,7 +181,6 @@ class _UpdateChildAssetViewState extends State { await provider.getSiteData(siteId: assetModel.site?.id, model: provider.childFormModel); } provider.setParentModel(assetModel); - log('child list length ${assetModel.childAssetList?.length}'); populateTextFields(model: provider.childFormModel); } } @@ -383,8 +380,8 @@ class _UpdateChildAssetViewState extends State { ///Need to check which details show here... void _saveTap() async { - if(!_formKey.currentState!.validate()) return; - if(assetDeliveryProvider.childFormModel.installationDate==null){ + if (!_formKey.currentState!.validate()) return; + if (assetDeliveryProvider.childFormModel.installationDate == null) { "Installation Date is Required".showToast; return; } @@ -401,7 +398,7 @@ class _UpdateChildAssetViewState extends State { final result = await Navigator.push( context, MaterialPageRoute( - builder: (context) => InspectionChecklistBottomSheet( + builder: (context) => InspectionCheckListView( initialValues: checkList, ))); if (result != null) { diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart index 14944824..ceafcfe6 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart @@ -28,8 +28,6 @@ import '../../../../models/new_models/department.dart'; import '../../../../new_views/common_widgets/app_filled_button.dart'; import '../../../../new_views/common_widgets/default_app_bar.dart'; -//TODO need to refactor this screen also add loaders when done ... - class UpdateParentAssetView extends StatefulWidget { final TechnicalInspectionAssetModel assetModel; final int? lineId; @@ -438,7 +436,6 @@ class _UpdateParentAssetViewState extends State { assetDeliveryProvider.parentFormModel.tableItemId = widget.tableItemId; assetDeliveryProvider.parentFormModel.costCenterId = widget.costCenterItemId; - log('model data ${assetDeliveryProvider.parentFormModel.toJson()}'); showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); await assetDeliveryProvider.saveTechnicalInspectionAssetData(model: assetDeliveryProvider.parentFormModel).then((status) async { Navigator.pop(context); @@ -453,7 +450,7 @@ class _UpdateParentAssetViewState extends State { final result = await Navigator.push( context, MaterialPageRoute( - builder: (context) => InspectionChecklistBottomSheet( + builder: (context) => InspectionCheckListView( initialValues: checkList, ))); @@ -462,18 +459,6 @@ class _UpdateParentAssetViewState extends State { setState(() {}); } buildInspectionPayload(checkList); - if (checkList.isNotEmpty) { - final isPass = checkList.every((e) => e.status == 'PASS'); - log('Final Status: ${isPass ? 'PASS' : 'FAIL'}'); - } - -// call this as bottomsheet. - // final result = await showModalBottomSheet>>( - // context: context, - // isScrollControlled: true, - // backgroundColor: Colors.transparent, - // builder: (_) => const InspectionChecklistBottomSheet(), - // ); } bool _isPass(List list, String title) { @@ -528,446 +513,9 @@ class _UpdateParentAssetViewState extends State { break; } } - checkList.forEach((item) { - log('items ${item.toJson()}'); - }); } String _statusFromBool(bool? value) { return value == true ? 'PASS' : 'FAIL'; } } - -// import 'dart:developer'; -// 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/string_extensions.dart'; -// import 'package:test_sa/extensions/text_extensions.dart'; -// import 'package:test_sa/extensions/widget_extensions.dart'; -// import 'package:test_sa/models/new_models/building.dart'; -// import 'package:test_sa/models/new_models/floor.dart'; -// import 'package:test_sa/models/new_models/site.dart'; -// import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart'; -// import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart'; -// import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart'; -// import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart'; -// import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart'; -// import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; -// import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; -// import 'package:test_sa/new_views/app_style/app_color.dart'; -// import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; -// import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; -// import 'package:test_sa/providers/gas_request_providers/site_provider.dart'; -// import 'package:test_sa/providers/loading_list_notifier.dart'; -// import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; -// import '../../../../models/new_models/department.dart'; -// import '../../../../new_views/common_widgets/app_filled_button.dart'; -// import '../../../../new_views/common_widgets/default_app_bar.dart'; -// -// //TODO need to refactor this screen when done ... -// -// class UpdateParentAssetView extends StatefulWidget { -// final TechnicalInspectionParentAssetModel assetModel; -// final int? lineId; -// -// UpdateParentAssetView({ -// Key? key, -// required this.assetModel, -// this.lineId, -// }) : super(key: key); -// -// @override -// State createState() => _UpdateParentAssetViewState(); -// } -// -// class _UpdateParentAssetViewState extends State { -// final GlobalKey _formKey = GlobalKey(); -// final GlobalKey _scaffoldKey = GlobalKey(); -// List checkList = []; -// late SiteProvider siteProvider; -// late AssetDeliveryProvider assetDeliveryProvider; -// -// @override -// void initState() { -// siteProvider = Provider.of(context, listen: false); -// assetDeliveryProvider = Provider.of(context, listen: false); -// // WidgetsBinding.instance.addPostFrameCallback((_) { -// populateForm(); -// // }); -// super.initState(); -// } -// -// void populateForm() async { -// // _model = widget.assetModel; -// assetDeliveryProvider.setModel(widget.assetModel); -// applyInspectionFlagsToChecklist(model: widget.assetModel,checklist: checkList); -// if (widget.assetModel.site != null) { -// await assetDeliveryProvider.getSiteData(siteId: widget.assetModel.site?.id, model: _model); -// } -// setState(() {}); -// } -// -// @override -// void dispose() { -// super.dispose(); -// } -// -// @override -// Widget build(BuildContext context) { -// return Scaffold( -// key: _scaffoldKey, -// appBar: DefaultAppBar( -// title: 'Parent Details'.addTranslation, -// titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), -// ), -// body: Form( -// key: _formKey, -// child: Column( -// children: [ -// SingleChildScrollView( -// padding: const EdgeInsets.all(16), -// child: Column( -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// inspectionDetailsForm(lineId: widget.lineId), -// 8.height, -// const Divider().defaultStyle(context), -// 8.height, -// childList(context), -// ], -// ).toShadowContainer(context, borderRadius: 20, padding: 12)) -// .expanded, -// FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), -// ], -// ), -// ), -// ); -// } -// -// Widget childList(BuildContext context) { -// final assetDeliveryTableList = ['abc', 'def', 'ghi', 'fhg', 'hjhh']; -// return Column( -// mainAxisSize: MainAxisSize.min, -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// Row( -// children: [ -// Text( -// "Test List", -// style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), -// ), -// 8.width, -// 'web_link_icon'.toSvgAsset().onPress(() { -// openInspectionChecklist(context); -// }), -// ], -// ), -// 8.height, -// ListView.separated( -// itemCount: assetDeliveryTableList.length, -// separatorBuilder: (_, __) => 8.height, -// padding: EdgeInsets.zero, -// shrinkWrap: true, -// physics: const NeverScrollableScrollPhysics(), -// itemBuilder: (listContext, itemIndex) { -// return TechnicalInspectionAssetCard( -// assetModel: TechnicalInspectionParentAssetModel(), -// ischild: true, -// editPress: () { -// Navigator.push(context, MaterialPageRoute(builder: (context) => UpdateChildAssetView())); -// }, -// isViewOnly: false, -// ); -// }, -// ), -// ], -// ); -// } -// -// Widget inspectionDetailsForm({int? lineId}) { -// return Column( -// children: [ -// //Replace with simple container... -// AppTextFormField( -// labelText: 'Asset Number'.addTranslation, -// backgroundColor: AppColor.fieldBgColor(context), -// initialValue: _model.assetNumber, -// textAlign: TextAlign.center, -// labelStyle: AppTextStyles.textFieldLabelStyle, -// textInputType: TextInputType.number, -// showShadow: false, -// enable: false, -// style: Theme.of(context).textTheme.titleMedium, -// ).onPress(() async { -// var data = await Navigator.push( -// context, -// MaterialPageRoute( -// builder: (context) => TechnicalInspectionSearchAssetView( -// lineId: lineId, -// ))); -// if (data != null) { -// TechnicalInspectionParentAssetModel? assetModel = await assetDeliveryProvider.getAssetDetails(assetId: data?.id); -// -// if (assetModel != null) { -// _model =TechnicalInspectionParentAssetModel(); -// setState(() { -// -// }); -// setState(() { -// _model = assetModel; -// }); -// if (assetModel.site != null) { -// await assetDeliveryProvider.getSiteData(siteId: assetModel.site?.id, model: _model); -// } -// setState(() {}); -// } -// } -// }), -// 8.height, -// AppTextFormField( -// labelText: 'Serial Number'.addTranslation, -// backgroundColor: AppColor.fieldBgColor(context), -// initialValue: _model.serialNo ?? '', -// textAlign: TextAlign.center, -// labelStyle: AppTextStyles.textFieldLabelStyle, -// textInputType: TextInputType.number, -// showShadow: false, -// onSaved: (value) { -// _model.serialNo = value; -// }, -// style: Theme.of(context).textTheme.titleMedium, -// ), -// 8.height, -// AppTextFormField( -// labelText: 'System ID'.addTranslation, -// backgroundColor: AppColor.fieldBgColor(context), -// initialValue: _model.systemId ?? '', -// textAlign: TextAlign.center, -// labelStyle: AppTextStyles.textFieldLabelStyle, -// showShadow: false, -// onSaved: (value) { -// _model.systemId = value; -// }, -// style: Theme.of(context).textTheme.titleMedium, -// ), -// 8.height, -// SingleItemDropDownMenu( -// context: context, -// title: 'Site', -// initialValue: _model.site, -// loading: assetDeliveryProvider.isSiteLoading, -// showAsBottomSheet: true, -// backgroundColor: AppColor.fieldBgColor(context), -// showShadow: false, -// // enabled: false, -// onSelect: (value) { -// if (value == null) { -// return; -// } -// _model.site = value; -// _model.building = null; -// _model.floor = null; -// _model.department = null; -// setState(() {}); -// }, -// ), -// 8.height, -// SingleItemDropDownMenu( -// context: context, -// title: 'Building', -// backgroundColor: AppColor.fieldBgColor(context), -// showAsBottomSheet: true, -// loading: assetDeliveryProvider.isSiteLoading, -// showShadow: false, -// initialValue: _model.building, -// enabled: _model.site?.buildings?.isNotEmpty ?? false, -// staticData: _model.site?.buildings ?? [], -// onSelect: (value) { -// if (value == null) { -// return; -// } -// _model.building = value; -// _model.floor = null; -// _model.department = null; -// setState(() {}); -// }, -// ), -// 8.height, -// SingleItemDropDownMenu( -// context: context, -// showAsBottomSheet: true, -// backgroundColor: AppColor.fieldBgColor(context), -// loading: assetDeliveryProvider.isSiteLoading, -// showShadow: false, -// title: 'Floor', -// initialValue: _model.floor, -// enabled: _model.building?.floors?.isNotEmpty ?? false, -// staticData: _model.building?.floors ?? [], -// onSelect: (value) { -// if (value == null) { -// return; -// } -// _model.floor = value; -// _model.department = null; -// setState(() {}); -// }, -// ), -// 8.height, -// SingleItemDropDownMenu( -// context: context, -// title: 'Department', -// backgroundColor: AppColor.fieldBgColor(context), -// loading: assetDeliveryProvider.isSiteLoading, -// showAsBottomSheet: true, -// showShadow: false, -// initialValue: _model.department, -// enabled: _model.floor?.departments?.isNotEmpty ?? false, -// staticData: _model.floor?.departments ?? [], -// onSelect: (value) { -// if (value == null) { -// return; -// } -// _model.department = value; -// _model.room = null; -// setState(() {}); -// }, -// ), -// -// 8.height, -// ADatePicker( -// label: 'Installation Date'.addTranslation, -// hideShadow: true, -// height: 56.toScreenHeight, -// backgroundColor: AppColor.fieldBgColor(context), -// date: _model.installationDate, -// // from: widget.pickerFromDate, -// formatDateWithTime: true, -// onDatePicker: (selectedDate) { -// showTimePicker( -// context: context, -// initialTime: TimeOfDay.now(), -// builder: (BuildContext context, Widget? child) { -// final ThemeData currentTheme = Theme.of(context); -// return Theme( -// data: currentTheme.copyWith( -// timePickerTheme: TimePickerThemeData( -// dialHandColor: AppColor.primary10, -// dialBackgroundColor: Colors.grey.withOpacity(0.1), -// hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), -// dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), -// dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), -// dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), -// entryModeIconColor: AppColor.primary10, -// ), -// textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), -// ), -// child: child!, -// ); -// }, -// ).then((selectedTime) { -// if (selectedTime != null) { -// _model.installationDate = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); -// setState(() {}); -// } -// }); -// }, -// ), -// 8.height, -// ], -// ); -// } -// -// ///Need to check which details show here... -// -// void _saveTap() async { -// _formKey.currentState!.save(); -// } -// -// Future openInspectionChecklist(BuildContext context) async { -// final result = await Navigator.push( -// context, -// MaterialPageRoute( -// builder: (context) => InspectionChecklistBottomSheet( -// initialValues: checkList, -// ))); -// -// log('result i got is $result'); -// if(result!=null){ -// checkList = result; -// setState(() {}); -// } -// if (checkList.isNotEmpty) { -// final isPass = checkList.every((e) => e.status == 'PASS'); -// log('Final Status: ${isPass ? 'PASS' : 'FAIL'}'); -// } -// final payload = buildInspectionPayload(checkList); -// -// log('API Payload: $payload'); -// // call this as bottomsheet. -// // final result = await showModalBottomSheet>>( -// // context: context, -// // isScrollControlled: true, -// // backgroundColor: Colors.transparent, -// // builder: (_) => const InspectionChecklistBottomSheet(), -// // ); -// } -// -// bool _isPass(List list, String title) { -// return list -// .firstWhere( -// (e) => e.title == title, -// orElse: () => InspectionChecklistItem(status: 'FAIL'), -// ) -// .status == -// 'PASS'; -// } -// -// Map buildInspectionPayload(List checklist) { -// return { -// 'flagphysicalInspection': _isPass(checklist, 'Physical Inspection As Per Manufacturer Instructions'), -// 'flagFunctionPerformance': _isPass(checklist, 'Functional Performance As Per Results Of Manufacturer Recommended Check List'), -// 'flagGroundingResistance': _isPass(checklist, 'Grounding Resistance: Ω'), -// 'flagChassiss': _isPass(checklist, 'Chassis Leakage Current: µA'), -// 'flagLeadsLeakage': _isPass(checklist, 'Leads Leakage Current: µA'), -// 'flagAlert': _isPass(checklist, 'This Device Is Not Subject To Any Alert Or Recall Until The Date Of Preparation Of This Inspection Form'), -// }; -// } -// -// void applyInspectionFlagsToChecklist({ -// required List checklist, -// required TechnicalInspectionParentAssetModel model, -// }) { -// for (final item in checklist) { -// switch (item.title) { -// case 'Physical Inspection As Per Manufacturer Instructions': -// item.status = _statusFromBool(model.flagphysicalInspection); -// break; -// -// case 'Functional Performance As Per Results Of Manufacturer Recommended Check List': -// item.status = _statusFromBool(model.flagFunctionPerformance); -// break; -// -// case 'Grounding Resistance: Ω': -// item.status = _statusFromBool(model.flagGroundingResistance); -// break; -// -// case 'Chassis Leakage Current: µA': -// item.status = _statusFromBool(model.flagChassiss); -// break; -// -// case 'Leads Leakage Current: µA': -// item.status = _statusFromBool(model.flagLeadsLeakage); -// break; -// -// case 'This Device Is Not Subject To Any Alert Or Recall Until The Date Of Preparation Of This Inspection Form': -// item.status = _statusFromBool(model.flagAlert); -// break; -// } -// } -// } -// String _statusFromBool(bool? value) { -// return value == true ? 'PASS' : 'FAIL'; -// } -// } From 4bd055cfe852a4787955f56abdb2aa090903a15e Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 20 Jan 2026 11:00:43 +0300 Subject: [PATCH 26/26] merge conflict resolved. --- .../notification/firebase_notification_manger.dart | 7 +++---- lib/modules/cm_module/cm_detail_page.dart | 2 +- lib/modules/cx_module/chat/chat_widget.dart | 6 +++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/controllers/notification/firebase_notification_manger.dart b/lib/controllers/notification/firebase_notification_manger.dart index b941e40e..243e8a57 100644 --- a/lib/controllers/notification/firebase_notification_manger.dart +++ b/lib/controllers/notification/firebase_notification_manger.dart @@ -13,9 +13,8 @@ import 'package:test_sa/modules/cm_module/cm_detail_page.dart'; import 'package:test_sa/modules/cx_module/survey/survey_page.dart'; import 'package:test_sa/modules/pm_module/ppm_wo/ppm_details_page.dart'; import 'package:test_sa/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart'; -import 'package:test_sa/modules/tm_module/tasks_wo/task_request_detail_view.dart'; -import 'package:test_sa/views/pages/device_transfer/device_transfer_details.dart'; -import 'package:test_sa/views/pages/user/gas_refill/gas_refill_details.dart'; +import 'package:test_sa/modules/tm_module/device_transfer/device_transfer_details.dart'; +import 'package:test_sa/modules/tm_module/tasks/task_request_detail_view.dart'; import 'package:test_sa/modules/tm_module/gas_refill/gas_refill_details.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; @@ -99,7 +98,7 @@ class FirebaseNotificationManger { switch (moduleId) { case 1: // cm - serviceClass = ServiceRequestDetailMain(requestId: requestNumber, moduleId: moduleId); + serviceClass = CMDetailPage(requestId: requestNumber, moduleId: moduleId); break; case 2: // gas refill serviceClass = GasRefillDetailsPage( diff --git a/lib/modules/cm_module/cm_detail_page.dart b/lib/modules/cm_module/cm_detail_page.dart index b9870847..15b1b503 100644 --- a/lib/modules/cm_module/cm_detail_page.dart +++ b/lib/modules/cm_module/cm_detail_page.dart @@ -42,7 +42,7 @@ class _CMDetailPageState extends State { @override void initState() { super.initState(); - _requestProvider = Provider.of(context, listen: false); + _requestProvider = Provider.of(context, listen: false); WidgetsBinding.instance.addPostFrameCallback((_) { Provider.of(context, listen: false).reset(); getInitialData(); diff --git a/lib/modules/cx_module/chat/chat_widget.dart b/lib/modules/cx_module/chat/chat_widget.dart index 43c5d5fc..8d5011e8 100644 --- a/lib/modules/cx_module/chat/chat_widget.dart +++ b/lib/modules/cx_module/chat/chat_widget.dart @@ -5,7 +5,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; +import 'package:test_sa/modules/cm_module/cm_detail_provider.dart'; import 'package:test_sa/new_views/common_widgets/custom_badge.dart'; import 'chat_page.dart'; @@ -59,13 +59,13 @@ class _ChatWidgetState extends State { ChatProvider cProvider = Provider.of(context, listen: false); if (cProvider.chatLoginResponse != null && cProvider.referenceID == widget.requestId) return; - String assigneeEmployeeNumber = widget.assigneeEmployeeNumber ?? Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; + String assigneeEmployeeNumber = widget.assigneeEmployeeNumber ?? Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; String myEmployeeId = widget.myLoginUserID ?? context.userProvider.user!.username!; String receiver = context.userProvider.isNurse ? assigneeEmployeeNumber : (context.userProvider.isEngineer - ? (widget.contactEmployeeINumber ?? Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId!) + ? (widget.contactEmployeeINumber ?? Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId!) : ""); cProvider.getUserAutoLoginTokenSilent(widget.moduleId, widget.requestId, widget.title, myEmployeeId, receiver, isMounted: mounted);