diff --git a/ios/Podfile b/ios/Podfile index 5596a08a..72d600e0 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '14.0' +platform :ios, '15.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -40,7 +40,7 @@ post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) target.build_configurations.each do |config| - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '14.0' + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0' # Fix for Xcode 15+ DT_TOOLCHAIN_DIR issue if config.base_configuration_reference && File.exist?(config.base_configuration_reference.real_path) @@ -55,7 +55,7 @@ post_install do |installer| installer.generated_projects.each do |project| project.targets.each do |target| target.build_configurations.each do |config| - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '14.0' + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0' config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ '$(inherited)', ## dart: PermissionGroup.microphone diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 3c09fbf5..e0fcb9d1 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -379,7 +379,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -403,7 +403,7 @@ ENABLE_USER_SCRIPT_SANDBOXING = NO; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Atoms; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -534,7 +534,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -587,7 +587,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -613,7 +613,7 @@ ENABLE_USER_SCRIPT_SANDBOXING = NO; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Atoms; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -709,7 +709,7 @@ ENABLE_USER_SCRIPT_SANDBOXING = NO; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Atoms; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 644b8957..1a6e0c18 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -1,7 +1,7 @@ class URLs { URLs._(); - static const String appReleaseBuildNumber = "55"; + static const String appReleaseBuildNumber = "56"; // static const host1 = "https://atomsm.hmg.com"; // production url // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url @@ -68,6 +68,8 @@ class URLs { static get getSiteRequests => "$_baseUrl/SiteRequest/GetSiteRequests"; // get site request history static get getDepartmentsBySites => "$_baseUrl/Customer/GetDepartmentsBySites"; // post get departments by sites static getUserSites(String userId) => "$_baseUrl/Customer/GetSitesForUser?userId=$userId"; // get user's current sites + static getSitesNotAccessibleForUser(String userId) => "$_baseUrl/Customer/GetSitesNotAccessibleForUser?userId=$userId"; // get user's current sites + static get getCustomersAutoCompleteSameOrg => "$_baseUrl/Customer/GetCustomersAutoCompleteSameOrg"; // get user's current sites // static get login => "$_baseUrl/MobileAuth/LoginIntegration"; // mobile login static get register => "$_baseUrl/handle/create/user"; // post @@ -254,8 +256,13 @@ class URLs { static get getRegularVisits => "$_baseUrl/Visit/GetVisits"; // get static get updateRegularVisits => "$_baseUrl/Visit/UpdateVisits"; // get - static get getPlanPreventiveVisitById => "$_baseUrl/PlanPreventiveVisit/GetPlanPreventiveVisitById"; // get - static get updateVisitByEngineer => "$_baseUrl/PlanPreventiveVisit/UpdateVisitByEngineer"; // get + static get getPlanPreventiveVisitById => "$_baseUrl/PlanPreventiveVisit/GetPlanPreventiveVisitById"; + static get updateVisitByEngineer => "$_baseUrl/PlanPreventiveVisit/UpdateVisitByEngineer"; + static get createPmActivitySparePart => "$_baseUrl/PlanPreventiveVisit/CreateActivitySparePart"; + static get updatePmActivitySparePart => "$_baseUrl/PlanPreventiveVisit/UpdateActivitySparePart"; + static get deletePmActivitySparePart => "$_baseUrl/PlanPreventiveVisit/DeleteActivitySparePart"; + static get updatePmActivityCost => "$_baseUrl/PlanPreventiveVisit/EngineerUpdateCost"; + static get getSingleServiceRequest => "$_baseUrl/return/call/information"; // get static get getSuppliersAutoComplete => "$_baseUrl/Supplier/GetSuppliersAutoComplete"; @@ -322,6 +329,8 @@ class URLs { static get genderLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=3065"; static get getDemoDocumentTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=4106"; + // static get getAttachmentTypesLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=4021"; + static get getAttachmentTypesLookup => "$_baseUrl/Lookups/GetLookup"; static get getClassificationTypeLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=450"; @@ -386,6 +395,8 @@ class URLs { static get updateDeviceTransfer => "$_baseUrl/AssetTransfer/UpdateEngineerAssetTransferNew"; // get static get assetTransferAssignEngineerToHimself => "$_baseUrl/AssetTransfer/AssignEngineerToHimself"; // get static get assetTransferEngineerReject => "$_baseUrl/AssetTransfer/EngineerReject"; // get + static get assetDocumentHistory => "$_baseUrl/DocumentLibrary/SearchDocuments"; + // employee static get getEmployees => "$_baseUrl/Lookups/GetLookup?lookupEnum=33"; // get @@ -633,4 +644,8 @@ class URLs { static get copilotHubUrl => "$_host/VoiceWebSocket"; + +// spare part request endpoint. + + } diff --git a/lib/controllers/providers/api/device_transfer_provider.dart b/lib/controllers/providers/api/device_transfer_provider.dart index 63468cc5..60afd310 100644 --- a/lib/controllers/providers/api/device_transfer_provider.dart +++ b/lib/controllers/providers/api/device_transfer_provider.dart @@ -153,6 +153,7 @@ class DeviceTransferProvider extends ChangeNotifier { Response response; try { showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + log('payload: ${model.toCreateAssetTransferJson()}'); response = await ApiManager.instance.post(URLs.createAssetTransferRequest, body: model.toCreateAssetTransferJson()); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { diff --git a/lib/controllers/providers/api/devices_provider.dart b/lib/controllers/providers/api/devices_provider.dart index 5ff68d3d..01333d86 100644 --- a/lib/controllers/providers/api/devices_provider.dart +++ b/lib/controllers/providers/api/devices_provider.dart @@ -33,6 +33,7 @@ class AssetProvider extends ChangeNotifier { final pageItemNumber = 10; final searchPageItemNumber = 10; + final documentPageItemNumber = 20; bool nextPage = true; @@ -260,6 +261,38 @@ class AssetProvider extends ChangeNotifier { } } + Future<({List documents, int totalRows})> getAssetDocumentHistory({ + required int assetId, + int pageNumber = 1, + }) async { + Response response; + List documents = []; + try { + var body = { + "pageSize": documentPageItemNumber, + "pageNumber": pageNumber, + "assetIds": [assetId], + }; + response = await ApiManager.instance.post(URLs.assetDocumentHistory, body: body); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + final jsonData = json.decode(response.body); + List attachmentJson = jsonData["data"] ?? []; + int totalRows = jsonData["totalRows"] ?? 0; + + documents = attachmentJson.map((request) => GenericAttachmentModel.fromAssetDocumentJson(request)).toList(); + + nextPage = documents.length < totalRows; + + return (documents: documents, totalRows: totalRows); + } + return (documents: documents, totalRows: 0); + } catch (e) { + log('Error in getAssetDocumentHistory: $e'); + return (documents: documents, totalRows: 0); + } + } + Future predictDevice(File image) async { try { final files = >[ @@ -274,13 +307,12 @@ class AssetProvider extends ChangeNotifier { body: {}, showToast: false, files: files, - ); if (response.statusCode >= 200 && response.statusCode < 300) { final responseData = json.decode(response.body)['data']; return PredictDeviceResponse.fromJson(responseData); - }else{ + } else { return null; } } catch (error) { diff --git a/lib/controllers/providers/api/parts_provider.dart b/lib/controllers/providers/api/parts_provider.dart index fc2829b8..e50b7a7b 100644 --- a/lib/controllers/providers/api/parts_provider.dart +++ b/lib/controllers/providers/api/parts_provider.dart @@ -88,32 +88,39 @@ class PartsProvider extends ChangeNotifier { late Response response; try { if (partNo != null) { - response = await ApiManager.instance.post(URLs.getPartNumber, body: {"partNo": partNo, }); + response = await ApiManager.instance.post(URLs.getPartNumber, body: { + "partNo": partNo, + }); } else { - response = await ApiManager.instance.post(URLs.getPartNumber, body: {"partName": partName, }); + response = await ApiManager.instance.post(URLs.getPartNumber, body: { + "partName": partName, + }); } List page = []; if (response.statusCode >= 200 && response.statusCode < 300) { // client's request was successfully received List categoriesListJson = json.decode(response.body)["data"]; - page = categoriesListJson.map((part) => SparePart.fromJson(part,false)).toList(); + page = categoriesListJson.map((part) => SparePart.fromJson(part, false)).toList(); } return page; } catch (error) { return []; } } + // Implement this only for spare part request for now show and search on display name .... Future> getPartsListByDisplayName({num? assetId, String? displayName}) async { late Response response; try { - response = await ApiManager.instance.post(URLs.getPartNumber, body: {"displayName": displayName, }); + response = await ApiManager.instance.post(URLs.getPartNumber, body: { + "displayName": displayName, + }); List page = []; if (response.statusCode >= 200 && response.statusCode < 300) { // client's request was successfully received List categoriesListJson = json.decode(response.body)["data"]; - page = categoriesListJson.map((part) => SparePart.fromJson(part,true)).toList(); + page = categoriesListJson.map((part) => SparePart.fromJson(part, true)).toList(); } return page; } catch (error) { diff --git a/lib/controllers/providers/api/ppm_provider.dart b/lib/controllers/providers/api/ppm_provider.dart index 81a7e066..7861b5b1 100644 --- a/lib/controllers/providers/api/ppm_provider.dart +++ b/lib/controllers/providers/api/ppm_provider.dart @@ -9,9 +9,12 @@ import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/helper_data_models/spare_part/activity_spare_part_model.dart'; +import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; import 'package:test_sa/models/plan_preventive_visit/plan_preventive_visit_model.dart'; import 'package:test_sa/models/ppm/ppm.dart'; import 'package:test_sa/models/ppm/ppm_search.dart'; +import 'package:test_sa/models/service_request/spare_parts.dart'; import 'package:test_sa/models/user.dart'; import '../../../new_views/common_widgets/app_lazy_loading.dart'; @@ -20,6 +23,15 @@ class PpmProvider extends ChangeNotifier { // number of items call in each request final pageItemNumber = 12; + bool _isReadOnlyRequest = false; + + bool get isReadOnlyRequest => _isReadOnlyRequest; + + set isReadOnlyRequest(bool value) { + _isReadOnlyRequest = value; + notifyListeners(); + } + PlanPreventiveVisit? _planPreventiveVisit; late int _totalTabs = 4; TabController? tabController; @@ -61,6 +73,15 @@ class PpmProvider extends ChangeNotifier { stateCode = null; } + List _storeAvailability = []; + + List get storeAvailability => _storeAvailability; + + set storeAvailability(List value) { + _storeAvailability = value; + notifyListeners(); + } + // state code of current request to defied error message // like 400 customer request failed // 500 service not available @@ -78,6 +99,13 @@ class PpmProvider extends ChangeNotifier { bool isLoading = false; PpmSearch visitsSearch = PpmSearch(); + WorkOrderCostModel? workOrderCostModel; + SparePartHelperModel? sparePartHelperModel; + + void updateSparePartHelperModel(SparePartHelperModel? value) { + sparePartHelperModel = value; + notifyListeners(); + } /// return -2 if request in progress /// return -1 if error happen when sending request @@ -164,11 +192,22 @@ class PpmProvider extends ChangeNotifier { if (response.statusCode >= 200 && response.statusCode < 300) { ppmPlanAttachments = []; planPreventiveVisit = PlanPreventiveVisit.fromJson(json.decode(response.body)["data"]); + + // Set isReadOnly based on visit status (1 or 3 means closed/completed) if (planPreventiveVisit?.visitStatus?.value! == 1 || planPreventiveVisit?.visitStatus?.value == 3) { isReadOnly = true; } else { isReadOnly = false; } + + // Set isReadOnlyRequest based on visit status - same logic as CMDetailProvider + //Need to confirm this with backend Status values: 3 = Closed, 5 = Completed, 6 = Cancelled (adjust based on your PM status values) + if (planPreventiveVisit?.visitStatus?.value == 3 || planPreventiveVisit?.visitStatus?.value == 5 || planPreventiveVisit?.visitStatus?.value == 6) { + isReadOnlyRequest = true; + } else { + isReadOnlyRequest = false; + } + isLoading = false; notifyListeners(); return planPreventiveVisit; @@ -364,4 +403,119 @@ class PpmProvider extends ChangeNotifier { return true; } + + Future createActivitySparePart() async { + isLoading = true; + Response response; + try { + response = await ApiManager.instance.post(URLs.createPmActivitySparePart, body: sparePartHelperModel!.toPMJson()); + stateCode = response.statusCode; + isLoading = false; + notifyListeners(); + if (stateCode == 200) { + return true; + } + return false; + } catch (error) { + isLoading = false; + stateCode = -1; + notifyListeners(); + return false; + } + } + + Future updateActivitySparePart() async { + Response response; + try { + response = await ApiManager.instance.post(URLs.updatePmActivitySparePart, body: sparePartHelperModel!.toPMJson(), showToast: false); + + if (response.statusCode == 200) { + return ""; + } else { + final responseBody = jsonDecode(response.body); + if (responseBody is Map) { + final message = responseBody["message"]; // Reuse parsed body + if (message != null && message.toString().isNotEmpty) { + return message; + } + } + return "Failed, Try Again"; + } + } catch (error) { + return "Failed, Try Again"; + } + } + + Future deleteActivitySparePart({required int id}) async { + isLoading = true; + notifyListeners(); + try { + final response = await ApiManager.instance.delete('${URLs.deletePmActivitySparePart}?activitySparePartPPMId=$id', body: {}); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) {} + isLoading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + isLoading = false; + notifyListeners(); + return -1; + } + } + + Future engineerUpdateCost() async { + isLoading = true; + Response response; + try { + response = await ApiManager.instance.post(URLs.updatePmActivityCost, body: workOrderCostModel!.toPMCostJson()); + stateCode = response.statusCode; + isLoading = false; + notifyListeners(); + if (stateCode == 200) { + planPreventiveVisit = PlanPreventiveVisit.fromJson(json.decode(response.body)["data"]); + + // Update isReadOnlyRequest after fetching updated data + if (planPreventiveVisit?.visitStatus?.value == 3 || planPreventiveVisit?.visitStatus?.value == 5 || planPreventiveVisit?.visitStatus?.value == 6) { + isReadOnlyRequest = true; + } else { + isReadOnlyRequest = false; + } + + notifyListeners(); + return true; + } + return false; + } catch (error) { + isLoading = false; + stateCode = -1; + notifyListeners(); + return false; + } + } + + Future getStoreAvailabilityById({required num? partId}) async { + try { + isLoading = true; + notifyListeners(); + + final response = await ApiManager.instance.post( + URLs.getSparePartAvailableQuantity + "?PartId=$partId", + body: {}, + ); + + stateCode = response.statusCode; + + if (response.statusCode >= 200 && response.statusCode < 300) { + final List data = json.decode(response.body)["data"]; + storeAvailability = data.map((item) => StoreAvailability.fromJson(item)).toList(); + } + + isLoading = false; + notifyListeners(); + } catch (e) { + log("getStoreAvalivility [error] : $e"); + isLoading = false; + notifyListeners(); + } + } } diff --git a/lib/dashboard_latest/dashboard_provider.dart b/lib/dashboard_latest/dashboard_provider.dart index a25a10fe..68524413 100644 --- a/lib/dashboard_latest/dashboard_provider.dart +++ b/lib/dashboard_latest/dashboard_provider.dart @@ -56,7 +56,7 @@ class DashBoardProvider extends ChangeNotifier { // Helper method to check if a tab index is UnAssigned bool isUnassignedTab(int index) { if (index >= 0 && index < tabs.length) { - return tabs[index].requestType == RequestTypeEnum.unassigned; + return tabs[index].requestType == RequestStatusEnum.unassigned; } return false; } @@ -64,7 +64,7 @@ class DashBoardProvider extends ChangeNotifier { // Helper method to get the UnAssigned tab index (returns -1 if not found) int getUnassignedTabIndex() { for (int i = 0; i < tabs.length; i++) { - if (tabs[i].requestType == RequestTypeEnum.unassigned) { + if (tabs[i].requestType == RequestStatusEnum.unassigned) { return i; } } @@ -111,25 +111,25 @@ class DashBoardProvider extends ChangeNotifier { DD.DashboardDetail? get requestDetailList => _requestDetailList; - int getStatusCount(RequestTypeEnum requestType) { + int getStatusCount(RequestStatusEnum requestType) { switch (requestType) { - case RequestTypeEnum.unassigned: + case RequestStatusEnum.unassigned: return dashboardCount?.data?.countUnAssigned ?? 0; - case RequestTypeEnum.open: + case RequestStatusEnum.open: return dashboardCount?.data?.countOpen ?? 0; - case RequestTypeEnum.inProgress: + case RequestStatusEnum.inProgress: return dashboardCount?.data?.countInprogress ?? 0; - case RequestTypeEnum.completed: + case RequestStatusEnum.completed: return dashboardCount?.data?.countComplete ?? 0; - case RequestTypeEnum.pendingAcknowledgment: + case RequestStatusEnum.pendingAcknowledgment: return dashboardCount?.data?.countAcknowledge ?? 0; - case RequestTypeEnum.canceled: + case RequestStatusEnum.canceled: return dashboardCount?.data?.countCanceled ?? 0; - case RequestTypeEnum.closed: + case RequestStatusEnum.closed: return dashboardCount?.data?.countClose ?? 0; - case RequestTypeEnum.overdue: + case RequestStatusEnum.overdue: return dashboardCount?.data?.countOverdue ?? 0; - case RequestTypeEnum.highPriority: + case RequestStatusEnum.highPriority: return dashboardCount?.data?.countHighPriority ?? 0; default: return 0; @@ -310,30 +310,30 @@ class DashBoardProvider extends ChangeNotifier { } // Status categories (Open, InProgress, Completed, Closed) - if (!tab.isHighPriority && !tab.isOverDue && tab.requestType != RequestTypeEnum.unassigned) { + if (!tab.isHighPriority && !tab.isOverDue && tab.requestType != RequestStatusEnum.unassigned) { // Map requestType to status value switch (tab.requestType) { - case RequestTypeEnum.open: + case RequestStatusEnum.open: if (!statusTransaction.contains(1)) statusTransaction.add(1); break; - case RequestTypeEnum.inProgress: + case RequestStatusEnum.inProgress: if (!statusTransaction.contains(2)) statusTransaction.add(2); break; - case RequestTypeEnum.completed: + case RequestStatusEnum.completed: if (!statusTransaction.contains(4)) statusTransaction.add(4); break; - case RequestTypeEnum.closed: + case RequestStatusEnum.closed: if (!statusTransaction.contains(4)) statusTransaction.add(4); break; - case RequestTypeEnum.canceled: + case RequestStatusEnum.canceled: if (!statusTransaction.contains(5)) statusTransaction.add(5); break; - case RequestTypeEnum.pendingAcknowledgment: + case RequestStatusEnum.pendingAcknowledgment: if (!statusTransaction.contains(4)) statusTransaction.add(4); break; - case RequestTypeEnum.unassigned: - case RequestTypeEnum.highPriority: - case RequestTypeEnum.overdue: + case RequestStatusEnum.unassigned: + case RequestStatusEnum.highPriority: + case RequestStatusEnum.overdue: // These are handled separately above break; } @@ -556,7 +556,7 @@ class CategoryTabs { String label; int tag; int id; - RequestTypeEnum requestType; + RequestStatusEnum requestType; String icon; Color iconColor; bool isHighPriority; @@ -568,12 +568,12 @@ class CategoryTabs { List tabs = []; if (userType == UsersTypes.engineer) { // Order: 1-UnAssigned, 2-HighPriority, 3-Overdue, 4-Open, 5-InProgress, 6-Completed - tabs.add(CategoryTabs(label: 'UnAssigned', tag: 1, id: 1, requestType: RequestTypeEnum.unassigned, icon: "dashboard/unassigned", iconColor: AppColor.unassignedStatus(context))); - tabs.add(CategoryTabs(label: context.translation.highPriority, tag: 3, id: 4, requestType: RequestTypeEnum.highPriority, icon: "high_priority", iconColor: AppColor.red30, isHighPriority: true)); - tabs.add(CategoryTabs(label: context.translation.overdue, tag: 3, id: 4, requestType: RequestTypeEnum.overdue, icon: "overdue", iconColor: AppColor.yellowIcon(context), isOverDue: true)); - tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2, requestType: RequestTypeEnum.open, icon: "dashboard/open_icon", iconColor: AppColor.openColor)); - tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3, requestType: RequestTypeEnum.inProgress, icon: "dashboard/inprogress_icon", iconColor: AppColor.primary10)); - tabs.add(CategoryTabs(label: 'Completed', tag: 3, id: 4, requestType: RequestTypeEnum.completed, icon: "complete_request", iconColor: AppColor.completedColor)); + tabs.add(CategoryTabs(label: 'UnAssigned', tag: 1, id: 1, requestType: RequestStatusEnum.unassigned, icon: "dashboard/unassigned", iconColor: AppColor.unassignedStatus(context))); + tabs.add(CategoryTabs(label: context.translation.highPriority, tag: 3, id: 4, requestType: RequestStatusEnum.highPriority, icon: "high_priority", iconColor: AppColor.red30, isHighPriority: true)); + tabs.add(CategoryTabs(label: context.translation.overdue, tag: 3, id: 4, requestType: RequestStatusEnum.overdue, icon: "overdue", iconColor: AppColor.yellowIcon(context), isOverDue: true)); + tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2, requestType: RequestStatusEnum.open, icon: "dashboard/open_icon", iconColor: AppColor.openColor)); + tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3, requestType: RequestStatusEnum.inProgress, icon: "dashboard/inprogress_icon", iconColor: AppColor.primary10)); + tabs.add(CategoryTabs(label: 'Completed', tag: 3, id: 4, requestType: RequestStatusEnum.completed, icon: "complete_request", iconColor: AppColor.completedColor)); return tabs; } @@ -584,29 +584,29 @@ class CategoryTabs { // tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 2)); // tabs.add(CategoryTabs(label: 'Completed', tag: 4, id: 3)); - tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 2, requestType: RequestTypeEnum.inProgress, icon: "dashboard/inprogress_icon", iconColor: AppColor.primary10)); - tabs.add(CategoryTabs(label: 'Completed', tag: 4, id: 3, requestType: RequestTypeEnum.completed, icon: "complete_request", iconColor: AppColor.completedColor)); + tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 2, requestType: RequestStatusEnum.inProgress, icon: "dashboard/inprogress_icon", iconColor: AppColor.primary10)); + tabs.add(CategoryTabs(label: 'Completed', tag: 4, id: 3, requestType: RequestStatusEnum.completed, icon: "complete_request", iconColor: AppColor.completedColor)); return tabs; } if (userType == UsersTypes.qualityUser) { - tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2, requestType: RequestTypeEnum.open, icon: "dashboard/open_icon", iconColor: AppColor.openColor)); - tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3, requestType: RequestTypeEnum.inProgress, icon: "dashboard/inprogress_icon", iconColor: AppColor.primary10)); - tabs.add(CategoryTabs(label: 'Closed', tag: 3, id: 4, requestType: RequestTypeEnum.closed, icon: "complete_request", iconColor: AppColor.completedColor)); + tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2, requestType: RequestStatusEnum.open, icon: "dashboard/open_icon", iconColor: AppColor.openColor)); + tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3, requestType: RequestStatusEnum.inProgress, icon: "dashboard/inprogress_icon", iconColor: AppColor.primary10)); + tabs.add(CategoryTabs(label: 'Closed', tag: 3, id: 4, requestType: RequestStatusEnum.closed, icon: "complete_request", iconColor: AppColor.completedColor)); return tabs; } if (userType == UsersTypes.commissioningEngineer) { - tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2, requestType: RequestTypeEnum.open, icon: "dashboard/open_icon", iconColor: AppColor.openColor)); - tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3, requestType: RequestTypeEnum.inProgress, icon: "dashboard/inprogress_icon", iconColor: AppColor.primary10)); - tabs.add(CategoryTabs(label: 'Closed', tag: 3, id: 4, requestType: RequestTypeEnum.closed, icon: "complete_request", iconColor: AppColor.completedColor)); + tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2, requestType: RequestStatusEnum.open, icon: "dashboard/open_icon", iconColor: AppColor.openColor)); + tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3, requestType: RequestStatusEnum.inProgress, icon: "dashboard/inprogress_icon", iconColor: AppColor.primary10)); + tabs.add(CategoryTabs(label: 'Closed', tag: 3, id: 4, requestType: RequestStatusEnum.closed, icon: "complete_request", iconColor: AppColor.completedColor)); return tabs; } - tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2, requestType: RequestTypeEnum.open, icon: "dashboard/open_icon", iconColor: AppColor.openColor)); - tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3, requestType: RequestTypeEnum.inProgress, icon: "dashboard/inprogress_icon", iconColor: AppColor.primary10)); + tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2, requestType: RequestStatusEnum.open, icon: "dashboard/open_icon", iconColor: AppColor.openColor)); + tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3, requestType: RequestStatusEnum.inProgress, icon: "dashboard/inprogress_icon", iconColor: AppColor.primary10)); // tabs.add(CategoryTabs(label: 'Pending Acknowledgement', tag: 3, id: 1, requestType: RequestTypeEnum.pendingAcknowledgment, icon: "complete_request", iconColor: AppColor.overdueColor)); - tabs.add(CategoryTabs(label: 'Acknowledgement', tag: 4, id: 1, requestType: RequestTypeEnum.pendingAcknowledgment, icon: "complete_request", iconColor: AppColor.overdueColor)); - tabs.add(CategoryTabs(label: 'Canceled', tag: 6, id: 4, requestType: RequestTypeEnum.canceled, icon: "dashboard/unassigned", iconColor: AppColor.red30)); + tabs.add(CategoryTabs(label: 'Acknowledgement', tag: 4, id: 1, requestType: RequestStatusEnum.pendingAcknowledgment, icon: "complete_request", iconColor: AppColor.overdueColor)); + tabs.add(CategoryTabs(label: 'Canceled', tag: 6, id: 4, requestType: RequestStatusEnum.canceled, icon: "dashboard/unassigned", iconColor: AppColor.red30)); return tabs; } } diff --git a/lib/dashboard_latest/dashboard_view.dart b/lib/dashboard_latest/dashboard_view.dart index c560be1e..22c2e744 100644 --- a/lib/dashboard_latest/dashboard_view.dart +++ b/lib/dashboard_latest/dashboard_view.dart @@ -150,29 +150,29 @@ class _DashboardViewState extends State { } // Status categories - if (!tab.isHighPriority && !tab.isOverDue && tab.requestType != RequestTypeEnum.unassigned) { + if (!tab.isHighPriority && !tab.isOverDue && tab.requestType != RequestStatusEnum.unassigned) { switch (tab.requestType) { - case RequestTypeEnum.open: + case RequestStatusEnum.open: if (!statusTransaction.contains(1)) statusTransaction.add(1); break; - case RequestTypeEnum.inProgress: + case RequestStatusEnum.inProgress: if (!statusTransaction.contains(2)) statusTransaction.add(2); break; - case RequestTypeEnum.completed: + case RequestStatusEnum.completed: if (!statusTransaction.contains(4)) statusTransaction.add(4); break; - case RequestTypeEnum.closed: + case RequestStatusEnum.closed: if (!statusTransaction.contains(4)) statusTransaction.add(4); break; - case RequestTypeEnum.canceled: + case RequestStatusEnum.canceled: if (!statusTransaction.contains(5)) statusTransaction.add(5); break; - case RequestTypeEnum.pendingAcknowledgment: + case RequestStatusEnum.pendingAcknowledgment: if (!statusTransaction.contains(3)) statusTransaction.add(3); break; - case RequestTypeEnum.unassigned: - case RequestTypeEnum.highPriority: - case RequestTypeEnum.overdue: + case RequestStatusEnum.unassigned: + case RequestStatusEnum.highPriority: + case RequestStatusEnum.overdue: break; } } diff --git a/lib/dashboard_latest/widgets/app_bar_widget.dart b/lib/dashboard_latest/widgets/app_bar_widget.dart index 39a97f7a..8dcc73b2 100644 --- a/lib/dashboard_latest/widgets/app_bar_widget.dart +++ b/lib/dashboard_latest/widgets/app_bar_widget.dart @@ -142,18 +142,19 @@ class _AppBarWidgetState extends State with TickerProviderStateMix children: [ Text( snapshot.user?.username ?? "", + maxLines: 2, style: AppTextStyles.heading6.copyWith(color: AppColor.headingTextColor(context), fontSize: context.isTablet() ? 14 : null), ), - Text( - snapshot.user?.type?.name.toCamelCase ?? "", - style: AppTextStyles.bodyText.copyWith(color: AppColor.lightTextColor(context), fontSize: context.isTablet() ? 12 : null), - ), + // Text( + // snapshot.user?.roleName ?? "", + // style: AppTextStyles.bodyText.copyWith(color: AppColor.lightTextColor(context), fontSize: context.isTablet() ? 12 : null), + // ), ], ), ), ), ), - const Spacer(), + // const Spacer(), // Action icons with right-to-left fade animation SlideTransition( position: _rightSlideAnimation, diff --git a/lib/dashboard_latest/widgets/request_category_fragment.dart b/lib/dashboard_latest/widgets/request_category_fragment.dart index c6f80cad..2ebaf87e 100644 --- a/lib/dashboard_latest/widgets/request_category_fragment.dart +++ b/lib/dashboard_latest/widgets/request_category_fragment.dart @@ -380,7 +380,7 @@ class _RequestCategoryFragmentState extends State with }); // Check if this is UnAssigned tab (index 0 for engineer) - bool isUnassignedTab = tabs[index].requestType == RequestTypeEnum.unassigned; + bool isUnassignedTab = tabs[index].requestType == RequestStatusEnum.unassigned; // Update selection state requestsProvider.currentListIndex = index; diff --git a/lib/dashboard_latest/widgets/requests_fragment.dart b/lib/dashboard_latest/widgets/requests_fragment.dart index e613d0eb..2be44381 100644 --- a/lib/dashboard_latest/widgets/requests_fragment.dart +++ b/lib/dashboard_latest/widgets/requests_fragment.dart @@ -46,24 +46,24 @@ class RequestsFragment extends StatelessWidget { List listItems = []; if (context.userProvider.isNurse) { listItems = [ - requestType(data.dashboardCount?.data?.countOpen ?? 0, "dashboard/open_icon", context.translation.open, context, data.isLoading, RequestTypeEnum.open, AppColor.openColor), - requestType(data.dashboardCount?.data?.countInprogress ?? 0, "dashboard/inprogress_icon", context.translation.inProgress, context, data.isLoading, RequestTypeEnum.inProgress, + requestType(data.dashboardCount?.data?.countOpen ?? 0, "dashboard/open_icon", context.translation.open, context, data.isLoading, RequestStatusEnum.open, AppColor.openColor), + requestType(data.dashboardCount?.data?.countInprogress ?? 0, "dashboard/inprogress_icon", context.translation.inProgress, context, data.isLoading, RequestStatusEnum.inProgress, AppColor.primary10), requestType( - data.dashboardCount?.data?.countAcknowledge ?? 0, "complete_request", "Acknowledgement", context, data.isLoading, RequestTypeEnum.pendingAcknowledgment, AppColor.overdueColor), - requestType(data.dashboardCount?.data?.countCanceled ?? 0, "dashboard/unassigned", "Canceled", context, data.isLoading, RequestTypeEnum.canceled, AppColor.red30), + data.dashboardCount?.data?.countAcknowledge ?? 0, "complete_request", "Acknowledgement", context, data.isLoading, RequestStatusEnum.pendingAcknowledgment, AppColor.overdueColor), + requestType(data.dashboardCount?.data?.countCanceled ?? 0, "dashboard/unassigned", "Canceled", context, data.isLoading, RequestStatusEnum.canceled, AppColor.red30), ]; } else { listItems = [ requestType( - data.dashboardCount?.data?.countUnAssigned ?? 0, "dashboard/unassigned", "UnAssigned", context, data.isLoading, RequestTypeEnum.unassigned, AppColor.unassignedStatus(context)), - requestType(data.dashboardCount?.data?.countOpen ?? 0, "dashboard/open_icon", context.translation.open, context, data.isLoading, RequestTypeEnum.open, AppColor.openColor), - requestType(data.dashboardCount?.data?.countInprogress ?? 0, "dashboard/inprogress_icon", context.translation.inProgress, context, data.isLoading, RequestTypeEnum.inProgress, + data.dashboardCount?.data?.countUnAssigned ?? 0, "dashboard/unassigned", "UnAssigned", context, data.isLoading, RequestStatusEnum.unassigned, AppColor.unassignedStatus(context)), + requestType(data.dashboardCount?.data?.countOpen ?? 0, "dashboard/open_icon", context.translation.open, context, data.isLoading, RequestStatusEnum.open, AppColor.openColor), + requestType(data.dashboardCount?.data?.countInprogress ?? 0, "dashboard/inprogress_icon", context.translation.inProgress, context, data.isLoading, RequestStatusEnum.inProgress, AppColor.primary10), requestType( - data.dashboardCount?.data?.countComplete ?? 0, "complete_request", context.translation.completed, context, data.isLoading, RequestTypeEnum.completed, AppColor.completedColor), - requestType(data.dashboardCount?.data?.countOverdue ?? 0, "overdue", context.translation.overdue, context, data.isLoading, RequestTypeEnum.overdue, AppColor.yellowIcon(context)), - requestType(data.dashboardCount?.data?.countHighPriority ?? 0, "high_priority", context.translation.highPriority, context, data.isLoading, RequestTypeEnum.highPriority, AppColor.red30), + data.dashboardCount?.data?.countComplete ?? 0, "complete_request", context.translation.completed, context, data.isLoading, RequestStatusEnum.completed, AppColor.completedColor), + requestType(data.dashboardCount?.data?.countOverdue ?? 0, "overdue", context.translation.overdue, context, data.isLoading, RequestStatusEnum.overdue, AppColor.yellowIcon(context)), + requestType(data.dashboardCount?.data?.countHighPriority ?? 0, "high_priority", context.translation.highPriority, context, data.isLoading, RequestStatusEnum.highPriority, AppColor.red30), ]; } @@ -77,7 +77,7 @@ class RequestsFragment extends StatelessWidget { }); } - Widget requestType(int value, String icon, String title, BuildContext context, bool isLoading, RequestTypeEnum requestType, Color iconColor) { + Widget requestType(int value, String icon, String title, BuildContext context, bool isLoading, RequestStatusEnum requestType, Color iconColor) { return CustomBadge( value: isLoading ? 0 : value, positionR: -4, diff --git a/lib/extensions/enum_extensions.dart b/lib/extensions/enum_extensions.dart index 5039329c..a3275466 100644 --- a/lib/extensions/enum_extensions.dart +++ b/lib/extensions/enum_extensions.dart @@ -197,7 +197,7 @@ enum AssetDeliveryStageEnum { other, } -enum RequestTypeEnum { +enum RequestStatusEnum { unassigned, open, inProgress, diff --git a/lib/helper/utils.dart b/lib/helper/utils.dart index 53496f1f..a2ab7f05 100644 --- a/lib/helper/utils.dart +++ b/lib/helper/utils.dart @@ -7,9 +7,12 @@ import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:google_api_availability/google_api_availability.dart'; import 'package:haptic_feedback/haptic_feedback.dart'; +import 'package:http/http.dart' as http; import 'package:nfc_manager/nfc_manager.dart'; import 'package:nfc_manager/nfc_manager_android.dart' show NfcAAndroid, NfcBAndroid; import 'package:nfc_manager/nfc_manager_ios.dart' show MiFareIos, Iso15693Ios; +import 'package:open_file/open_file.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/views/widgets/dialogs/confirm_dialog.dart'; @@ -193,6 +196,73 @@ class Utils { ); } + static Future downloadFile( + String url, { + bool autoOpen = true, + bool showToast = true, + String? authToken, + String? fileName, + }) async { + final client = http.Client(); + try { + if (showToast) { + Utils.showToast("Downloading file...", longDuration: false); + } + fileName ??= url.split('/').last.split('?').first; + if (!fileName.contains('.')) { + fileName = 'downloaded_file_${DateTime.now().millisecondsSinceEpoch}.jpg'; + } + final request = http.Request('GET', Uri.parse(url)); + if (authToken != null) { + request.headers['Authorization'] = 'Bearer $authToken'; + } + request.followRedirects = false; + final streamedResponse = await client.send(request); + File? file; + final dir = await getTemporaryDirectory(); + if (streamedResponse.statusCode == 302) { + final redirectUrl = streamedResponse.headers['location']; + if (redirectUrl == null) { + throw Exception('302 Redirect missing Location header'); + } + final headers = authToken != null ? {'Authorization': 'Bearer $authToken'} : {}; + final fileResponse = await http.get(Uri.parse(redirectUrl), headers: headers); + if (fileResponse.statusCode == 200) { + file = File('${dir.path}/$fileName'); + await file.writeAsBytes(fileResponse.bodyBytes); + } else { + throw Exception('Download from redirect failed: ${fileResponse.statusCode}'); + } + } + else if (streamedResponse.statusCode == 200) { + file = File('${dir.path}/$fileName'); + await file.writeAsBytes(await streamedResponse.stream.toBytes()); + } + else { + throw Exception('Download failed with status: ${streamedResponse.statusCode}'); + } + if (showToast) { + Utils.showToast("File downloaded successfully", longDuration: false); + } + if (autoOpen) { + await OpenFile.open(file.path); + } + return file; + } catch (ex) { + if (showToast) { + Utils.showToast("Download failed: ${ex.toString()}"); + } + return null; + } finally { + client.close(); + } + } + + static bool isLocalFile(String path) { + if (path.isEmpty) return false; + return path.startsWith("/") || path.startsWith("file://") || (path.length > 1 && path.substring(1).startsWith(':\\')); + } + // // static Widget getNoDataWidget(BuildContext context) { // return Column( diff --git a/lib/main.dart b/lib/main.dart index 9f90baf4..56b8b3cb 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -70,6 +70,7 @@ import 'package:test_sa/modules/applicationDemo/providers/application_demo_reque import 'package:test_sa/modules/applicationDemo/screens/application_demo_request_form_screen.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'; import 'package:test_sa/modules/traf_module/traf_request_provider.dart'; import 'package:test_sa/new_views/app_style/app_themes.dart'; import 'package:test_sa/new_views/pages/help_center_page.dart'; @@ -149,7 +150,6 @@ import 'modules/tm_module/device_transfer/device_filter_screen.dart'; import 'modules/tm_module/device_transfer/device_search_screen.dart'; import 'modules/tm_module/tasks/create_task_view.dart'; import 'modules/tm_module/gas_refill/gas_refill_request_form.dart'; -import 'modules/traf_module/create_traf_request_page.dart'; import 'modules/traf_module/update_traf_request_page.dart'; import 'providers/lookups/classification_lookup_provider.dart'; import 'providers/lookups/customer_lookup_provider.dart'; @@ -260,6 +260,7 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => EndUserStatusLookupProvider(), lazy: true), ChangeNotifierProvider(create: (_) => EndUserRejectionReasonLookupProvider(), lazy: true), ChangeNotifierProvider(create: (_) => AttachmentTypeLookupProvider(), lazy: true), + ChangeNotifierProvider(create: (_) => AttachmentTypeLookupProviderLatest(), lazy: true), ChangeNotifierProvider(create: (_) => DemoPeriodLookupProvider(), lazy: true), ChangeNotifierProvider(create: (_) => DemoDocumentLookupProvider(), lazy: true), ChangeNotifierProvider(create: (_) => IncidentStatusLookupProvider(), lazy: true), @@ -359,6 +360,7 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => DepartmentProvider(), lazy: true), ChangeNotifierProvider(create: (_) => DepartmentBySitesProvider(), lazy: true), ChangeNotifierProvider(create: (_) => SiteProvider(), lazy: true), + ChangeNotifierProvider(create: (_) => SameOrgSiteProvider(), lazy: true), ChangeNotifierProvider(create: (_) => MappedSiteProvider(), lazy: true), ChangeNotifierProvider(create: (_) => MedicalDepartmentProvider(), lazy: true), ChangeNotifierProvider(create: (_) => FlowMedicalDepartmentProvider(), lazy: true), diff --git a/lib/models/device/asset_by_id_model.dart b/lib/models/device/asset_by_id_model.dart index ab177b23..4c7dee4d 100644 --- a/lib/models/device/asset_by_id_model.dart +++ b/lib/models/device/asset_by_id_model.dart @@ -55,7 +55,7 @@ class AssetByIdModel { String? comment; bool? isEnabled; String? tagCode; - List? assetAttachments; + List? assetAttachments; String? retirementTypeName; String? retirementStatusName; String? retirementDate; @@ -198,9 +198,9 @@ class AssetByIdModel { isEnabled = json['isEnabled']; tagCode = json['tagCode']; if (json['assetAttachments'] != null) { - assetAttachments = []; + assetAttachments = []; json['assetAttachments'].forEach((v) { - assetAttachments!.add(AssetAttachment.fromJson(v)); + assetAttachments!.add(GenericAttachmentModel.fromAssetJson(v)); }); } retirementTypeName = json['retirementTypeName']; @@ -298,7 +298,7 @@ class AssetByIdModel { data['isEnabled'] = isEnabled; data['tagCode'] = tagCode; if (assetAttachments != null) { - data['assetAttachments'] = assetAttachments!.map((v) => v).toList(); + data['assetAttachments'] = assetAttachments!.map((v) => v.toAssetJson()).toList(); } data['retirementTypeName'] = retirementTypeName; data['retirementStatusName'] = retirementStatusName; diff --git a/lib/models/device/asset_transfer_attachment.dart b/lib/models/device/asset_transfer_attachment.dart index 7aed25f8..48186ed1 100644 --- a/lib/models/device/asset_transfer_attachment.dart +++ b/lib/models/device/asset_transfer_attachment.dart @@ -1,30 +1,39 @@ -class AssetTransferAttachment { - AssetTransferAttachment({ - this.id, - this.attachmentName, - }); - - AssetTransferAttachment.fromJson(dynamic json) { - id = json['id']; - attachmentName = json['attachmentName']; - } - - num? id; // Now nullable - String? attachmentName; // Now nullable - - AssetTransferAttachment copyWith({ - num? id, // Parameter is now nullable - String? attachmentName, // Parameter is now nullable - }) => - AssetTransferAttachment( - id: id ?? this.id, - attachmentName: attachmentName ?? this.attachmentName, - ); - - Map toJson() { - final map = {}; - map['id'] = id; - map['attachmentName'] = attachmentName; - return map; - } -} +//TODO: need to remove this class +// import 'package:test_sa/models/lookup.dart'; +// +// class AssetTransferAttachment { +// AssetTransferAttachment({ +// this.id, +// this.attachmentName, +// this.documentType, +// +// }); +// +// AssetTransferAttachment.fromJson(dynamic json) { +// id = json['id']; +// attachmentName = json['attachmentName']; +// } +// +// num? id; // Now nullable +// String? attachmentName; // Now nullable +// Lookup ? documentType; +// +// AssetTransferAttachment copyWith({ +// num? id, // Parameter is now nullable +// String? attachmentName, // Parameter is now nullable +// Lookup? documentType, // Parameter is now nullable +// }) => +// AssetTransferAttachment( +// id: id ?? this.id, +// attachmentName: attachmentName ?? this.attachmentName, +// documentType: documentType ?? this.documentType, +// ); +// +// Map toJson() { +// final map = {}; +// map['id'] = id; +// map['attachmentName'] = attachmentName; +// map['documentTypeId'] = documentType?.id; +// return map; +// } +// } diff --git a/lib/models/device/device_transfer.dart b/lib/models/device/device_transfer.dart index 67b7d465..ef7f96ff 100644 --- a/lib/models/device/device_transfer.dart +++ b/lib/models/device/device_transfer.dart @@ -1,4 +1,5 @@ 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/models/new_models/assistant_employee.dart'; import 'package:test_sa/models/new_models/work_order_detail_model.dart'; @@ -95,7 +96,6 @@ class DeviceTransfer { this.assistantEmployList, this.assetTransferAssistantEmployeesReceiver, this.assetTransferAssistantEmployeesSender, - this.statusValue, }); @@ -130,13 +130,13 @@ class DeviceTransfer { if (json['senderAttachments'] != null) { senderAttachments = []; json['senderAttachments'].forEach((v) { - senderAttachments!.add(AssetTransferAttachment.fromJson(v)); + senderAttachments!.add(GenericAttachmentModel.fromAssetTransferJson(v)); }); } if (json['assetTransferAttachments'] != null) { assetTransferAttachments = []; json['assetTransferAttachments'].forEach((v) { - assetTransferAttachments?.add(AssetTransferAttachment.fromJson(v)); + assetTransferAttachments?.add(GenericAttachmentModel.fromAssetTransferJson(v)); }); } if (json['assetTransferContactPersons'] != null) { @@ -198,7 +198,7 @@ class DeviceTransfer { if (json['receiverAttachments'] != null) { receiverAttachments = []; json['receiverAttachments'].forEach((v) { - receiverAttachments!.add(AssetTransferAttachment.fromJson(v)); + receiverAttachments!.add(GenericAttachmentModel.fromAssetTransferJson(v)); }); } assetNumber = json['assetNumber']; @@ -270,9 +270,9 @@ class DeviceTransfer { String? senderWorkingHours; String? senderTravelingHours; String? senderEngSignature; - List? senderAttachments; - List? attachments; - List? assetTransferAttachments; + List? senderAttachments; + List? attachments; + List? assetTransferAttachments; String? receiverAssignedEmployeeId; String? receiverAssignedEmployeeNumber; num? receiverMachineStatusId; @@ -283,7 +283,7 @@ class DeviceTransfer { String? receiverWorkingHours; String? receiverTravelingHours; String? receiverEngSignature; - List? receiverAttachments; + List? receiverAttachments; num? supplierId; String? supplierName; String? destSiteName; @@ -314,11 +314,11 @@ class DeviceTransfer { List? assetTransferEngineerTimers; List? timerModelList = []; List? assistantEmployees; - List? assetTransferAssistantEmployeesSender=[]; - List? assetTransferAssistantEmployeesReceiver=[]; + List? assetTransferAssistantEmployeesSender = []; + List? assetTransferAssistantEmployeesReceiver = []; List? assetTransferContactPersons; AssetTransferAssistantEmployees? modelAssistantEmployees; - List? assistantEmployList=[]; + List? assistantEmployList = []; TimerModel? tbsTimer = TimerModel(); TimerModel? deviceTimePicker; @@ -349,7 +349,7 @@ class DeviceTransfer { String? senderWorkingHours, String? senderTravelingHours, String? senderEngSignature, - List? senderAttachments, + List? senderAttachments, String? receiverAssignedEmployeeId, String? receiverAssignedEmployeeNumber, num? receiverMachineStatusId, @@ -359,7 +359,7 @@ class DeviceTransfer { String? receiverWorkingHours, String? receiverTravelingHours, String? receiverEngSignature, - List? receiverAttachments, + List? receiverAttachments, num? supplierId, String? supplierName, String? destSiteName, @@ -472,7 +472,7 @@ class DeviceTransfer { senderVisitTimers: senderVisitTimers ?? this.senderVisitTimers, receiverVisitTimers: receiverVisitTimers ?? this.receiverVisitTimers, tbsTimer: tbsTimer ?? this.tbsTimer, - assistantEmployList: assistantEmployList??this.assistantEmployList, + assistantEmployList: assistantEmployList ?? this.assistantEmployList, deviceTimePicker: deviceTimePicker ?? this.deviceTimePicker, manufacturerName: manufacturerName ?? this.manufacturerName); @@ -510,7 +510,7 @@ class DeviceTransfer { map['assetTransferReceiverTimers'] = receiverVisitTimers!.map((v) => v.toJson()).toList(); } if (senderAttachments != null) { - map['senderAttachments'] = senderAttachments!.map((v) => v.toJson()).toList(); + map['senderAttachments'] = senderAttachments!.map((v) => v.toAssetTransferJson()).toList(); } map['receiverAssignedEmployeeId'] = receiverAssignedEmployeeId; map['receiverAssignedEmployeeNumber'] = receiverAssignedEmployeeNumber; @@ -522,7 +522,7 @@ class DeviceTransfer { map['receiverTravelingHours'] = receiverTravelingHours; map['receiverEngSignature'] = receiverEngSignature; if (receiverAttachments != null) { - map['receiverAttachments'] = receiverAttachments!.map((v) => v.toJson()).toList(); + map['receiverAttachments'] = receiverAttachments?.map((v) => v.toAssetTransferJson() ?? {}).toList(); } map["supplierId"] = supplierId; map["supplierName"] = supplierName; @@ -571,7 +571,7 @@ class DeviceTransfer { map['destRoomId'] = destRoomId; map['comment'] = comment; if (attachments != null) { - map['attachments'] = attachments!.map((v) => v.toJson()).toList(); + map['attachments'] = attachments!.map((v) => v.toAssetTransferJson()).toList(); } return map; } @@ -586,7 +586,7 @@ class DeviceTransfer { map['assetTransferAssistantEmployees'] = modelAssistantEmployees; map['assetTransferEngineerTimers'] = assetTransferEngineerTimers; if (attachments != null) { - map['attachments'] = attachments!.map((v) => v.toJson()).toList(); + map['attachments'] = attachments!.map((v) => v.toAssetTransferJson()).toList(); } if (assetTransferEngineerTimers != null) { map['assetTransferEngineerTimers'] = assetTransferEngineerTimers!.map((v) => v.toJson()).toList(); @@ -634,7 +634,7 @@ class DeviceTransfer { map['senderTravelingHours'] = senderTravelingHours; map['senderEngSignature'] = senderEngSignature; if (senderAttachments != null) { - map['senderAttachments'] = senderAttachments!.map((v) => v.toJson()).toList(); + map['senderAttachments'] = senderAttachments!.map((v) => v.toAssetTransferJson()).toList(); } if (senderVisitTimers != null) { map['assetTransferSenderTimers'] = senderVisitTimers!.map((v) => v.toJson()).toList(); @@ -652,7 +652,7 @@ class DeviceTransfer { map['receiverTravelingHours'] = receiverTravelingHours; map['receiverEngSignature'] = receiverEngSignature; if (receiverAttachments != null) { - map['receiverAttachments'] = receiverAttachments!.map((v) => v.toJson()).toList(); + map['receiverAttachments'] = receiverAttachments!.map((v) => v.toAssetTransferJson() ?? {}).toList(); } return map; } diff --git a/lib/models/enums/request_attachment_type_enum.dart b/lib/models/enums/request_attachment_type_enum.dart new file mode 100644 index 00000000..de1052ba --- /dev/null +++ b/lib/models/enums/request_attachment_type_enum.dart @@ -0,0 +1,213 @@ + +enum RequestAttachmentTypeEnum { + correctiveMaintenance, // 1 + gasRefill, // 2 + transferAsset, // 3 + preventiveMaintenance, // 4 + recurrentWo, // 5 + taskRequest, // 6 + recallAndAlert, // 7 + assetInventory, // 8 + assessmentOfNeedAndTechnology, // 9 + equipmentInternalAudit, // 10 + systemInternalAudit, // 11 + loanEquipment, // 12 + assetDelivery, // 13 + medicalGasInspection, // 14 + demo, // 15 + incidents, // 16 + sparePartActivity, // 17 + updateDeliveryNotes, // 18 + traf,//19 + ppmSparePartActivity// 20 +} + +extension RequestAttachmentTypeEnumExtension on RequestAttachmentTypeEnum { + int get id { + switch (this) { + case RequestAttachmentTypeEnum.correctiveMaintenance: + return 1; + case RequestAttachmentTypeEnum.gasRefill: + return 2; + case RequestAttachmentTypeEnum.transferAsset: + return 3; + case RequestAttachmentTypeEnum.preventiveMaintenance: + return 4; + case RequestAttachmentTypeEnum.recurrentWo: + return 5; + case RequestAttachmentTypeEnum.taskRequest: + return 6; + case RequestAttachmentTypeEnum.recallAndAlert: + return 7; + case RequestAttachmentTypeEnum.assetInventory: + return 8; + case RequestAttachmentTypeEnum.assessmentOfNeedAndTechnology: + return 9; + case RequestAttachmentTypeEnum.equipmentInternalAudit: + return 10; + case RequestAttachmentTypeEnum.systemInternalAudit: + return 11; + case RequestAttachmentTypeEnum.loanEquipment: + return 12; + case RequestAttachmentTypeEnum.assetDelivery: + return 13; + case RequestAttachmentTypeEnum.medicalGasInspection: + return 14; + case RequestAttachmentTypeEnum.demo: + return 15; + case RequestAttachmentTypeEnum.incidents: + return 16; + case RequestAttachmentTypeEnum.sparePartActivity: + return 17; + case RequestAttachmentTypeEnum.updateDeliveryNotes: + return 18; + case RequestAttachmentTypeEnum.traf: + return 19; + case RequestAttachmentTypeEnum.ppmSparePartActivity: + return 20; + } + } + int get lookupEnumId { + switch (this) { + ///values with 0 we need to check with backend team for the correct lookupEnumId + case RequestAttachmentTypeEnum.correctiveMaintenance: + return 40305; + case RequestAttachmentTypeEnum.gasRefill: + return 40307; + case RequestAttachmentTypeEnum.transferAsset: + return 40304; + case RequestAttachmentTypeEnum.preventiveMaintenance: + return 40313; + case RequestAttachmentTypeEnum.recurrentWo: + return 40314; + case RequestAttachmentTypeEnum.taskRequest: + return 40317; + case RequestAttachmentTypeEnum.recallAndAlert: + return 40316; + case RequestAttachmentTypeEnum.assetInventory: + return 40303; + case RequestAttachmentTypeEnum.assessmentOfNeedAndTechnology: + return 40319; + case RequestAttachmentTypeEnum.equipmentInternalAudit: + return 40323; + case RequestAttachmentTypeEnum.systemInternalAudit: + return 40322; + case RequestAttachmentTypeEnum.loanEquipment: + return 3053; + case RequestAttachmentTypeEnum.assetDelivery: + return 5009; + case RequestAttachmentTypeEnum.medicalGasInspection: + return 3012; + case RequestAttachmentTypeEnum.demo: + return 4106; + case RequestAttachmentTypeEnum.incidents: + return 40308; + case RequestAttachmentTypeEnum.sparePartActivity: + return 40321; + case RequestAttachmentTypeEnum.ppmSparePartActivity: + return 4021; + case RequestAttachmentTypeEnum.updateDeliveryNotes: + return 40309; + case RequestAttachmentTypeEnum.traf: + return 40319; + } + } + // String getName(BuildContext context) { + // switch (this) { + // case RequestTypeEnum.correctiveMaintenance: + // return context.translation.correctiveMaintenance; + // case RequestTypeEnum.gasRefill: + // return context.translation.gasRefill; + // case RequestTypeEnum.transferAsset: + // return context.translation.transferAsset; + // case RequestTypeEnum.preventiveMaintenance: + // return context.translation.preventiveMaintenance; + // case RequestTypeEnum.recurrentWo: + // return context.translation.recurrentWo; + // case RequestTypeEnum.taskRequest: + // return context.translation.taskRequest; + // case RequestTypeEnum.recallAndAlert: + // return 'Recall and Alert'; + // case RequestTypeEnum.assetInventory: + // return 'Asset Inventory'; + // case RequestTypeEnum.assessmentOfNeedAndTechnology: + // return 'Assessment of Need & Technology'; + // case RequestTypeEnum.equipmentInternalAudit: + // return 'Equipment Internal Audit'; + // case RequestTypeEnum.systemInternalAudit: + // return 'System Internal Audit'; + // case RequestTypeEnum.loanEquipment: + // return 'Loan Equipment'; + // case RequestTypeEnum.assetDelivery: + // return 'Asset Delivery'; + // case RequestTypeEnum.medicalGasInspection: + // return 'Medical Gas Inspection'; + // case RequestTypeEnum.demo: + // return 'Demo'; + // case RequestTypeEnum.incidents: + // return 'Incidents'; + // case RequestTypeEnum.sparePartActivity: + // return 'Spare Part Activity'; + // case RequestTypeEnum.updateDeliveryNotes: + // return 'Update Delivery Notes'; + // case RequestTypeEnum.traf: + // return 'Traf'; + // } + // } + + static RequestAttachmentTypeEnum? fromId(int? id) { + if (id == null) return null; + switch (id) { + case 1: + return RequestAttachmentTypeEnum.correctiveMaintenance; + case 2: + return RequestAttachmentTypeEnum.gasRefill; + case 3: + return RequestAttachmentTypeEnum.transferAsset; + case 4: + return RequestAttachmentTypeEnum.preventiveMaintenance; + case 5: + return RequestAttachmentTypeEnum.recurrentWo; + case 6: + return RequestAttachmentTypeEnum.taskRequest; + case 7: + return RequestAttachmentTypeEnum.recallAndAlert; + case 8: + return RequestAttachmentTypeEnum.assetInventory; + case 9: + return RequestAttachmentTypeEnum.assessmentOfNeedAndTechnology; + case 10: + return RequestAttachmentTypeEnum.equipmentInternalAudit; + case 11: + return RequestAttachmentTypeEnum.systemInternalAudit; + case 12: + return RequestAttachmentTypeEnum.loanEquipment; + case 13: + return RequestAttachmentTypeEnum.assetDelivery; + case 14: + return RequestAttachmentTypeEnum.medicalGasInspection; + case 15: + return RequestAttachmentTypeEnum.demo; + case 16: + return RequestAttachmentTypeEnum.incidents; + case 17: + return RequestAttachmentTypeEnum.sparePartActivity; + case 18: + return RequestAttachmentTypeEnum.updateDeliveryNotes; + case 19: + return RequestAttachmentTypeEnum.traf; + case 20: + return RequestAttachmentTypeEnum.ppmSparePartActivity; + default: + return null; + } + } + // static String getNameFromId(int id, BuildContext context) { + // final requestType = fromId(id); + // return requestType?.getName(context) ?? "Type $id"; + // } + static int? getLookupEnumIdFromId(int? id) { + final requestType = fromId(id); + return requestType?.lookupEnumId; + } +} \ No newline at end of file diff --git a/lib/models/generic_attachment_model.dart b/lib/models/generic_attachment_model.dart index 6ba126e1..1418d4c4 100644 --- a/lib/models/generic_attachment_model.dart +++ b/lib/models/generic_attachment_model.dart @@ -1,33 +1,358 @@ -import 'dart:io'; +import 'dart:developer'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/models/lookup.dart'; + class GenericAttachmentModel { - GenericAttachmentModel({this.id, this.name, this.originalName, this.createdBy, this.documentTypeId}); + GenericAttachmentModel({ + this.id, + this.name, + this.module, + this.subModule, + this.uploadedBy, + this.originalName, + this.createdBy, + this.documentType, + this.attachmentDescription, + this.attachmentURL, + this.moduleReferenceId, + this.attachmentTypeId, + this.createdDate, + this.modifiedBy, + this.modifiedDate, + this.supplierId, + }); int? id; String? name; + String? module; + String? subModule; + String? uploadedBy; String? createdBy; String? originalName; - Lookup? documentTypeId; + Lookup? documentType; + String? attachmentDescription; + String? attachmentURL; + num? moduleReferenceId; + num? attachmentTypeId; + String? createdDate; + String? modifiedBy; + String? modifiedDate; + num? supplierId; GenericAttachmentModel.fromJson(Map json, {bool convertToLink = false}) { id = json['id']; - name = json['name'] ?? json['imageName']; + name = json['name'] ?? json['attachmentName'] ?? json['imageName']; createdBy = json['createdBy']; + documentType = json['attachmentType'] != null ? Lookup.fromJson(json['attachmentType']) : null; originalName = json['originalName'] ?? json['imageOriginalName']; if (convertToLink) { name = URLs.getFileUrl(name); } } + GenericAttachmentModel.fromAssetDocumentJson(Map json, {bool convertToLink = false}) { + id = json['id']; + name = json['attachmentName'] ?? json['name'] ?? json['imageName']; + module = json['module']; + subModule = json['subModule']; + createdBy = json['createdBy']; + createdDate = json['createdDate']; + uploadedBy = json['uploadedBy']; + originalName = json['originalName'] ?? json['imageOriginalName']; + documentType = json['attachmentType'] != null ? Lookup(name: json['attachmentType'], id: 0) : null; + if (convertToLink && name != null) { + name = URLs.getFileUrl(name); + } + } + + GenericAttachmentModel.fromWorkOrderJson(Map json) { + id = json['id']; + name = json['name']; + documentType = json['attachmentType'] != null ? Lookup.fromJson(json['attachmentType']) : null; + createdBy = json['createdBy']; + } + + GenericAttachmentModel.fromLoanJson(Map json) { + id = json['id']?.toInt(); + name = json['attachmentName']; + attachmentDescription = json['attachmentDescription']; + documentType = json['documentType'] != null ? Lookup.fromJson(json['documentType']) : null; + moduleReferenceId = json['loanId']; + attachmentTypeId = json['loanAttachmentTypeId']; + } + + GenericAttachmentModel.fromLoanDetailJson(Map json) { + id = json['id']; + name = json['attachmentName']; + attachmentDescription = json['attachmentDescription']; + moduleReferenceId = json['loanId']; + documentType = json['documentType'] != null ? Lookup.fromJson(json['documentType']) : null; + attachmentTypeId = json['loanAttachmentTypeId']; + createdBy = json['createdBy']; + createdDate = json['createdDate']; + modifiedBy = json['modifiedBy']; + modifiedDate = json['modifiedDate']; + } + + GenericAttachmentModel.fromPpmJson(Map json) { + id = json['id']; + name = json['attachmentName'] ?? json['name']; + moduleReferenceId = json['visitId']; + documentType = json['attachmentType'] != null ? Lookup.fromJson(json['attachmentType']) : null; + attachmentURL = json['attachmentURL']; + } + + GenericAttachmentModel.fromSupplierJson(Map json) { + id = json['id']; + name = json['attachmentName'] ?? json['name']; + supplierId = json['supplierId']; + moduleReferenceId = json['visitId']; + documentType = json['attachmentType'] != null ? Lookup.fromJson(json['attachmentType']) : null; + attachmentURL = json['attachmentURL']; + } + + GenericAttachmentModel.fromGasRefillJson(Map json) { + id = json['id']; + name = json['attachmentName']; + moduleReferenceId = json['gasRefillId']; + documentType = json['documentType'] != null ? Lookup.fromJson(json['documentType']) : null; + } + + GenericAttachmentModel.fromIncidentJson(Map json) { + id = json['id']; + name = json['attachmentName']; + moduleReferenceId = json['incidentId']; + attachmentDescription = json['attachmentDescription']; + documentType = json['attachmentType'] != null ? Lookup.fromJson(json['attachmentType']) : null; + } + + GenericAttachmentModel.fromAssetTransferJson(Map json) { + id = json['id']; + name = json['attachmentName']; + documentType = json['attachmentType'] != null ? Lookup.fromJson(json['attachmentType']) : null; + } + + GenericAttachmentModel.fromDemoJson(Map json) { + id = json['id']; + name = json['attachmentName']; + originalName = json['originalName']; + documentType = json['documentType'] != null ? Lookup.fromJson(json['documentType']) : null; + moduleReferenceId = json['demoRequestId']; + } + + GenericAttachmentModel.fromInternalAuditJson(Map json) { + id = json['id']; + name = (json['name'] != null && !json['name'].toString().startsWith('data:image/jpeg')) ? json['name'] : null; + originalName = json['originalName']; + createdBy = json['createdBy']; + documentType = json['attachmentType'] != null ? Lookup.fromJson(json['attachmentType']) : null; + } + + GenericAttachmentModel.fromPreventiveVisitJson(Map json) { + id = json['id']; + name = json['attachmentName']; + documentType = json['attachmentType'] != null ? Lookup.fromJson(json['attachmentType']) : null; + } + + GenericAttachmentModel.fromAssetJson(Map json) { + id = json['id']; + name = json['attachmentName']; + attachmentURL = json['attachmentURL']; + documentType = json['documentType'] != null ? Lookup.fromJson(json['documentType']) : null; + originalName = json['originalName']; + } + + GenericAttachmentModel.fromAssetInventoryJson(Map json) { + id = json['id']; + name = json['attachmentName']; + attachmentURL = json['attachmentURL']; + documentType = json['attachmentType'] != null ? Lookup.fromJson(json['attachmentType']) : null; + originalName = json['originalName']; + } + + GenericAttachmentModel.fromTrafJson(Map json) { + id = json['id']; + moduleReferenceId = json['trafId']; + name = json['attachmentName']; + attachmentDescription = json['attachmentDescription']; + moduleReferenceId = json['trafId']; + documentType = json['attachmentType'] != null ? Lookup.fromJson(json['attachmentType']) : null; + } + Map toJson() { final Map data = {}; data['id'] = id; data['name'] = name; data['createdBy'] = createdBy; data['originalName'] = originalName; + data['documentTypeId'] = documentType?.id; + return data; + } + + Map toSparePartJson() { + final Map data = {}; + data['id'] = id; + data['name'] = name; + data['createdBy'] = createdBy; + data['originalName'] = originalName; + data['attachmentTypeId'] = documentType?.id; + return data; + } + + Map toWorkOrderJson() { + final Map data = {}; + data['id'] = id; + data['name'] = name; + data['createdBy'] = createdBy; + + ///TODO need to keep same variable for document type in backend for all modules, currently it is different for different modules + if (documentType != null) { + data['attachmentTypeId'] = documentType?.id; + } + return data; + } + + Map toLoanJson() { + final Map data = {}; + data['id'] = id; + data['attachmentName'] = name; + data['loanId'] = moduleReferenceId; + data['loanAttachmentTypeId'] = documentType?.id; + // data['documentTypeId'] = documentType?.id; + data['attachmentDescription'] = attachmentDescription; + return data; + } + + Map toLoanDetailJson() { + final Map data = {}; + data['id'] = id; + data['attachmentName'] = name; + data['loanId'] = moduleReferenceId; + data['loanAttachmentTypeId'] = attachmentTypeId; + data['attachmentDescription'] = attachmentDescription; + data['createdBy'] = createdBy; + data['createdDate'] = createdDate; + data['documentTypeId'] = documentType?.id; + + data['modifiedBy'] = modifiedBy; + data['modifiedDate'] = modifiedDate; + return data; + } + + Map toGasRefillJson() { + final Map data = {}; + data['id'] = id; + data['gasRefillId'] = moduleReferenceId; + data['attachmentName'] = name; + data['documentTypeId'] = documentType?.id; + return data; + } + + Map toIncidentJson() { + final Map data = {}; + data['id'] = id; + data['attachmentName'] = name; + data['incidentId'] = moduleReferenceId; + data['attachmentTypeId'] = documentType?.id; + data['attachmentDescription'] = attachmentDescription; + return data; + } + + Map toAssetTransferJson() { + final Map data = {}; + data['id'] = id; + data['attachmentName'] = name; + data['attachmentTypeId'] = documentType?.id; + return data; + } + + Map toDemoJson() { + final Map data = {}; + data['id'] = id; + data['attachmentName'] = name; + data['demoRequestId'] = moduleReferenceId; + data['originalName'] = originalName; + if (documentType != null) { + data['documentTypeId'] = documentType?.id; + } + return data; + } + + Map toInternalAuditJson() { + final Map data = {}; + data['id'] = id; + data['name'] = name; + data['originalName'] = originalName; + data['attachmentTypeId'] = documentType?.id; + return data; + } + + Map toPreventiveVisitJson() { + final Map data = {}; + data['id'] = id; + data['attachmentName'] = name; + data['attachmentTypeId'] = documentType?.id; + return data; + } + + Map toAssetJson() { + final Map data = {}; + data['id'] = id; + data['attachmentName'] = name; + data['attachmentURL'] = attachmentURL; + data['documentTypeId'] = documentType?.id; + data['originalName'] = originalName; + return data; + } + + Map toAssetDeliveryJson() { + final Map data = {}; + data['id'] = id; + data['name'] = name; + data['attachmentTypeId'] = documentType?.id; + data['originalName'] = originalName; + data['createdBy'] = createdBy; + return data; + } + + Map toInventoryJson() { + final Map data = {}; + data['id'] = id; + data['Name'] = name; + data['attachmentURL'] = attachmentURL; + data['attachmentTypeId'] = documentType?.id; + data['originalName'] = originalName; + return data; + } + + Map toTrafJson() { + final Map data = {}; + data['id'] = id; + data['trafId'] = moduleReferenceId; + data['attachmentName'] = name; + data['attachmentTypeId'] = documentType?.id; + return data; + } + + Map toSupplierJson() { + final Map data = {}; + data['id'] = id; + data['supplierId'] = supplierId; + data['documentTypeId'] = documentType?.id; + data['attachmentName'] = name; + data['attachmentURL'] = attachmentURL; + return data; + } + + Map toTaskJson() { + final Map data = {}; + data['id'] = id; + data['name'] = name; + data['createdBy'] = createdBy; + data['originalName'] = originalName; + data['attachmentTypeId'] = documentType?.id; return data; } } diff --git a/lib/models/helper_data_models/asset_retired/asset_retired_model.dart b/lib/models/helper_data_models/asset_retired/asset_retired_model.dart index 172d816a..e7b80f2f 100644 --- a/lib/models/helper_data_models/asset_retired/asset_retired_model.dart +++ b/lib/models/helper_data_models/asset_retired/asset_retired_model.dart @@ -1,3 +1,4 @@ +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; class AssetRetiredHelperModel { @@ -5,7 +6,7 @@ class AssetRetiredHelperModel { int? workOrderId; Lookup? retirmentReason; String? retirementComment; - List? + List? activityAssetToBeRetiredAttachments=[]; AssetRetiredHelperModel( @@ -30,14 +31,3 @@ class AssetRetiredHelperModel { } } -class ActivityAssetToBeRetiredAttachments { - int? id; - String? name; - ActivityAssetToBeRetiredAttachments({this.id, this.name}); - Map toJson() { - final Map data = {}; - data['id'] = id; - data['name'] = name; - return data; - } -} diff --git a/lib/models/helper_data_models/spare_part/activity_spare_part_model.dart b/lib/models/helper_data_models/spare_part/activity_spare_part_model.dart index 1c51821f..0a77f858 100644 --- a/lib/models/helper_data_models/spare_part/activity_spare_part_model.dart +++ b/lib/models/helper_data_models/spare_part/activity_spare_part_model.dart @@ -1,9 +1,11 @@ +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/service_request/spare_parts.dart'; class SparePartHelperModel { int? id; int? workOrderId; + String? pmVisitId; int? partCatalogItemId; int? activityStatusId; SparePart? sparePart; @@ -12,11 +14,12 @@ class SparePartHelperModel { num? installQty; num? returnQty; String? comment; - List? sparePartAttachments; + List? sparePartAttachments; SparePartHelperModel({ this.id, this.workOrderId, + this.pmVisitId, this.partCatalogItemId, this.quantity, this.installQty, @@ -24,9 +27,9 @@ class SparePartHelperModel { this.sparePart, this.activityStatusId, this.activityStatus, - this.comment,this.sparePartAttachments, - }); - + this.comment, + List? sparePartAttachments, + }) : sparePartAttachments = sparePartAttachments ?? []; Map toJson() { final Map data = {}; @@ -36,33 +39,28 @@ class SparePartHelperModel { data['quantity'] = quantity; data['installQty'] = installQty; data['returnQty'] = returnQty; - if(activityStatus!=null){ + if (activityStatus != null) { data['activityStatusId'] = activityStatus?.id; } data['comment'] = comment; if (sparePartAttachments != null) { - data['acitiySparePartAttachments'] = - sparePartAttachments!.map((v) => v.toJson()).toList(); + data['acitiySparePartAttachments'] = sparePartAttachments!.map((v) => v?.toSparePartJson() ?? {}).toList(); } return data; } -} - -class SparePartAttachments { - int? id; - String? name; - - SparePartAttachments({this.id, this.name}); - - SparePartAttachments.fromJson(Map json) { - id = json['id']; - name = json['name']; - } - Map toJson() { + Map toPMJson() { final Map data = {}; data['id'] = id; - data['name'] = name; + data['planPreventiveVisitId'] = pmVisitId; + data['partCatalogItemId'] = sparePart?.id; + data['quantity'] = quantity; + data['comment'] = comment; + data['installQty'] = installQty; + data['returnQty'] = returnQty; + if (sparePartAttachments?.isNotEmpty ?? false) { + data['acitiySparePartAttachments'] = sparePartAttachments!.map((v) => v.toSparePartJson()).toList(); + } return data; } -} \ No newline at end of file +} diff --git a/lib/models/helper_data_models/workorder/work_order_helper_models.dart b/lib/models/helper_data_models/workorder/work_order_helper_models.dart index b15924d6..cd2c9141 100644 --- a/lib/models/helper_data_models/workorder/work_order_helper_models.dart +++ b/lib/models/helper_data_models/workorder/work_order_helper_models.dart @@ -1,4 +1,5 @@ import 'package:test_sa/models/fault_description.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import '../../new_models/work_order_detail_model.dart'; @@ -24,7 +25,7 @@ class WorkOrderHelperModel { int? problemDescriptionId; String? comments; String? voiceNote; - List? workOrderAttachments; + List? workOrderAttachments; WorkOrderHelperModel({this.assetId, this.equipmentStatusId, this.priorityId, this.problemDescriptionId, this.comments, this.voiceNote, this.workOrderAttachments}); @@ -37,42 +38,21 @@ class WorkOrderHelperModel { data['comments'] = comments; data['voiceNote'] = voiceNote; if (workOrderAttachments != null) { - data['workOrderAttachments'] = workOrderAttachments!.map((v) => v.toJson()).toList(); + data['workOrderAttachments'] = workOrderAttachments!.map((v) => v.toWorkOrderJson()).toList(); } return data; } - Map toUploadAttachmentJson(int? workOrderId, List? workOrderAttachments) { + Map toUploadAttachmentJson(int? workOrderId, List? workOrderAttachments) { final Map data = {}; data['workOrderId'] = workOrderId; if (workOrderAttachments != null) { - data['workOrderAttachments'] = workOrderAttachments!.map((v) => v.toJson()).toList(); + data['workOrderAttachments'] = workOrderAttachments.map((v) => v.toWorkOrderJson()).toList(); } return data; } } -class WorkOrderAttachments { - WorkOrderAttachments({this.id, this.name,this.createdBy}); - - int? id; - String? name; - String ?createdBy; - WorkOrderAttachments.fromJson(Map json) { - id = json['id']; - name = json['name']; - createdBy = json['createdBy']; - } - - Map toJson() { - final Map data = {}; - data['id'] = id; - data['name'] = name; - data['createdBy'] = createdBy; - return data; - } -} - class EngineerUpdateWorkOrderHelperModel { int? workOrderId; Lookup? equipmentStatus; @@ -173,9 +153,22 @@ class WorkOrderCostModel { String? mrNo; num? exchangeCost; - WorkOrderCostModel({this.workOrderId, this.sparePartCost, this.labourCost, this.travelCost, this.qAmount, this.poNo, this.prNo,this.mrNo,this.exchangeCost}); + WorkOrderCostModel({this.workOrderId, this.sparePartCost, this.labourCost, this.travelCost, this.qAmount, this.poNo, this.prNo, this.mrNo, this.exchangeCost}); Map toJson() { - return {'workOrderId': workOrderId, 'sparePartCost': sparePartCost, 'laborCost': labourCost, 'travelCost': travelCost, 'qAmount': qAmount, 'prNo': prNo, 'poNo': poNo,'mrNo':mrNo,'exchangeCost':exchangeCost}; + return { + 'workOrderId': workOrderId, + 'sparePartCost': sparePartCost, + 'laborCost': labourCost, + 'travelCost': travelCost, + 'qAmount': qAmount, + 'prNo': prNo, + 'poNo': poNo, + 'mrNo': mrNo, + 'exchangeCost': exchangeCost + }; + } + Map toPMCostJson() { + return {'planPreventiveVisitId': workOrderId, 'sparePartCost': sparePartCost, 'laborCost': labourCost, 'travelCost': travelCost, 'qAmount': qAmount, 'prNo': prNo, 'poNo': poNo,'mrNo':mrNo,'exchangeCost':exchangeCost}; } } diff --git a/lib/models/new_models/gas_refill_model.dart b/lib/models/new_models/gas_refill_model.dart index a50373df..da5400b7 100644 --- a/lib/models/new_models/gas_refill_model.dart +++ b/lib/models/new_models/gas_refill_model.dart @@ -3,6 +3,7 @@ import 'dart:typed_data'; import 'package:flutter/cupertino.dart'; import 'package:fluttertoast/fluttertoast.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/models/new_models/assigned_employee.dart'; import 'package:test_sa/models/new_models/building.dart'; @@ -87,7 +88,7 @@ class GasRefillModel { TimerModel? gasRefillTimePicker; List? timerModelList = []; List? gasRefillTimers = []; - List? gasRefillAttachments; + List? gasRefillAttachments; List? gasRefillContactPerson; int? statusValue; @@ -115,9 +116,9 @@ class GasRefillModel { workingHours = json['gasRefillTimers'].fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item['endDate']).difference(DateTime.parse(item['startDate'])).inSeconds) ?? 0; } if (json['gasRefillAttachments'] != null) { - gasRefillAttachments = []; + gasRefillAttachments = []; json['gasRefillAttachments'].forEach((v) { - gasRefillAttachments!.add(GasRefillAttachments.fromJson(v)); + gasRefillAttachments!.add(GenericAttachmentModel.fromGasRefillJson(v)); }); } if (json['gasRefillContactPerson'] != null) { @@ -127,24 +128,6 @@ class GasRefillModel { }); } - // try { - // final DateTime? sd = DateTime.tryParse(startDate ?? ""); - // final DateTime? st = DateTime.tryParse(startTime ?? ""); - // final DateTime? ed = DateTime.tryParse(endDate ?? ""); - // final DateTime? et = DateTime.tryParse(endTime ?? ""); - // timer = TimerModel( - // startAt: st == null ? sd : sd?.add(Duration(hours: st.hour, minutes: st.minute, seconds: st.second)), // Handle potential null 'sd' - // endAt: et == null ? ed : ed?.add(Duration(hours: et.hour, minutes: et.minute, seconds: et.second)), // Handle potential null 'ed' - // ); - // if (timer!.endAt != null && timer!.startAt != null) { - // // Use '!' since timer could be null after initialization - // timer!.durationInSecond = (timer!.endAt!.difference(timer!.startAt!)).inSeconds; - // workingHours = (((timer!.durationInSecond ?? 0) / 60) / 60); - // } - // } catch (e) { - // print(e); - // } - engSignature = json['engSignature']; nurseSignature = json['nurseSignature']; site = json['site'] != null ? Site.fromJson(json['site']) : null; @@ -188,7 +171,7 @@ class GasRefillModel { map['comment'] = comment; if (gasRefillAttachments != null) { - map['gasRefillAttachments'] = gasRefillAttachments?.map((v) => v.toJson()).toList(); + map['gasRefillAttachments'] = gasRefillAttachments?.map((v) => v.toGasRefillJson() ?? {}).toList(); } //older code..... @@ -241,8 +224,8 @@ class GasRefillModel { if (gasRefillTimers != null) { map['gasRefillTimers'] = gasRefillTimers?.map((v) => v.toJson()).toList(); } - if (gasRefillAttachments != null) { - map['gasRefillAttachments'] = gasRefillAttachments?.map((v) => v.toJson()).toList(); + if (gasRefillContactPerson != null) { + map['gasRefillContactPerson'] = gasRefillContactPerson?.map((v) => v?.toJson() ?? {}).toList(); } return map; @@ -454,27 +437,30 @@ class GasRefillTimer { } } -class GasRefillAttachments { - int? id; - num? gasRefillId; - String? attachmentName; - - GasRefillAttachments({this.id, this.attachmentName, this.gasRefillId}); - - GasRefillAttachments.fromJson(Map json) { - id = json['id']; - gasRefillId = json['gasRefillId']; - attachmentName = json['attachmentName']; - } - - Map toJson() { - final Map data = {}; - data['id'] = id; - data['gasRefillId'] = gasRefillId; - data['attachmentName'] = attachmentName; - return data; - } -} +// class GasRefillAttachments { +// int? id; +// num? gasRefillId; +// String? attachmentName; +// Lookup ? documentType; +// +// GasRefillAttachments({this.id, this.attachmentName,this.documentType, this.gasRefillId}); +// +// GasRefillAttachments.fromJson(Map json) { +// id = json['id']; +// gasRefillId = json['gasRefillId']; +// attachmentName = json['attachmentName']; +// documentType = json['documentType']; +// } +// +// Map toJson() { +// final Map data = {}; +// data['id'] = id; +// data['gasRefillId'] = gasRefillId; +// data['attachmentName'] = attachmentName; +// data['documentTypeId'] = documentType?.id; +// return data; +// } +// } class GasRefillContactPerson { int? id; diff --git a/lib/models/new_models/task_request/task_request_model.dart b/lib/models/new_models/task_request/task_request_model.dart index 235b3851..fd4dc795 100644 --- a/lib/models/new_models/task_request/task_request_model.dart +++ b/lib/models/new_models/task_request/task_request_model.dart @@ -1,6 +1,7 @@ import 'dart:typed_data'; import 'package:test_sa/models/base.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/new_models/assistant_employee.dart'; import 'package:test_sa/models/new_models/building.dart'; @@ -63,7 +64,7 @@ class TaskData { Department? department; Rooms? room; String? callComment; - List? taskJobAttachments; + List? taskJobAttachments; TaskContactUser? assignedEngineer; List? taskJobAssistantEmployees = []; TaskJobAssistantEmployees? modelAssistantEmployees; @@ -146,18 +147,18 @@ class TaskData { }); } if (json['attachments'] != null) { - taskJobAttachments = []; + taskJobAttachments = []; json['attachments'].forEach((v) { - taskJobAttachments!.add(TaskJobAttachment.fromJson(v)); + taskJobAttachments!.add(GenericAttachmentModel.fromJson(v)); }); } taskType = json['taskType'] != null ? TaskTypeModel.fromJson(json['taskType']) : null; taskJobStatus = json['taskJobStatus'] != null ? TaskJobStatus.fromJson(json['taskJobStatus']) : null; callComment = json['callComment']; if (json['taskJobAttachments'] != null) { - taskJobAttachments = []; + taskJobAttachments = []; json['taskJobAttachments'].forEach((v) { - taskJobAttachments!.add(TaskJobAttachment.fromJson(v)); + taskJobAttachments!.add(GenericAttachmentModel.fromJson(v)); }); } assignedEngineer = json['assignedEngineer'] != null ? TaskContactUser.fromJson(json['assignedEngineer']) : null; @@ -283,7 +284,7 @@ class TaskData { data['callComment'] = callComment; if (taskJobAttachments != null) { - data['taskJobAttachments'] = taskJobAttachments!.map((e) => e.toJson()).toList(); + data['taskJobAttachments'] = taskJobAttachments!.map((e) => e.toTaskJson()).toList(); } if (assignedEngineer != null) { @@ -368,7 +369,7 @@ class TaskData { data['taskJobActivityEngineerTimers'] = taskJobActivityEngineerTimers!.map((v) => v.toJson()).toList(); } if (taskJobAttachments != null) { - data['attachments'] = taskJobAttachments!.map((v) => v.toJson()).toList(); + data['attachments'] = taskJobAttachments!.map((v) => v.toTaskJson()).toList(); } data['installationBuildingId'] = building?.id; data['installationFloorId'] = floor?.id; @@ -567,26 +568,6 @@ class TaskJobStatus { }; } -class TaskJobAttachment { - final int? id; - final String? name; - String? createdBy; - - TaskJobAttachment({this.id, this.name, this.createdBy}); - - factory TaskJobAttachment.fromJson(Map json) => TaskJobAttachment( - id: json['id'], - name: json['name'], - createdBy: json['createdBy'], - ); - - Map toJson() => { - 'id': id, - 'name': name, - 'createdBy': createdBy, - }; -} - class TaskJobAssistantEmployees { DateTime? startDate; int? id; @@ -755,7 +736,7 @@ class AddTaskModel { TaskEvaluatorUser? taskEvaluatorUser; String? alertNo; String? estimationDeliveryDate; - List? attachments; + List? attachments; String? reasonOfFSCA; String? correctiveActionDescription; @@ -800,7 +781,7 @@ class AddTaskModel { 'reasonOfFSCA': reasonOfFSCA, 'correctiveActionDescription': correctiveActionDescription, 'evaluatorUserId': taskEvaluatorUser?.userId, - 'attachments': attachments?.map((x) => x.toJson()).toList(), + 'attachments': attachments?.map((x) => x.toTaskJson()).toList(), }; } diff --git a/lib/models/new_models/work_order_detail_model.dart b/lib/models/new_models/work_order_detail_model.dart index 984edca5..8bfb5e9a 100644 --- a/lib/models/new_models/work_order_detail_model.dart +++ b/lib/models/new_models/work_order_detail_model.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:test_sa/models/fault_description.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/helper_data_models/spare_part/activity_spare_part_model.dart'; import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; import 'package:test_sa/models/lookup.dart'; @@ -146,7 +147,7 @@ class WorkOrderData { Lookup? problemDescription; String? comments; String? voiceNote; - List workOrderAttachments; + List workOrderAttachments; String? returnToService; Lookup? serviceType; Lookup? failureReasone; @@ -232,7 +233,7 @@ class WorkOrderData { comments: json["comments"], voiceNote: json["voiceNote"], edd: json["edd"], - workOrderAttachments: json["workOrderAttachments"] == null ? [] : List.from(json['workOrderAttachments']).map((e) => WorkOrderAttachments.fromJson(e)).toList(), + workOrderAttachments: json["workOrderAttachments"] == null ? [] : List.from(json['workOrderAttachments']).map((e) => GenericAttachmentModel.fromWorkOrderJson(e)).toList(), returnToService: json["returnToService"], serviceType: json["serviceType"] == null ? null : Lookup.fromJson(json["serviceType"]), failureReasone: json["failureReasone"] == null ? null : Lookup.fromJson(json["failureReasone"]), @@ -286,7 +287,7 @@ class WorkOrderData { "edd": edd, 'mrNo': mrNo, 'exchangeCost': exchangeCost, - "workOrderAttachments": workOrderAttachments.map((e) => e.toJson()).toList(), + "workOrderAttachments": workOrderAttachments.map((e) => e.toWorkOrderJson() ?? {}).toList(), "returnToService": returnToService, "serviceType": serviceType?.toJson(), "failureReasone": failureReasone?.toJson(), @@ -503,7 +504,7 @@ class ActivitySparePart { double? installQty; double? returnQty; String? comment; - List? acitiySparePartAttachments; + List? acitiySparePartAttachments; ActivitySparePart({this.id, this.partCatalogItem, this.quantity, this.installQty, this.returnQty, this.comment, this.acitiySparePartAttachments}); @@ -515,9 +516,9 @@ class ActivitySparePart { returnQty = json['returnQty']; comment = json['comment']; if (json['acitiySparePartAttachments'] != null) { - acitiySparePartAttachments = []; + acitiySparePartAttachments = []; json['acitiySparePartAttachments'].forEach((v) { - acitiySparePartAttachments!.add(SparePartAttachments.fromJson(v)); + acitiySparePartAttachments!.add(GenericAttachmentModel.fromJson(v)); }); } } @@ -533,7 +534,7 @@ class ActivitySparePart { data['returnQty'] = returnQty; data['comment'] = comment; if (acitiySparePartAttachments != null) { - data['acitiySparePartAttachments'] = acitiySparePartAttachments!.map((v) => v.toJson()).toList(); + data['acitiySparePartAttachments'] = acitiySparePartAttachments!.map((v) => v?.toJson() ?? {}).toList(); } return data; } diff --git a/lib/models/plan_preventive_visit/plan_preventive_visit_model.dart b/lib/models/plan_preventive_visit/plan_preventive_visit_model.dart index b8f5fd94..99a51444 100644 --- a/lib/models/plan_preventive_visit/plan_preventive_visit_model.dart +++ b/lib/models/plan_preventive_visit/plan_preventive_visit_model.dart @@ -1,9 +1,12 @@ +import 'dart:developer'; import 'dart:io'; import 'package:flutter/widgets.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/helper_data_models/spare_part/activity_spare_part_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/service_request/supplier_details.dart'; import 'package:test_sa/models/timer_model.dart'; @@ -42,13 +45,22 @@ class PlanPreventiveVisit { Lookup? safety; String? engSignature; String? nurseSignature; - List? preventiveVisitAttachments; + List? preventiveVisitAttachments; List? attachments = []; List? preventiveVisitCalibrations; List? preventiveVisitChecklists; List? preventiveVisitKits; List? preventiveVisitTimers; List? preventiveVisitSuppliers; + List? activities; + num? sparePartCost; + num? labourCost; + num? travelCost; + num? qAmount; + String? prNo; + String? poNo; + String? mrNo; + num? exchangeCost; TimerModel? tbsTimer = TimerModel(); List? timerModelList = []; TimerModel? ppMTimePicker; @@ -95,6 +107,15 @@ class PlanPreventiveVisit { this.preventiveVisitTimers, this.timerModelList, this.ppMTimePicker, + this.activities, + this.labourCost, + this.sparePartCost, + this.travelCost, + this.qAmount, + this.prNo, + this.poNo, + this.mrNo, + this.exchangeCost, this.preventiveVisitSuppliers}); PlanPreventiveVisit.fromJson(Map json) { @@ -131,10 +152,18 @@ class PlanPreventiveVisit { safety = json['safety'] != null ? Lookup.fromJson(json['safety']) : null; engSignature = json['engSignature']; nurseSignature = json['nurseSignature']; + travelCost = json['travelCost']; + sparePartCost = json['sparePartCost']; + labourCost = json['laborCost']; + qAmount = json['qAmount']; + prNo = json['prNo']; + poNo = json['poNo']; + mrNo = json['mrNo']; + exchangeCost = json['exchangeCost']; if (json['preventiveVisitAttachments'] != null) { - preventiveVisitAttachments = []; + preventiveVisitAttachments = []; json['preventiveVisitAttachments'].forEach((v) { - preventiveVisitAttachments!.add(PreventiveVisitAttachments.fromJson(v)); + preventiveVisitAttachments!.add(GenericAttachmentModel.fromPreventiveVisitJson(v)); }); } if (json['preventiveVisitCalibrations'] != null) { @@ -167,6 +196,12 @@ class PlanPreventiveVisit { preventiveVisitSuppliers!.add(PreventiveVisitSuppliers.fromJson(v)); }); } + if (json['activitySparePartsPPM'] != null) { + activities = []; + json['activitySparePartsPPM'].forEach((v) { + activities!.add(PMSparePartActivityModel.fromJson(v)); + }); + } } Map toJson({required int status}) { @@ -183,53 +218,9 @@ class PlanPreventiveVisit { data['safetyId'] = safety?.id; data['engSignature'] = engSignature; data['nurseSignature'] = nurseSignature; - // - // if (asset != null) { - // data['asset'] = asset!.toJson(); - // } - // data['visitNo'] = visitNo; - // data['planNo'] = planNo; - // data['planName'] = planName; - // data['nextPMDate'] = nextPMDate; - // data['assetName'] = assetName; - // data['model'] = model; - // data['manufacturer'] = manufacturer; - // data['supplierName'] = supplierName; - // data['siteName'] = siteName; - // data['buildingName'] = buildingName; - // data['floorName'] = floorName; - // data['departmentName'] = departmentName; - // data['roomName'] = roomName; - // data['fromDate'] = fromDate; - // data['toDate'] = toDate; - // if (assignedEmployee != null) { - // data['assignedEmployee'] = assignedEmployee!.toJson(); - // } - // data['acutalDateOfVisit'] = acutalDateOfVisit; - // if (typeOfService != null) { - // data['typeOfService'] = typeOfService!.toJson(); - // } - // if (visitStatus != null) { - // data['visitStatus'] = visitStatus!.toJson(); - // } - // data['travelingHours'] = travelingHours; - // data['comments'] = comments; - // data['executionTimeFrame'] = executionTimeFrame; - // if (taskStatus != null) { - // data['taskStatus'] = taskStatus!.toJson(); - // } - // if (deviceStatus != null) { - // data['deviceStatus'] = deviceStatus!.toJson(); - // } - // data['assetAvailability'] = assetAvailability; - // if (safety != null) { - // data['safety'] = safety!.toJson(); - // } - // data['engSignature'] = engSignature; - // data['nurseSignature'] = nurseSignature; if (preventiveVisitAttachments != null) { - data['preventiveVisitAttachments'] = preventiveVisitAttachments!.map((v) => v.toJson()).toList(); + data['preventiveVisitAttachments'] = preventiveVisitAttachments!.map((v) => v.toPreventiveVisitJson()).toList(); } if (preventiveVisitCalibrations != null) { data['preventiveVisitCalibrations'] = preventiveVisitCalibrations!.map((v) => v.toJson()).toList(); @@ -246,14 +237,12 @@ class PlanPreventiveVisit { if (preventiveVisitSuppliers != null) { data['preventiveVisitSuppliers'] = preventiveVisitSuppliers!.map((v) => v.toJson()).toList(); } + if (activities != null) { + data['activitySparePartsPPM'] = activities!.map((v) => v.toJson()).toList(); + } return data; } - bool _isLocalUrl(String url) { - if (url.isEmpty != false) return false; - return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\'); - } - Future validate(BuildContext context) async { if (visitStatus?.id == null) { await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.status}"); @@ -263,10 +252,6 @@ class PlanPreventiveVisit { await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.actualDate}"); return false; } - // if (expectedDate == null) { - // await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.visitDate}"); - // return false; - // } if (tbsTimer?.startAt == null) { await Fluttertoast.showToast(msg: "Working Hours Required"); return false; @@ -276,11 +261,6 @@ class PlanPreventiveVisit { return false; } - // if (externalEngineerTimer?.startAt != null && externalEngineerTimer?.endAt == null) { - // await Fluttertoast.showToast(msg: "Please Stop External Engineer Timer"); - // return false; - // } - return true; } @@ -290,276 +270,6 @@ class PlanPreventiveVisit { } } -// class PlanPreventiveVisit { -// String? id; -// String? visitNo; -// Asset? asset; -// String? planNo; -// String? planName; -// String? nextPMDate; -// String? assetName; -// String? model; -// String? manufacturer; -// String? supplierName; -// String? siteName; -// String? buildingName; -// String? floorName; -// String? departmentName; -// String? roomName; -// String? fromDate; -// String? toDate; -// AssignedEmployee? assignedEmployee; -// String? acutalDateOfVisit; -// TypeOfService? typeOfService; -// VisitStatus? visitStatus; -// String? travelingHours; -// String? comments; -// int? executionTimeFrame; -// Lookup? taskStatus; -// String? deviceStatus; -// Lookup? assetAvailability; -// Lookup? safety; -// String? engSignature; -// String? nurseSignature; -// List? preventiveVisitAttachments; -// List? preventiveVisitCalibrations; -// List? preventiveVisitChecklists; -// List? preventiveVisitKits; -// List? preventiveVisitTimers; -// List? preventiveVisitSuppliers; -// TimerModel? tbsTimer = TimerModel(); -// -// PlanPreventiveVisit( -// {this.id, -// this.visitNo, -// this.asset, -// this.planNo, -// this.planName, -// this.nextPMDate, -// this.assetName, -// this.model, -// this.manufacturer, -// this.supplierName, -// this.siteName, -// this.buildingName, -// this.floorName, -// this.departmentName, -// this.roomName, -// this.fromDate, -// this.toDate, -// this.assignedEmployee, -// this.acutalDateOfVisit, -// this.typeOfService, -// this.visitStatus, -// this.travelingHours, -// this.comments, -// this.executionTimeFrame, -// this.taskStatus, -// this.deviceStatus, -// this.assetAvailability, -// this.safety, -// this.engSignature, -// this.nurseSignature, -// this.preventiveVisitAttachments, -// this.preventiveVisitCalibrations, -// this.preventiveVisitChecklists, -// this.preventiveVisitKits, -// this.preventiveVisitTimers, -// this.preventiveVisitSuppliers}); -// -// PlanPreventiveVisit.fromJson(Map json) { -// id = json['id']; -// visitNo = json['visitNo']; -// asset = json['asset'] != null ? Asset.fromJson(json['asset']) : null; -// planNo = json['planNo']; -// planName = json['planName']; -// nextPMDate = json['nextPMDate']; -// assetName = json['assetName']; -// model = json['model']; -// manufacturer = json['manufacturer']; -// supplierName = json['supplierName']; -// siteName = json['siteName']; -// buildingName = json['buildingName']; -// floorName = json['floorName']; -// departmentName = json['departmentName']; -// roomName = json['roomName']; -// fromDate = json['fromDate']; -// toDate = json['toDate']; -// assignedEmployee = json['assignedEmployee'] != null ? AssignedEmployee.fromJson(json['assignedEmployee']) : null; -// acutalDateOfVisit = json['acutalDateOfVisit']; -// typeOfService = json['typeOfService'] != null ? TypeOfService.fromJson(json['typeOfService']) : null; -// visitStatus = json['visitStatus'] != null ? VisitStatus.fromJson(json['visitStatus']) : null; -// travelingHours = json['travelingHours']; -// comments = json['comments']; -// executionTimeFrame = json['executionTimeFrame']; -// taskStatus = json['taskStatus']; -// deviceStatus = json['deviceStatus']; -// assetAvailability = json['assetAvailability']; -// safety = json['safety']; -// engSignature = json['engSignature']; -// nurseSignature = json['nurseSignature']; -// if (json['preventiveVisitAttachments'] != null) { -// preventiveVisitAttachments = []; -// json['preventiveVisitAttachments'].forEach((v) { -// preventiveVisitAttachments!.add(PreventiveVisitChecklists.fromJson(v)); -// }); -// } -// if (json['preventiveVisitCalibrations'] != null) { -// preventiveVisitCalibrations = []; -// json['preventiveVisitCalibrations'].forEach((v) { -// preventiveVisitCalibrations!.add( PreventiveVisitChecklists.fromJson(v)); -// }); -// } -// if (json['preventiveVisitChecklists'] != null) { -// preventiveVisitChecklists = []; -// json['preventiveVisitChecklists'].forEach((v) { -// preventiveVisitChecklists!.add( PreventiveVisitChecklists.fromJson(v)); -// }); -// } -// if (json['preventiveVisitKits'] != null) { -// preventiveVisitKits = []; -// json['preventiveVisitKits'].forEach((v) { -// preventiveVisitKits!.add( PreventiveVisitChecklists.fromJson(v)); -// }); -// } -// if (json['preventiveVisitTimers'] != null) { -// preventiveVisitTimers = []; -// json['preventiveVisitTimers'].forEach((v) { -// preventiveVisitTimers!.add( PreventiveVisitTimers.fromJson(v)); -// }); -// } -// if (json['preventiveVisitSuppliers'] != null) { -// preventiveVisitSuppliers = []; -// json['preventiveVisitSuppliers'].forEach((v) { -// preventiveVisitSuppliers!.add( PreventiveVisitChecklists.fromJson(v)); -// }); -// } -// } -// -// Map toJson() { -// final Map data = Map(); -// data['id'] = this.id; -// data['visitNo'] = this.visitNo; -// if (this.asset != null) { -// data['asset'] = this.asset!.toJson(); -// } -// data['planNo'] = this.planNo; -// data['planName'] = this.planName; -// data['nextPMDate'] = this.nextPMDate; -// data['assetName'] = this.assetName; -// data['model'] = this.model; -// data['manufacturer'] = this.manufacturer; -// data['supplierName'] = this.supplierName; -// data['siteName'] = this.siteName; -// data['buildingName'] = this.buildingName; -// data['floorName'] = this.floorName; -// data['departmentName'] = this.departmentName; -// data['roomName'] = this.roomName; -// data['fromDate'] = this.fromDate; -// data['toDate'] = this.toDate; -// if (this.assignedEmployee != null) { -// data['assignedEmployee'] = this.assignedEmployee!.toJson(); -// } -// data['acutalDateOfVisit'] = this.acutalDateOfVisit; -// if (this.typeOfService != null) { -// data['typeOfService'] = this.typeOfService!.toJson(); -// } -// if (this.visitStatus != null) { -// data['visitStatus'] = this.visitStatus!.toJson(); -// } -// data['travelingHours'] = this.travelingHours; -// data['comments'] = this.comments; -// data['executionTimeFrame'] = this.executionTimeFrame; -// data['taskStatus'] = this.taskStatus; -// data['deviceStatus'] = this.deviceStatus; -// data['assetAvailability'] = this.assetAvailability; -// data['safety'] = this.safety; -// data['engSignature'] = this.engSignature; -// data['nurseSignature'] = this.nurseSignature; -// if (this.preventiveVisitAttachments != null) { -// data['preventiveVisitAttachments'] = this.preventiveVisitAttachments!.map((v) => v.toJson()).toList(); -// } -// if (this.preventiveVisitCalibrations != null) { -// data['preventiveVisitCalibrations'] = this.preventiveVisitCalibrations!.map((v) => v.toJson()).toList(); -// } -// if (this.preventiveVisitChecklists != null) { -// data['preventiveVisitChecklists'] = this.preventiveVisitChecklists!.map((v) => v.toJson()).toList(); -// } -// if (this.preventiveVisitKits != null) { -// data['preventiveVisitKits'] = this.preventiveVisitKits!.map((v) => v.toJson()).toList(); -// } -// if (this.preventiveVisitTimers != null) { -// data['preventiveVisitTimers'] = this.preventiveVisitTimers!.map((v) => v.toJson()).toList(); -// } -// if (this.preventiveVisitSuppliers != null) { -// data['preventiveVisitSuppliers'] = this.preventiveVisitSuppliers!.map((v) => v.toJson()).toList(); -// } -// return data; -// } -// -// bool _isLocalUrl(String url) { -// if (url.isEmpty != false) return false; -// return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\'); -// } -// -// Future validate(BuildContext context) async { -// if (visitStatus?.id == null) { -// await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.status}"); -// return false; -// } -// if (acutalDateOfVisit == null) { -// await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.actualDate}"); -// return false; -// } -// // if (expectedDate == null) { -// // await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.visitDate}"); -// // return false; -// // } -// if (tbsTimer?.startAt == null) { -// await Fluttertoast.showToast(msg: "Working Hours Required"); -// return false; -// } -// if (tbsTimer?.endAt == null) { -// await Fluttertoast.showToast(msg: "Please Stop The Timer"); -// return false; -// } -// -// // if (externalEngineerTimer?.startAt != null && externalEngineerTimer?.endAt == null) { -// // await Fluttertoast.showToast(msg: "Please Stop External Engineer Timer"); -// // return false; -// // } -// -// return true; -// } -// -// void removeEmptyObjects() { -// // if (vCalibrationTools?.isNotEmpty ?? false) vCalibrationTools!.removeWhere((element) => element.assetId == null && element.calibrationDateOfTesters == null); -// // if (vKits?.isNotEmpty ?? false) vKits!.removeWhere((element) => element.partName == null && element.partNumber == null); -// } -// } - -// class Asset { -// num? id; -// String? assetNumber; -// String? assetSerialNo; -// -// Asset({this.id, this.assetNumber, this.assetSerialNo}); -// -// Asset.fromJson(Map json) { -// id = json['id']; -// assetNumber = json['assetNumber']; -// assetSerialNo = json['assetSerialNo']; -// } -// -// Map toJson() { -// final Map data = Map(); -// data['id'] = this.id; -// data['assetNumber'] = this.assetNumber; -// data['assetSerialNo'] = this.assetSerialNo; -// return data; -// } -// } - class AssignedEmployee { String? userId; String? userName; @@ -588,50 +298,6 @@ class AssignedEmployee { } } -// class Lookup { -// int? id; -// String? name; -// int? value; -// -// Lookup({this.id, this.name, this.value}); -// -// Lookup.fromJson(Map json) { -// id = json['id']; -// name = json['name']; -// value = json['value']; -// } -// -// Map toJson() { -// final Map data = Map(); -// data['id'] = this.id; -// data['name'] = this.name; -// data['value'] = this.value; -// return data; -// } -// } - -// class VisitStatus { -// int? id; -// String? name; -// int? value; -// -// VisitStatus({this.id, this.name, this.value}); -// -// VisitStatus.fromJson(Map json) { -// id = json['id']; -// name = json['name']; -// value = json['value']; -// } -// -// Map toJson() { -// final Map data = Map(); -// data['id'] = this.id; -// data['name'] = this.name; -// data['value'] = this.value; -// return data; -// } -// } - class PreventiveVisitChecklists { int? id; Lookup? taskStatus; @@ -655,9 +321,6 @@ class PreventiveVisitChecklists { data['taskStatusId'] = taskStatus?.id; data['taskComment'] = taskComment; data['measuredValue'] = measuredValue; - // if (instructionText != null) { - // data['instructionText'] = instructionText!.toJson(); - // } return data; } } @@ -706,25 +369,6 @@ class PreventiveVisitTimers { } } -class PreventiveVisitAttachments { - int? id; - String? attachmentName; - - PreventiveVisitAttachments({this.id, this.attachmentName}); - - PreventiveVisitAttachments.fromJson(Map json) { - id = json['id']; - attachmentName = json['attachmentName']; - } - - Map toJson() { - final Map data = {}; - data['id'] = id; - data['attachmentName'] = attachmentName; - return data; - } -} - class PreventiveVisitCalibrations { num? id; Asset? asset; @@ -742,7 +386,6 @@ class PreventiveVisitCalibrations { final Map data = {}; data['id'] = id; if (asset != null) { - // data['asset'] = asset!.toJson(); data['assetId'] = asset?.id; } data['calibrationDateOfTesters'] = calibrationDateOfTesters; @@ -774,11 +417,9 @@ class PreventiveVisitSuppliers { final Map data = {}; data['id'] = id; if (supplier != null) { - // data['supplier'] = supplier!.toJson(); data['supplierId'] = supplier?.id; } if (suppPerson != null) { - // data['suppPerson'] = suppPerson!.toJson(); data['suppPersonId'] = suppPerson?.id; } data['startDateTime'] = startDateTime?.toIso8601String(); @@ -788,171 +429,6 @@ class PreventiveVisitSuppliers { } } -// class Supplier { -// int? id; -// String? suppliername; -// String? name; -// String? website; -// String? email; -// String? code; -// int? suppNo; -// String? suppStatusId; -// String? cityId; -// String? person; -// String? comment; -// String? zipcode; -// String? contact; -// List? telephones; -// List? faxes; -// List? addresses; -// List? attachments; -// List? suppPersons; -// List? suppTCodes; -// -// Supplier( -// {this.id, -// this.suppliername, -// this.name, -// this.website, -// this.email, -// this.code, -// this.suppNo, -// this.suppStatusId, -// this.cityId, -// this.person, -// this.comment, -// this.zipcode, -// this.contact, -// this.telephones, -// this.faxes, -// this.addresses, -// this.attachments, -// this.suppPersons, -// this.suppTCodes}); -// -// Supplier.fromJson(Map json) { -// id = json['id']; -// suppliername = json['suppliername']; -// name = json['name']; -// website = json['website']; -// email = json['email']; -// code = json['code']; -// suppNo = json['suppNo']; -// suppStatusId = json['suppStatusId']; -// cityId = json['cityId']; -// person = json['person']; -// comment = json['comment']; -// zipcode = json['zipcode']; -// contact = json['contact']; -// if (json['telephones'] != null) { -// telephones = []; -// json['telephones'].forEach((v) { -// telephones!.add(v); -// }); -// } -// if (json['faxes'] != null) { -// faxes = []; -// json['faxes'].forEach((v) { -// faxes!.add(v); -// }); -// } -// if (json['addresses'] != null) { -// addresses = []; -// json['addresses'].forEach((v) { -// addresses!.add(v); -// }); -// } -// if (json['attachments'] != null) { -// attachments = []; -// json['attachments'].forEach((v) { -// attachments!.add(v); -// }); -// } -// if (json['suppPersons'] != null) { -// suppPersons = []; -// json['suppPersons'].forEach((v) { -// suppPersons!.add(SuppPersons.fromJson(v)); -// }); -// } -// if (json['suppTCodes'] != null) { -// suppTCodes = []; -// json['suppTCodes'].forEach((v) { -// suppTCodes!.add(v); -// }); -// } -// } -// -// Map toJson() { -// final Map data = {}; -// data['id'] = id; -// data['suppliername'] = suppliername; -// data['name'] = name; -// data['website'] = website; -// data['email'] = email; -// data['code'] = code; -// data['suppNo'] = suppNo; -// data['suppStatusId'] = suppStatusId; -// data['cityId'] = cityId; -// data['person'] = person; -// data['comment'] = comment; -// data['zipcode'] = zipcode; -// data['contact'] = contact; -// if (telephones != null) { -// data['telephones'] = telephones!.map((v) => v).toList(); -// } -// if (faxes != null) { -// data['faxes'] = faxes!.map((v) => v).toList(); -// } -// if (addresses != null) { -// data['addresses'] = addresses!.map((v) => v).toList(); -// } -// if (attachments != null) { -// data['attachments'] = attachments!.map((v) => v).toList(); -// } -// if (suppPersons != null) { -// data['suppPersons'] = suppPersons!.map((v) => v.toJson()).toList(); -// } -// if (suppTCodes != null) { -// data['suppTCodes'] = suppTCodes!.map((v) => v).toList(); -// } -// return data; -// } -// } - -// class SuppPersons { -// int? id; -// int? supplierId; -// String? personName; -// int? personRoleId; -// String? contact; -// String? externalEngCode; -// String? email; -// -// SuppPersons({this.id, this.supplierId, this.personName, this.personRoleId, this.contact, this.externalEngCode, this.email}); -// -// SuppPersons.fromJson(Map json) { -// id = json['id']; -// supplierId = json['supplierId']; -// personName = json['personName']; -// personRoleId = json['personRoleId']; -// contact = json['contact']; -// externalEngCode = json['externalEngCode']; -// email = json['email']; -// } -// -// Map toJson() { -// final Map data = Map(); -// data['id'] = this.id; -// data['supplierId'] = this.supplierId; -// data['personName'] = this.personName; -// data['personRoleId'] = this.personRoleId; -// data['contact'] = this.contact; -// data['externalEngCode'] = this.externalEngCode; -// data['email'] = this.email; -// return data; -// } -// } - class PreventiveVisitKits { int? id; PartCatalogItem? partCatalogItem; @@ -999,3 +475,76 @@ class PartCatalogItem { return data; } } + +class PMSparePartActivityModel { + int? id; + PartCatalogItem? partCatalogItem; + Lookup? activityStatus; + double? quantity; + double? installQty; + double? returnQty; + String? comment; + dynamic price; + + List activitySparePartPPMAttachments; + + PMSparePartActivityModel({ + this.id, + this.partCatalogItem, + this.activityStatus, + this.quantity, + this.installQty, + this.returnQty, + this.comment, + this.price, + List? activitySparePartPPMAttachments, + }) : activitySparePartPPMAttachments = activitySparePartPPMAttachments ?? []; + + PMSparePartActivityModel.fromJson(Map json) : activitySparePartPPMAttachments = [] { + id = json['id']; + + partCatalogItem = json['partCatalogItem'] != null ? PartCatalogItem.fromJson(json['partCatalogItem']) : null; + + activityStatus = json['activityStatus'] != null ? Lookup.fromJson(json['activityStatus']) : null; + + quantity = json['quantity']?.toDouble(); + installQty = json['installQty']?.toDouble(); + returnQty = json['returnQty']?.toDouble(); + + comment = json['comment']; + price = json['price']; + + // Handle typo in API response: "acitiySparePartPPMAttachments" instead of "activitySparePartPPMAttachments" + final attachmentsKey = json.containsKey('acitiySparePartPPMAttachments') ? 'acitiySparePartPPMAttachments' : 'activitySparePartPPMAttachments'; + + activitySparePartPPMAttachments = json[attachmentsKey] == null ? [] : List.from(json[attachmentsKey]).map((e) => GenericAttachmentModel.fromJson(e)).toList(); + } + + Map toJson() { + final Map data = {}; + + data['id'] = id; + + if (partCatalogItem != null) { + data['partCatalogItem'] = partCatalogItem!.toJson(); + } + + if (activityStatus != null) { + data['activityStatus'] = activityStatus!.toJson(); + } + + data['quantity'] = quantity; + data['installQty'] = installQty; + data['returnQty'] = returnQty; + data['comment'] = comment; + data['price'] = price; + + data['activitySparePartPPMAttachments'] = activitySparePartPPMAttachments + .map( + (v) => v.toJson(), + ) + .toList(); + + return data; + } +} diff --git a/lib/models/ppm/ppm.dart b/lib/models/ppm/ppm.dart index 44090346..5cdee63f 100644 --- a/lib/models/ppm/ppm.dart +++ b/lib/models/ppm/ppm.dart @@ -5,6 +5,7 @@ import 'dart:typed_data'; import 'package:flutter/cupertino.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/ppm/ppm_attachment.dart'; import 'package:test_sa/models/ppm/ppm_calibration_tools.dart'; import 'package:test_sa/models/ppm/ppm_check_list.dart'; @@ -173,7 +174,7 @@ class Ppm { if (json['vAttachments'] != null) { files = []; json['vAttachments'].forEach((v) { - files!.add(PpmAttachments.fromJson(v)); + files!.add(GenericAttachmentModel.fromPpmJson(v)); }); } visitStatusId = json['visitStatusId']; @@ -286,7 +287,7 @@ class Ppm { List? vKits; List? vContacts; List? vChecklists; - List? files; + List? files; num? visitStatusId; List? visitTimers; @@ -380,7 +381,7 @@ class Ppm { List? vKits, List? vContacts, List? vChecklists, - List? files, + List? files, num? visitStatusId, List? visitTimers, String? startDate, @@ -574,7 +575,7 @@ class Ppm { if (files?.isNotEmpty ?? false) { map["vAttachments"] = files! .map((file) => - {"attachmentName": _isLocalUrl(file.attachmentName!) ? ("${file.attachmentName!.split("/").last}|${base64Encode(File(file.attachmentName!).readAsBytesSync())}") : file.attachmentName}) + {"attachmentName": _isLocalUrl(file.name!) ? ("${file.name!.split("/").last}|${base64Encode(File(file.name!).readAsBytesSync())}") : file.name}) .toList(); } map['visitStatusId'] = visitStatusId; diff --git a/lib/models/ppm/ppm_attachment.dart b/lib/models/ppm/ppm_attachment.dart index e1e15df8..b0d7df0e 100644 --- a/lib/models/ppm/ppm_attachment.dart +++ b/lib/models/ppm/ppm_attachment.dart @@ -1,40 +1,42 @@ -class PpmAttachments { - PpmAttachments({ - this.id, - this.visitId, - this.attachmentName, - this.attachmentURL, - }); +//TODO need to delete this - PpmAttachments.fromJson(dynamic json) { - id = json['id']; - visitId = json['visitId']; - attachmentName = json['attachmentName'] ?? json['attachmentURL']; // Handle potential null and prioritize'attachmentName' - } - - num? id; // Now nullable - num? visitId; // Now nullable - String? attachmentName; // Now nullable - String? attachmentURL; // Now nullable - - PpmAttachments copyWith({ - num? id, - num? visitId, - String? attachmentName, - String? attachmentURL, - }) => - PpmAttachments( - id: id ?? this.id, - visitId: visitId ?? this.visitId, - attachmentName: attachmentName ?? this.attachmentName,attachmentURL: attachmentURL ?? this.attachmentURL, - ); - - Map toJson() { - final map = {}; - map['id'] = id; - map['visitId'] = visitId; - map['attachmentName'] = attachmentName; - map['attachmentURL'] = attachmentURL; - return map; - } -} \ No newline at end of file +// class PpmAttachments { +// PpmAttachments({ +// this.id, +// this.visitId, +// this.attachmentName, +// this.attachmentURL, +// }); +// +// PpmAttachments.fromJson(dynamic json) { +// id = json['id']; +// visitId = json['visitId']; +// attachmentName = json['attachmentName'] ?? json['attachmentURL']; // Handle potential null and prioritize'attachmentName' +// } +// +// num? id; // Now nullable +// num? visitId; // Now nullable +// String? attachmentName; // Now nullable +// String? attachmentURL; // Now nullable +// +// PpmAttachments copyWith({ +// num? id, +// num? visitId, +// String? attachmentName, +// String? attachmentURL, +// }) => +// PpmAttachments( +// id: id ?? this.id, +// visitId: visitId ?? this.visitId, +// attachmentName: attachmentName ?? this.attachmentName,attachmentURL: attachmentURL ?? this.attachmentURL, +// ); +// +// Map toJson() { +// final map = {}; +// map['id'] = id; +// map['visitId'] = visitId; +// map['attachmentName'] = attachmentName; +// map['attachmentURL'] = attachmentURL; +// return map; +// } +// } \ No newline at end of file diff --git a/lib/models/service_request/search_work_order.dart b/lib/models/service_request/search_work_order.dart index 41f282cf..611339dc 100644 --- a/lib/models/service_request/search_work_order.dart +++ b/lib/models/service_request/search_work_order.dart @@ -1,6 +1,7 @@ import 'dart:typed_data'; 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/models/service_request/service_report.dart'; import 'package:test_sa/models/service_request/spare_parts.dart'; @@ -10,7 +11,6 @@ import 'package:test_sa/models/service_request/wo_call_request.dart'; import 'package:test_sa/models/service_request/wo_parent.dart'; import 'package:test_sa/models/timer_model.dart'; -import '../../attachment.dart'; import '../fault_description.dart'; import '../new_models/assigned_employee.dart'; import '../new_models/assistant_employee.dart'; @@ -41,12 +41,12 @@ class SearchWorkOrder { this.travelingHours, this.travelingExpenses, this.faultDescription, - this.sparePartsWorkOrders, - this.reviewComment, - this.comment, - this.attachmentsWorkOrder, - this.equipmentStatus, - this.suppEngineerWorkOrders, + this.sparePartsWorkOrders, + this.reviewComment, + this.comment, + List? attachmentsWorkOrder, + this.equipmentStatus, + this.suppEngineerWorkOrders, this.engSignature, this.nurseSignature, this.woParentDto, @@ -106,7 +106,7 @@ class SearchWorkOrder { if (json['attachmentsWorkOrder'] != null) { attachmentsWorkOrder = []; json['attachmentsWorkOrder'].forEach((v) { - attachmentsWorkOrder!.add(Attachment.fromJson(v)); + attachmentsWorkOrder!.add(GenericAttachmentModel.fromJson(v)); }); } equipmentStatus = json['equipmentStatus'] != null ? Lookup.fromJson(json['equipmentStatus']) : null; @@ -155,8 +155,8 @@ class SearchWorkOrder { sparePartsWorkOrders = (wo.sparePartsWorkOrders ?? sparePartsWorkOrders)?.map((e) => SparePartsWorkOrders.fromJson(e.toJson() ?? {})).toList() ?? []; reviewComment = wo.reviewComment ?? reviewComment; comment = wo.comment ?? comment; - attachmentsWorkOrder = (wo.attachmentsWorkOrder ?? attachmentsWorkOrder)?.map((e) => Attachment.fromJson(e.toJson() ?? {})).toList() ?? []; - equipmentStatus = Lookup.fromJson((wo.equipmentStatus ?? equipmentStatus)?.toJson() ?? {}); + attachmentsWorkOrder = (wo.attachmentsWorkOrder ?? attachmentsWorkOrder)?.map((e) => GenericAttachmentModel.fromJson(e?.toJson() ?? {})).toList() ?? []; + equipmentStatus = wo.equipmentStatus ?? equipmentStatus; suppEngineerWorkOrders = (wo.suppEngineerWorkOrders ?? suppEngineerWorkOrders)?.map((e) => SuppEngineerWorkOrders.fromJson(e.toJson() ?? {})).toList() ?? []; engSignature = wo.engSignature ?? engSignature; nurseSignature = wo.nurseSignature ?? nurseSignature; @@ -191,7 +191,7 @@ class SearchWorkOrder { List? sparePartsWorkOrders; String? reviewComment; String? comment; - List? attachmentsWorkOrder; + List? attachmentsWorkOrder; Lookup? equipmentStatus; List? suppEngineerWorkOrders; String? engSignature; @@ -233,7 +233,7 @@ class SearchWorkOrder { List? sparePartsWorkOrders, String? reviewComment, String? comment, - List? attachmentsWorkOrder, + List? attachmentsWorkOrder, Lookup? equipmentStatus, List? suppEngineerWorkOrders, String? engSignature, diff --git a/lib/models/service_request/service_report.dart b/lib/models/service_request/service_report.dart index 56a1da6f..e09c9ac8 100644 --- a/lib/models/service_request/service_report.dart +++ b/lib/models/service_request/service_report.dart @@ -5,6 +5,7 @@ import 'package:fluttertoast/fluttertoast.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/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/service_request/spare_parts.dart'; import 'package:test_sa/models/service_request/supp_engineer_work_orders.dart'; @@ -13,7 +14,6 @@ import 'package:test_sa/models/service_request/wo_call_request.dart'; import 'package:test_sa/models/service_request/wo_parent.dart'; import 'package:test_sa/models/timer_model.dart'; -import '../../attachment.dart'; import '../device/asset.dart'; import '../fault_description.dart'; import '../new_models/assigned_employee.dart'; @@ -118,7 +118,7 @@ class ServiceReport { attachmentsWorkOrder = []; json['attachmentsWorkOrder'].forEach((v) { v["name"] = URLs.getFileUrl(v["name"]); - attachmentsWorkOrder!.add(Attachment.fromJson(v)); + attachmentsWorkOrder!.add(GenericAttachmentModel.fromJson(v)); }); } equipmentStatus = json['equipmentStatus'] != null ? Lookup.fromJson(json['equipmentStatus']) : null; @@ -163,7 +163,7 @@ class ServiceReport { List? sparePartsWorkOrders; String? reviewComment; String? comment; - List? attachmentsWorkOrder; + List? attachmentsWorkOrder; Lookup? equipmentStatus; List? suppEngineerWorkOrders; String? engSignature; @@ -204,7 +204,7 @@ class ServiceReport { List? sparePartsWorkOrders, String? reviewComment, String? comment, - List? attachmentsWorkOrder, + List? attachmentsWorkOrder, Lookup? equipmentStatus, List? suppEngineerWorkOrders, String? engSignature, @@ -311,7 +311,7 @@ class ServiceReport { map['reviewComment'] = reviewComment; map['comment'] = comment; if (attachmentsWorkOrder != null) { - map['attachmentsWorkOrder'] = attachmentsWorkOrder!.map((v) => {"name": v.name!.getFileName}).toList(); + map['attachmentsWorkOrder'] = attachmentsWorkOrder!.where((v) => v?.name != null).map((v) => {"name": v!.name!.getFileName}).toList(); } if (equipmentStatus != null) { map['equipmentStatus'] = equipmentStatus!.toJson(); diff --git a/lib/models/service_request/supplier_details.dart b/lib/models/service_request/supplier_details.dart index 884206ad..06447c00 100644 --- a/lib/models/service_request/supplier_details.dart +++ b/lib/models/service_request/supplier_details.dart @@ -1,4 +1,5 @@ import 'package:test_sa/models/base.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; class SupplierDetails extends Base { SupplierDetails({ @@ -60,7 +61,7 @@ class SupplierDetails extends Base { if (json['attachments'] != null) { attachments = []; json['attachments'].forEach((v) { - attachments!.add(Attachments.fromJson(v)); + attachments!.add(GenericAttachmentModel.fromSupplierJson(v)); }); } if (json['suppPersons'] != null) { @@ -93,7 +94,7 @@ class SupplierDetails extends Base { List? telephones; List? faxes; List? addresses; - List? attachments; + List? attachments; List? suppPersons; List? suppTCodes; @@ -114,7 +115,7 @@ class SupplierDetails extends Base { List? telephones, List? faxes, List? addresses, - List? attachments, + List? attachments, List? suppPersons, List? suppTCodes, }) => @@ -165,7 +166,7 @@ class SupplierDetails extends Base { map['addresses'] = addresses!.map((v) => v.toJson()).toList(); } if (attachments != null) { - map['attachments'] = attachments!.map((v) => v.toJson()).toList(); + map['attachments'] = attachments!.map((v) => v.toSupplierJson()).toList(); } if (suppPersons != null) { map['suppPersons'] = suppPersons!.map((v) => v.toJson()).toList(); @@ -283,48 +284,48 @@ class SuppPersons extends Base { } } -class Attachments { - Attachments({ - this.id, - this.supplierId, - this.attachmentName, - this.attachmentURL, - }); - - Attachments.fromJson(dynamic json) { - id = json['id']; - supplierId = json['supplierId']; - attachmentName = json['attachmentName']; - attachmentURL = json['attachmentURL']; - } - - num? id; - num? supplierId; - String? attachmentName; - String? attachmentURL; - - Attachments copyWith({ - num? id, - num? supplierId, - String? attachmentName, - String? attachmentURL, - }) => - Attachments( - id: id ?? this.id, - supplierId: supplierId ?? this.supplierId, - attachmentName: attachmentName ?? this.attachmentName, - attachmentURL: attachmentURL ?? this.attachmentURL, - ); - - Map toJson() { - final map = {}; - map['id'] = id; - map['supplierId'] = supplierId; - map['attachmentName'] = attachmentName; - map['attachmentURL'] = attachmentURL; - return map; - } -} +// class Attachments { +// Attachments({ +// this.id, +// this.supplierId, +// this.attachmentName, +// this.attachmentURL, +// }); +// +// Attachments.fromJson(dynamic json) { +// id = json['id']; +// supplierId = json['supplierId']; +// attachmentName = json['attachmentName']; +// attachmentURL = json['attachmentURL']; +// } +// +// num? id; +// num? supplierId; +// String? attachmentName; +// String? attachmentURL; +// +// Attachments copyWith({ +// num? id, +// num? supplierId, +// String? attachmentName, +// String? attachmentURL, +// }) => +// Attachments( +// id: id ?? this.id, +// supplierId: supplierId ?? this.supplierId, +// attachmentName: attachmentName ?? this.attachmentName, +// attachmentURL: attachmentURL ?? this.attachmentURL, +// ); +// +// Map toJson() { +// final map = {}; +// map['id'] = id; +// map['supplierId'] = supplierId; +// map['attachmentName'] = attachmentName; +// map['attachmentURL'] = attachmentURL; +// return map; +// } +// } class Addresses { Addresses({ diff --git a/lib/models/user.dart b/lib/models/user.dart index aa3389dc..608e0989 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -100,6 +100,8 @@ class User { return {"username": userName, "password": password, "fireBaseToken": FirebaseNotificationManger?.token ?? "", "notificationType": notificationType}; } + String get roleName => userRoles?.first.name ?? ""; + UsersTypes? get type { switch (userRoles?.first.value) { case "R-6": diff --git a/lib/modules/asset_delivery_module/helper_function.dart b/lib/modules/asset_delivery_module/helper_function.dart index ba1c2584..cbdb666f 100644 --- a/lib/modules/asset_delivery_module/helper_function.dart +++ b/lib/modules/asset_delivery_module/helper_function.dart @@ -35,6 +35,7 @@ class HelperFunction { builder: (context) => AssetDeliveryAttachmentView( tableItemId: deliveryTableItemId, attachmentType: result!.value, + documentType: Lookup(id: result.id, value: result.value, name: result.name), // viewOnly: viewOnly, attachmentList: list, ))); diff --git a/lib/modules/asset_delivery_module/pages/attachment_view.dart b/lib/modules/asset_delivery_module/pages/attachment_view.dart index fc9d8fbd..88355180 100644 --- a/lib/modules/asset_delivery_module/pages/attachment_view.dart +++ b/lib/modules/asset_delivery_module/pages/attachment_view.dart @@ -9,7 +9,9 @@ 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/enums/request_attachment_type_enum.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/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'; @@ -19,11 +21,14 @@ 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/item_views/info_header_widget.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; class AssetDeliveryAttachmentView extends StatefulWidget { final int? tableItemId; final int? attachmentType; + final Lookup? documentType; + // bool viewOnly = false; final List attachmentList; @@ -32,6 +37,7 @@ class AssetDeliveryAttachmentView extends StatefulWidget { required this.attachmentList, // this.viewOnly = false, this.attachmentType, + this.documentType, this.tableItemId, }); @@ -73,22 +79,21 @@ class _AssetDeliveryAttachmentViewState extends State URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []).toShadowContainer( + ? FilesList( + showAsListView: true, + types: _attachments.map((doc) { + final attachmentType = doc.documentType?.name ?? ''; + return attachmentType.isNotEmpty ? attachmentType : 'Asset Guide'; + }).toList(), + images: _attachments + .map( + (e) => URLs.getFileUrl(e.name ?? '') ?? '', + ) + .toList() ?? + []) + .toShadowContainer( context, borderRadius: 20, padding: 12, @@ -126,13 +143,13 @@ class _AssetDeliveryAttachmentViewState extends State _onSavePressed() async { - final List attachmentPayload = _attachments.map((item) { + 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, - ); + documentType: widget.documentType, + ).toAssetDeliveryJson(); }).toList(); showDialog( diff --git a/lib/modules/asset_delivery_module/provider/attachment_type_provider.dart b/lib/modules/asset_delivery_module/provider/attachment_type_provider.dart index 2ef16d0b..becc0696 100644 --- a/lib/modules/asset_delivery_module/provider/attachment_type_provider.dart +++ b/lib/modules/asset_delivery_module/provider/attachment_type_provider.dart @@ -1,10 +1,13 @@ 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/enums/request_attachment_type_enum.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/providers/loading_list_notifier.dart'; +///TODO need to remove this after verifying we need to use the same for all modules .. class AttachmentTypeLookupProvider extends LoadingListNotifier { @override Future getData({int? id}) async { @@ -31,3 +34,41 @@ class AttachmentTypeLookupProvider extends LoadingListNotifier { } } } + +class AttachmentTypeLookupProviderLatest extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading == true) return -2; + loading = true; + notifyListeners(); + int? lookupEnum = RequestAttachmentTypeEnumExtension.getLookupEnumIdFromId(id); + if (lookupEnum == null) { + log('Invalid request type id: $id'); + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + try { + log('Request type id: $id, Lookup enum: $lookupEnum'); + Response response = await ApiManager.instance.get( + '${URLs.getAttachmentTypesLookup}?lookupEnum=$lookupEnum', + useCache: true, + enableToastMessage: false, + ); + 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_inventory_module/models/asset_inventory_model.dart b/lib/modules/asset_inventory_module/models/asset_inventory_model.dart index 4a4e6587..c63f477f 100644 --- a/lib/modules/asset_inventory_module/models/asset_inventory_model.dart +++ b/lib/modules/asset_inventory_module/models/asset_inventory_model.dart @@ -1,5 +1,7 @@ import 'dart:developer'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/new_models/building.dart'; import 'package:test_sa/models/new_models/floor.dart'; import 'package:test_sa/models/new_models/room_model.dart'; @@ -106,7 +108,7 @@ class AssetInventoryModel { Department? department; Rooms? room; SupplierDetails? supplier; - List assetInventoryDetailAssetAttachments = []; + List assetInventoryDetailAssetAttachments = []; AssetInventoryModel({ this.id, @@ -195,10 +197,10 @@ class AssetInventoryModel { photo = json['photo']; photoOriginName = json['photoOriginName']; remarks = json['remarks']; - if (json['assetTransferAttachments'] != null) { + if (json['assetInventoryDetailAssetAttachments'] != null) { assetInventoryDetailAssetAttachments = []; json['assetInventoryDetailAssetAttachments'].forEach((v) { - assetInventoryDetailAssetAttachments.add(AssetInventoryDetailAssetAttachments.fromJson(v)); + assetInventoryDetailAssetAttachments.add(GenericAttachmentModel.fromAssetInventoryJson(v)); }); } @@ -240,9 +242,7 @@ class AssetInventoryModel { 'newSupplierName': newSupplierName, 'photo': photo, 'remarks': remarks, - 'assetInventoryDetailAssetAttachments': assetInventoryDetailAssetAttachments != null - ? assetInventoryDetailAssetAttachments!.map((v) => v.toJson()).toList() - : [], + 'assetInventoryDetailAssetAttachments': assetInventoryDetailAssetAttachments.map((v) => v.toInventoryJson() ?? {}).toList(), }; } @@ -307,39 +307,3 @@ class AssetInventoryModel { } -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_inventory_module/models/session_model.dart b/lib/modules/asset_inventory_module/models/session_model.dart index 8de8503b..ba18ab36 100644 --- a/lib/modules/asset_inventory_module/models/session_model.dart +++ b/lib/modules/asset_inventory_module/models/session_model.dart @@ -43,11 +43,9 @@ class SessionModel { 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(); } diff --git a/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart b/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart index 60a5c710..d90ec511 100644 --- a/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart +++ b/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart @@ -11,6 +11,7 @@ import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_mo import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/widgets/loaders/image_loader.dart'; +///TODO We are not showing attachment here we need to check this with backend team and flow . class AssetDetailCardView extends StatelessWidget { AssetInventoryModel assetInventoryModel; VoidCallback onDeletePress; diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart index 14f35072..17d47bf4 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart @@ -11,6 +11,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/models/enums/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/device/predict_device_model.dart'; import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; @@ -25,6 +26,7 @@ import 'package:test_sa/new_views/common_widgets/app_text_form_field.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/item_views/info_header_widget.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'; @@ -296,14 +298,12 @@ class _AssetInventoryFormViewState extends State { classificationWidget(label: _scannedAssetModel?.status), ], 12.height, - Text( - 'Attachments'.addTranslation, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.white936), - ), - 12.height, + AttachmentPicker( + moduleId: RequestAttachmentTypeEnum.assetInventory.id, label: context.translation.attachFiles, attachment: attachments, + showAsListView: true, buttonColor: AppColor.black10, onlyImages: false, buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), @@ -434,7 +434,7 @@ class _AssetInventoryFormViewState extends State { // try { for (var item in attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - _scannedAssetModel?.assetInventoryDetailAssetAttachments.add(AssetInventoryDetailAssetAttachments(id: item.id, name: fileName)); + _scannedAssetModel?.assetInventoryDetailAssetAttachments.add(GenericAttachmentModel(id: item.id, name: fileName, documentType: item.documentType)); } // // } catch (error) { // // print(error); diff --git a/lib/modules/cleaner_module/pages/one_time_task_preview_screen.dart b/lib/modules/cleaner_module/pages/one_time_task_preview_screen.dart index 19ef67fb..57433425 100644 --- a/lib/modules/cleaner_module/pages/one_time_task_preview_screen.dart +++ b/lib/modules/cleaner_module/pages/one_time_task_preview_screen.dart @@ -300,6 +300,7 @@ class OneTimeTaskPreviewScreen extends StatelessWidget { InfoHeader16Widget( 'Attachments', ), + 4.height, FilesList( images: taskData.attachments!.map((attachment) => URLs.getFileUrl(attachment.name ?? '') ?? '').toList(), showAsListView: true, diff --git a/lib/modules/cm_module/cm_detail_provider.dart b/lib/modules/cm_module/cm_detail_provider.dart index 9aa4aa4d..8f7ea659 100644 --- a/lib/modules/cm_module/cm_detail_provider.dart +++ b/lib/modules/cm_module/cm_detail_provider.dart @@ -260,15 +260,15 @@ class CMDetailProvider extends ChangeNotifier { } //upload workorder attachment by engineer.. - Future addWorkOrderAttachment({required int woId, required List attachments, required List otherAttachment}) async { + Future addWorkOrderAttachment({required int woId, required List attachments, required List otherAttachment}) async { try { - List woAttachments = []; + List woAttachments = []; if (otherAttachment.isNotEmpty) { woAttachments.addAll(otherAttachment); } for (var file in attachments) { String fileName = CMRequestUtils.isLocalUrl(file.name ?? '') ? ("${file.name ?? ''.split("/").last}|${base64Encode(File(file.name ?? '').readAsBytesSync())}") : file.name ?? ''; - woAttachments.add(WorkOrderAttachments(id: file.id, name: fileName, createdBy: file.createdBy)); + woAttachments.add(GenericAttachmentModel(id: file.id, name: fileName, createdBy: file.createdBy, documentType: file.documentType)); } isLoading = true; @@ -747,23 +747,16 @@ class CMDetailProvider extends ChangeNotifier { } } - Future updateActivitySparePart() async { - isLoading = true; + Future updateActivitySparePart() async { Response response; try { response = await ApiManager.instance.post(URLs.updateActivitySparePartUrl, body: sparePartHelperModel!.toJson()); - stateCode = response.statusCode; - isLoading = false; - notifyListeners(); if (stateCode == 200) { - return true; + return ""; } - return false; + return "Failed, Try Again"; } catch (error) { - isLoading = false; - stateCode = -1; - notifyListeners(); - return false; + return "Failed, Try Again"; } } diff --git a/lib/modules/cm_module/create_cm_request.dart b/lib/modules/cm_module/create_cm_request.dart index 6dcf83e0..bc54fae1 100644 --- a/lib/modules/cm_module/create_cm_request.dart +++ b/lib/modules/cm_module/create_cm_request.dart @@ -12,6 +12,7 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/enums/request_attachment_type_enum.dart'; import 'package:test_sa/models/enums/user_types.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; @@ -157,6 +158,8 @@ class _CreateCMRequestState extends State with TickerProviderSt 24.height, AttachmentPicker( label: context.translation.attachImage, + moduleId: RequestAttachmentTypeEnum.correctiveMaintenance.id, + showAsListView: true, attachment: _deviceImages, onlyImages: false, buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), @@ -350,10 +353,10 @@ class _CreateCMRequestState extends State with TickerProviderSt _serviceRequest.audio = "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}"; } } - List attachement = []; + List attachement = []; for (var item in _deviceImages) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - attachement.add(WorkOrderAttachments(id: 0, name: fileName)); + attachement.add(GenericAttachmentModel(id: 0, name: fileName, documentType: item.documentType)); } _requestDetailProvider.workOrderHelperModel = WorkOrderHelperModel( assetId: _serviceRequest.device?.id, diff --git a/lib/modules/cm_module/views/components/activities_list_view.dart b/lib/modules/cm_module/views/components/activities_list_view.dart index a543651f..882ae77c 100644 --- a/lib/modules/cm_module/views/components/activities_list_view.dart +++ b/lib/modules/cm_module/views/components/activities_list_view.dart @@ -4,9 +4,11 @@ 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/generic_attachment_model.dart'; import 'package:test_sa/models/helper_data_models/maintenance_request/activity_maintenance_model.dart'; import 'package:test_sa/models/helper_data_models/spare_part/activity_spare_part_model.dart'; import 'package:test_sa/models/new_models/assistant_employee.dart'; @@ -172,7 +174,20 @@ class _ActivitiesListViewState extends State { if (activity.activitySparePart?.acitiySparePartAttachments?.isNotEmpty ?? false) ...[ 2.height, const Divider().defaultStyle(context), - FilesList(images: activity.activitySparePart!.acitiySparePartAttachments!.map((toElement) => URLs.getFileUrl(toElement.name!)!).toList()), + InfoHeader16Widget("Attachments".addTranslation), + 4.height, + FilesList( + showAsListView: true, + types: activity.activitySparePart!.acitiySparePartAttachments! + .whereType() + .where((e) => e.documentType != null && e.documentType!.name!.isNotEmpty) + .map((toElement) => toElement.documentType!.name!) + .toList(), + images: activity.activitySparePart!.acitiySparePartAttachments! + .whereType() + .where((e) => e.name != null) + .map((toElement) => URLs.getFileUrl(toElement.name!)!) + .toList()), ], ], ).toShadowContainer(context, showShadow: false).onPress(() { @@ -216,7 +231,6 @@ class _ActivitiesListViewState extends State { ), ], ), - if (showActionButtons) Row( crossAxisAlignment: CrossAxisAlignment.start, @@ -251,7 +265,6 @@ class _ActivitiesListViewState extends State { label: context.translation.assistantEmployee, value: activity.activityMaintenance?.assistantEmployees?.first.user?.userName, ), - ] else ...[ InfoTextWidget( label: context.translation.assignedEmployee, @@ -344,27 +357,31 @@ class _ActivitiesListViewState extends State { } void editSparePartRequest({required BuildContext context, required CMDetailProvider requestDetailProvider, required Activities activity}) async { - requestDetailProvider.sparePartHelperModel = SparePartHelperModel( + final model = SparePartHelperModel( id: activity.id, workOrderId: requestDetailProvider.currentWorkOrder?.data?.requestId, comment: activity.activitySparePart?.comment, sparePartAttachments: activity.activitySparePart?.acitiySparePartAttachments ?? [], activityStatus: activity.activityStatus, sparePart: SparePart( - id: activity.activitySparePart?.partCatalogItem?.id, - partName: activity.activitySparePart?.partCatalogItem?.partName, - partNo: activity.activitySparePart?.partCatalogItem?.partNumber, - oracleCode: activity.activitySparePart?.partCatalogItem?.oracleCode), + id: activity.activitySparePart?.partCatalogItem?.id, + partName: activity.activitySparePart?.partCatalogItem?.partName, + partNo: activity.activitySparePart?.partCatalogItem?.partNumber, + oracleCode: activity.activitySparePart?.partCatalogItem?.oracleCode, + ), quantity: activity.activitySparePart?.quantity, installQty: activity.activitySparePart?.installQty, returnQty: activity.activitySparePart?.returnQty, activityStatusId: activity.activityStatus?.id, ); - requestDetailProvider.updateSparePartHelperModel(requestDetailProvider.sparePartHelperModel); - + // Navigate and let SparePartRequest._initializeModel() handle provider setup Navigator.of(context).push(MaterialPageRoute( - builder: (_) => const SparePartRequest(), + builder: (_) => SparePartRequest( + model: model, + provider: requestDetailProvider, + fromCm: true, + ), )); } } 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 04fdd0ce..2272212a 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 @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/app_strings/app_asset.dart'; +import 'package:test_sa/controllers/providers/api/ppm_provider.dart'; import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; @@ -668,16 +669,26 @@ class ServiceRequestBottomSheet { } void onItemTap({required int index, required BuildContext context}) { + CMDetailProvider requestDetailProvider = Provider.of(context, listen: false); switch (index) { case 0: - Provider.of(context, listen: false).sparePartHelperModel = SparePartHelperModel(); + // Create fresh model - SparePartRequest will handle setting it in provider + final model = SparePartHelperModel( + id: 0, + workOrderId: requestDetailProvider.currentWorkOrder?.data?.requestId, + ); Navigator.pushReplacement( context, - MaterialPageRoute(builder: (context) => const SparePartRequest()), + MaterialPageRoute( + builder: (context) => SparePartRequest( + model: model, + provider: requestDetailProvider, + fromCm: true, + ), + ), ); break; case 1: - CMDetailProvider requestDetailProvider = Provider.of(context, listen: false); requestDetailProvider.activityMaintenanceHelperModel = ActivityMaintenanceHelperModel( workOrderId: requestDetailProvider.currentWorkOrder?.data?.requestId, id: 0, @@ -768,7 +779,7 @@ class ServiceRequestBottomSheet { })); } - static Future addAnotherSpareRequestBottomSheet({required BuildContext context}) { + static Future addAnotherSpareRequestBottomSheet({required BuildContext context, bool fromCm = false}) { return buildBottomSheetParent( context: context, childWidget: Consumer( @@ -804,11 +815,23 @@ class ServiceRequestBottomSheet { buttonColor: AppColor.primary10, loading: false, onPressed: () { + dynamic provider = fromCm ? Provider.of(context, listen: false) : Provider.of(context, listen: false); Navigator.pop(context); - Provider.of(context, listen: false).sparePartHelperModel = SparePartHelperModel(); + final model = SparePartHelperModel( + id: 0, + workOrderId: fromCm? provider.currentWorkOrder?.data?.requestId:null, + pmVisitId: !fromCm? provider.planPreventiveVisit?.id:null, + ); + Navigator.pushReplacement( context, - MaterialPageRoute(builder: (context) => const SparePartRequest()), + MaterialPageRoute( + builder: (context) => SparePartRequest( + model: model, + provider: provider, + fromCm: fromCm, + ), + ), ); }, ).expanded, diff --git a/lib/modules/cm_module/views/components/service_request_detail_view.dart b/lib/modules/cm_module/views/components/service_request_detail_view.dart index 73a7f9ea..9f49fa8a 100644 --- a/lib/modules/cm_module/views/components/service_request_detail_view.dart +++ b/lib/modules/cm_module/views/components/service_request_detail_view.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; @@ -8,6 +10,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/models/enums/request_attachment_type_enum.dart'; import 'package:test_sa/models/enums/user_types.dart'; import 'package:test_sa/models/enums/work_order_next_step.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; @@ -41,7 +44,7 @@ class ServiceRequestDetailView extends StatefulWidget { class _ServiceRequestDetailViewState extends State { List _userAttachments = []; - List _attachments = []; + List _attachments = []; @override void initState() { @@ -53,13 +56,15 @@ class _ServiceRequestDetailViewState extends State { UserProvider userProvider = Provider.of(context, listen: false); return Consumer(builder: (pContext, requestProvider, _) { if (userProvider.user?.type == UsersTypes.engineer) { - // _userAttachments = requestProvider.currentWorkOrder?.data?.workOrderAttachments.where((e) => e.createdBy == _userProvider.user?.userID).map((e) => File(e.name ?? '')).toList() ?? []; - _userAttachments = - requestProvider.currentWorkOrder?.data?.workOrderAttachments.where((e) => e.createdBy == userProvider.user?.userID).map((e) => GenericAttachmentModel.fromJson(e.toJson())).toList() ?? []; - _attachments = requestProvider.currentWorkOrder?.data?.workOrderAttachments.where((e) => e.createdBy != userProvider.user?.userID).toList() ?? []; + _userAttachments = requestProvider.currentWorkOrder?.data?.workOrderAttachments + .whereType() + .where((e) => e.createdBy == userProvider.user?.userID) + .map((e) => GenericAttachmentModel(id: e.id, name: e.name, createdBy: e.createdBy, documentType: e.documentType)) + .toList() ?? + []; + _attachments = requestProvider.currentWorkOrder?.data?.workOrderAttachments.whereType().where((e) => e.createdBy != userProvider.user?.userID).toList() ?? []; } else { - //show only nurse attachments - _attachments = requestProvider.currentWorkOrder?.data?.workOrderAttachments.where((e) => e.createdBy == userProvider.user?.userID).toList() ?? []; + _attachments = requestProvider.currentWorkOrder?.data?.workOrderAttachments.whereType().where((e) => e.createdBy == userProvider.user?.userID).toList() ?? []; } bool showInitialVisitCard = requestProvider.currentWorkOrder?.data?.needAVisitDateTime != null && @@ -261,26 +266,50 @@ class _ServiceRequestDetailViewState extends State { if (_attachments.isNotEmpty) ...[ const Divider().defaultStyle(context), InfoHeader16Widget("Attachments".addTranslation), - FilesList(images: _attachments.map((toElement) => URLs.getFileUrl(toElement.name!) ?? '').toList()), + 4.height, + FilesList( + showAsListView: true, + images: _attachments.map((toElement) => URLs.getFileUrl(toElement.name!) ?? '').toList(), + types: _attachments + .whereType() + .where((e) => e.documentType != null && e.documentType!.name!.isNotEmpty) + .map((toElement) => toElement.documentType!.name!) + .toList(), + ), ], if (!requestProvider.isReadOnlyRequest && workOrder.nextStep?.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) ...[ const Divider().defaultStyle(context), AttachmentPicker( label: context.translation.attachments, + showAsListView: true, attachment: _userAttachments, + moduleId: RequestAttachmentTypeEnum.correctiveMaintenance.id, buttonColor: AppColor.primary10, onlyImages: false, - // showAsGrid: true, buttonIcon: 'quotation_icon'.toSvgAsset(color: AppColor.primary10), onChange: (attachment) { - requestProvider.addWorkOrderAttachment(woId: workOrder.requestId!, attachments: attachment, otherAttachment: _attachments); + requestProvider.addWorkOrderAttachment( + woId: workOrder.requestId!, + attachments: attachment, + otherAttachment: _attachments, + ); }, ), ], ] else ...[ if (_attachments.isNotEmpty) ...[ const Divider().defaultStyle(context), - FilesList(images: _attachments.map((toElement) => URLs.getFileUrl(toElement.name!)!).toList()), + InfoHeader16Widget("Attachments".addTranslation), + 4.height, + FilesList( + images: _attachments.map((toElement) => URLs.getFileUrl(toElement.name!)!).toList(), + showAsListView: true, + types: _attachments + .whereType() + .where((e) => e.documentType != null && e.documentType!.name!.isNotEmpty) + .map((toElement) => toElement.documentType!.name!) + .toList(), + ), ], //handle nurse case.. ], @@ -338,8 +367,26 @@ class _ServiceRequestDetailViewState extends State { const Spacer(), if (!provider.isReadOnlyRequest) "edit_icon".toSvgAsset(height: 24, width: 24, color: AppColor.icon2Color(context)).onPress(() async { + WorkOrderData currentWorkOrderData = provider.currentWorkOrder!.data!; + provider.workOrderCostModel = WorkOrderCostModel( + workOrderId: currentWorkOrderData.requestId, + labourCost: currentWorkOrderData.labourCost, + sparePartCost: currentWorkOrderData.sparePartCost, + travelCost: currentWorkOrderData.travelCost, + qAmount: currentWorkOrderData.qAmount, + prNo: currentWorkOrderData.prNo, + poNo: currentWorkOrderData.poNo, + mrNo: currentWorkOrderData.mrNo, + exchangeCost: currentWorkOrderData.exchangeCost, + ); provider.refreshTimer = false; - await Navigator.push(context, MaterialPageRoute(builder: (context) => CostDetailFormScreen(isEdit: true))); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CostDetailFormScreen( + model: provider.workOrderCostModel, + provider: provider, + ))); provider.refreshTimer = true; }), ], diff --git a/lib/modules/cm_module/views/forms/asset_retired/asset_retired.dart b/lib/modules/cm_module/views/forms/asset_retired/asset_retired.dart index d31dbf94..41e4bc68 100644 --- a/lib/modules/cm_module/views/forms/asset_retired/asset_retired.dart +++ b/lib/modules/cm_module/views/forms/asset_retired/asset_retired.dart @@ -7,6 +7,7 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/enums/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/helper_data_models/asset_retired/asset_retired_model.dart'; import 'package:test_sa/models/lookup.dart'; @@ -106,9 +107,11 @@ class _AssetRetiredState extends State with TickerProviderStateMix AttachmentPicker( label: context.translation.attachFiles, attachment: _attachments, + moduleId: RequestAttachmentTypeEnum.assetDelivery.id, + showAsListView: true, onlyImages: false, buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), - buttonColor: AppColor.black10, + // buttonColor: AppColor.black10, ), ], ).paddingOnly(start: 13, end: 13, top: 14, bottom: 16), @@ -125,7 +128,8 @@ class _AssetRetiredState extends State with TickerProviderStateMix for (var item in _attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - requestDetailProvider.assetRetiredHelperModel?.activityAssetToBeRetiredAttachments?.add(ActivityAssetToBeRetiredAttachments(id: item.id, name: fileName)); + requestDetailProvider.assetRetiredHelperModel?.activityAssetToBeRetiredAttachments + ?.add(GenericAttachmentModel(id: item.id, name: fileName, documentType: item.documentType)); } int status = await requestDetailProvider.createActivityAssetToBeRetired(); if (status == 200) { diff --git a/lib/modules/cm_module/views/forms/cost/cost_detail_form_screen.dart b/lib/modules/cm_module/views/forms/cost/cost_detail_form_screen.dart index f7be5cab..94b7f842 100644 --- a/lib/modules/cm_module/views/forms/cost/cost_detail_form_screen.dart +++ b/lib/modules/cm_module/views/forms/cost/cost_detail_form_screen.dart @@ -1,273 +1,216 @@ +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/extensions/widget_extensions.dart'; import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.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/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/providers/service_request_providers/equipment_status_provider.dart'; class CostDetailFormScreen extends StatefulWidget { static const String id = "/cost-detail-form-screen"; - bool isEdit = false; + final WorkOrderCostModel? model; + final dynamic provider; // CMDetailProvider or PpmProvider - CostDetailFormScreen({Key? key, required this.isEdit}) : super(key: key); + const CostDetailFormScreen({ + Key? key, + required this.model, + required this.provider, + }) : super(key: key); @override _CostDetailFormScreenState createState() => _CostDetailFormScreenState(); } -class _CostDetailFormScreenState extends State with TickerProviderStateMixin { - CMDetailProvider? _requestDetailProvider; - - final GlobalKey _scaffoldKey = GlobalKey(); +class _CostDetailFormScreenState extends State { + late WorkOrderCostModel _localModel; @override void initState() { super.initState(); - } - - void assignValues() { - // ServiceRequestDetailProvider requestDetailProvider = Provider.of(context, listen: false); - // _requestDetailProvider = Provider.of(context, listen: false); - WorkOrderData currentWorkOrderData = _requestDetailProvider!.currentWorkOrder!.data!; - _requestDetailProvider!.workOrderCostModel = WorkOrderCostModel( - workOrderId: currentWorkOrderData.requestId, - labourCost: currentWorkOrderData.labourCost, - sparePartCost: currentWorkOrderData.sparePartCost, - travelCost: currentWorkOrderData.travelCost, - qAmount: currentWorkOrderData.qAmount, - prNo: currentWorkOrderData.prNo, - poNo: currentWorkOrderData.poNo, - mrNo: currentWorkOrderData.mrNo, - exchangeCost: currentWorkOrderData.exchangeCost, + _localModel = WorkOrderCostModel( + workOrderId: widget.model?.workOrderId, + labourCost: widget.model?.labourCost, + sparePartCost: widget.model?.sparePartCost, + travelCost: widget.model?.travelCost, + qAmount: widget.model?.qAmount, + prNo: widget.model?.prNo, + poNo: widget.model?.poNo, + mrNo: widget.model?.mrNo, + exchangeCost: widget.model?.exchangeCost, ); + log('Initialized Cost Model: ${_localModel.toJson()}'); } @override Widget build(BuildContext context) { - if (_requestDetailProvider == null) { - _requestDetailProvider = Provider.of(context, listen: false); - assignValues(); - } - return Scaffold( - key: _scaffoldKey, appBar: const DefaultAppBar(title: "Cost Details"), - body: Consumer(builder: (context, CMDetailProvider requestDetailProvider, child) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - AppTextFormField( - labelText: "Spare Part Cost", - backgroundColor: AppColor.neutral100, - initialValue: requestDetailProvider.workOrderCostModel?.sparePartCost?.toString(), - textAlign: TextAlign.center, - enable: false, - labelStyle: AppTextStyles.textFieldLabelStyle, - textInputType: TextInputType.number, - showShadow: false, - onChange: (value) { - requestDetailProvider.workOrderCostModel?.sparePartCost = num.parse(value); - }, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - AppTextFormField( - initialValue: requestDetailProvider.workOrderCostModel?.labourCost?.toString(), - textAlign: TextAlign.center, - labelText: "Labor Cost", - backgroundColor: AppColor.fieldBgColor(context), - labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), - textInputType: const TextInputType.numberWithOptions(decimal: true), - showShadow: false, - onChange: (value) { - requestDetailProvider.workOrderCostModel?.labourCost = num.parse(value); - }, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - AppTextFormField( - labelText: "Travel Cost", - backgroundColor: AppColor.fieldBgColor(context), - labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), - initialValue: requestDetailProvider.workOrderCostModel?.travelCost?.toString(), - textAlign: TextAlign.center, - textInputType: const TextInputType.numberWithOptions(decimal: true), - showShadow: false, - onChange: (value) { - requestDetailProvider.workOrderCostModel?.travelCost = num.parse(value); - }, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - AppTextFormField( - labelText: "Quot Amount", - backgroundColor: AppColor.fieldBgColor(context), - labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), - initialValue: requestDetailProvider.workOrderCostModel?.qAmount?.toString(), - textAlign: TextAlign.center, - textInputType: const TextInputType.numberWithOptions(decimal: true), - showShadow: false, - onChange: (value) { - requestDetailProvider.workOrderCostModel?.qAmount = num.parse(value); - }, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - AppTextFormField( - labelText: "PR No", - backgroundColor: AppColor.fieldBgColor(context), - labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), - initialValue: requestDetailProvider.workOrderCostModel?.prNo, - textAlign: TextAlign.center, - textInputType: const TextInputType.numberWithOptions(decimal: true), - showShadow: false, - onChange: (value) { - requestDetailProvider.workOrderCostModel?.prNo = value; - }, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - AppTextFormField( - labelText: "PO No", - backgroundColor: AppColor.fieldBgColor(context), - labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), - initialValue: requestDetailProvider.workOrderCostModel?.poNo, - textAlign: TextAlign.center, - textInputType: const TextInputType.numberWithOptions(decimal: true), - showShadow: false, - onChange: (value) { - requestDetailProvider.workOrderCostModel?.poNo = value; - }, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - AppTextFormField( - labelText: "MR No", - backgroundColor: AppColor.fieldBgColor(context), - labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), - initialValue: requestDetailProvider.workOrderCostModel?.mrNo, - textAlign: TextAlign.center, - textInputType: const TextInputType.numberWithOptions(decimal: true), - showShadow: false, - onChange: (value) { - requestDetailProvider.workOrderCostModel?.mrNo = value; - }, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - AppTextFormField( - labelText: "Exchange Cost", - backgroundColor: AppColor.fieldBgColor(context), - labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), - initialValue: requestDetailProvider.workOrderCostModel?.exchangeCost != null ? requestDetailProvider.workOrderCostModel?.exchangeCost.toString() : '', - textAlign: TextAlign.center, - textInputType: const TextInputType.numberWithOptions(decimal: true), - showShadow: false, - onChange: (value) { - requestDetailProvider.workOrderCostModel?.exchangeCost = num.parse(value); - }, - style: Theme.of(context).textTheme.titleMedium, - ), - ], - ).toShadowContainer(context).paddingAll(16), - ).expanded, - FooterActionButton.footerContainer( - context: context, - child: AppFilledButton( - label: "Update Cost Details", - buttonColor: AppColor.primary10, - onPressed: () async { - if (validateForm(requestDetailProvider: requestDetailProvider)) { - showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - await requestDetailProvider.engineerUpdateCost().then((success) { - Navigator.pop(context); - if (success) { - Navigator.pop(context); - } - }); - } - }, + body: ListenableBuilder( + listenable: widget.provider, + builder: (context, child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + AppTextFormField( + labelText: "Spare Part Cost", + backgroundColor: AppColor.neutral100, + initialValue: _localModel.sparePartCost?.toString() ?? '0', + textAlign: TextAlign.center, + enable: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + textInputType: TextInputType.number, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + initialValue: _localModel.labourCost?.toString() ?? '', + textAlign: TextAlign.center, + labelText: "Labor Cost", + backgroundColor: AppColor.fieldBgColor(context), + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + textInputType: const TextInputType.numberWithOptions(decimal: true), + showShadow: false, + onChange: (value) { + _localModel.labourCost = num.tryParse(value); + }, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: "Travel Cost", + backgroundColor: AppColor.fieldBgColor(context), + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + initialValue: _localModel.travelCost?.toString() ?? '', + textAlign: TextAlign.center, + textInputType: const TextInputType.numberWithOptions(decimal: true), + showShadow: false, + onChange: (value) { + _localModel.travelCost = num.tryParse(value); + }, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: "Quot Amount", + backgroundColor: AppColor.fieldBgColor(context), + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + initialValue: _localModel.qAmount?.toString() ?? '', + textAlign: TextAlign.center, + textInputType: const TextInputType.numberWithOptions(decimal: true), + showShadow: false, + onChange: (value) { + _localModel.qAmount = num.tryParse(value); + }, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: "PR No", + backgroundColor: AppColor.fieldBgColor(context), + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + initialValue: _localModel.prNo ?? '', + textAlign: TextAlign.center, + textInputType: TextInputType.text, + showShadow: false, + onChange: (value) { + _localModel.prNo = value.isEmpty ? null : value; + }, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: "PO No", + backgroundColor: AppColor.fieldBgColor(context), + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + initialValue: _localModel.poNo ?? '', + textAlign: TextAlign.center, + textInputType: TextInputType.text, + showShadow: false, + onChange: (value) { + _localModel.poNo = value.isEmpty ? null : value; + }, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: "MR No", + backgroundColor: AppColor.fieldBgColor(context), + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + initialValue: _localModel.mrNo ?? '', + textAlign: TextAlign.center, + textInputType: TextInputType.text, + showShadow: false, + onChange: (value) { + _localModel.mrNo = value.isEmpty ? null : value; + }, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: "Exchange Cost", + backgroundColor: AppColor.fieldBgColor(context), + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + initialValue: _localModel.exchangeCost?.toString() ?? '', + textAlign: TextAlign.center, + textInputType: const TextInputType.numberWithOptions(decimal: true), + showShadow: false, + onChange: (value) { + _localModel.exchangeCost = num.tryParse(value); + }, + style: Theme.of(context).textTheme.titleMedium, + ), + ], + ).toShadowContainer(context).paddingAll(16), + ), ), - ), - ], - ); - }), + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + label: "Update Cost Details", + buttonColor: AppColor.primary10, + onPressed: () => _onSubmit(), + ), + ), + ], + ); + }, + ), ); } - bool validateForm({required CMDetailProvider requestDetailProvider}) { - bool isValid = true; - if (!widget.isEdit) { - return true; - } - // if (requestDetailProvider.engineerUpdateWorkOrderHelperModel!.equipmentStatus != null) { - // if (requestDetailProvider.engineerUpdateWorkOrderHelperModel!.equipmentStatus!.value == 1 || requestDetailProvider.engineerUpdateWorkOrderHelperModel!.equipmentStatus!.value == 2) { - // if (requestDetailProvider.engineerUpdateWorkOrderHelperModel!.returnToService == null) { - // Fluttertoast.showToast(msg: "Return to service is required ", toastLength: Toast.LENGTH_LONG); - // return false; - // } - // } - // } - return isValid; - } + Future _onSubmit() async { + widget.provider.workOrderCostModel = _localModel; + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => const AppLazyLoading(), + ); - Widget assetStatusWidget({required BuildContext context, required EngineerUpdateWorkOrderHelperModel workOrderData}) { - return Consumer(builder: (cxt, snapshot, _) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - context.translation.assetStatus.bodyText(context).custom(color: AppColor.black20), - 8.height, - Wrap( - runSpacing: 8, - spacing: 8, - children: [ - for (var element in snapshot.items) - Row( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - width: 24, - height: 24, - child: Radio( - value: element, - activeColor: Colors.red, - fillColor: WidgetStateColor.resolveWith((states) { - if (states.contains(WidgetState.selected)) return AppColor.primary10; - return AppColor.neutral130; - }), - groupValue: workOrderData.equipmentStatus, - onChanged: (state) { - setState(() { - workOrderData.equipmentStatus = element; - }); - }), - ), - 8.width, - Text(element.name ?? '', style: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral120)), - ], - ) - ], - ).toShimmer(isShow: snapshot.loading, context: context), - ], - ); - }); + try { + final success = await widget.provider.engineerUpdateCost(); + + if (mounted) Navigator.pop(context); // Close loading + + if (success && mounted) { + Navigator.pop(context); + } + } catch (e) { + if (mounted) Navigator.pop(context); + log('Error updating cost: $e'); + } } } diff --git a/lib/modules/cm_module/views/forms/spare_part/spare_part_request.dart b/lib/modules/cm_module/views/forms/spare_part/spare_part_request.dart index 75140eb4..1dff3d3c 100644 --- a/lib/modules/cm_module/views/forms/spare_part/spare_part_request.dart +++ b/lib/modules/cm_module/views/forms/spare_part/spare_part_request.dart @@ -1,7 +1,6 @@ -import 'dart:async'; import 'dart:convert'; +import 'dart:developer'; import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/api/parts_provider.dart'; @@ -11,12 +10,12 @@ 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/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/helper_data_models/spare_part/activity_spare_part_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/service_request/spare_parts.dart'; import 'package:test_sa/models/size_config.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/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart'; @@ -28,385 +27,445 @@ 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/loading_list_notifier.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/item_views/info_header_widget.dart'; import 'package:test_sa/views/widgets/item_views/info_text_widget.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; class SparePartRequest extends StatefulWidget { static const String id = "/spare-part-request"; + final SparePartHelperModel? model; + final dynamic provider; + final bool fromCm; - const SparePartRequest({Key? key}) : super(key: key); + const SparePartRequest({ + Key? key, + required this.model, + required this.provider, + this.fromCm = false, + }) : super(key: key); @override _SparePartRequestState createState() => _SparePartRequestState(); } -class _SparePartRequestState extends State with TickerProviderStateMixin { - CMDetailProvider? _requestDetailProvider; +class _SparePartRequestState extends State { PartsProvider? _partsProvider; bool _isLoading = false; List _spareParts = []; + List _attachments = []; - List attachments = []; final GlobalKey _formKey = GlobalKey(); - final GlobalKey _scaffoldKey = GlobalKey(); - final TextEditingController _partQtyController = TextEditingController(); - final TextEditingController _installQtyController = TextEditingController(); - final TextEditingController _returnQtyController = TextEditingController(); - final TextEditingController _oracleNoController = TextEditingController(); - final TextEditingController _descriptionController = TextEditingController(); - Lookup statusLookup = Lookup.fromJson({"id": 5619, "name": "New", "value": 1}); - int? activityStatus; @override void initState() { super.initState(); _partsProvider = Provider.of(context, listen: false); - _requestDetailProvider = Provider.of(context, listen: false); - _requestDetailProvider?.sparePartHelperModel = SparePartHelperModel( - id: _requestDetailProvider?.sparePartHelperModel?.id ?? 0, - workOrderId: _requestDetailProvider?.sparePartHelperModel?.workOrderId ?? _requestDetailProvider?.currentWorkOrder?.data?.requestId, - sparePartAttachments: _requestDetailProvider?.sparePartHelperModel?.sparePartAttachments ?? [], - sparePart: _requestDetailProvider?.sparePartHelperModel?.sparePart ?? SparePart(), - quantity: _requestDetailProvider?.sparePartHelperModel?.quantity, - installQty: _requestDetailProvider?.sparePartHelperModel?.installQty, - returnQty: _requestDetailProvider?.sparePartHelperModel?.returnQty, - activityStatusId: _requestDetailProvider?.sparePartHelperModel?.activityStatusId ?? statusLookup.id, - activityStatus: _requestDetailProvider?.sparePartHelperModel?.activityStatus ?? statusLookup, - comment: _requestDetailProvider?.sparePartHelperModel?.comment ?? '', - ); - _partQtyController.text = _requestDetailProvider?.sparePartHelperModel?.quantity != null ? _requestDetailProvider!.sparePartHelperModel!.quantity!.round().toString() : ''; - _installQtyController.text = _requestDetailProvider?.sparePartHelperModel?.installQty != null ? _requestDetailProvider!.sparePartHelperModel!.installQty!.round().toString() : ''; - _returnQtyController.text = _requestDetailProvider?.sparePartHelperModel?.returnQty != null ? _requestDetailProvider!.sparePartHelperModel!.returnQty!.round().toString() : ''; - _oracleNoController.text = _requestDetailProvider?.sparePartHelperModel?.sparePart?.oracleCode != null ? _requestDetailProvider!.sparePartHelperModel!.sparePart!.oracleCode! : ''; - _descriptionController.text = _requestDetailProvider?.sparePartHelperModel?.comment != null ? _requestDetailProvider!.sparePartHelperModel!.comment! : ''; - activityStatus = _requestDetailProvider?.sparePartHelperModel?.activityStatus?.value; - scheduleMicrotask(() async { - _isLoading = true; - attachments = _requestDetailProvider?.sparePartHelperModel?.sparePartAttachments?.map((e) => GenericAttachmentModel(id: e.id!, name: e.name ?? '')).toList() ?? []; - setState(() {}); - _spareParts = await _partsProvider!.getPartsListByDisplayName(assetId: _requestDetailProvider?.currentWorkOrder?.data?.asset?.id); - _isLoading = false; - setState(() {}); - }); + _initializeModel(); + _loadInitialData(); } - void restValues({required CMDetailProvider requestDetailProvider}) { - requestDetailProvider.sparePartHelperModel = SparePartHelperModel(id: 0, workOrderId: _requestDetailProvider?.currentWorkOrder?.data?.requestId, sparePartAttachments: []); - _partQtyController.clear(); - _installQtyController.clear(); - _returnQtyController.clear(); - _oracleNoController.clear(); - _descriptionController.clear(); - attachments = []; + void _initializeModel() { + final bool isNewActivity = widget.model?.id == null || widget.model?.id == 0; + if (isNewActivity) { + widget.provider.sparePartHelperModel = SparePartHelperModel( + id: 0, + workOrderId: widget.fromCm ? widget.provider.currentWorkOrder?.data?.requestId : null, + pmVisitId: !widget.fromCm ? widget.provider.planPreventiveVisit?.id : null, + sparePartAttachments: [], + sparePart: SparePart(), + quantity: null, + installQty: null, + returnQty: null, + activityStatusId: statusLookup.id, + activityStatus: statusLookup, + comment: '', + ); + } else if (widget.provider.sparePartHelperModel == null || widget.provider.sparePartHelperModel?.id != widget.model?.id) { + widget.provider.sparePartHelperModel = SparePartHelperModel( + id: widget.model?.id ?? 0, + workOrderId: widget.fromCm ? widget.model?.workOrderId ?? widget.provider.currentWorkOrder?.data?.requestId : null, + pmVisitId: !widget.fromCm ? widget.model?.pmVisitId : null, + sparePartAttachments: widget.model?.sparePartAttachments ?? [], + sparePart: widget.model?.sparePart ?? SparePart(), + quantity: widget.model?.quantity, + installQty: widget.model?.installQty, + returnQty: widget.model?.returnQty, + activityStatusId: widget.model?.activityStatusId ?? statusLookup.id, + activityStatus: widget.model?.activityStatus ?? statusLookup, + comment: widget.model?.comment ?? '', + ); + } + log('Initialized SparePartHelperModel: ${widget.provider.sparePartHelperModel?.toJson()}'); } - @override - void dispose() { - _partQtyController.dispose(); - _installQtyController.dispose(); - _returnQtyController.dispose(); - _oracleNoController.dispose(); - _descriptionController.dispose(); - super.dispose(); - } + Future _loadInitialData() async { + setState(() => _isLoading = true); + _spareParts = await _partsProvider!.getPartsListByDisplayName( + assetId: widget.fromCm ? widget.provider.currentWorkOrder?.data?.asset?.id : widget.provider.planPreventiveVisit.asset.id, + ); + final bool isNewActivity = widget.model?.id == null || widget.model?.id == 0; + _attachments = []; + if (!isNewActivity) { + try { + final attachmentsList = widget.model?.sparePartAttachments; + if (attachmentsList != null && attachmentsList.isNotEmpty) { + for (var item in attachmentsList) { + _attachments.add(GenericAttachmentModel( + id: item.id ?? 0, + name: item.name ?? '', + )); + } + } + log('Loaded ${_attachments.length} attachments for existing activity'); + } catch (e) { + log('Error loading attachments: $e'); + _attachments = []; + } + } else { + log('New activity - starting with empty attachments'); + } - bool _isLocalUrl(String url) { - if (url.isEmpty != false) return false; - return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\'); + if (mounted) setState(() => _isLoading = false); } @override Widget build(BuildContext context) { - bool showInstallAndReturnQty = activityStatus == 3 || activityStatus == 4; return Scaffold( - key: _scaffoldKey, appBar: DefaultAppBar(title: context.translation.sparePartRequest), - body: Consumer(builder: (context, CMDetailProvider requestDetailProvider, child) { - return Form( - key: _formKey, - child: Column( - children: [ - SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: IgnorePointer( - ignoring: _requestDetailProvider!.isReadOnlyRequest, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Column( + body: ListenableBuilder( + listenable: widget.provider, + builder: (context, _) { + final provider = widget.provider; + final model = provider.sparePartHelperModel; + final bool showInstallAndReturnQty = (model?.activityStatus?.value == 3 || model?.activityStatus?.value == 4); + final bool isReadOnly = provider.isReadOnlyRequest ?? false; + + return Form( + key: _formKey, + child: Column( + children: [ + Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: IgnorePointer( + ignoring: isReadOnly, + child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - context.translation.sparePartDetails.heading5(context).custom(color: AppColor.textStyleColor(context)), - // 12.height, - // SingleItemDropDownMenu( - // context: context, - // height: 56.toScreenHeight, - // title: context.translation.activityStatus, - // showShadow: false, - // backgroundColor: AppColor.neutral100, - // initialValue: requestDetailProvider.sparePartHelperModel?.activityStatus, - // onSelect: (status) { - // requestDetailProvider.sparePartHelperModel?.activityStatus = status; - // }, - // ), - 12.height, - SingleItemDropDownMenu( - context: context, - title: context.translation.part, - staticData: _spareParts, - showShadow: false, - showAsBottomSheet: true, - loading: _isLoading, - initialValue: requestDetailProvider.sparePartHelperModel?.sparePart, - // backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, - onSelect: (part) async { - if (part != null) { - requestDetailProvider.sparePartHelperModel?.sparePart = part; - _oracleNoController.text = part.oracleCode ?? ''; - requestDetailProvider.updateSparePartHelperModel(_requestDetailProvider?.sparePartHelperModel); - } - }, - ), - - if (requestDetailProvider.sparePartHelperModel?.sparePart?.id != null) ...[ - 12.height, - SizedBox( - height: 30.toScreenHeight, - child: Text('View Parts Availability', - style: TextStyle( - fontSize: 12.toScreenWidth, - fontWeight: FontWeight.w500, - fontStyle: FontStyle.normal, - color: AppColor.primary10, - decorationColor: AppColor.primary10, - decoration: TextDecoration.underline, - )).onPress( - () async { - requestDetailProvider.getStoreAvailabilityById(partId: requestDetailProvider.sparePartHelperModel?.sparePart?.id); - showModalBottomSheet( - context: context, - useSafeArea: true, - isScrollControlled: true, - isDismissible: true, - backgroundColor: AppColor.bottomSheetColor(context), - builder: (BuildContext context) => PartDetailBottomSheetSheet().bottomSheetContainer(context), - ); - }, - ), - ), - ], - 12.height, - AppTextFormField( - controller: _partQtyController, - labelText: context.translation.quantity, - textInputType: TextInputType.number, - labelStyle: AppTextStyles.textFieldLabelStyle, - // showWithoutDecoration: true, - // backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, - enable: requestDetailProvider.sparePartHelperModel?.sparePart?.id != null, - validator: (value) => value == null || value.isEmpty - ? context.translation.requiredField - : Validator.isNumeric(value) - ? null - : context.translation.onlyNumbers, - onChange: (value) { - requestDetailProvider.sparePartHelperModel?.quantity = num.tryParse(value ?? ""); - }, - onSaved: (text) { - requestDetailProvider.sparePartHelperModel?.quantity = num.tryParse(text ?? ""); - }, - ), - 12.height, - if (showInstallAndReturnQty) ...[ - AppTextFormField( - controller: _installQtyController, - labelText: context.translation.installedQty, - textInputType: const TextInputType.numberWithOptions(decimal: true), - labelStyle: AppTextStyles.textFieldLabelStyle, - // showWithoutDecoration: true, - // backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, - enable: requestDetailProvider.sparePartHelperModel?.sparePart?.id != null, - validator: (value) => value == null || value.isEmpty - ? context.translation.requiredField - : Validator.isNumeric(value) - ? null - : context.translation.onlyNumbers, - onChange: (value) { - requestDetailProvider.sparePartHelperModel?.installQty = num.tryParse(value ?? ""); - }, - onSaved: (text) { - requestDetailProvider.sparePartHelperModel?.installQty = num.tryParse(text ?? ""); - }, - ), - 12.height, - AppTextFormField( - controller: _returnQtyController, - labelText: context.translation.returnQty, - textInputType: TextInputType.number, - labelStyle: AppTextStyles.textFieldLabelStyle, - // showWithoutDecoration: true, - // backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, - enable: requestDetailProvider.sparePartHelperModel?.sparePart?.id != null, - validator: (value) => value == null || value.isEmpty - ? context.translation.requiredField - : Validator.isNumeric(value) - ? null - : context.translation.onlyNumbers, - onChange: (value) { - requestDetailProvider.sparePartHelperModel?.returnQty = num.tryParse(value ?? ""); - }, - onSaved: (text) { - requestDetailProvider.sparePartHelperModel?.returnQty = num.tryParse(text ?? ""); - }, - ), - 12.height, - ], - AppTextFormField( - labelStyle: AppTextStyles.textFieldLabelStyle, - controller: _oracleNoController, - labelText: context.translation.oracleNo, - textInputType: TextInputType.number, - // showWithoutDecoration: true, - backgroundColor: AppColor.disableFieldBackground(context), - enable: false, - ), - 12.height, - AppTextFormField( - initialValue: requestDetailProvider.sparePartHelperModel?.comment, - labelStyle: AppTextStyles.textFieldLabelStyle, - controller: _descriptionController, - showSpeechToText: true, - // backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, - labelText: "Engineer Comment", - alignLabelWithHint: true, - // showWithoutDecoration: true, - textInputType: TextInputType.multiline, - onChange: (value) { - requestDetailProvider.sparePartHelperModel?.comment = value; - }, - onSaved: (value) { - requestDetailProvider.sparePartHelperModel?.comment = value; - }, - ), - 12.height, - AttachmentPicker( - label: context.translation.attachQuotation, - attachment: attachments, - buttonIcon: 'quotation_icon'.toSvgAsset(color: AppColor.primary10), - buttonColor: AppColor.primary10, + _buildFormContent( + context, + model, + provider, + showInstallAndReturnQty, ), ], - ).toShadowContainer(context), - 8.height, - ], + ), + ), ), ), - ).expanded, - if (!requestDetailProvider.isReadOnlyRequest) - FooterActionButton.footerContainer( - context: context, - child: AppFilledButton( - label: _requestDetailProvider?.sparePartHelperModel?.id == 0 ? context.translation.addSparePartActivity : context.translation.updateSparePartActivity, - buttonColor: AppColor.green70, - onPressed: () { - _onSubmit(requestDetailProvider: requestDetailProvider); - }, - )), - ], + if (!isReadOnly) _buildSubmitButton(context, provider), + ], + ), + ); + }, + ), + ); + } + + Widget _buildFormContent( + BuildContext context, + SparePartHelperModel? model, + dynamic provider, + bool showInstallAndReturnQty, + ) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + spacing: 12, + children: [ + InfoHeader16Widget(context.translation.sparePartDetails), + SingleItemDropDownMenu( + context: context, + title: context.translation.part, + staticData: _spareParts, + showShadow: false, + showAsBottomSheet: true, + loading: _isLoading, + initialValue: model?.sparePart, + onSelect: (part) { + if (part != null) { + model?.sparePart = part; + provider.updateSparePartHelperModel(model); + } + }, + ), + if (model?.sparePart?.id != null) ...[ + SizedBox( + // height: 30.toScreenHeight, + child: Text( + 'View Parts Availability', + style: TextStyle( + fontSize: 12.toScreenWidth, + fontWeight: FontWeight.w500, + color: AppColor.primary10, + decorationColor: AppColor.primary10, + decoration: TextDecoration.underline, + ), + ).onPress(() { + provider.getStoreAvailabilityById(partId: model?.sparePart?.id); + showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + isDismissible: true, + backgroundColor: AppColor.bottomSheetColor(context), + builder: (ctx) => PartDetailBottomSheetSheet(provider: provider).bottomSheetContainer(ctx), + ); + }), ), - ); - }), + ], + AppTextFormField( + key: ValueKey('quantity_${model?.quantity}'), + initialValue: model?.quantity?.round().toString() ?? '', + labelText: context.translation.quantity, + textInputType: TextInputType.number, + labelStyle: AppTextStyles.textFieldLabelStyle, + enable: model?.sparePart?.id != null, + validator: (value) => value == null || value.isEmpty + ? context.translation.requiredField + : Validator.isNumeric(value) + ? null + : context.translation.onlyNumbers, + onChange: (value) { + model?.quantity = num.tryParse(value); + }, + onSaved: (text) { + model?.quantity = num.tryParse(text ?? ''); + }, + ), + if (showInstallAndReturnQty) ...[ + AppTextFormField( + key: ValueKey('installQty_${model?.installQty}'), + initialValue: model?.installQty?.round().toString() ?? '', + labelText: context.translation.installedQty, + textInputType: const TextInputType.numberWithOptions(decimal: true), + labelStyle: AppTextStyles.textFieldLabelStyle, + enable: model?.sparePart?.id != null, + validator: (value) => value == null || value.isEmpty + ? context.translation.requiredField + : Validator.isNumeric(value) + ? null + : context.translation.onlyNumbers, + onChange: (value) { + model?.installQty = num.tryParse(value); + }, + onSaved: (text) { + model?.installQty = num.tryParse(text ?? ''); + }, + ), + AppTextFormField( + key: ValueKey('returnQty_${model?.returnQty}'), + initialValue: model?.returnQty?.round().toString() ?? '', + labelText: context.translation.returnQty, + textInputType: TextInputType.number, + labelStyle: AppTextStyles.textFieldLabelStyle, + enable: model?.sparePart?.id != null, + validator: (value) => value == null || value.isEmpty + ? context.translation.requiredField + : Validator.isNumeric(value) + ? null + : context.translation.onlyNumbers, + onChange: (value) { + model?.returnQty = num.tryParse(value); + }, + onSaved: (text) { + model?.returnQty = num.tryParse(text ?? ''); + }, + ), + ], + AppTextFormField( + key: ValueKey('oracle_${model?.sparePart?.oracleCode}'), + initialValue: model?.sparePart?.oracleCode ?? '', + labelStyle: AppTextStyles.textFieldLabelStyle, + labelText: context.translation.oracleNo, + textInputType: TextInputType.number, + backgroundColor: AppColor.disableFieldBackground(context), + enable: false, + ), + AppTextFormField( + key: ValueKey('comment_${model?.comment}'), + initialValue: model?.comment ?? '', + labelStyle: AppTextStyles.textFieldLabelStyle, + showSpeechToText: true, + labelText: "Engineer Comment", + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + onChange: (value) { + model?.comment = value; + }, + onSaved: (value) { + model?.comment = value; + }, + ), + AttachmentPicker( + label: context.translation.attachQuotation, + showAsListView: true, + moduleId: widget.fromCm?RequestAttachmentTypeEnum.sparePartActivity.id:RequestAttachmentTypeEnum.ppmSparePartActivity.id, + attachment: _attachments, + buttonIcon: 'quotation_icon'.toSvgAsset(color: AppColor.primary10), + buttonColor: AppColor.primary10, + ), + ], + ).toShadowContainer(context); + } + + Widget _buildSubmitButton(BuildContext context, dynamic provider) { + return FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + label: provider.sparePartHelperModel?.id == 0 ? context.translation.addSparePartActivity : context.translation.updateSparePartActivity, + buttonColor: AppColor.green70, + onPressed: () => _onSubmit(provider), + ), ); } - _onSubmit({required CMDetailProvider requestDetailProvider}) async { - if (requestDetailProvider.sparePartHelperModel?.sparePart?.id == null) { + Future _onSubmit(dynamic provider) async { + final model = provider.sparePartHelperModel; + + if (model?.sparePart?.id == null) { "Please select spare part".showToast; return; - } else if (requestDetailProvider.sparePartHelperModel?.quantity == null) { + } else if (model?.quantity == null) { "Please enter quantity".showToast; return; } - requestDetailProvider.sparePartHelperModel?.sparePartAttachments?.clear(); - - for (var item in attachments) { + model?.sparePartAttachments?.clear(); + for (var item in _attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - requestDetailProvider.sparePartHelperModel?.sparePartAttachments?.add( - SparePartAttachments(id: item.id, name: fileName), + + model?.sparePartAttachments?.add( + GenericAttachmentModel(id: item.id, name: fileName, documentType: item.documentType), + // SparePartAttachments(id: item.id, name: fileName), ); } - // Show loading dialog + // Show loading showDialog( context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading(), ); + + // Submit bool success = false; - if (_requestDetailProvider?.sparePartHelperModel?.id == 0) { - success = await requestDetailProvider.createActivitySparePart(); + String message = ""; + if (model?.id == 0) { + success = await provider.createActivitySparePart(); } else { - success = await requestDetailProvider.updateActivitySparePart(); + message = await provider.updateActivitySparePart(); + success = message.isEmpty; } - if (mounted) Navigator.pop(context); + + if (mounted) Navigator.pop(context); // Close loading + if (success) { - requestDetailProvider.getWorkOrderById( - id: requestDetailProvider.currentWorkOrder!.data!.requestId!, - ); - if (mounted) Navigator.pop(context); - if (_requestDetailProvider?.sparePartHelperModel?.id == 0) { - ServiceRequestBottomSheet.addAnotherSpareRequestBottomSheet(context: context); + if (widget.fromCm) { + provider.getWorkOrderById( + id: provider.currentWorkOrder!.data!.requestId!, + ); + } else { + provider.getPlanPreventiveVisitById( + int.tryParse(provider.planPreventiveVisit?.id ?? ''), + ); + } + + if (mounted) Navigator.pop(context); // Close form + + if (model?.id == 0 && widget.fromCm) { + ServiceRequestBottomSheet.addAnotherSpareRequestBottomSheet(context: context, fromCm: widget.fromCm); const SizedBox().flushBar( context: context, title: context.translation.sparePartActivitySuccess, message: '', ); } + } else { + if(message.isNotEmpty) { + context.showInfoDialog(message, title: "Error"); + } } } } +/// Bottom Sheet for showing parts availability class PartDetailBottomSheetSheet extends StatelessWidget { - PartDetailBottomSheetSheet({Key? key}) : super(key: key); + final dynamic provider; + + const PartDetailBottomSheetSheet({ + Key? key, + required this.provider, + }) : super(key: key); @override Widget build(BuildContext context) { return SizedBox( height: SizeConfig.screenHeight! / 2.2, width: SizeConfig.screenWidth, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 8.height, - 'Parts Availability'.heading6(context).paddingOnly(top: 12, start: 12), - Consumer(builder: (context, requestDetailProvider, child) { - return requestDetailProvider.isLoading - ? CircularProgressIndicator(color: AppColor.loadingColor(context)).center - : requestDetailProvider.storeAvailability.isEmpty - ? const NoDataFound().center - : ListView.separated( - padding: const EdgeInsets.only(top: 12), - itemCount: requestDetailProvider.storeAvailability.length, - separatorBuilder: (czt, index) => 12.height, - itemBuilder: (context, index) { - StoreAvailability model = requestDetailProvider.storeAvailability[index]; - return partAvailableQuantityCard(context: context, model: model); - }, - ); - }).expanded, - ], + child: SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 12.height, + 'Parts Availability'.heading4(context), + Expanded( + child: ListenableBuilder( + listenable: provider, + builder: (context, _) { + return provider.isLoading + ? CircularProgressIndicator( + color: AppColor.loadingColor(context), + ).center + : provider.storeAvailability.isEmpty + ? const NoDataFound().center + : ListView.separated( + padding: const EdgeInsets.only(top: 12, bottom: 12), + itemCount: provider.storeAvailability.length, + separatorBuilder: (czt, index) => 12.height, + itemBuilder: (context, index) { + StoreAvailability model = provider.storeAvailability[index]; + return _partAvailableQuantityCard(context: context, model: model); + }, + ); + }, + ), + ), + ], + ), ), ); } - Widget partAvailableQuantityCard({required StoreAvailability model, required BuildContext context}) { - return Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - InfoTextWidget(label: "Site Name:".addTranslation, value: model.siteName ?? ''), - InfoTextWidget(label: "Store Name:".addTranslation, value: model.storeName ?? ''), - InfoTextWidget(label: "Available Quantity:".addTranslation, value: model.availablityQty != null ? model.availablityQty.toString() : ''), - ]).toShadowContainer(context, padding: 12, showShadow: false,); + Widget _partAvailableQuantityCard({required StoreAvailability model, required BuildContext context}) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InfoTextWidget( + label: "Site Name".addTranslation, + value: model.siteName ?? '', + ), + InfoTextWidget( + label: "Store Name".addTranslation, + value: model.storeName ?? '', + ), + InfoTextWidget( + label: "Available Quantity".addTranslation, + value: model.availablityQty?.toString() ?? '', + ), + ], + ).toShadowContainer(context); } } diff --git a/lib/modules/demo_module/create_demo_request_page.dart b/lib/modules/demo_module/create_demo_request_page.dart index 4ff8f3ff..5f7beccf 100644 --- a/lib/modules/demo_module/create_demo_request_page.dart +++ b/lib/modules/demo_module/create_demo_request_page.dart @@ -13,6 +13,7 @@ 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/request_attachment_type_enum.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'; @@ -25,7 +26,6 @@ import 'package:test_sa/models/service_request/supp_engineer_work_orders.dart'; import 'package:test_sa/models/service_request/supplier_details.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/demo_module/models/demo_attachment_model.dart'; import 'package:test_sa/modules/demo_module/provider/demo_period_lookup_provider.dart'; import 'package:test_sa/modules/demo_module/provider/demo_provider.dart'; import 'package:test_sa/modules/loan_module/models/loan_form_model.dart'; @@ -495,36 +495,37 @@ class _CreateDemoRequestPageState extends State with Tick List attachmentSection() { return [ InfoHeader16Widget('Attachments'.addTranslation), - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: "Document Type", - initialValue: demoDocumentLookup, - showShadow: false, - validator: (value) { - if (value == null) return "Mandatory"; - return null; - }, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - onSelect: (value) { - demoDocumentLookup = value; - setState(() {}); - }, - ), + // SingleItemDropDownMenu( + // context: context, + // height: 56.toScreenHeight, + // title: "Document Type", + // initialValue: demoDocumentLookup, + // showShadow: false, + // validator: (value) { + // if (value == null) return "Mandatory"; + // return null; + // }, + // backgroundColor: AppColor.fieldBgColor(context), + // showAsBottomSheet: true, + // onSelect: (value) { + // demoDocumentLookup = value; + // setState(() {}); + // }, + // ), AttachmentPicker( label: context.translation.attachments, attachment: _attachments, buttonColor: AppColor.primary10.withOpacity(demoDocumentLookup != null ? 1 : .4), onlyImages: false, - enabled: demoDocumentLookup != null, - documentType: demoDocumentLookup, + // enabled: demoDocumentLookup != null, + // documentType: demoDocumentLookup, showAsListView: true, - buttonIcon: 'image-plus'.toSvgAsset(color: (AppColor.primary10).withOpacity(demoDocumentLookup != null ? 1 : .4)), - onChange: (attachments) { - _attachments = attachments; - setState(() {}); - }, + moduleId: RequestAttachmentTypeEnum.demo.id, + buttonIcon: 'image-plus'.toSvgAsset(color: (AppColor.primary10)), + // onChange: (attachments) { + // _attachments = attachments; + // setState(() {}); + // }, ), ]; } @@ -537,7 +538,12 @@ class _CreateDemoRequestPageState extends State with Tick _demoFormModel.demoAttachment = []; for (var item in _attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - _demoFormModel.demoAttachment?.add(DemoAttachments(id: 0, attachmentName: fileName, demoRequestId: 0, documentTypeId: item.documentTypeId!.id!)); + _demoFormModel.demoAttachment?.add(GenericAttachmentModel( + id: 0, + name: fileName, + moduleReferenceId: 0, + documentType: item.documentType, + )); } Utils.showLoading(context); DemoProvider demoProvider = Provider.of(context, listen: false); diff --git a/lib/modules/demo_module/demo_activities_page.dart b/lib/modules/demo_module/demo_activities_page.dart index f9a7dc2c..0288afc4 100644 --- a/lib/modules/demo_module/demo_activities_page.dart +++ b/lib/modules/demo_module/demo_activities_page.dart @@ -3,7 +3,9 @@ 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/generic_attachment_model.dart'; import 'package:test_sa/views/widgets/images/files_list.dart'; +import 'package:test_sa/views/widgets/item_views/info_header_widget.dart'; import '../../controllers/api_routes/urls.dart'; import '../../extensions/text_extensions.dart'; @@ -53,14 +55,19 @@ class DemoActivitiesPage extends StatelessWidget { 12.height, if (allAttachments.isNotEmpty) ...[ const Divider().defaultStyle(context), - Text( - "Attachments".addTranslation, - style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), - ), - FilesList(images: allAttachments.map((e) => URLs.getFileUrl(e ?? '') ?? '').toList() ?? []), + InfoHeader16Widget("Attachments".addTranslation), + 4.height, + FilesList( + showAsListView: true, + types: allAttachments + .whereType() + .where((e) => e.documentType != null && e.documentType!.name!.isNotEmpty) + .map((toElement) => toElement.documentType!.name!) + .toList(), + images: allAttachments.map((e) => URLs.getFileUrl(e ?? '') ?? '').toList()), ], ], - ).toShadowContainer(context, borderRadius: 14, backgroundColor: Color(0xffF4F8FC), showShadow: false), + ).toShadowContainer(context, borderRadius: 14, backgroundColor: const Color(0xffF4F8FC), showShadow: false), 16.height, Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/modules/demo_module/demo_detail_view_page.dart b/lib/modules/demo_module/demo_detail_view_page.dart index 6d98e438..5aa0939a 100644 --- a/lib/modules/demo_module/demo_detail_view_page.dart +++ b/lib/modules/demo_module/demo_detail_view_page.dart @@ -6,6 +6,7 @@ import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/models/enums/demo_request_step.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; import 'package:test_sa/models/module_permissions_model.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; @@ -91,8 +92,8 @@ class _DemoDetailViewPageState extends State { if (snapshot.connectionState == ConnectionState.waiting) return CircularProgressIndicator(color: AppColor.loadingColor(context)).center; if (snapshot.data == null) return const NoDataFound().center; - List allAttachments = snapshot.data!.demoAttachments! ?? []; - List suppAttachments = snapshot.data!.supplierDemoAttachments! ?? []; + List allAttachments = snapshot.data!.demoAttachments! ?? []; + List suppAttachments = snapshot.data!.supplierDemoAttachments! ?? []; DemoRequestModel demoData = snapshot.data!; @@ -125,18 +126,20 @@ class _DemoDetailViewPageState extends State { if (allAttachments.isNotEmpty) ...[ const Divider().defaultStyle(context), InfoHeader16Widget("Attachments"), + 4.height, FilesList( showAsListView: true, - images: allAttachments.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList(), + images: allAttachments.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList(), types: allAttachments.map((e) => e.documentType?.name ?? '').toList()), ], if (suppAttachments.isNotEmpty) ...[ const Divider().defaultStyle(context), InfoHeader16Widget("Supplier Attachments"), + 4.height, FilesList( showAsListView: true, - images: suppAttachments.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList(), - types: suppAttachments.map((e) => e.documentType?.name ?? '').toList()), + images: suppAttachments.whereType().map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList(), + types: suppAttachments.whereType().map((e) => e.documentType?.name ?? '').toList()), ], ], ).toShadowContainer(context, padding: 12), diff --git a/lib/modules/demo_module/demo_document_lookup_provider.dart b/lib/modules/demo_module/demo_document_lookup_provider.dart index 2078b412..d16f222b 100644 --- a/lib/modules/demo_module/demo_document_lookup_provider.dart +++ b/lib/modules/demo_module/demo_document_lookup_provider.dart @@ -6,7 +6,7 @@ import 'package:test_sa/providers/loading_list_notifier.dart'; import '../../controllers/api_routes/api_manager.dart'; import '../../controllers/api_routes/urls.dart'; import '../../models/lookup.dart'; - +///TODO need to remove this when we have real api for demo document types lookup class DemoDocumentLookupProvider extends LoadingListNotifier { @override Future getData({int? id}) async { @@ -36,3 +36,4 @@ class DemoDocumentLookupProvider extends LoadingListNotifier { } } } + diff --git a/lib/modules/demo_module/models/demo_attachment_model.dart b/lib/modules/demo_module/models/demo_attachment_model.dart index ecc6475e..37c76e8a 100644 --- a/lib/modules/demo_module/models/demo_attachment_model.dart +++ b/lib/modules/demo_module/models/demo_attachment_model.dart @@ -1,31 +1,33 @@ -import 'package:test_sa/models/lookup.dart'; +//TODO : need to remove this class -class DemoAttachments { - int? id; - num? demoRequestId; - num? documentTypeId; - Lookup? documentType; - String? attachmentName; - String? originalName; - - DemoAttachments({this.id, this.documentTypeId, this.documentType, this.attachmentName, this.demoRequestId, this.originalName}); - - DemoAttachments.fromJson(dynamic json) { - id = json['id']; - documentTypeId = json['documentTypeId']; - documentType = json['documentType'] != null ? Lookup.fromJson(json['documentType']) : null; - demoRequestId = json['demoRequestId']; - attachmentName = json['attachmentName']; - originalName = json['originalName']; - } - - Map toJson() { - final map = {}; - map['id'] = id; - map['documentTypeId'] = documentTypeId; - map['attachmentName'] = attachmentName; - map['demoRequestId'] = demoRequestId; - map['originalName'] = originalName; - return map; - } -} +// import 'package:test_sa/models/lookup.dart'; +// +// class DemoAttachments { +// int? id; +// num? demoRequestId; +// Lookup? documentType; +// String? attachmentName; +// String? originalName; +// +// DemoAttachments({this.id, this.documentType, this.attachmentName, this.demoRequestId, this.originalName}); +// +// DemoAttachments.fromJson(dynamic json) { +// id = json['id']; +// documentType = json['documentType'] != null ? Lookup.fromJson(json['documentType']) : null; +// demoRequestId = json['demoRequestId']; +// attachmentName = json['attachmentName']; +// originalName = json['originalName']; +// } +// +// Map toJson() { +// final map = {}; +// map['id'] = id; +// if(documentType!=null){ +// map['documentTypeId'] = documentType?.id; +// } +// map['attachmentName'] = attachmentName; +// map['demoRequestId'] = demoRequestId; +// map['originalName'] = originalName; +// return map; +// } +// } diff --git a/lib/modules/demo_module/models/demo_form_model.dart b/lib/modules/demo_module/models/demo_form_model.dart index c591dd98..4adc1970 100644 --- a/lib/modules/demo_module/models/demo_form_model.dart +++ b/lib/modules/demo_module/models/demo_form_model.dart @@ -1,3 +1,4 @@ +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/new_models/building.dart'; import 'package:test_sa/models/new_models/floor.dart'; @@ -32,7 +33,7 @@ class DemoFormModel { Rooms? room; SuppEngineerWorkOrders? supEngineer; SupplierDetails? vendor; - List? demoAttachment; + List? demoAttachment; bool demoEaluationAcknowledge; bool acknowledgeNotEquipment; @@ -87,34 +88,7 @@ class DemoFormModel { "demoEaluationAcknowledge": demoEaluationAcknowledge, "acknowledgeNotEquipment": acknowledgeNotEquipment, "demoAttachments": - // [ - // { - // "id": 3, - // // "documentType": { - // // "id": 7748, - // // "name": "February", - // // "value": 2 - // // }, - // "documentTypeId": 7748, - // "attachmentName": "6c9f50b0-1c92-4ae9-ae64-7c284c61ea72.jpg", - // "originalName": "scaled_d245df97-1289-4d0c-92a0-569abedfb0db8154518103327960943.jpg", - // "demoRequestId": 3 - // }, - // { - // "id": 4, - // // "documentType": { - // // "id": 7748, - // // "name": "February", - // // "value": 2 - // // }, - // "documentTypeId": 7748, - // "attachmentName": "346e04f6-0f9b-4004-ad85-4cdbf8318f7c.jpg", - // "originalName": "scaled_85790b6c-7b16-46e6-891c-11c316d5897a2973693360957767376.jpg", - // "demoRequestId": 3 - // } - // ] - - demoAttachment != null ? demoAttachment!.map((v) => v.toJson()).toList() : [], + demoAttachment != null ? demoAttachment!.map((v) => v.toDemoJson()).toList() : [], }; } @@ -123,7 +97,7 @@ class DemoFormModel { "id": id, "supplierId": vendor?.id, "suppPersonId": supEngineer?.id, - "demoAttachments": demoAttachment != null ? demoAttachment!.map((v) => v.toJson()).toList() : [], + "demoAttachments": demoAttachment != null ? demoAttachment!.whereType().map((v) => v.toDemoJson()).toList() : [], }; } } diff --git a/lib/modules/demo_module/models/demo_request_model.dart b/lib/modules/demo_module/models/demo_request_model.dart index 2c07f111..856ede80 100644 --- a/lib/modules/demo_module/models/demo_request_model.dart +++ b/lib/modules/demo_module/models/demo_request_model.dart @@ -1,8 +1,8 @@ import 'package:test_sa/models/device/asset_by_id_model.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/service_request/supp_engineer_work_orders.dart'; import 'package:test_sa/models/service_request/supplier_details.dart'; -import 'package:test_sa/modules/demo_module/models/demo_attachment_model.dart'; import 'package:test_sa/modules/loan_module/models/medical_department_model.dart'; class DemoRequestModel { @@ -29,8 +29,8 @@ class DemoRequestModel { SuppEngineerWorkOrders? suppPerson; Lookup? status; Lookup? endUserStatus; - List? demoAttachments; - List? supplierDemoAttachments; + List? demoAttachments; + List? supplierDemoAttachments; dynamic demoAsset; dynamic demoInstallationTaskJob; dynamic demoPullOutTaskJob; @@ -96,8 +96,8 @@ class DemoRequestModel { suppPerson = json['suppPerson'] != null ? (SuppEngineerWorkOrders.fromJson(json['suppPerson'])) : null; status = json['status'] != null ? (Lookup.fromJson(json['status'])) : null; endUserStatus = json['endUserStatus'] != null ? (Lookup.fromJson(json['endUserStatus'])) : null; - demoAttachments = json['demoAttachments'] != null ? (json['demoAttachments'] as List).map((e) => DemoAttachments.fromJson(e)).toList() : null; - supplierDemoAttachments = json['supplierDemoAttachments'] != null ? (json['supplierDemoAttachments'] as List).map((e) => DemoAttachments.fromJson(e)).toList() : null; + demoAttachments = json['demoAttachments'] != null ? (json['demoAttachments'] as List).map((e) => GenericAttachmentModel.fromDemoJson(e)).toList() : null; + supplierDemoAttachments = json['supplierDemoAttachments'] != null ? (json['supplierDemoAttachments'] as List).map((e) => GenericAttachmentModel.fromDemoJson(e)).toList() : null; demoAsset = json['demoAsset']; demoInstallationTaskJob = json['demoInstallationTaskJob']; demoPullOutTaskJob = json['demoPullOutTaskJob']; @@ -124,8 +124,8 @@ class DemoRequestModel { "demoPeriodId": demoPeriod?.id, "supplierId": supplier?.id, "suppPersonId": suppPerson?.id, - "demoAttachments": demoAttachments != null ? demoAttachments!.map((v) => v.toJson()).toList() : [], - "supplierDemoAttachments": supplierDemoAttachments != null ? supplierDemoAttachments!.map((v) => v.toJson()).toList() : [], + "demoAttachments": demoAttachments != null ? demoAttachments!.whereType().map((v) => v.toDemoJson()).toList() : [], + "supplierDemoAttachments": supplierDemoAttachments != null ? supplierDemoAttachments!.whereType().map((v) => v.toDemoJson()).toList() : [], }; } } diff --git a/lib/modules/demo_module/update_demo-request_view.dart b/lib/modules/demo_module/update_demo-request_view.dart index 02dae2d2..0fd95ef1 100644 --- a/lib/modules/demo_module/update_demo-request_view.dart +++ b/lib/modules/demo_module/update_demo-request_view.dart @@ -11,6 +11,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/helper/utils.dart'; +import 'package:test_sa/models/enums/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/new_models/building.dart'; @@ -20,7 +21,6 @@ import 'package:test_sa/models/service_request/supp_engineer_work_orders.dart'; import 'package:test_sa/models/service_request/supplier_details.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/demo_module/models/demo_attachment_model.dart'; import 'package:test_sa/modules/demo_module/models/demo_request_model.dart'; import 'package:test_sa/modules/demo_module/provider/demo_period_lookup_provider.dart'; import 'package:test_sa/modules/demo_module/provider/demo_provider.dart'; @@ -161,9 +161,9 @@ class _UpdateDemoRequestViewState extends State with Tick attachments.clear(); if (widget.dataModel.demoAttachments?.isNotEmpty ?? false) { for (final item in widget.dataModel.demoAttachments!) { - if ((item.attachmentName ?? '').isNotEmpty) { + if ((item.name ?? '').isNotEmpty) { attachments.add( - GenericAttachmentModel(name: item.attachmentName, id: item.id ?? 0, originalName: item.originalName, documentTypeId: item.documentType), + GenericAttachmentModel(name: item.name, id: item.id ?? 0, originalName: item.originalName, documentType: item.documentType), ); } } @@ -201,33 +201,34 @@ class _UpdateDemoRequestViewState extends State with Tick 16.height, "Attachments".bodyText(context).custom(color: AppColor.black10), 8.height, - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: "Document Type", - initialValue: demoDocumentLookup, - showShadow: false, - validator: (value) { - if (value == null) return "Mandatory"; - return null; - }, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - onSelect: (value) { - demoDocumentLookup = value; - setState(() {}); - }, - ), - 16.height, + + ///Need to confirm we can use same lookup.. + // SingleItemDropDownMenu( + // context: context, + // height: 56.toScreenHeight, + // title: "Document Type", + // initialValue: demoDocumentLookup, + // showShadow: false, + // validator: (value) { + // if (value == null) return "Mandatory"; + // return null; + // }, + // backgroundColor: AppColor.fieldBgColor(context), + // showAsBottomSheet: true, + // onSelect: (value) { + // demoDocumentLookup = value; + // setState(() {}); + // }, + // ), + // 16.height, AttachmentPicker( label: context.translation.attachments, attachment: attachments, buttonColor: AppColor.black10.withOpacity(demoDocumentLookup != null ? 1 : .4), onlyImages: false, - documentType: demoDocumentLookup, - enabled: demoDocumentLookup != null, + moduleId: RequestAttachmentTypeEnum.demo.id, showAsListView: true, - buttonIcon: 'image-plus'.toSvgAsset(color: (AppColor.primary10).withOpacity(demoDocumentLookup != null ? 1 : .4)), + buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), ), ], ).toShadowContainer(context, borderRadius: 20), @@ -615,7 +616,13 @@ class _UpdateDemoRequestViewState extends State with Tick for (var item in attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; //Todo need to pass attachmentType id as well. - _demoFormModel.demoAttachment?.add(DemoAttachments(id: item.id, demoRequestId: _demoFormModel.id ?? 0, attachmentName: fileName,originalName: fileName, documentTypeId: item.documentTypeId!.id)); + _demoFormModel.demoAttachment?.add(GenericAttachmentModel( + id: item.id, + name: fileName, + originalName: fileName, + moduleReferenceId: _demoFormModel.id ?? 0, + documentType: item.documentType, + )); } Utils.showLoading(context); DemoProvider demoProvider = Provider.of(context, listen: false); diff --git a/lib/modules/incident_module/create_incident_request_page.dart b/lib/modules/incident_module/create_incident_request_page.dart index d1535400..425f931d 100644 --- a/lib/modules/incident_module/create_incident_request_page.dart +++ b/lib/modules/incident_module/create_incident_request_page.dart @@ -11,6 +11,7 @@ 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/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/new_models/building.dart'; @@ -41,7 +42,6 @@ import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import '../../models/new_models/department.dart'; import '../../new_views/swipe_module/dialoge/info_dialog.dart'; import 'flow_medical_department_provider.dart'; -import 'incident_attachment_model.dart'; class CreateIncidentRequestPage extends StatefulWidget { static const String id = "/create-incident"; @@ -172,6 +172,7 @@ class _CreateIncidentRequestPageState extends State { label: context.translation.attachments, attachment: attachments, buttonColor: AppColor.black10, + moduleId: RequestAttachmentTypeEnum.incidents.id, onlyImages: false, showAsListView: true, buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), @@ -694,16 +695,16 @@ class _CreateIncidentRequestPageState extends State { payload["occurrenceDate"] = occurrenceDate!.toIso8601String(); _formKey.currentState!.save(); - List attachmentList = []; + List attachmentList = []; for (var item in attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - attachmentList.add(IncidentAttachments(id: 0, attachmentName: fileName, incidentId: 0)); + attachmentList.add(GenericAttachmentModel(id: 0, name: fileName, moduleReferenceId: 0,documentType: item.documentType)); } Utils.showLoading(context); IncidentProvider incidentProvider = Provider.of(context, listen: false); - payload["incidentAttachments"] = attachmentList.map((v) => v.toJson()).toList(); + payload["incidentAttachments"] = attachmentList.map((v) => v.toIncidentJson()).toList(); bool isSuccess = await incidentProvider.addIncidentRequest(payload); Utils.hideLoading(context); if (isSuccess) { diff --git a/lib/modules/incident_module/incident_attachment_model.dart b/lib/modules/incident_module/incident_attachment_model.dart index bf1eabc9..2edd8811 100644 --- a/lib/modules/incident_module/incident_attachment_model.dart +++ b/lib/modules/incident_module/incident_attachment_model.dart @@ -1,24 +1,26 @@ -class IncidentAttachments { - num? id; - num? incidentId; - String? attachmentName; - String? attachmentDescription; +//TODO : need to delete this - IncidentAttachments({this.id, this.attachmentName, this.incidentId, this.attachmentDescription}); - - IncidentAttachments.fromJson(dynamic json) { - id = json['id']; - incidentId = json['incidentId']; - attachmentName = json['attachmentName']; - attachmentDescription = json['attachmentDescription']; - } - - Map toJson() { - final map = {}; - map['id'] = id; - map['attachmentName'] = attachmentName; - map['incidentId'] = incidentId; - map['attachmentDescription'] = attachmentDescription; - return map; - } -} +// class IncidentAttachments { +// num? id; +// num? incidentId; +// String? attachmentName; +// String? attachmentDescription; +// +// IncidentAttachments({this.id, this.attachmentName, this.incidentId, this.attachmentDescription}); +// +// IncidentAttachments.fromJson(dynamic json) { +// id = json['id']; +// incidentId = json['incidentId']; +// attachmentName = json['attachmentName']; +// attachmentDescription = json['attachmentDescription']; +// } +// +// Map toJson() { +// final map = {}; +// map['id'] = id; +// map['attachmentName'] = attachmentName; +// map['incidentId'] = incidentId; +// map['attachmentDescription'] = attachmentDescription; +// return map; +// } +// } diff --git a/lib/modules/incident_module/incident_data_model.dart b/lib/modules/incident_module/incident_data_model.dart index 7c9f3ba7..82ae1306 100644 --- a/lib/modules/incident_module/incident_data_model.dart +++ b/lib/modules/incident_module/incident_data_model.dart @@ -1,3 +1,4 @@ +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/modules/incident_module/incident_attachment_model.dart'; class IncidentDataModel { @@ -73,7 +74,7 @@ class IncidentDataModel { String? approvalSignature; String? occurrenceDate; String? createdDate; - List? incidentAttachments; + List? incidentAttachments; int? workOrderId; String? workOrderNo; @@ -230,9 +231,9 @@ class IncidentDataModel { workOrderId = json['workOrderId']; workOrderNo = json['workOrderNo']; if (json['incidentAttachments'] != null) { - incidentAttachments = []; + incidentAttachments = []; json['incidentAttachments'].forEach((v) { - incidentAttachments!.add(IncidentAttachments.fromJson(v)); + incidentAttachments!.add(GenericAttachmentModel.fromIncidentJson(v)); }); } } @@ -314,7 +315,7 @@ class IncidentDataModel { data['workOrderId'] = this.workOrderId; data['workOrderNo'] = this.workOrderNo; if (this.incidentAttachments != null) { - data['incidentAttachments'] = this.incidentAttachments!.map((v) => v.toJson()).toList(); + data['incidentAttachments'] = this.incidentAttachments!.map((v) => v.toIncidentJson()).toList(); } return data; } diff --git a/lib/modules/incident_module/incident_detail_page.dart b/lib/modules/incident_module/incident_detail_page.dart index e9602f8c..848a59c5 100644 --- a/lib/modules/incident_module/incident_detail_page.dart +++ b/lib/modules/incident_module/incident_detail_page.dart @@ -9,6 +9,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/models/generic_attachment_model.dart'; import 'package:test_sa/modules/cm_module/cm_detail_page.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/incident_module/incident_attachment_model.dart'; @@ -40,44 +41,51 @@ class IncidentDetailPage extends StatelessWidget { if (snapshot.connectionState == ConnectionState.waiting) return CircularProgressIndicator(color: AppColor.loadingColor(context)).center; if (snapshot.data == null) return const NoDataFound().center; - List allAttachments = snapshot.data!.incidentAttachments!; + List allAttachments = (snapshot.data!.incidentAttachments ?? []).whereType().toList(); - return SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - StatusLabel( - label: snapshot.data!.incidentStatusName!, - textColor: AppColor.getRequestStatusTextColorByName(context, snapshot.data!.incidentStatusName!), - backgroundColor: AppColor.getRequestStatusColorByName(context, snapshot.data!.incidentStatusName!), - ), - 1.width.expanded, - InfoDateWidget(snapshot.data!.createdDate?.toString() ?? ""), - ], - ), - // 12.height, - ...requesterDetails(context, snapshot.data!), - const Divider().defaultStyle(context), - ...requestDetails(context, snapshot.data!), - if (snapshot.data!.ovrTicketNumber?.isNotEmpty ?? false) ovrInformation(context, snapshot.data!.ovrTicketNumber!), - const Divider().defaultStyle(context), - ...assetDetails(context, snapshot.data!), - const Divider().defaultStyle(context), - ...personInvolvedDetails(context, snapshot.data!), - if (allAttachments.isNotEmpty) ...[ - const Divider().defaultStyle(context), - InfoHeader16Widget("Attachments".addTranslation), - FilesList(images: allAttachments.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), + return SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: snapshot.data!.incidentStatusName!, + textColor: AppColor.getRequestStatusTextColorByName(context, snapshot.data!.incidentStatusName!), + backgroundColor: AppColor.getRequestStatusColorByName(context, snapshot.data!.incidentStatusName!), + ), + 1.width.expanded, + InfoDateWidget(snapshot.data!.createdDate?.toString() ?? ""), ], + ), + // 12.height, + ...requesterDetails(context, snapshot.data!), + const Divider().defaultStyle(context), + ...requestDetails(context, snapshot.data!), + if (snapshot.data!.ovrTicketNumber?.isNotEmpty ?? false) ovrInformation(context, snapshot.data!.ovrTicketNumber!), + const Divider().defaultStyle(context), + ...assetDetails(context, snapshot.data!), + const Divider().defaultStyle(context), + ...personInvolvedDetails(context, snapshot.data!), + if (allAttachments.isNotEmpty) ...[ + const Divider().defaultStyle(context), + InfoHeader16Widget("Attachments".addTranslation), + 4.height, + FilesList( + showAsListView: true, + types: allAttachments + .whereType() + .where((e) => e.documentType != null && e.documentType!.name!.isNotEmpty) + .map((toElement) => toElement.documentType!.name!) + .toList(), + images: allAttachments.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), ], - ).toShadowContainer(context), - ); - }), - )); + ], + ).toShadowContainer(context), + ); + }))); } List requestDetails(BuildContext context, IncidentDataModel incidentData) { diff --git a/lib/modules/internal_audit_module/models/engineer_data_model.dart b/lib/modules/internal_audit_module/models/engineer_data_model.dart index dbb34d24..b21ec833 100644 --- a/lib/modules/internal_audit_module/models/engineer_data_model.dart +++ b/lib/modules/internal_audit_module/models/engineer_data_model.dart @@ -1,4 +1,4 @@ -import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; class EngineerData { int? id; @@ -9,7 +9,7 @@ class EngineerData { bool? isComplete; int? statusId; int? requestId; - List? attachments; + List? attachments; EngineerData({ this.id, @@ -32,7 +32,7 @@ class EngineerData { isComplete = json['isComplete']; statusId = json['statusId']; requestId = json['requestId']; - attachments = json['attachments'] != null ? (json['attachments'] as List).map((e) => InternalAuditAttachments.fromJson(e)).toList() : []; + attachments = json['attachments'] != null ? (json['attachments'] as List).map((e) => GenericAttachmentModel.fromInternalAuditJson(e)).toList() : []; } Map toJson() { @@ -46,7 +46,7 @@ class EngineerData { data['statusId'] = statusId; data['requestId'] = requestId; if (attachments != null) { - data['attachments'] = attachments!.map((e) => e.toJson()).toList(); + data['attachments'] = attachments!.whereType().map((e) => e.toInternalAuditJson()).toList(); } return data; } diff --git a/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart b/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart index 1e62dd1d..32dc2a08 100644 --- a/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart +++ b/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart @@ -1,6 +1,5 @@ - import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/engineer_data_model.dart'; -import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/internal_audit_timer_model.dart'; class EquipmentInternalAuditDataModel { @@ -15,7 +14,7 @@ class EquipmentInternalAuditDataModel { dynamic manufacture; String? remarks; List? equipmentsFindings; - List? attachments; + List? attachments; EngineerData? engineerData; @@ -54,7 +53,7 @@ class EquipmentInternalAuditDataModel { } attachments = json['attachments'] != null ? (json['attachments'] as List) - .map((e) => InternalAuditAttachments.fromJson(e)) + .map((e) => GenericAttachmentModel.fromInternalAuditJson(e)) .where((e) => e.name != null) // optional filter if you want to skip null names .toList() : []; @@ -86,7 +85,9 @@ class EquipmentInternalAuditDataModel { data['equipmentsFindings'] = equipmentsFindings!.map((v) => v.toJson()).toList(); } - data['attachments'] = attachments; + if (attachments != null) { + data['attachments'] = attachments!.whereType().map((v) => v.toInternalAuditJson()).toList(); + } if (engineerData != null) data['engineerData'] = engineerData!.toJson(); return data; } diff --git a/lib/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart b/lib/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart index e6a79e91..c23d9724 100644 --- a/lib/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart +++ b/lib/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart @@ -5,7 +5,7 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/models/device/asset.dart'; import 'package:test_sa/models/fault_description.dart'; import 'package:test_sa/models/lookup.dart'; -import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; class EquipmentInternalAuditFormModel { int? id=0; @@ -14,7 +14,7 @@ class EquipmentInternalAuditFormModel { String? woOrderNo; List? devicePhotos; List findings =[]; - List attachments = []; + List attachments = []; String? remarks; Asset? device; EquipmentInternalAuditFormModel({ @@ -32,7 +32,7 @@ class EquipmentInternalAuditFormModel { 'assetId': device?.id, 'auditorId': auditorId, 'findings': findings.map((e) => {'findingId': e.value}).toList(), - 'attachments': attachments.map((e) => e.toJson()).toList(), + 'attachments': attachments.whereType().map((e) => e.toInternalAuditJson()).toList(), 'remarks': remarks, }; } diff --git a/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart b/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart index f2b14df1..12adfa2d 100644 --- a/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart +++ b/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart @@ -1,26 +1,32 @@ -import 'dart:developer'; - -class InternalAuditAttachments { - InternalAuditAttachments({this.id, this.originalName, this.name, this.createdBy}); - - int? id; - String? name; - String? originalName; - String? createdBy; - - InternalAuditAttachments.fromJson(Map json) { - id = json['id']; - name = (json['name'] != null && !json['name'].toString().startsWith('data:image/jpeg')) ? json['name'] : null; - originalName = json['originalName']; - createdBy = json['createdBy']; - } - - Map toJson() { - final Map data = {}; - data['id'] = id; - data['name'] = name; - data['originalName'] = originalName; - // data['createdBy'] = createdBy; - return data; - } -} +//TODO : need to remove this class. +// import 'dart:developer'; +// +// import 'package:test_sa/models/lookup.dart'; +// +// class InternalAuditAttachments { +// InternalAuditAttachments({this.id, this.originalName, this.name, this.createdBy,this.documentType}); +// +// int? id; +// String? name; +// String? originalName; +// String? createdBy; +// Lookup ? documentType; +// +// InternalAuditAttachments.fromJson(Map json) { +// id = json['id']; +// name = (json['name'] != null && !json['name'].toString().startsWith('data:image/jpeg')) ? json['name'] : null; +// originalName = json['originalName']; +// createdBy = json['createdBy']; +// documentType =json['documentType']; +// } +// +// Map toJson() { +// final Map data = {}; +// data['id'] = id; +// data['name'] = name; +// data['originalName'] = originalName; +// data['documentTypeId'] = documentType?.id; +// // data['createdBy'] = createdBy; +// return data; +// } +// } diff --git a/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart b/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart index 0546ccdc..32d66d87 100644 --- a/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart +++ b/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart @@ -1,6 +1,6 @@ import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/modules/internal_audit_module/models/engineer_data_model.dart'; -import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart'; class SystemInternalAuditDataModel { @@ -19,7 +19,7 @@ class SystemInternalAuditDataModel { String? createdDate; String? modifiedBy; String? modifiedDate; - List? attachments; + List? attachments; EngineerData? engineerData; SystemInternalAuditDataModel({ @@ -60,7 +60,7 @@ class SystemInternalAuditDataModel { modifiedDate = json['modifiedDate']; attachments = json['attachments'] != null ? (json['attachments'] as List) - .map((e) => InternalAuditAttachments.fromJson(e)) + .map((e) => GenericAttachmentModel.fromInternalAuditJson(e)) .where((e) => e.name != null) // optional filter if you want to skip null names .toList() : []; @@ -84,6 +84,9 @@ class SystemInternalAuditDataModel { data['createdDate'] = createdDate; data['modifiedBy'] = modifiedBy; data['modifiedDate'] = modifiedDate; + if (attachments != null) { + data['attachments'] = attachments!.whereType().map((v) => v.toInternalAuditJson()).toList(); + } if (engineerData != null) data['engineerData'] = engineerData!.toJson(); return data; } diff --git a/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart b/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart index 3fda34d0..f3de4f53 100644 --- a/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart +++ b/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart @@ -1,7 +1,7 @@ import 'dart:developer'; import 'package:test_sa/models/lookup.dart'; -import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; class SystemInternalAuditFormModel { int? id; @@ -13,7 +13,7 @@ class SystemInternalAuditFormModel { int? correctiveMaintenanceId; int? planPreventiveVisitId; int? assetTransferId; - List? attachments = []; + List? attachments = []; int? taskJobId; int? taskAlertJobId; int? gasRefillId; @@ -56,7 +56,7 @@ class SystemInternalAuditFormModel { 'gasRefillId': gasRefillId, 'planRecurrentTaskId': planRecurrentTaskId, 'statusId': statusId, - 'attachments': attachments?.map((e) => e.toJson()).toList(), + 'attachments': attachments?.whereType().map((e) => e.toInternalAuditJson()).toList(), }; } } diff --git a/lib/modules/internal_audit_module/models/update_audit_form_model.dart b/lib/modules/internal_audit_module/models/update_audit_form_model.dart index 6942d51f..bdf9ec00 100644 --- a/lib/modules/internal_audit_module/models/update_audit_form_model.dart +++ b/lib/modules/internal_audit_module/models/update_audit_form_model.dart @@ -1,5 +1,5 @@ import 'package:test_sa/models/timer_model.dart'; -import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/internal_audit_timer_model.dart'; class AuditFormModel { @@ -10,7 +10,7 @@ class AuditFormModel { DateTime? startTime; DateTime? endTime; double? totalHours; - List? attachments; + List? attachments; bool? isComplete; TimerModel? auditTimerModel = TimerModel(); List? auditTimers = []; @@ -40,7 +40,7 @@ class AuditFormModel { endTime = json['endTime'] != null ? DateTime.tryParse(json['endTime']) : null; totalHours = json['totalHours']?.toDouble(); if (json['attachments'] != null) { - attachments = (json['attachments'] as List).map((e) => InternalAuditAttachments.fromJson(e)).toList(); + attachments = (json['attachments'] as List).map((e) => GenericAttachmentModel.fromInternalAuditJson(e)).toList(); } isComplete = json['isComplete']; } @@ -54,7 +54,7 @@ class AuditFormModel { 'endTime': endTime?.toIso8601String(), // 'auditTimer': auditTimers, 'totalHours': totalHours, - 'attachments': attachments?.map((e) => e.toJson()).toList(), + 'attachments': attachments?.whereType().map((e) => e.toInternalAuditJson()).toList(), 'isComplete': isComplete, }; } diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart index 99889178..c501205e 100644 --- a/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart @@ -8,12 +8,13 @@ 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/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.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/models/generic_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart'; -import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; @@ -119,6 +120,8 @@ class _CreateEquipmentInternalAuditFormState extends State const AppLazyLoading()); _equipmentinternalAuditModel.auditorId = context.userProvider.user?.userID; diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart index b617db05..239a366a 100644 --- a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart @@ -10,7 +10,7 @@ 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/internal_audit_module/models/equipment_internal_audit_data_model.dart'; -import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; @@ -41,7 +41,7 @@ class _EquipmentInternalAuditDetailPageState extends State allAttachments = []; + List allAttachments = []; @override void initState() { @@ -56,8 +56,8 @@ class _EquipmentInternalAuditDetailPageState extends State() ?? []), + ...(model?.engineerData?.attachments?.whereType() ?? []), ]; } @@ -118,17 +118,24 @@ class _EquipmentInternalAuditDetailPageState extends State URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), + InfoHeader16Widget("Attachments".addTranslation), + 4.height, + FilesList( + showAsListView: true, + types: allAttachments + .whereType() + .where((e) => e.documentType != null && e.documentType!.name!.isNotEmpty) + .map((toElement) => toElement.documentType!.name!) + .toList(), + images: allAttachments.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), ], ], ).paddingAll(0).toShadowContainer(context), diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart index 9c5be1d2..cf60b860 100644 --- a/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart @@ -10,14 +10,14 @@ 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/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/timer_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/internal_audit_module/models/internal_audit_timer_model.dart'; -import 'package:test_sa/modules/internal_audit_module/models/update_audit_form_model.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart'; -import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/update_audit_form_model.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_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'; @@ -26,6 +26,7 @@ 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/working_time_tile.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/item_views/info_header_widget.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import 'package:test_sa/views/widgets/timer/app_timer.dart'; import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart'; @@ -62,7 +63,7 @@ class _UpdateEquipmentInternalAuditPageState extends State GenericAttachmentModel(id: e.id?.toInt() ?? 0, name: e.name!)).toList() ?? []; + _attachments = widget.model?.engineerData?.attachments?.whereType().map((e) => GenericAttachmentModel(id: e.id?.toInt() ?? 0, name: e.name ?? '')).toList() ?? []; calculateWorkingTime(); } @@ -129,9 +130,10 @@ class _UpdateEquipmentInternalAuditPageState extends State(context, listen: false); if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); - _model.attachments=[]; + _model.attachments = []; for (var item in _attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - _model.attachments?.add(InternalAuditAttachments(id: item.id, name: fileName)); + _model.attachments?.add(GenericAttachmentModel( + id: item.id, + name: fileName, + documentType: item.documentType, + )); } showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); _model.auditorId = context.userProvider.user?.userID; diff --git a/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart index 7e52f0cf..1f264369 100644 --- a/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart +++ b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart @@ -9,7 +9,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/cm_module/views/components/action_button/footer_action_button.dart'; -import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_data_model.dart'; import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/update_system_internal_audit_page.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; @@ -39,7 +39,7 @@ class _SystemInternalAuditDetailPageState extends State allAttachments = []; + List allAttachments = []; @override void initState() { @@ -54,8 +54,8 @@ class _SystemInternalAuditDetailPageState extends State() ?? []), + ...(model?.engineerData?.attachments?.whereType() ?? []), ]; } @@ -86,19 +86,19 @@ class _SystemInternalAuditDetailPageState extends State URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), + 8.height, + FilesList( + showAsListView: true, + types: allAttachments + .whereType() + .where((e) => e.documentType != null && e.documentType!.name!.isNotEmpty) + .map((toElement) => toElement.documentType!.name!) + .toList(), + images: allAttachments.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), ], ], ).paddingAll(0).toShadowContainer(context), diff --git a/lib/modules/internal_audit_module/pages/system_internal_audit/update_system_internal_audit_page.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/update_system_internal_audit_page.dart index 2c8541e0..ae430aec 100644 --- a/lib/modules/internal_audit_module/pages/system_internal_audit/update_system_internal_audit_page.dart +++ b/lib/modules/internal_audit_module/pages/system_internal_audit/update_system_internal_audit_page.dart @@ -10,14 +10,13 @@ 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/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/timer_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/internal_audit_module/models/internal_audit_timer_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_data_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/update_audit_form_model.dart'; -import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_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'; @@ -62,7 +61,7 @@ class _UpdateSystemInternalAuditPageState extends State GenericAttachmentModel(id: e.id?.toInt() ?? 0, name: e.name!)).toList() ?? []; + _attachments = widget.model?.engineerData?.attachments?.whereType().map((e) => GenericAttachmentModel(id: e.id?.toInt() ?? 0, name: e.name ?? '')).toList() ?? []; calculateWorkingTime(); } @@ -130,8 +129,9 @@ class _UpdateSystemInternalAuditPageState extends State json) { - loanId = json['loanId']; - attachmentName = json['attachmentName']; - loanAttachmentTypeId = json['loanAttachmentTypeId']; - attachmentDescription = json['attachmentDescription']; - id = json['id']; - createdBy = json['createdBy']; - createdDate = json['createdDate']; - modifiedBy = json['modifiedBy']; - modifiedDate = json['modifiedDate']; - } - - Map toJson() { - final Map data = new Map(); - data['loanId'] = this.loanId; - data['attachmentName'] = this.attachmentName; - data['loanAttachmentTypeId'] = this.loanAttachmentTypeId; - data['attachmentDescription'] = this.attachmentDescription; - data['id'] = this.id; - data['createdBy'] = this.createdBy; - data['createdDate'] = this.createdDate; - data['modifiedBy'] = this.modifiedBy; - data['modifiedDate'] = this.modifiedDate; - return data; - } -} +//TODO need to delete this . +// class LoanAttachmentModel { +// int? loanId; +// String? attachmentName; +// int? loanAttachmentTypeId; +// String? attachmentDescription; +// int? id; +// String? createdBy; +// String? createdDate; +// String? modifiedBy; +// String? modifiedDate; +// +// LoanAttachmentModel({this.loanId, this.attachmentName, this.loanAttachmentTypeId, this.attachmentDescription, this.id, this.createdBy, this.createdDate, this.modifiedBy, this.modifiedDate}); +// +// LoanAttachmentModel.fromJson(Map json) { +// loanId = json['loanId']; +// attachmentName = json['attachmentName']; +// loanAttachmentTypeId = json['loanAttachmentTypeId']; +// attachmentDescription = json['attachmentDescription']; +// id = json['id']; +// createdBy = json['createdBy']; +// createdDate = json['createdDate']; +// modifiedBy = json['modifiedBy']; +// modifiedDate = json['modifiedDate']; +// } +// +// Map toJson() { +// final Map data = new Map(); +// data['loanId'] = this.loanId; +// data['attachmentName'] = this.attachmentName; +// data['loanAttachmentTypeId'] = this.loanAttachmentTypeId; +// data['attachmentDescription'] = this.attachmentDescription; +// data['id'] = this.id; +// data['createdBy'] = this.createdBy; +// data['createdDate'] = this.createdDate; +// data['modifiedBy'] = this.modifiedBy; +// data['modifiedDate'] = this.modifiedDate; +// return data; +// } +// } diff --git a/lib/modules/loan_module/models/loan_form_model.dart b/lib/modules/loan_module/models/loan_form_model.dart index e1722ba7..b8211caa 100644 --- a/lib/modules/loan_module/models/loan_form_model.dart +++ b/lib/modules/loan_module/models/loan_form_model.dart @@ -1,3 +1,4 @@ +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/site.dart'; @@ -24,7 +25,7 @@ class LoanFormModel { SupplierDetails? supplier; SuppEngineerWorkOrders? supEngineer; MedicalDepartmentModel? department; - List? loanAttachment; + List? loanAttachment; MappedSite? mappedSite; TrafDepartment? mappedDepartment; @@ -51,40 +52,6 @@ class LoanFormModel { this.mappedDepartment, }); - //{ - // "id": 0, - // "employeeId": "fa29a9de-1337-4729-b823-68c6ecffdd33", - // "requestorUserID": "fa29a9de-1337-4729-b823-68c6ecffdd33", - // "employeeName": "engineer-dev", - // "employeeEmail": "Engineer_Dev@yahoo.com", - // "positionName": "High", - // "requesterExtensionNumber": "7726", - // "requesterContactNumber": "72132197", - // "siteId": 1, - // "departmentId": 5, - // "loanTypeId": 6448, - // "doctorName": "Doctor A", - // "doctorContact": "0561432451", - // "doctorEmail": "doctor@test.com", - // "itemDescription": "Test item", - // "requestDescription": "Test request", - // "loanPeriodId": 6453, - // "assetId": null, - // "assetNumber": "", - // "assetName": "", - // "assetSerialNumber": "", - // "model": "Model A", - // "manufacturer": "Siemens", - // "vendorName": "Vendor A", - // "vendorRepName": "Vendor Rep A", - // "vendorContact": "0561432455", - // "vendorEmail": "vendor@test.com", - // "loanStatusId": 1, - // "loanAttachments": [], - // "submittedAt": "2025-11-13T12:11:12.673Z", - // "updatedAt": null, - // "cMWOItemId": null - // } Map toJson() { return { @@ -103,50 +70,10 @@ class LoanFormModel { "vendorContact": vendorNumber, "vendorEmail": vendorEmail, "isNewVendor": isNewVendor, - // 'siteId': site?.id, 'siteId': mappedSite?.id, - // 'departmentId': department?.id, 'departmentId': mappedDepartment?.id, - "loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toJson()).toList() : [], + "loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toLoanJson()).toList() : [], }; } } -class LoanAttachments { - num? id; - num? loanAttachmentTypeId; - num? loanId; - String? attachmentName; - String? attachmentDescription; - - LoanAttachments({this.id, this.loanAttachmentTypeId, this.attachmentName, this.loanId, this.attachmentDescription}); - - LoanAttachments.fromJson(dynamic json) { - id = json['id']; - loanAttachmentTypeId = json['loanAttachmentTypeId']; - loanId = json['loanId']; - attachmentName = json['attachmentName']; - attachmentDescription = json['attachmentDescription']; - } - - // LoanAttachments copyWith({ - // num? id, // Parameter is now nullable - // String? name, // Parameter is now nullable - // String? originalName, // Parameter is now nullable - // }) => - // LoanAttachments( - // id: id ?? this.id, - // name: name ?? this.name, - // originalName: originalName ?? this.originalName, - // ); - - Map toJson() { - final map = {}; - map['id'] = id; - map['loanAttachmentTypeId'] = loanAttachmentTypeId; - map['attachmentName'] = attachmentName; - map['loanId'] = loanId; - map['attachmentDescription'] = attachmentDescription; - return map; - } -} diff --git a/lib/modules/loan_module/models/loan_installation_pullout_form_model.dart b/lib/modules/loan_module/models/loan_installation_pullout_form_model.dart index ff2129db..e4d37276 100644 --- a/lib/modules/loan_module/models/loan_installation_pullout_form_model.dart +++ b/lib/modules/loan_module/models/loan_installation_pullout_form_model.dart @@ -1,14 +1,14 @@ import 'dart:convert'; import 'dart:typed_data'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/timer_model.dart'; -import 'package:test_sa/modules/loan_module/models/loan_form_model.dart'; class LoanInstallationPullOutFormModel { String? snNo; DateTime? date; Uint8List? signature; - List? loanAttachment; + List? loanAttachment; TimerModel? timerModel = TimerModel(); DateTime? startTime; DateTime? endTime; @@ -32,13 +32,11 @@ class LoanInstallationPullOutFormModel { }); Map toJson() { - //Need to check payload parm they need return { - // 'snNo': snNo, 'serialNumber': snNo, 'installationDate': date?.toIso8601String(), 'pulloutDate': date?.toIso8601String(), - "loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toJson()).toList() : [], + "loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toLoanJson()).toList() : [], "installationSignature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, "signature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, "pulloutSignature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, @@ -53,16 +51,11 @@ class LoanInstallationPullOutFormModel { } Map toInstallationJson() { - //Need to check payload parm they need return { - // 'snNo': snNo, 'serialNumber': snNo, 'installationDate': date?.toIso8601String(), - // 'pulloutDate': date?.toIso8601String(), - "loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toJson()).toList() : [], + "loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toLoanJson()).toList() : [], "installationSignature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, - // "signature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, - // "pulloutSignature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, 'startTime': startTime?.toIso8601String(), 'endTime': endTime?.toIso8601String(), 'totalHours': totalHours, @@ -74,15 +67,10 @@ class LoanInstallationPullOutFormModel { } Map toPulloutJson() { - //Need to check payload parm they need return { - // 'snNo': snNo, 'serialNumber': snNo, - // 'installationDate': date?.toIso8601String(), 'pulloutDate': date?.toIso8601String(), - "loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toJson()).toList() : [], - // "installationSignature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, - // "signature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, + "loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toLoanJson()).toList() : [], "pulloutSignature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, 'startTime': startTime?.toIso8601String(), 'endTime': endTime?.toIso8601String(), diff --git a/lib/modules/loan_module/models/loan_request_model.dart b/lib/modules/loan_module/models/loan_request_model.dart index 1f76cda8..04b097e9 100644 --- a/lib/modules/loan_module/models/loan_request_model.dart +++ b/lib/modules/loan_module/models/loan_request_model.dart @@ -1,3 +1,4 @@ +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'loan_attachment_model.dart'; @@ -34,7 +35,7 @@ class LoanRequestModel { String? vendorRepName; String? vendorContact; String? vendorEmail; - List? loanAttachments; + List? loanAttachments; int? loanStatusId; String? loanStatusName; int? loanStatusValue; @@ -154,11 +155,11 @@ class LoanRequestModel { vendorRepName = json['vendorRepName']; vendorContact = json['vendorContact']; vendorEmail = json['vendorEmail']; - loanAttachments = []; + loanAttachments = []; if (json['loanAttachments'] != null) { - loanAttachments = []; + loanAttachments = []; json['loanAttachments'].forEach((v) { - loanAttachments!.add(new LoanAttachmentModel.fromJson(v)); + loanAttachments!.add(GenericAttachmentModel.fromLoanDetailJson(v)); }); } loanStatusId = json['loanStatusId']; @@ -222,8 +223,8 @@ class LoanRequestModel { data['vendorRepName'] = this.vendorRepName; data['vendorContact'] = this.vendorContact; data['vendorEmail'] = this.vendorEmail; - if (this.loanAttachments != null) { - data['loanAttachments'] = this.loanAttachments!.map((v) => v.toJson()).toList(); + if (loanAttachments != null) { + data['loanAttachments'] = loanAttachments!.map((v) => v.toLoanDetailJson()).toList(); } data['loanStatusId'] = this.loanStatusId; data['loanStatusName'] = this.loanStatusName; 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 6e068eb9..6e03259f 100644 --- a/lib/modules/loan_module/pages/create_loan_request_page.dart +++ b/lib/modules/loan_module/pages/create_loan_request_page.dart @@ -10,6 +10,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/helper/utils.dart'; +import 'package:test_sa/models/enums/request_attachment_type_enum.dart'; 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'; @@ -155,6 +156,7 @@ class _CreateLoanRequestPageState extends State with Tick AttachmentPicker( label: context.translation.attachments, attachment: attachments, + moduleId: RequestAttachmentTypeEnum.loanEquipment.id, onlyImages: false, showAsListView: true, buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), @@ -627,7 +629,7 @@ class _CreateLoanRequestPageState extends State with Tick _loanFormModel.loanAttachment = []; for (var item in attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - _loanFormModel.loanAttachment?.add(LoanAttachments(id: 0, attachmentName: fileName, loanId: 0)); + _loanFormModel.loanAttachment?.add(GenericAttachmentModel(id: 0, name: fileName, moduleReferenceId: 0,documentType: item.documentType)); } Utils.showLoading(context); LoanProvider loanProvider = Provider.of(context, listen: false); diff --git a/lib/modules/loan_module/pages/installation_form_view.dart b/lib/modules/loan_module/pages/installation_form_view.dart index 5ad7e3c4..08e81686 100644 --- a/lib/modules/loan_module/pages/installation_form_view.dart +++ b/lib/modules/loan_module/pages/installation_form_view.dart @@ -10,6 +10,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/helper/utils.dart'; +import 'package:test_sa/models/enums/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/timer_model.dart'; import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; @@ -166,6 +167,7 @@ class _InstallationFormViewState extends State { attachment: _attachments, buttonColor: AppColor.primary10, onlyImages: false, + moduleId: RequestAttachmentTypeEnum.loanEquipment.id, showAsListView: true, buttonIcon: 'attachment_icon'.toSvgAsset(color: AppColor.primary10), onChange: (attachments) { @@ -209,7 +211,7 @@ class _InstallationFormViewState extends State { for (var item in _attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - _formData.loanAttachment!.add(LoanAttachments(id: 0, attachmentName: fileName, loanId: widget.loanData?.id)); + _formData.loanAttachment!.add(GenericAttachmentModel(id: 0, name: fileName, moduleReferenceId: widget.loanData?.id, documentType: item.documentType)); } Utils.showLoading(context); _formData.loanStatusId = widget.loanData?.loanStatusValue; diff --git a/lib/modules/loan_module/pages/installation_pullout_form_view.dart b/lib/modules/loan_module/pages/installation_pullout_form_view.dart index f94163cc..7dc09df8 100644 --- a/lib/modules/loan_module/pages/installation_pullout_form_view.dart +++ b/lib/modules/loan_module/pages/installation_pullout_form_view.dart @@ -11,6 +11,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/helper/utils.dart'; +import 'package:test_sa/models/enums/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/timer_model.dart'; import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; @@ -169,6 +170,7 @@ class _InstallationPullOutFormViewState extends State(context, listen: false); diff --git a/lib/modules/loan_module/pages/intallation_details_view.dart b/lib/modules/loan_module/pages/intallation_details_view.dart index 8bfd6e8b..3a92268d 100644 --- a/lib/modules/loan_module/pages/intallation_details_view.dart +++ b/lib/modules/loan_module/pages/intallation_details_view.dart @@ -83,8 +83,8 @@ class InstallationDetailsView extends StatelessWidget { "Uploads Phase 2 docs".addTranslation, style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ), - 8.height, - FilesList(showAsListView: true, images: loanData.loanAttachments?.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), + 4.height, + FilesList(showAsListView: true, images: loanData.loanAttachments?.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), ], ], ).toShadowContainer(context, borderRadius: 20), diff --git a/lib/modules/loan_module/pages/loan_equipment_detail_page.dart b/lib/modules/loan_module/pages/loan_equipment_detail_page.dart index 57126edf..b19b20ff 100644 --- a/lib/modules/loan_module/pages/loan_equipment_detail_page.dart +++ b/lib/modules/loan_module/pages/loan_equipment_detail_page.dart @@ -6,6 +6,8 @@ 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/modules/loan_module/provider/loan_provider.dart'; import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/loan_module/models/loan_attachment_model.dart'; @@ -59,7 +61,7 @@ class _LoanEquipmentDetailPageState extends State { if (snapshot.connectionState == ConnectionState.waiting) return CircularProgressIndicator(color: AppColor.loadingColor(context)).center; if (snapshot.data == null) return const NoDataFound().center; - List allAttachments = snapshot.data!.loanAttachments!; + List allAttachments = (snapshot.data!.loanAttachments ?? []).whereType().toList(); return Column(children: [ ListView( @@ -95,7 +97,15 @@ class _LoanEquipmentDetailPageState extends State { if (allAttachments.isNotEmpty) ...[ const Divider().defaultStyle(context), InfoHeader16Widget("Attachments".addTranslation), - FilesList(images: allAttachments.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), + 4.height, + FilesList( + showAsListView: true, + types: allAttachments + .whereType() + .where((e) => e.documentType != null && e.documentType!.name!.isNotEmpty) + .map((toElement) => toElement.documentType!.name!) + .toList(), + images: allAttachments.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), ], ], ).toShadowContainer(context) 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 b499f20b..3840418c 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 @@ -6,6 +6,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/models/generic_attachment_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/create_medical_gas_request_page.dart'; import 'package:test_sa/modules/medical_gas_inspection/models/medical_gas_data_model.dart'; @@ -103,7 +104,15 @@ class _MedicalGasInspectionDetailPageState extends State URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), + 4.height, + FilesList( + showAsListView: true, + types: model!.deliveryNoteAttachmentDto + .whereType() + .where((e) => e.documentType != null && e.documentType!.name!.isNotEmpty) + .map((toElement) => toElement.documentType!.name!) + .toList(), + images: model!.deliveryNoteAttachmentDto.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), ], ], ).toShadowContainer(context,), 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 index ae0f43a0..fa55d368 100644 --- a/lib/modules/medical_gas_inspection/models/medical_gas_form_model.dart +++ b/lib/modules/medical_gas_inspection/models/medical_gas_form_model.dart @@ -55,7 +55,7 @@ class MedicalGasFormModel { 'siteId': site?.id, 'supplierId': supplier?.id, 'isSubmitted': isSubmitted, - 'gasRequestDetailDtos':gasRequestDetail != null? gasRequestDetail?.map((e) => e.toJson()).toList():[], + 'gasRequestDetailDtos': gasRequestDetail != null ? gasRequestDetail?.map((e) => e.toJson()).toList() : [], }; } } @@ -81,7 +81,7 @@ class MedicalGasFormDetailModel { return { 'id': id, 'medicalGasAttributeId': medicalGasAttributeId, - 'requestedQuantity': requestedQuantity??0, + 'requestedQuantity': requestedQuantity ?? 0, }; } } 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 eecb9d9e..f4d518aa 100644 --- a/lib/modules/medical_gas_inspection/update_delivery_notes_page.dart +++ b/lib/modules/medical_gas_inspection/update_delivery_notes_page.dart @@ -10,6 +10,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/models/enums/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_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'; @@ -72,7 +73,7 @@ class _UpdateDeliveryNotesState extends State { deliveryNoteNumber: dataModel.deliveryNote); if (dataModel.deliveryNoteAttachmentDto.isNotEmpty) { - _attachments.addAll(dataModel.deliveryNoteAttachmentDto.map((e) => GenericAttachmentModel(id: e.id, name: e.name)).toList()); + _attachments.addAll(dataModel.deliveryNoteAttachmentDto.map((e) => GenericAttachmentModel(id: e.id, documentType: e.documentType, name: e.name)).toList()); } //Need to Confirm this condition // selectedItemList = dataModel.requestDetailDtos.where((item) => item.deliveredQuantity != null && item.deliveredQuantity! > 0).toList(); @@ -230,8 +231,9 @@ class _UpdateDeliveryNotesState extends State { AttachmentPicker( label: 'Upload Attachment', attachment: _attachments, + showAsListView: true, buttonColor: AppColor.primary10, - // showAsListView: true, + moduleId: RequestAttachmentTypeEnum.updateDeliveryNotes.id, onlyImages: false, buttonIcon: 'attachment_icon'.toSvgAsset(color: AppColor.primary10), ), @@ -350,7 +352,7 @@ class _UpdateDeliveryNotesState extends State { try { for (var item in _attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - formModel.attachments.add(GenericAttachmentModel(id: item.id, name: fileName)); + formModel.attachments.add(GenericAttachmentModel(id: item.id, name: fileName, documentType: item.documentType)); } } catch (error) { print(error); diff --git a/lib/modules/medical_gas_inspection/update_medical_gas_inspection_page.dart b/lib/modules/medical_gas_inspection/update_medical_gas_inspection_page.dart index b11a0a92..93b29587 100644 --- a/lib/modules/medical_gas_inspection/update_medical_gas_inspection_page.dart +++ b/lib/modules/medical_gas_inspection/update_medical_gas_inspection_page.dart @@ -8,10 +8,10 @@ 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/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; -import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_data_model.dart'; import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart'; import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/update_system_internal_audit_page.dart'; @@ -203,6 +203,7 @@ class _UpdateMedicalGasInspectionPageState extends State { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + List activities = []; + + bool disableNewActivity = false; + + @override + Widget build(BuildContext context) { + UserProvider userProvider = Provider.of(context); + return Scaffold( + appBar: const DefaultAppBar(title: "Spare Part Requests"), + body: Consumer(builder: (context, PpmProvider pmProvider, child) { + activities = pmProvider.planPreventiveVisit?.activities ?? []; + if (activities.isNotEmpty && (activities.last.activityStatus!.value == 14 || activities.last.activityStatus!.value == 19)) { + disableNewActivity = true; + } else { + disableNewActivity = false; + } + + return Column( + children: [ + (activities.isEmpty) + ? NoDataFound(message: context.translation.noDataFound).center.expanded + : ListView.separated( + padding: const EdgeInsets.all(16), + itemCount: activities.length, + separatorBuilder: (czt, index) => 12.height, + itemBuilder: (context, index) { + return sparePartActivityCard(pmProvider: pmProvider, userProvider: userProvider, context: context, activity: activities[index]); + }, + ).expanded, + if (userProvider.user!.type == UsersTypes.engineer && (pmProvider.planPreventiveVisit?.visitStatus?.value != 5 && pmProvider.planPreventiveVisit?.visitStatus?.value != 3)) + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + label: "Create Spare Part Request", + maxWidth: true, + buttonColor: AppColor.primary10, + loading: pmProvider.isLoading, + disableButton: disableNewActivity, + onPressed: () async { + final model = SparePartHelperModel( + id: 0, + pmVisitId: pmProvider.planPreventiveVisit?.id, + ); + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SparePartRequest( + model: model, + provider: pmProvider, + fromCm: false, + ), + ), + ); + }, + )) + ], + ); + }), + ); + } + + Widget sparePartActivityCard({required PpmProvider pmProvider, required UserProvider userProvider, required BuildContext context, required PMSparePartActivityModel activity}) { + bool showActionButtons = userProvider.user!.userID == pmProvider.planPreventiveVisit?.assignedEmployee?.userId && + userProvider.user!.type == UsersTypes.engineer && + pmProvider.planPreventiveVisit?.visitStatus?.value != 5 && + pmProvider.planPreventiveVisit?.visitStatus?.value != 3; + + bool canDelete = showActionButtons && activity.activityStatus?.value == 1; + bool canEdit = showActionButtons && (canDelete || activity.activityStatus!.value! == 3); + + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + StatusLabel( + label: activity.activityStatus?.name, + textColor: AppColor.white10, + backgroundColor: AppColor.primary10, + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + spacing: 12, + children: [ + if (canEdit) + "edit_icon".toSvgAsset(height: 24, width: 24, color: AppColor.icon2Color(context)).onPress(() { + editSparePartRequest(context: context, pmProvider: pmProvider, activity: activity); + }), + if (canDelete) + "delete_icon".toSvgAsset(height: 24, width: 24).onPress(() async { + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + int status = await pmProvider.deleteActivitySparePart(id: activity.id!); + if (status == 200) { + await pmProvider.getPlanPreventiveVisitById((int.tryParse(pmProvider.planPreventiveVisit?.id ?? '')) as int); + Navigator.pop(context); + } else { + Navigator.pop(context); + } + }), + ], + ) + ], + ), + 6.height, + InfoTextWidget( + label: context.translation.partName, + value: activity.partCatalogItem?.partName, + ), + InfoTextWidget( + label: context.translation.partNo, + value: activity.partCatalogItem?.partNumber, + ), + InfoTextWidget( + label: context.translation.oracleCode, + value: activity.partCatalogItem?.oracleCode, + ), + if (activity.quantity != null && activity.quantity! > 0) + InfoTextWidget( + label: context.translation.quantity, + value: activity.quantity.toString(), + ), + if (activity.installQty != null && activity.installQty! > 0) + InfoTextWidget( + label: context.translation.installedQty, + value: activity.installQty.toString(), + ), + if (activity.returnQty != null && activity.returnQty! > 0) + InfoTextWidget( + label: context.translation.returnQty, + value: activity.returnQty.toString(), + ), + if (activity.comment?.isNotEmpty ?? false) ...[ + const Divider().defaultStyle(context), + InfoTextLabelWidget(label: activity.comment ?? ""), + ], + if (activity.activitySparePartPPMAttachments.isNotEmpty) ...[ + const Divider().defaultStyle(context), + FilesList( + types: activity.activitySparePartPPMAttachments! + .whereType() + .where((e) => e.documentType != null && e.documentType!.name!.isNotEmpty) + .map((toElement) => toElement.documentType!.name!) + .toList(), + images: activity.activitySparePartPPMAttachments.map((toElement) => URLs.getFileUrl(toElement.name ?? '') ?? '').toList(), showAsListView: true), + ], + ], + ).toShadowContainer(context, showShadow: false).onPress(() { + if (showActionButtons) return; + if (pmProvider.isReadOnlyRequest) { + editSparePartRequest(context: context, pmProvider: pmProvider, activity: activity); + } else if (userProvider.user!.userID == pmProvider.planPreventiveVisit?.assignedEmployee?.userId) { + pmProvider.isReadOnlyRequest = true; + editSparePartRequest(context: context, pmProvider: pmProvider, activity: activity); + } + }); + } + + void editSparePartRequest({required BuildContext context, required PpmProvider pmProvider, required PMSparePartActivityModel activity}) async { + final model = SparePartHelperModel( + id: activity.id, + pmVisitId: pmProvider.planPreventiveVisit?.id, + comment: activity.comment, + sparePartAttachments: activity.activitySparePartPPMAttachments, + activityStatus: activity.activityStatus, + sparePart: SparePart( + id: activity.partCatalogItem?.id, + partName: activity.partCatalogItem?.partName, + partNo: activity.partCatalogItem?.partNumber, + oracleCode: activity.partCatalogItem?.oracleCode, + ), + quantity: activity.quantity, + installQty: activity.installQty, + returnQty: activity.returnQty, + activityStatusId: activity.activityStatus?.id, + ); + Navigator.of(context).push(MaterialPageRoute( + builder: (_) => SparePartRequest( + model: model, + provider: pmProvider, + fromCm: false, // This is PM, not CM + ), + )); + } +} diff --git a/lib/modules/pm_module/ppm_wo/ppm_details_page.dart b/lib/modules/pm_module/ppm_wo/ppm_details_page.dart index bf64bf9a..ffcc3679 100644 --- a/lib/modules/pm_module/ppm_wo/ppm_details_page.dart +++ b/lib/modules/pm_module/ppm_wo/ppm_details_page.dart @@ -8,6 +8,7 @@ import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/plan_preventive_visit/plan_preventive_visit_model.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/pm_module/ppm_wo/activities/pm_activities_list_view.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/widgets/item_views/info_header_widget.dart'; import 'package:test_sa/views/widgets/item_views/info_text_widget.dart'; @@ -82,6 +83,20 @@ class _PpmDetailsPageState extends State { textColor: AppColor.getRequestStatusTextColorByName(context, planPreventiveVisit.visitStatus!.name!), backgroundColor: AppColor.getRequestStatusColorByName(context, planPreventiveVisit.visitStatus!.name!), ), + // "edit_icon".toSvgAsset(height: 24, width: 24, color: AppColor.icon2Color(context)).onPress(() { + // if(userProvider!.user!.type == UsersTypes.engineer && (!ppmProvider.isReadOnly)){ + // FooterActionButton.footerContainer( + // child: AppFilledButton( + // onPressed: () async { + // await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdatePpm(ppm: null, planPreventiveVisit: planPreventiveVisit))); + // getVisitData(); + // }, + // label: context.translation.updateWorkOrder, + // ), + // context: context, + // ); + // } + // }) ], ), InfoHeader16Widget(planPreventiveVisit.assetName?.cleanupWhitespace.capitalizeFirstOfEach ?? ''), @@ -102,29 +117,23 @@ class _PpmDetailsPageState extends State { ], ).toShadowContainer(context), ).expanded, - if (userProvider!.user!.type == UsersTypes.engineer && (!ppmProvider.isReadOnly)) ...[ + // if (userProvider!.user!.type == UsersTypes.engineer && (!ppmProvider.isReadOnly)) ...[ FooterActionButton.footerContainer( - child: AppFilledButton( - onPressed: () async { - await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdatePpm(ppm: null, planPreventiveVisit: planPreventiveVisit))); - getVisitData(); - }, - label: context.translation.updateWorkOrder, + child: Column( + children: [ + AppFilledButton( + onPressed: () async { + await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdatePpm(ppm: null, planPreventiveVisit: planPreventiveVisit))); + getVisitData(); + }, + label: userProvider!.user!.type == UsersTypes.engineer && (!ppmProvider.isReadOnly)? context.translation.updateWorkOrder:context.translation.viewDetails, + ), + + ], ), context: context, ) - ] else ...[ - // FooterActionButton.footerContainer( - // context: context, - // child: AppFilledButton( - // onPressed: () async { - // await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdatePpm(ppm: null, planPreventiveVisit: planPreventiveVisit))); - // getVisitData(); - // }, - // label: context.translation.viewDetails, - // ), - // ) - ] + // ] ]) : const Center(child: NoDataFound()); }), diff --git a/lib/modules/pm_module/ppm_wo/update_ppm/update_ppm.dart b/lib/modules/pm_module/ppm_wo/update_ppm/update_ppm.dart index a61a8efd..6886920a 100644 --- a/lib/modules/pm_module/ppm_wo/update_ppm/update_ppm.dart +++ b/lib/modules/pm_module/ppm_wo/update_ppm/update_ppm.dart @@ -10,10 +10,12 @@ 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/plan_preventive_visit/plan_preventive_visit_model.dart'; import 'package:test_sa/models/ppm/ppm.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/pm_module/ppm_wo/activities/pm_activities_list_view.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'; @@ -44,14 +46,17 @@ class _UpdatePpmState extends State with TickerProviderStateMixin { TabController? _tabController; late PpmProvider ppmProvider; - _onSubmit({required int status}) async { if (ppmProvider.validate()) { showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); ppmProvider.planPreventiveVisit?.preventiveVisitAttachments = []; for (var item in ppmProvider.ppmPlanAttachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - ppmProvider.planPreventiveVisit?.preventiveVisitAttachments?.add(PreventiveVisitAttachments(id: item.id, attachmentName: fileName)); + ppmProvider.planPreventiveVisit?.preventiveVisitAttachments?.add(GenericAttachmentModel( + id: item.id, + name: fileName, + documentType: item.documentType, + )); } ppmProvider.planPreventiveVisit?.preventiveVisitTimers = ppmProvider.planPreventiveVisit?.preventiveVisitTimers ?? []; @@ -94,27 +99,33 @@ class _UpdatePpmState extends State with TickerProviderStateMixin { @override void initState() { + super.initState(); ppmProvider = Provider.of(context, listen: false); _planPreventiveVisit = widget.planPreventiveVisit; - // WidgetsBinding.instance.addPostFrameCallback((_) { - initTabs(_planPreventiveVisit.typeOfService); - // }); - super.initState(); + int initialTabs = (_planPreventiveVisit.typeOfService?.value == 2) ? 4 : 3; + _tabController = TabController(length: initialTabs, vsync: this); + WidgetsBinding.instance.addPostFrameCallback((_) { + ppmProvider.totalTabs = initialTabs; + }); } - - void initTabs(typeOfService) { if (typeOfService == null) { return; } - if (typeOfService?.value == 2) { - ppmProvider.totalTabs = 4; - } else { - ppmProvider.totalTabs = 3; + + int newTabCount = (typeOfService?.value == 2) ? 4 : 3; + + // Only recreate TabController if tab count has changed + if (_tabController?.length != newTabCount) { + _tabController?.dispose(); + _tabController = TabController(length: newTabCount, vsync: this); + + // Update provider safely after current build + WidgetsBinding.instance.addPostFrameCallback((_) { + ppmProvider.totalTabs = newTabCount; + }); } - _tabController?.dispose; - _tabController = TabController(length: ppmProvider.totalTabs, vsync: this); } int tabIndex = 0; @@ -208,70 +219,82 @@ class _UpdatePpmState extends State with TickerProviderStateMixin { ).expanded, FooterActionButton.footerContainer( context: context, - child: Row( + child: Column( children: [ - if (tabIndex == 1) ...[ - AppFilledButton( - buttonColor: _tabController!.index == 0 ? null : AppColor.background(context), - // buttonColor: _tabController!.index == 0 ? null : AppColor.background(context), - textColor: _tabController!.index == 0 ? null : AppColor.blueStatus(context), - showBorder: true, - disableButton: _tabController!.index == 0, - onPressed: () { - if (_tabController!.index == 0) { - return; - } - _tabController?.animateTo(_tabController!.index - 1); - setState(() {}); - return; - }, - label: context.translation.back, - ).expanded, - 8.width, - ], - if (!ppmProvider.isReadOnly) ...[ - AppFilledButton( - // buttonColor: AppColor.white60, - // textColor: AppColor.neutral50, - buttonColor: context.isDark ? AppColor.neutral50 : AppColor.white60, - textColor: context.isDark ? Colors.white : AppColor.neutral50, - onPressed: () { - _onSubmit(status: 0); - }, - label: context.translation.save, - ).expanded, - 8.width, - AppFilledButton( - onPressed: () { - if (tabIndex == 0) { - _onSubmit(status: 1); - return; - } - if (ppmProvider.totalTabs == _tabController!.index + 1) { - _onSubmit(status: 1); - } else { - _tabController?.animateTo(_tabController!.index + 1); - setState(() {}); - } - }, - label: tabIndex == 0 ? "Complete".addTranslation : ((ppmProvider.totalTabs == _tabController!.index + 1) ? "Complete".addTranslation : context.translation.next), - ).expanded, - ] else ...[ - Visibility( - visible: tabIndex != 0, - child: AppFilledButton( - onPressed: () { - if (ppmProvider.totalTabs == _tabController!.index + 1) { - Navigator.pop(context); + Row( + children: [ + if (tabIndex == 1) ...[ + AppFilledButton( + buttonColor: _tabController!.index == 0 ? null : AppColor.background(context), + // buttonColor: _tabController!.index == 0 ? null : AppColor.background(context), + textColor: _tabController!.index == 0 ? null : AppColor.blueStatus(context), + showBorder: true, + disableButton: _tabController!.index == 0, + onPressed: () { + if (_tabController!.index == 0) { + return; + } + _tabController?.animateTo(_tabController!.index - 1); + setState(() {}); return; - } - _tabController?.animateTo(_tabController!.index + 1); - setState(() {}); - }, - label: ppmProvider.totalTabs == _tabController!.index + 1 ? context.translation.close : context.translation.next, - ).expanded, - ), - ] + }, + label: context.translation.back, + ).expanded, + 8.width, + ], + if (!ppmProvider.isReadOnly) ...[ + AppFilledButton( + // buttonColor: AppColor.white60, + // textColor: AppColor.neutral50, + buttonColor: context.isDark ? AppColor.neutral50 : AppColor.white60, + textColor: context.isDark ? Colors.white : AppColor.neutral50, + onPressed: () { + _onSubmit(status: 0); + }, + label: context.translation.save, + ).expanded, + 8.width, + AppFilledButton( + onPressed: () { + if (tabIndex == 0) { + _onSubmit(status: 1); + return; + } + if (ppmProvider.totalTabs == _tabController!.index + 1) { + _onSubmit(status: 1); + } else { + _tabController?.animateTo(_tabController!.index + 1); + setState(() {}); + } + }, + label: tabIndex == 0 ? "Complete".addTranslation : ((ppmProvider.totalTabs == _tabController!.index + 1) ? "Complete".addTranslation : context.translation.next), + ).expanded, + ] else ...[ + Visibility( + visible: tabIndex != 0, + child: AppFilledButton( + onPressed: () { + if (ppmProvider.totalTabs == _tabController!.index + 1) { + Navigator.pop(context); + return; + } + _tabController?.animateTo(_tabController!.index + 1); + setState(() {}); + }, + label: ppmProvider.totalTabs == _tabController!.index + 1 ? context.translation.close : context.translation.next, + ).expanded, + ), + ] + ], + ), + 12.height, + AppFilledButton( + onPressed: () async { + Navigator.of(context).push(MaterialPageRoute(builder: (_) => const PmActivitiesListView())); + }, + buttonColor: context.isDark ? AppColor.primary10 : AppColor.neutral50, + label: "Spare Parts", + ), ], ), ), diff --git a/lib/modules/pm_module/ppm_wo/update_ppm/wo_info_form.dart b/lib/modules/pm_module/ppm_wo/update_ppm/wo_info_form.dart index 55170e3b..8d2e7726 100644 --- a/lib/modules/pm_module/ppm_wo/update_ppm/wo_info_form.dart +++ b/lib/modules/pm_module/ppm_wo/update_ppm/wo_info_form.dart @@ -1,3 +1,4 @@ +import 'dart:developer'; import 'dart:io'; import 'package:flutter/material.dart'; @@ -12,7 +13,9 @@ import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/models/device/asset.dart'; import 'package:test_sa/models/device/model_definition.dart'; import 'package:test_sa/models/device/supplier.dart'; +import 'package:test_sa/models/enums/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; 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'; @@ -21,6 +24,7 @@ import 'package:test_sa/models/new_models/room_model.dart'; import 'package:test_sa/models/new_models/site.dart'; import 'package:test_sa/models/plan_preventive_visit/plan_preventive_visit_model.dart'; import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; +import 'package:test_sa/modules/cm_module/views/forms/cost/cost_detail_form_screen.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'; @@ -32,6 +36,7 @@ import 'package:test_sa/providers/ppm_task_status_provider.dart'; import 'package:test_sa/views/widgets/bottom_sheets/asset_detail_bottom_sheet.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; import 'package:test_sa/views/widgets/date_and_time/time_picker.dart'; +import 'package:test_sa/views/widgets/equipment/asset_detail_page.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/item_views/info_header_widget.dart'; import 'package:test_sa/views/widgets/item_views/info_text_widget.dart'; @@ -61,7 +66,10 @@ class _WoInfoFormState extends State { calculateWorkingTime(); if (widget.planPreventiveVisit.preventiveVisitAttachments != null && widget.planPreventiveVisit.preventiveVisitAttachments!.isNotEmpty) { ppmProvider.ppmPlanAttachments = []; - ppmProvider.ppmPlanAttachments.addAll(widget.planPreventiveVisit.preventiveVisitAttachments!.map((e) => GenericAttachmentModel(id: e.id, name: e.attachmentName!)).toList()); + ppmProvider.ppmPlanAttachments.addAll(widget.planPreventiveVisit.preventiveVisitAttachments! + .whereType() + .map((e) => GenericAttachmentModel(id: e.id, name: e.name ?? '', documentType: e.documentType)) + .toList()); } }); @@ -94,16 +102,22 @@ class _WoInfoFormState extends State { @override Widget build(BuildContext context) { + + // double totalWorkingHours = // widget.planPreventiveVisit.preventiveVisitTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDateTime!).difference(DateTime.parse(item.startDateTime!)).inSeconds) ?? 0; return Consumer(builder: (context, ppmProvider, child) { + ppmProvider.ppmPlanAttachments.forEach((e){ + log('attachemnt type ${e.documentType}'); + }); return ListView( padding: const EdgeInsets.only(left: 16, right: 16, top: 8, bottom: 16), children: [ IgnorePointer( ignoring: ppmProvider.isReadOnly, child: Column( + spacing: 12, children: [ Column( mainAxisSize: MainAxisSize.min, @@ -145,7 +159,6 @@ class _WoInfoFormState extends State { // '${context.translation.executionTimeFrame}: ${widget.planPreventiveVisit.executionTimeFrame ?? ""} days'.bodyText2(context).custom(color: AppColor.neutral120), ], ).toShadowContainer(context), - 12.height, Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -156,23 +169,9 @@ class _WoInfoFormState extends State { children: [ InfoHeader16Widget(widget.planPreventiveVisit.assetName ?? '').expanded, // widget.planPreventiveVisit.assetName!.bodyText(context).custom(color: AppColor.headingTextColor(context)).expanded, - "info_icon".toSvgAsset(height: 17, width: 17).onPress( - () { - // There is only limited information for asset is returned from backend to show all info need to return the whole model from backend... - showModalBottomSheet( - context: context, - backgroundColor: AppColor.bottomSheetColor(context), - isScrollControlled: true, - // shape: const RoundedRectangleBorder( - // borderRadius: BorderRadius.vertical( - // top: Radius.circular(20), - // ), - // ), - clipBehavior: Clip.antiAliasWithSaveLayer, - builder: (BuildContext context) => _buildAssetDetailBottomSheet(context), - ); - }, - ) + const Icon(Icons.open_in_new_rounded, color: AppColor.primary10, size: 20).onPress(() { + Navigator.of(context).pushNamed(AssetDetailPage.id, arguments: widget.planPreventiveVisit.asset!.id); + }), ], ), // 2.height, @@ -219,9 +218,10 @@ class _WoInfoFormState extends State { // } // }, // ), - 8.height, + // 8.height,// Column( mainAxisAlignment: MainAxisAlignment.start, + spacing: 12, children: [ SingleItemDropDownMenu( context: context, @@ -236,7 +236,6 @@ class _WoInfoFormState extends State { } }, ), - 8.height, ADatePicker( label: context.translation.actualVisit, hideShadow: true, @@ -283,8 +282,6 @@ class _WoInfoFormState extends State { // } // }, // ), - - 8.height, SingleItemDropDownMenu( context: context, backgroundColor: AppColor.fieldBgColor(context), @@ -297,7 +294,6 @@ class _WoInfoFormState extends State { } }, ), - 8.height, SingleItemDropDownMenu( context: context, backgroundColor: AppColor.fieldBgColor(context), @@ -312,7 +308,6 @@ class _WoInfoFormState extends State { } }, ), - 8.height, SingleItemDropDownMenu( context: context, backgroundColor: AppColor.fieldBgColor(context), @@ -333,9 +328,7 @@ class _WoInfoFormState extends State { } }, ), - 8.height, _timerWidget(context, totalWorkingHours), - 8.height, AppTextFormField( labelText: context.translation.comment, backgroundColor: AppColor.fieldBgColor(context), @@ -347,16 +340,18 @@ class _WoInfoFormState extends State { widget.planPreventiveVisit.comments = value; }, ), - 16.height, AttachmentPicker( label: context.translation.attachments, + showAsListView: true, attachment: ppmProvider.ppmPlanAttachments, + moduleId: RequestAttachmentTypeEnum.preventiveMaintenance.id, buttonColor: AppColor.black10, onlyImages: false, buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), ), ], ).toShadowContainer(context), + costCard(context, ppmProvider), ], ), ), @@ -413,6 +408,7 @@ class _WoInfoFormState extends State { Widget _timerWidget(BuildContext context, double totalWorkingHours) { return Column( + spacing: 12, children: [ AppTimer( label: context.translation.workingHours, @@ -434,7 +430,6 @@ class _WoInfoFormState extends State { return true; }, ), - 11.height, if (totalWorkingHours > 0.0) ...[ WorkingTimeTile( timerList: timerList, @@ -454,6 +449,79 @@ class _WoInfoFormState extends State { ); } + Widget costCard(BuildContext context, PpmProvider provider) { + ///Need to update this when actual flow decided... + PlanPreventiveVisit? model = provider.planPreventiveVisit; + final costModel = WorkOrderCostModel( + workOrderId: int.tryParse(model?.id ?? ''), + labourCost: model?.labourCost, + sparePartCost: model?.sparePartCost, + travelCost: model?.travelCost, + qAmount: model?.qAmount, + prNo: model?.prNo, + poNo: model?.poNo, + mrNo: model?.mrNo, + exchangeCost: model?.exchangeCost, + ); + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + InfoHeader16Widget("Cost"), + const Spacer(), + if (!provider.isReadOnlyRequest) + "edit_icon".toSvgAsset(height: 24, width: 24, color: AppColor.icon2Color(context)).onPress(() async { + provider.workOrderCostModel = costModel; + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CostDetailFormScreen( + model: provider.workOrderCostModel, + provider: provider, + ), + ), + ); + }), + ], + ), + InfoTextWidget( + label: 'Spare Part Cost'.addTranslation, + value: costModel.sparePartCost?.toString() ?? '-', + ), + InfoTextWidget( + label: 'Labor Cost'.addTranslation, + value: costModel.labourCost?.toString() ?? '-', + ), + InfoTextWidget( + label: 'Travel Cost'.addTranslation, + value: costModel.travelCost?.toString() ?? '-', + ), + InfoTextWidget( + label: 'Quot Amount'.addTranslation, + value: costModel.qAmount?.toString() ?? '-', + ), + InfoTextWidget( + label: 'PR No'.addTranslation, + value: costModel.prNo?.toString() ?? '-', + ), + InfoTextWidget( + label: 'PO No'.addTranslation, + value: costModel.poNo?.toString() ?? '-', + ), + InfoTextWidget( + label: 'MR No'.addTranslation, + value: costModel.mrNo?.toString() ?? '-', + ), + InfoTextWidget( + label: 'Exchange Cost'.addTranslation, + value: costModel.exchangeCost?.toString() ?? '-', + ), + ], + ).toShadowContainer(context); + } + // String formatDuration1(int seconds) { // int hours = seconds ~/ 3600; // int minutes = (seconds % 3600) ~/ 60; diff --git a/lib/modules/site_request_module/providers/site_request_provider.dart b/lib/modules/site_request_module/providers/site_request_provider.dart index d97b5b7d..375c4d86 100644 --- a/lib/modules/site_request_module/providers/site_request_provider.dart +++ b/lib/modules/site_request_module/providers/site_request_provider.dart @@ -27,6 +27,7 @@ class SiteRequestProvider extends ChangeNotifier { // Data List _requestTypes = []; List _userCurrentSites = []; + List userFilterSites = []; List _requestHistory = []; // Pagination @@ -106,6 +107,24 @@ class SiteRequestProvider extends ChangeNotifier { ); } + /// Fetches user's current sites for Change/Remove Site operations + Future> getSitesByUserId(String userId) async { + List usersSite = []; + try { + Response response = await ApiManager.instance.post(URLs.getUserSites(userId), body: {},showToast: false); + if (response.statusCode >= 200 && response.statusCode < 300) { + List categoriesListJson = json.decode(response.body)["data"]; + usersSite = categoriesListJson + .map((item) => SiteRequestSiteModel( + id: item['siteId']?.toString() ?? '', + name: item['siteName'] ?? '', + )) + .toList(); + } + } catch (ex) {} + return usersSite; + } + /// Fetches user's current sites for Change/Remove Site operations Future fetchUserCurrentSites(String userId) async { if (_loading) return -2; @@ -125,6 +144,24 @@ class SiteRequestProvider extends ChangeNotifier { ); } + Future fetchUserFilteredSites(String userId) async { + if (_loading) return -2; + return _performApiCall( + apiCall: () => ApiManager.instance.post(URLs.getSitesNotAccessibleForUser(userId), showToast: false, body: {}), + onSuccess: (responseData) { + List listJson = responseData['data'] ?? []; + userFilterSites = listJson + .map((item) => SiteRequestSiteModel( + id: item['siteId']?.toString() ?? '', + name: item['siteName'] ?? '', + )) + .toList(); + notifyListeners(); + }, + errorMessage: 'Failed to fetch user sites', + ); + } + /// Submits a site request to the server Future submitSiteRequest(SiteRequestModel request, UserProvider userProvider) async { loading = true; diff --git a/lib/modules/site_request_module/screens/site_request_form_screen.dart b/lib/modules/site_request_module/screens/site_request_form_screen.dart index 1dde072a..86b905d5 100644 --- a/lib/modules/site_request_module/screens/site_request_form_screen.dart +++ b/lib/modules/site_request_module/screens/site_request_form_screen.dart @@ -175,11 +175,12 @@ class _SiteRequestFormScreenState extends State { _siteReplacements.clear(); _loadedDepartmentSiteIds.clear(); // Reset loaded department site IDs }); - + final userId = _provider.getCurrentUserUserId(_userProvider); // Fetch user's current sites if Change Site or Remove Site is selected if ((_isChangeSiteRequest() || _isRemoveSiteRequest()) && value != null) { - final userId = _provider.getCurrentUserUserId(_userProvider); await _provider.fetchUserCurrentSites(userId); + }else { + await _provider.fetchUserFilteredSites(userId); } // Fetch all sites if Change Site is selected (needed for new site dropdown) @@ -318,6 +319,40 @@ class _SiteRequestFormScreenState extends State { } Widget _buildSiteMultiSelect() { + return MultipleItemDropDownMenu( + context: context, + title: context.translation.site, + initialValue: _selectedSites + .map((s) => SiteRequestSiteModel( + id: s.identifier ?? '', + name: s.name ?? '', + )) + .toList(), + staticData: _provider.userFilterSites, + showAsFullScreenDialog: true, + backgroundColor: context.isDark ? AppColor.neutral60 : Colors.white, + showShadow: true, + height: 56.toScreenHeight, + showCancel: true, + onSelect: (value) { + if (value != null) { + setState(() { + _selectedSites = value.map((s) { + final site = Site( + id: int.tryParse(s.identifier ?? '0'), + custName: s.name, + ); + return site; + }).toList(); + final departmentProvider = Provider.of(context, listen: false); + final siteIds = value.map((site) => int.tryParse(site.identifier ?? '0') ?? 0).toList(); + departmentProvider.setSiteIds(siteIds); + departmentProvider.getData(); + }); + + } + }, + ); return MultipleItemDropDownMenu( context: context, title: context.translation.site, diff --git a/lib/modules/tm_module/device_transfer/create_device_transfer_request.dart b/lib/modules/tm_module/device_transfer/create_device_transfer_request.dart index 89c92bc1..4a582ffc 100644 --- a/lib/modules/tm_module/device_transfer/create_device_transfer_request.dart +++ b/lib/modules/tm_module/device_transfer/create_device_transfer_request.dart @@ -13,6 +13,7 @@ import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/device/asset.dart'; import 'package:test_sa/models/device/asset_transfer_attachment.dart'; import 'package:test_sa/models/device/device_transfer.dart'; +import 'package:test_sa/models/enums/request_attachment_type_enum.dart'; import 'package:test_sa/models/enums/user_types.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/new_models/department.dart'; @@ -74,10 +75,10 @@ class _CreateDeviceTransferRequestState extends State attachement = []; + 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(AssetTransferAttachment(id: item.id, attachmentName: fileName)); + attachement.add(GenericAttachmentModel(id: item.id, name: fileName, documentType: item.documentType)); } _transferModel.attachments = attachement; @@ -155,8 +156,9 @@ class _CreateDeviceTransferRequestState extends State( + SingleItemDropDownMenu( context: context, + requestById: context.userProvider.user?.clientId, title: context.translation.site, initialValue: _assetDestination.site, disableValue: isInternal ? null : _pickedAsset?.site, @@ -245,7 +247,9 @@ class _CreateDeviceTransferRequestState extends State { late DeviceSearch filter; Lookup? _commissioningStatus; - List _selectedSites = []; + List _selectedSites = []; List _selectedDepartments = []; String? startDate, endDate; bool loading = false; + List userSites = []; + @override void initState() { filter = widget.data ?? DeviceSearch(); @@ -47,11 +49,15 @@ class _DeviceFilterScreenState extends State { startDate = filter.supplyDateFrom; endDate = filter.supplyDateTo; _commissioningStatus = filter.assetStatus; + final departmentProvider = Provider.of(context, listen: false); - final siteProvider = Provider.of(context, listen: false); + Utils.showLoading(context); if (departmentProvider.items.isEmpty ?? true) await departmentProvider.getData(); - if (siteProvider.items.isEmpty ?? true) await siteProvider.getData(); - + if (userSites.isEmpty) { + userSites = await Provider.of(context, listen: false).getSitesByUserId(context.userProvider.user?.userID ?? ""); + } + await Future.delayed(const Duration(milliseconds: 100)); + Utils.hideLoading(context); // Initialize selected departments from filter if (filter.departments != null && filter.departments!.isNotEmpty) { _selectedDepartments = []; @@ -70,11 +76,11 @@ class _DeviceFilterScreenState extends State { if (filter.sites != null && filter.sites!.isNotEmpty) { _selectedSites = []; for (var siteName in filter.sites!) { - final match = siteProvider.items.firstWhere( + final match = userSites.firstWhere( (site) => site.name == siteName, - orElse: () => Site(), + orElse: () => SiteRequestSiteModel(id: '', name: ''), ); - if (match.id != null) { + if (match.identifier != null) { _selectedSites.add(match); } } @@ -118,14 +124,15 @@ class _DeviceFilterScreenState extends State { ListView( padding: const EdgeInsets.all(16), children: [ - AssetStatusButtons( - initialValue: _commissioningStatus, - onSelect: (value) { - if (value != null) { - _commissioningStatus = value; - } - }, - ), + // AssetStatusButtons( + // initialValue: _commissioningStatus, + // onSelect: (value) { + // if (value != null) { + // _commissioningStatus = value; + // } + // }, + // ), + context.translation.filter.heading5(context).custom(color: AppColor.textStyleColor(context)), 16.height, MultipleItemDropDownMenu( context: context, @@ -146,11 +153,12 @@ class _DeviceFilterScreenState extends State { }, ), 12.height, - MultipleItemDropDownMenu( + MultipleItemDropDownMenu( context: context, title: context.translation.bySite, initialValue: _selectedSites, showAsBottomSheet: true, + staticData: userSites, // backgroundColor: AppColor.fieldBgColor(context), backgroundColor: context.isDark ? AppColor.neutral60 : Colors.white, showShadow: true, diff --git a/lib/modules/tm_module/device_transfer/device_transfer_details.dart b/lib/modules/tm_module/device_transfer/device_transfer_details.dart index 3c4c0993..f39e4c6f 100644 --- a/lib/modules/tm_module/device_transfer/device_transfer_details.dart +++ b/lib/modules/tm_module/device_transfer/device_transfer_details.dart @@ -10,6 +10,7 @@ import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/models/device/device_transfer.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/modules/cx_module/chat/chat_widget.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/views/widgets/bottom_sheets/rejection_reason_bottom_sheet.dart'; @@ -64,8 +65,8 @@ class _DeviceTransferDetailsState extends State { if (snapshot.connectionState == ConnectionState.waiting) { return const ALoading(); } else { - _model = snapshot.data as DeviceTransfer?; - _attachments = _model?.assetTransferAttachments?.map((e) => File(e.attachmentName ?? '')).toList() ?? []; + _model = snapshot.data; + _attachments = _model?.assetTransferAttachments?.map((e) => File(e.name ?? '')).toList() ?? []; return _model != null ? Form( key: _formKey, @@ -75,6 +76,7 @@ class _DeviceTransferDetailsState extends State { stateCode: 200, onRefresh: () async {}, child: SingleChildScrollView( + padding: const EdgeInsets.all(16), child: Column( children: [ Column( @@ -121,12 +123,22 @@ class _DeviceTransferDetailsState extends State { if (_attachments.isNotEmpty) ...[ const Divider().defaultStyle(context), InfoHeader16Widget("Attachments".addTranslation), - FilesList(images: _model?.assetTransferAttachments?.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), + 4.height, + FilesList( + showAsListView: true, + types: _model?.assetTransferAttachments != null + ? _model!.assetTransferAttachments! + .whereType() + .where((e) => e.documentType != null && e.documentType!.name!.isNotEmpty) + .map((toElement) => toElement.documentType!.name!) + .toList() + : [], + images: _model?.assetTransferAttachments?.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), ] ], ), ], - ).toShadowContainer(context, padding: 16), + ).toShadowContainer(context), 8.height, if (_model?.transferType?.value == 1) ...[ _internalRequestDetailsCard() @@ -171,7 +183,7 @@ class _DeviceTransferDetailsState extends State { ), ], ], - ).paddingAll(16), + ), ), ), ) diff --git a/lib/modules/tm_module/device_transfer/update_device_transfer.dart b/lib/modules/tm_module/device_transfer/update_device_transfer.dart index fab25250..ad844699 100644 --- a/lib/modules/tm_module/device_transfer/update_device_transfer.dart +++ b/lib/modules/tm_module/device_transfer/update_device_transfer.dart @@ -13,6 +13,7 @@ import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/models/device/asset_transfer_attachment.dart'; import 'package:test_sa/models/device/device_transfer.dart'; +import 'package:test_sa/models/enums/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/new_models/assigned_employee.dart'; import 'package:test_sa/models/new_models/assistant_employee.dart'; @@ -116,11 +117,14 @@ class _UpdateDeviceTransferState extends State { _formModel.assetTransferEngineerTimers = _formModel.receiverVisitTimers; } try { + _formModel.assetTransferAttachments ??= []; + List newAttachments = []; for (var item in attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - _formModel.assetTransferAttachments!.add(AssetTransferAttachment(id: item.id, attachmentName: fileName)); - _formModel.attachments = _formModel.assetTransferAttachments; + newAttachments.add(GenericAttachmentModel(id: item.id, documentType: item.documentType, name: fileName)); } + _formModel.assetTransferAttachments = [...?_formModel.assetTransferAttachments, ...newAttachments]; + _formModel.attachments = _formModel.assetTransferAttachments; } catch (error) { print(error); } @@ -204,7 +208,7 @@ class _UpdateDeviceTransferState extends State { @override void initState() { _formModel.fromDetails(widget.model); - attachments = widget.model.assetTransferAttachments?.map((e) => GenericAttachmentModel(id: e.id?.toInt()??0, name: e.attachmentName!)).toList() ?? []; + attachments = widget.model.assetTransferAttachments?.map((e) => GenericAttachmentModel(id: e.id?.toInt()??0, name: e.name!)).toList() ?? []; calculateWorkingTime(); super.initState(); } @@ -293,6 +297,8 @@ class _UpdateDeviceTransferState extends State { 8.height, AttachmentPicker( label: context.translation.attachFiles, + showAsListView: true, + moduleId: RequestAttachmentTypeEnum.transferAsset.id, attachment: attachments, buttonColor: AppColor.black10, onlyImages: false, diff --git a/lib/modules/tm_module/gas_refill/gas_refill_details.dart b/lib/modules/tm_module/gas_refill/gas_refill_details.dart index bbeee78a..77b5b70a 100644 --- a/lib/modules/tm_module/gas_refill/gas_refill_details.dart +++ b/lib/modules/tm_module/gas_refill/gas_refill_details.dart @@ -3,14 +3,19 @@ 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/controllers/providers/api/gas_refill_provider.dart'; import 'package:test_sa/controllers/providers/api/gas_refill_comments.dart'; import 'package:test_sa/controllers/providers/api/gas_refill_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/helper/utils.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/new_models/gas_refill_model.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/cx_module/chat/chat_widget.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; @@ -92,7 +97,7 @@ class _GasRefillDetailsPageState extends State { return const ALoading(); } else if (snap.hasData) { _model = snap.data as GasRefillModel; - _attachments = _model.gasRefillAttachments?.map((e) => File(e.attachmentName ?? '')).toList() ?? []; + _attachments = _model.gasRefillAttachments?.whereType().map((e) => File(e.name ?? '')).toList() ?? []; isDataUpdated = false; return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -233,7 +238,11 @@ class _GasRefillDetailsPageState extends State { if (_attachments.isNotEmpty) ...[ const Divider().defaultStyle(context), InfoHeader16Widget("Attachments".addTranslation), - FilesList(images: _model.gasRefillAttachments?.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), + 4.height, + FilesList( + showAsListView: true, + types: _model.gasRefillAttachments?.whereType().where((e) => e.documentType != null && e.documentType!.name != null).map((toElement) => toElement.documentType!.name!).toList() ?? [], + images: _model.gasRefillAttachments?.whereType().where((e) => e.name != null).map((e) => URLs.getFileUrl(e.name!) ?? '').toList() ?? []), ], ], ).expanded, diff --git a/lib/modules/tm_module/gas_refill/gas_refill_request_form.dart b/lib/modules/tm_module/gas_refill/gas_refill_request_form.dart index 6e6e46d3..87f788c2 100644 --- a/lib/modules/tm_module/gas_refill/gas_refill_request_form.dart +++ b/lib/modules/tm_module/gas_refill/gas_refill_request_form.dart @@ -10,6 +10,7 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/enums/request_attachment_type_enum.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'; @@ -216,7 +217,9 @@ class _GasRefillRequestFormState extends State { 8.height, AttachmentPicker( label: context.translation.attachFiles, + showAsListView: true, attachment: attachments, + moduleId: RequestAttachmentTypeEnum.gasRefill.id, buttonColor: AppColor.black10, onlyImages: false, buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), @@ -238,7 +241,7 @@ class _GasRefillRequestFormState extends State { _gasModel.gasRefillAttachments = []; for (var item in attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - _gasModel.gasRefillAttachments?.add(GasRefillAttachments(id: item.id, gasRefillId: _gasModel.id ?? 0, attachmentName: fileName)); + _gasModel.gasRefillAttachments?.add(GenericAttachmentModel(id: item.id, moduleReferenceId: _gasModel.id ?? 0, name: fileName, documentType: item.documentType)); } await _gasRefillProvider?.addGasRefillRequest( context: context, diff --git a/lib/modules/tm_module/gas_refill/update_gas_refill_request.dart b/lib/modules/tm_module/gas_refill/update_gas_refill_request.dart index b254dd79..368a1f71 100644 --- a/lib/modules/tm_module/gas_refill/update_gas_refill_request.dart +++ b/lib/modules/tm_module/gas_refill/update_gas_refill_request.dart @@ -11,6 +11,7 @@ import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/enums/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/timer_model.dart'; @@ -86,7 +87,7 @@ class _UpdateGasRefillRequestState extends State { } catch (ex) {} } if (_formModel.gasRefillAttachments != null && _formModel.gasRefillAttachments!.isNotEmpty) { - _attachments.addAll(_formModel.gasRefillAttachments!.map((e) => GenericAttachmentModel(id: e.id, name: e.attachmentName!)).toList()); + _attachments.addAll(_formModel.gasRefillAttachments!.whereType().where((e) => e.id != null && e.name != null).map((e) => GenericAttachmentModel(id: e.id, name: e.name, documentType: e.documentType)).toList()); } } @@ -182,7 +183,7 @@ class _UpdateGasRefillRequestState extends State { _formModel.gasRefillAttachments = []; for (var item in _attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - _formModel.gasRefillAttachments?.add(GasRefillAttachments(id: item.id, gasRefillId: _formModel.id ?? 0, attachmentName: fileName)); + _formModel.gasRefillAttachments?.add(GenericAttachmentModel(id: item.id, moduleReferenceId: _formModel.id ?? 0, name: fileName, documentType: item.documentType)); } await _gasRefillProvider?.updateGasRefill(status: status, model: _formModel).then((success) { @@ -292,6 +293,8 @@ class _UpdateGasRefillRequestState extends State { AttachmentPicker( label: context.translation.attachFiles, attachment: _attachments, + moduleId: RequestAttachmentTypeEnum.gasRefill.id, + showAsListView: true, buttonColor: AppColor.black10, onlyImages: false, buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), diff --git a/lib/modules/tm_module/tasks/create_task_view.dart b/lib/modules/tm_module/tasks/create_task_view.dart index f3aab34c..d3a06e45 100644 --- a/lib/modules/tm_module/tasks/create_task_view.dart +++ b/lib/modules/tm_module/tasks/create_task_view.dart @@ -5,10 +5,12 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/dashboard_latest/dashboard_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/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/enums/request_attachment_type_enum.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'; @@ -44,7 +46,7 @@ class CreateTaskView extends StatefulWidget { } class _CreateTaskViewState extends State with TickerProviderStateMixin { - final List attachments = []; + List attachments = []; final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); List _deviceList = []; @@ -58,7 +60,9 @@ class _CreateTaskViewState extends State with TickerProviderStat void initState() { // TODO: implement initState super.initState(); - Provider.of(context, listen: false).reset(); + // WidgetsBinding.instance.addPostFrameCallback((_) { + Provider.of(context, listen: false).reset(); + // }); } @override @@ -116,14 +120,11 @@ class _CreateTaskViewState extends State with TickerProviderStat AttachmentPicker( label: context.translation.attachImage, attachment: attachments, + moduleId: RequestAttachmentTypeEnum.taskRequest.id, buttonColor: AppColor.black10, + showAsListView: true, onlyImages: false, buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), - //verify this if not required delete this .. - onChange: (attachments) { - attachments = attachments; - setState(() {}); - }, ), ], ).toShadowContainer(context).paddingAll(16), @@ -457,7 +458,7 @@ class _CreateTaskViewState extends State with TickerProviderStat } for (var item in attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - _addTaskModel?.attachments?.add(TaskJobAttachment(id: item.id, name: fileName)); + _addTaskModel?.attachments?.add(GenericAttachmentModel(id: item.id, name: fileName, documentType: item.documentType)); } TaskRequestProvider taskRequestProvider = Provider.of(context, listen: false); await taskRequestProvider.addTask(context: context, task: _addTaskModel!); diff --git a/lib/modules/tm_module/tasks/task_request_detail_view.dart b/lib/modules/tm_module/tasks/task_request_detail_view.dart index a382bddb..b60740fb 100644 --- a/lib/modules/tm_module/tasks/task_request_detail_view.dart +++ b/lib/modules/tm_module/tasks/task_request_detail_view.dart @@ -9,6 +9,7 @@ import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/models/all_requests_and_count_model.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/new_models/task_request/task_request_model.dart'; import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; @@ -159,7 +160,11 @@ class _TaskRequestDetailsViewState extends State { if (taskProvider.taskRequestModel?.taskJobAttachments?.isNotEmpty ?? false) ...[ const Divider().defaultStyle(context), InfoHeader16Widget("Attachments".addTranslation), - FilesList(images: taskProvider.taskRequestModel!.taskJobAttachments!.map((toElement) => URLs.getFileUrl(toElement.name ?? '') ?? '').toList()), + 4.height, + FilesList( + showAsListView: true, + types: taskProvider.taskRequestModel!.taskJobAttachments!.whereType().where((e) => e.name != null).map((toElement) => toElement.documentType?.name ?? '').toList(), + images: taskProvider.taskRequestModel!.taskJobAttachments!.whereType().where((e) => e.name != null).map((toElement) => URLs.getFileUrl(toElement.name ?? '') ?? '').toList()), ], buildTechnicalComments(taskModel: taskModel), ], diff --git a/lib/modules/tm_module/tasks/update_task_request_view.dart b/lib/modules/tm_module/tasks/update_task_request_view.dart index d5cfd48c..a47506a5 100644 --- a/lib/modules/tm_module/tasks/update_task_request_view.dart +++ b/lib/modules/tm_module/tasks/update_task_request_view.dart @@ -15,6 +15,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/helper/utils.dart'; +import 'package:test_sa/models/enums/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/new_models/building.dart'; @@ -63,7 +64,7 @@ class _UpdateTaskRequestState extends State { final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); List attachments = []; - List otherAttachments = []; + List otherAttachments = []; bool installationType = true; String comments = ''; List timerList = []; @@ -87,8 +88,8 @@ class _UpdateTaskRequestState extends State { _taskProvider?.refresh(); calculateWorkingTime(helperModel: taskModel!); if (taskModel.taskJobAttachments != null) { - attachments = taskModel.taskJobAttachments!.where((e) => e.createdBy == _userProvider.user?.userID).map((e) => GenericAttachmentModel(id: e.id, name: e.name ?? '')).toList(); - otherAttachments = taskModel.taskJobAttachments?.where((e) => e.createdBy != _userProvider.user?.userID).toList() ?? []; + attachments = taskModel.taskJobAttachments!.whereType().where((e) => e.createdBy == _userProvider.user?.userID && e.id != null).map((e) => GenericAttachmentModel(id: e.id, name: e.name ?? '',documentType: e.documentType)).toList(); + otherAttachments = taskModel.taskJobAttachments!.whereType().where((e) => e.createdBy != _userProvider.user?.userID).toList(); } } @@ -191,7 +192,9 @@ class _UpdateTaskRequestState extends State { 20.height, AttachmentPicker( label: context.translation.attachFiles, + showAsListView: true, attachment: attachments, + moduleId: RequestAttachmentTypeEnum.taskRequest.id, buttonColor: AppColor.black10, onlyImages: false, buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), @@ -254,13 +257,13 @@ class _UpdateTaskRequestState extends State { if (validate(model: taskModel)) { showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - List taskAttachment = []; + List taskAttachment = []; if (otherAttachments.isNotEmpty) { taskAttachment.addAll(otherAttachments); } for (var item in attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - taskAttachment.add(TaskJobAttachment(id: item.id, name: fileName)); + taskAttachment.add(GenericAttachmentModel(id: item.id, name: fileName,documentType: item.documentType)); } taskModel.taskJobAttachments = taskAttachment; taskModel.taskJobActivityEngineerTimers = []; diff --git a/lib/modules/traf_module/create_traf_request_page.dart b/lib/modules/traf_module/create_traf_request_page.dart index 4d552cf1..11b124c1 100644 --- a/lib/modules/traf_module/create_traf_request_page.dart +++ b/lib/modules/traf_module/create_traf_request_page.dart @@ -11,6 +11,7 @@ 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/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/new_models/traf_customer.dart'; @@ -516,7 +517,9 @@ class _CreateTRAFRequestPageState extends State { 12.height, AttachmentPicker( label: context.translation.attachFiles, + showAsListView: true, attachment: attachments, + moduleId: RequestAttachmentTypeEnum.traf.id, buttonColor: AppColor.black10, onlyImages: false, buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), @@ -622,7 +625,7 @@ class _CreateTRAFRequestPageState extends State { for (var item in attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; trafRequest?.attachments!.add( - Attachments(id: 0, trafId: 0, attachmentName: fileName), + GenericAttachmentModel(id: 0, moduleReferenceId: 0, name: fileName, documentType: item.documentType), ); } diff --git a/lib/modules/traf_module/traf_request_detail_page.dart b/lib/modules/traf_module/traf_request_detail_page.dart index 7f20e018..98337cff 100644 --- a/lib/modules/traf_module/traf_request_detail_page.dart +++ b/lib/modules/traf_module/traf_request_detail_page.dart @@ -10,6 +10,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/enums/user_types.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/modules/traf_module/traf_request_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'; @@ -63,7 +64,7 @@ class _TrafRequestDetailPageState extends State { if (isLoading) return const ALoading(); TrafRequestProvider trafProvider = Provider.of(context, listen: false); if (trafProvider.trafRequestDataModel?.attachments != null) { - _attachments = trafProvider.trafRequestDataModel!.attachments!.map((e) => File(URLs.getFileUrl(e.attachmentName ?? '') ?? '')).toList(); + _attachments = trafProvider.trafRequestDataModel!.attachments!.whereType().map((e) => File(URLs.getFileUrl(e.name ?? '') ?? '')).toList(); } return trafProvider.trafRequestDataModel == null ? const NoDataFound().center @@ -150,13 +151,17 @@ class _TrafRequestDetailPageState extends State { ], if (_attachments.isNotEmpty) ...[ 4.height, - Text( - // todo @waseem conver to header - "Attachments".addTranslation, - style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), - ), - // 8.height, - FilesList(images: _attachments.map((e) => URLs.getFileUrl(e.path ?? '') ?? '').toList() ?? []), + InfoHeader16Widget("Attachments".addTranslation), + 4.height, + FilesList( + showAsListView: true, + types: data.attachments + ?.whereType() + .where((e) => e.documentType != null && e.documentType!.name!.isNotEmpty) + .map((toElement) => toElement.documentType!.name!) + .toList() ?? + [], + images: _attachments.map((e) => URLs.getFileUrl(e.path ?? '') ?? '').toList()), ], ], ).toShadowContainer(context); diff --git a/lib/modules/traf_module/traf_request_model.dart b/lib/modules/traf_module/traf_request_model.dart index a9d7c40e..2b177cda 100644 --- a/lib/modules/traf_module/traf_request_model.dart +++ b/lib/modules/traf_module/traf_request_model.dart @@ -1,3 +1,6 @@ +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; + class TrafRequestModel { List? trafRequestDataModel; int? totalRows; @@ -92,7 +95,7 @@ class TrafRequestDataModel { String? isCombinationName; String? usedWithCombination; String? comment; - List? attachments; + List? attachments; bool? isFromMobile; int? isBudgetId; String? isBudgetName; @@ -309,9 +312,9 @@ class TrafRequestDataModel { comment = json['comment']; isFromMobile = json['isFromMobile']; if (json['attachments'] != null) { - attachments = []; + attachments = []; json['attachments'].forEach((v) { - attachments!.add(new Attachments.fromJson(v)); + attachments!.add(GenericAttachmentModel.fromTrafJson(v)); }); } isBudgetId = json['isBudgetId']; @@ -426,8 +429,8 @@ class TrafRequestDataModel { data['usedWithCombination'] = this.usedWithCombination; data['comment'] = this.comment; data['isFromMobile'] = this.isFromMobile; - if (this.attachments != null) { - data['attachments'] = this.attachments!.map((v) => v.toJson()).toList(); + if (attachments != null) { + data['attachments'] = attachments!.map((v) => v.toTrafJson()).toList(); } else { data['attachments'] = []; } @@ -536,7 +539,7 @@ class TrafRequestDataModel { data['isBudgetId'] = isBudgetId; data['attachments'] = - attachments?.map((v) => v.toJson()).toList() ?? []; + attachments?.map((v) => v.toTrafJson() ?? {}).toList() ?? []; return data; } @@ -632,25 +635,28 @@ class Departments { return data; } } - -class Attachments { - int? id; - int? trafId; - String? attachmentName; - - Attachments({this.id, this.trafId, this.attachmentName}); - - Attachments.fromJson(Map json) { - id = json['id']; - trafId = json['trafId']; - attachmentName = json['attachmentName']; - } - - Map toJson() { - final Map data = new Map(); - data['id'] = this.id; - data['trafId'] = this.trafId; - data['attachmentName'] = this.attachmentName; - return data; - } -} +//TODO need to remove this +// class Attachments { +// int? id; +// int? trafId; +// String? attachmentName; +// Lookup ? documentType; +// +// Attachments({this.id, this.trafId, this.attachmentName,this.documentType}); +// +// Attachments.fromJson(Map json) { +// id = json['id']; +// trafId = json['trafId']; +// attachmentName = json['attachmentName']; +// documentType = json['documentType']; +// } +// +// Map toJson() { +// final Map data = new Map(); +// data['id'] = this.id; +// data['trafId'] = this.trafId; +// data['attachmentName'] = this.attachmentName; +// data['documentTypeId'] = this.documentType?.id; +// return data; +// } +// } diff --git a/lib/modules/traf_module/update_traf_request_page.dart b/lib/modules/traf_module/update_traf_request_page.dart index 3e62c5cb..f41cc71c 100644 --- a/lib/modules/traf_module/update_traf_request_page.dart +++ b/lib/modules/traf_module/update_traf_request_page.dart @@ -7,6 +7,7 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/enums/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; @@ -58,7 +59,7 @@ class _UpdateTrafRequestPageState extends State { Provider.of(context, listen: false).reset(); trafRequestProvider = Provider.of(context, listen: false); trafRequest = trafRequestProvider.trafRequestDataModel!; - attachments = trafRequest.attachments?.map((item) => GenericAttachmentModel(id: item.id, name: item.attachmentName)).toList() ?? []; + attachments = trafRequest.attachments?.whereType().map((item) => GenericAttachmentModel(id: item.id, name: item.name ?? '')).toList() ?? []; } @override @@ -212,6 +213,8 @@ class _UpdateTrafRequestPageState extends State { 12.height, AttachmentPicker( label: context.translation.attachFiles, + showAsListView: true, + moduleId: RequestAttachmentTypeEnum.traf.id, attachment: attachments, buttonColor: AppColor.black10, onlyImages: false, @@ -233,7 +236,7 @@ class _UpdateTrafRequestPageState extends State { for (var item in attachments) { String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; trafRequest.attachments!.add( - Attachments(id: item.id, trafId: item.id, attachmentName: fileName), + GenericAttachmentModel(id: item.id, moduleReferenceId: item.id, name: fileName, documentType: item.documentType), ); } } 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 04eaf070..dcad5347 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 @@ -106,6 +106,7 @@ class _CreateRequestTypeBottomSheetState extends State { } } +class SameOrgSiteProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading ?? false) return -2; + loading = true; + notifyListeners(); + try { + Response response = await ApiManager.instance.get(URLs.getCustomersAutoCompleteSameOrg + "?senderSiteId=$id"); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List categoriesListJson = json.decode(response.body)["data"]; + items = categoriesListJson.map((item) => Site.fromJson(item)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } +} + class MappedSiteProvider extends LoadingListNotifier { @override Future getData({int? id}) async { diff --git a/lib/providers/task_request_provider/task_job_provider.dart b/lib/providers/task_request_provider/task_job_provider.dart index 8b9b74fc..e605b7fe 100644 --- a/lib/providers/task_request_provider/task_job_provider.dart +++ b/lib/providers/task_request_provider/task_job_provider.dart @@ -12,7 +12,6 @@ import '../../controllers/api_routes/urls.dart'; class TaskTypeProvider extends LoadingListNotifier { @override Future getData({int? id}) async { - print('get data called...'); if (loading == true) return -2; loading = true; notifyListeners(); @@ -23,7 +22,6 @@ class TaskTypeProvider extends LoadingListNotifier { // client's request was successfully received List categoriesListJson = json.decode(response.body)["data"]; items = categoriesListJson.map((item) => TaskType.fromJson(item)).toList(); - print('item lenght i got is ${items.length}'); } loading = false; diff --git a/lib/views/widgets/equipment/asset_detail_page.dart b/lib/views/widgets/equipment/asset_detail_page.dart index 0a51cc87..8144eb46 100644 --- a/lib/views/widgets/equipment/asset_detail_page.dart +++ b/lib/views/widgets/equipment/asset_detail_page.dart @@ -1,29 +1,20 @@ 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/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/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_by_id_model.dart'; -import 'package:test_sa/models/generic_attachment_model.dart'; -import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; -import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; -import 'package:test_sa/views/widgets/item_views/info_header_widget.dart'; -import 'package:test_sa/views/widgets/item_views/info_text_widget.dart'; +import 'package:test_sa/views/widgets/equipment/asset_details_view.dart'; +import 'package:test_sa/views/widgets/equipment/asset_document_history_view.dart'; import 'package:test_sa/views/widgets/equipment/asset_image_upload_page.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/app_loading.dart'; import 'package:test_sa/views/widgets/loaders/failed_loading.dart'; -import '../../../new_views/app_style/app_color.dart'; -import '../requests/request_status.dart'; - class AssetDetailPage extends StatefulWidget { static const String id = "/asset-details"; @@ -35,29 +26,11 @@ class AssetDetailPage extends StatefulWidget { } } -class _AssetDetailPageState extends State with SingleTickerProviderStateMixin { - late AnimationController _animationController; +class _AssetDetailPageState extends State { int? assetId; AssetProvider? _assetProvider; AssetByIdModel? assetModel; - @override - void initState() { - super.initState(); - _animationController = AnimationController( - duration: const Duration(milliseconds: 1400), - vsync: this, - ); - } - - @override - void dispose() { - _animationController.dispose(); - super.dispose(); - } - - List attachments = []; - @override Widget build(BuildContext context) { assetId ??= ModalRoute.of(context)?.settings.arguments as int; @@ -81,311 +54,50 @@ class _AssetDetailPageState extends State with SingleTickerProv } else if (snapshot.hasData) {} if (snapshot.hasData) { assetModel = snapshot.data!; - attachments = assetModel?.assetAttachments - ?.map((attachment) => GenericAttachmentModel( - id: attachment.id, - name: attachment.attachmentName, - originalName: attachment.originalName, - )) - .toList() ?? - []; - - if (!_animationController.isCompleted) { - _animationController.forward(from: 0.0); - } - - // Image animation - fade in with scale - final imageAnimation = Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation( - parent: _animationController, - curve: const Interval(0.0, 0.4, curve: Curves.easeOut), - ), - ); - - final imageScaleAnimation = Tween(begin: 0.92, end: 1.0).animate( - CurvedAnimation( - parent: _animationController, - curve: const Interval(0.0, 0.4, curve: Curves.easeOutCubic), - ), - ); - - // Status label animation - final statusAnimation = Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation( - parent: _animationController, - curve: const Interval(0.15, 0.5, curve: Curves.easeOut), - ), - ); - - final statusSlideAnimation = Tween( - begin: const Offset(0.0, 0.2), - end: Offset.zero, - ).animate( - CurvedAnimation( - parent: _animationController, - curve: const Interval(0.15, 0.5, curve: Curves.easeOutCubic), - ), - ); - - // Header animation - final headerAnimation = Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation( - parent: _animationController, - curve: const Interval(0.25, 0.6, curve: Curves.easeOut), - ), - ); - - final headerSlideAnimation = Tween( - begin: const Offset(0.0, 0.2), - end: Offset.zero, - ).animate( - CurvedAnimation( - parent: _animationController, - curve: const Interval(0.25, 0.6, curve: Curves.easeOutCubic), - ), - ); - - // Details row animation - final detailsAnimation = Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation( - parent: _animationController, - curve: const Interval(0.35, 0.75, curve: Curves.easeOut), - ), - ); - - final detailsSlideAnimation = Tween( - begin: const Offset(0.0, 0.15), - end: Offset.zero, - ).animate( - CurvedAnimation( - parent: _animationController, - curve: const Interval(0.35, 0.75, curve: Curves.easeOutCubic), - ), - ); - - // Dates section animation - final datesAnimation = Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation( - parent: _animationController, - curve: const Interval(0.50, 0.9, curve: Curves.easeOut), - ), - ); - - final datesSlideAnimation = Tween( - begin: const Offset(0.0, 0.15), - end: Offset.zero, - ).animate( - CurvedAnimation( - parent: _animationController, - curve: const Interval(0.50, 0.9, curve: Curves.easeOutCubic), - ), - ); - - // Description animation (if exists) - final descAnimation = Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation( - parent: _animationController, - curve: const Interval(0.65, 1.0, curve: Curves.easeOut), - ), - ); - - final descSlideAnimation = Tween( - begin: const Offset(0.0, 0.1), - end: Offset.zero, - ).animate( - CurvedAnimation( - parent: _animationController, - curve: const Interval(0.65, 1.0, curve: Curves.easeOutCubic), - ), - ); - - final attachmentAnimation = Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation( - parent: _animationController, - curve: const Interval(0.80, 1.0, curve: Curves.easeOut), - ), - ); - - final attachmentSlideAnimation = Tween( - begin: const Offset(0.0, 0.1), - end: Offset.zero, - ).animate( - CurvedAnimation( - parent: _animationController, - curve: const Interval(0.80, 1.0, curve: Curves.easeOutCubic), - ), - ); - - return Column( - children: [ - SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Animated image - FadeTransition( - opacity: imageAnimation, - child: ScaleTransition( - scale: imageScaleAnimation, - child: AspectRatio( - aspectRatio: 159 / 94, - child: Container( - width: 95, - height: 95, - decoration: ShapeDecoration( - color: AppColor.neutral30, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - image: DecorationImage( - fit: BoxFit.cover, - image: NetworkImage(assetModel?.assetPhoto != null ? URLs.getFileUrl(assetModel!.assetPhoto!)! : "https://www.lasteelcraft.com/images/no-image-available.png"), - )), - ), - ), - ), - ), - 6.height, - // Animated content column - Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Status label with animation - if (assetModel?.commissioningStatus != null) - FadeTransition( - opacity: statusAnimation, - child: SlideTransition( - position: statusSlideAnimation, - child: StatusLabel( - label: assetModel!.commissioningStatus!.name, - textColor: AppColor.getRequestStatusTextColorByName(context, assetModel!.commissioningStatus!.name!), - backgroundColor: AppColor.getRequestStatusColorByName(context, assetModel!.commissioningStatus!.name!), - ), - ), - ), - if (assetModel?.commissioningStatus != null) 8.height, - - // Header with animation - FadeTransition( - opacity: headerAnimation, - child: SlideTransition( - position: headerSlideAnimation, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - spacing: 2, - children: [ - InfoHeader16Widget(assetModel?.modelDefinition?.assetName?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"), - if (context.userProvider.isEngineer && !(assetModel?.hasTrainingImageData ?? true)) - const InfoTextLabelWidget(label: '*Upload Images for this asset', color: AppColor.red30), - ], - ), - ), - ), - 8.height, - // Details row with animation - FadeTransition( - opacity: detailsAnimation, - child: SlideTransition( - position: detailsSlideAnimation, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - spacing: 8, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - InfoTextWidget(label: context.translation.assetNo, value: assetModel!.multiAssets!.first.assetNumber, showEmptyValue: true, copyValue: true), - InfoTextWidget(label: context.translation.modelName, value: assetModel!.modelDefinition!.modelName, showEmptyValue: true), - InfoTextWidget(label: context.translation.supplier, value: assetModel!.supplier?.suppliername, showEmptyValue: true), - InfoTextWidget(label: context.translation.manufacture, value: assetModel!.modelDefinition!.manufacturerName, showEmptyValue: true), - ], - ).expanded, - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - InfoTextWidget(label: context.translation.snNo, value: assetModel!.multiAssets!.first.assetSerialNo, showEmptyValue: true), - InfoTextWidget(label: context.translation.site, value: assetModel!.site?.custName?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), - InfoTextWidget(label: context.translation.building, value: assetModel!.building?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), - InfoTextWidget(label: context.translation.floor, value: assetModel!.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), - InfoTextWidget(label: context.translation.md, value: assetModel!.department?.departmentName?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), - InfoTextWidget(label: context.translation.room, value: assetModel!.room?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), - ], - ).expanded, - ], - ), - ), - ), - // 8.height, - // Divider with animation - FadeTransition( - opacity: datesAnimation, - child: const Divider().defaultStyle(context), - ), - // 8.height, - // Dates section with animation - FadeTransition( - opacity: datesAnimation, - child: SlideTransition( - position: datesSlideAnimation, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - InfoTextWidget(label: context.translation.installationDate, value: assetModel?.installationDate?.toAssetDetailsFormat, showEmptyValue: true), - InfoTextWidget(label: context.translation.nextPmDate, value: assetModel?.nextPMDate?.toAssetDetailsFormat, showEmptyValue: true), - InfoTextWidget(label: context.translation.lastPmDate, value: assetModel?.lastPMDate?.toAssetDetailsFormat, showEmptyValue: true), - ], - ), - ), - ), - - // Description with animation (if exists) - if ((assetModel?.modelDefinition?.assetDescription ?? "").isNotEmpty) ...[ - // 8.height, - FadeTransition( - opacity: descAnimation, - child: const Divider().defaultStyle(context), - ), - FadeTransition( - opacity: descAnimation, - child: SlideTransition( - position: descSlideAnimation, - child: InfoTextWidget(label: assetModel!.modelDefinition!.assetDescription!, showEmptyValue: true, isMsg: true), - ), - ), - ], - - if (attachments.isNotEmpty) ...[ - // 8.height, - FadeTransition( - opacity: attachmentAnimation, - child: const Divider().defaultStyle(context), - ), - FadeTransition( - opacity: attachmentAnimation, - child: SlideTransition( - position: attachmentSlideAnimation, - child: FilesList(images: attachments.map((toElement) => URLs.getFileUrl(toElement.name!) ?? '').toList()), - ), - ), - ] - ], - ), - ], - ).toShadowContainer(context), - ).expanded, - if (context.userProvider.isEngineer && !(assetModel!.hasTrainingImageData ?? true)) - FooterActionButton.footerContainer( - context: context, - child: AppFilledButton( - buttonColor: AppColor.primary10, - label: "Upload Images", - onPressed: _upload, + return 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: AppColor.tabBarBackground(context), + border: Border.all(color: AppColor.tabBarBorder(context)), + borderRadius: BorderRadius.circular(20), + ), + child: TabBar( + padding: EdgeInsets.symmetric(vertical: 6.toScreenHeight, horizontal: 6.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, + overlayColor: WidgetStateProperty.all(Colors.transparent), + indicator: BoxDecoration( + color: AppColor.background(context), + borderRadius: BorderRadius.circular(15), + boxShadow: [BoxShadow(color: Colors.black.withValues(alpha: 0.03), blurRadius: 5, offset: const Offset(0, 0), spreadRadius: 0)]), + onTap: (index) { + // setState(() {}); + }, + tabs: [ + Tab(text: context.translation.assetDetails, height: 57.toScreenHeight), + Tab(text: 'Document history'.addTranslation, height: 57.toScreenHeight), + ], ), ), - ], + 12.height, + TabBarView( + children: [ + AssetDetailsView(assetModel: assetModel!, onUpload: _upload), + AssetDocumentHistoryView(assetId: assetId!), + ], + ).expanded, + ], + ), ); } return const Center(child: ALoading()); diff --git a/lib/views/widgets/equipment/asset_details_view.dart b/lib/views/widgets/equipment/asset_details_view.dart new file mode 100644 index 00000000..81ab2866 --- /dev/null +++ b/lib/views/widgets/equipment/asset_details_view.dart @@ -0,0 +1,360 @@ +import 'package:flutter/material.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/models/device/asset_by_id_model.dart'; +import 'package:test_sa/models/generic_attachment_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/app_filled_button.dart'; +import 'package:test_sa/views/widgets/item_views/info_header_widget.dart'; +import 'package:test_sa/views/widgets/item_views/info_text_widget.dart'; +import 'package:test_sa/views/widgets/images/files_list.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class AssetDetailsView extends StatefulWidget { + final AssetByIdModel assetModel; + final VoidCallback onUpload; + + const AssetDetailsView({ + Key? key, + required this.assetModel, + required this.onUpload, + }) : super(key: key); + + @override + State createState() => _AssetDetailsViewState(); +} + +class _AssetDetailsViewState extends State with SingleTickerProviderStateMixin { + late AnimationController _animationController; + List attachments = []; + + @override + void initState() { + super.initState(); + _animationController = AnimationController( + duration: const Duration(milliseconds: 1400), + vsync: this, + ); + attachments = widget.assetModel.assetAttachments?.whereType().toList() ?? []; + _animationController.forward(from: 0.0); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + // Image animation - fade in with scale + final imageAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.0, 0.4, curve: Curves.easeOut), + ), + ); + + final imageScaleAnimation = Tween(begin: 0.92, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.0, 0.4, curve: Curves.easeOutCubic), + ), + ); + + // Status label animation + final statusAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.15, 0.5, curve: Curves.easeOut), + ), + ); + + final statusSlideAnimation = Tween( + begin: const Offset(0.0, 0.2), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.15, 0.5, curve: Curves.easeOutCubic), + ), + ); + + // Header animation + final headerAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.25, 0.6, curve: Curves.easeOut), + ), + ); + + final headerSlideAnimation = Tween( + begin: const Offset(0.0, 0.2), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.25, 0.6, curve: Curves.easeOutCubic), + ), + ); + + // Details row animation + final detailsAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.35, 0.75, curve: Curves.easeOut), + ), + ); + + final detailsSlideAnimation = Tween( + begin: const Offset(0.0, 0.15), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.35, 0.75, curve: Curves.easeOutCubic), + ), + ); + + // Dates section animation + final datesAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.50, 0.9, curve: Curves.easeOut), + ), + ); + + final datesSlideAnimation = Tween( + begin: const Offset(0.0, 0.15), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.50, 0.9, curve: Curves.easeOutCubic), + ), + ); + + // Description animation (if exists) + final descAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.65, 1.0, curve: Curves.easeOut), + ), + ); + + final descSlideAnimation = Tween( + begin: const Offset(0.0, 0.1), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.65, 1.0, curve: Curves.easeOutCubic), + ), + ); + + final attachmentAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.80, 1.0, curve: Curves.easeOut), + ), + ); + + final attachmentSlideAnimation = Tween( + begin: const Offset(0.0, 0.1), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.80, 1.0, curve: Curves.easeOutCubic), + ), + ); + + return Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Animated image + FadeTransition( + opacity: imageAnimation, + child: ScaleTransition( + scale: imageScaleAnimation, + child: AspectRatio( + aspectRatio: 159 / 94, + child: Container( + width: 95, + height: 95, + decoration: ShapeDecoration( + color: AppColor.neutral30, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + image: DecorationImage( + fit: BoxFit.cover, + image: NetworkImage(widget.assetModel.assetPhoto != null ? URLs.getFileUrl(widget.assetModel.assetPhoto!)! : "https://www.lasteelcraft.com/images/no-image-available.png"), + )), + ), + ), + ), + ), + 6.height, + // Animated content column + Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Status label with animation + if (widget.assetModel.commissioningStatus != null) + FadeTransition( + opacity: statusAnimation, + child: SlideTransition( + position: statusSlideAnimation, + child: StatusLabel( + label: widget.assetModel.commissioningStatus!.name, + textColor: AppColor.getRequestStatusTextColorByName(context, widget.assetModel.commissioningStatus!.name!), + backgroundColor: AppColor.getRequestStatusColorByName(context, widget.assetModel.commissioningStatus!.name!), + ), + ), + ), + if (widget.assetModel.commissioningStatus != null) 8.height, + + // Header with animation + FadeTransition( + opacity: headerAnimation, + child: SlideTransition( + position: headerSlideAnimation, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 2, + children: [ + InfoHeader16Widget(widget.assetModel.modelDefinition?.assetName?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"), + if (context.userProvider.isEngineer && !(widget.assetModel.hasTrainingImageData ?? true)) + const InfoTextLabelWidget(label: '*Upload Images for this asset', color: AppColor.red30), + ], + ), + ), + ), + 8.height, + // Details row with animation + FadeTransition( + opacity: detailsAnimation, + child: SlideTransition( + position: detailsSlideAnimation, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 8, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InfoTextWidget(label: context.translation.assetNo, value: widget.assetModel.multiAssets!.first.assetNumber, showEmptyValue: true, copyValue: true), + InfoTextWidget(label: context.translation.modelName, value: widget.assetModel.modelDefinition!.modelName, showEmptyValue: true), + InfoTextWidget(label: context.translation.supplier, value: widget.assetModel.supplier?.suppliername, showEmptyValue: true), + InfoTextWidget(label: context.translation.manufacture, value: widget.assetModel.modelDefinition!.manufacturerName, showEmptyValue: true), + ], + ).expanded, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InfoTextWidget(label: context.translation.snNo, value: widget.assetModel.multiAssets!.first.assetSerialNo, showEmptyValue: true), + InfoTextWidget(label: context.translation.site, value: widget.assetModel.site?.custName?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), + InfoTextWidget(label: context.translation.building, value: widget.assetModel.building?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), + InfoTextWidget(label: context.translation.floor, value: widget.assetModel.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), + InfoTextWidget(label: context.translation.md, value: widget.assetModel.department?.departmentName?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), + InfoTextWidget(label: context.translation.room, value: widget.assetModel.room?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), + ], + ).expanded, + ], + ), + ), + ), + // Divider with animation + FadeTransition( + opacity: datesAnimation, + child: const Divider().defaultStyle(context), + ), + // Dates section with animation + FadeTransition( + opacity: datesAnimation, + child: SlideTransition( + position: datesSlideAnimation, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InfoTextWidget(label: context.translation.installationDate, value: widget.assetModel.installationDate?.toAssetDetailsFormat, showEmptyValue: true), + InfoTextWidget(label: context.translation.nextPmDate, value: widget.assetModel.nextPMDate?.toAssetDetailsFormat, showEmptyValue: true), + InfoTextWidget(label: context.translation.lastPmDate, value: widget.assetModel.lastPMDate?.toAssetDetailsFormat, showEmptyValue: true), + ], + ), + ), + ), + + // Description with animation (if exists) + if ((widget.assetModel.modelDefinition?.assetDescription ?? "").isNotEmpty) ...[ + FadeTransition( + opacity: descAnimation, + child: const Divider().defaultStyle(context), + ), + FadeTransition( + opacity: descAnimation, + child: SlideTransition( + position: descSlideAnimation, + child: InfoTextWidget(label: widget.assetModel.modelDefinition!.assetDescription!, showEmptyValue: true, isMsg: true), + ), + ), + ], + + if (attachments.isNotEmpty) ...[ + FadeTransition( + opacity: attachmentAnimation, + child: const Divider().defaultStyle(context), + ), + FadeTransition( + opacity: attachmentAnimation, + child: SlideTransition( + position: attachmentSlideAnimation, + child: InfoHeader16Widget("Attachments".addTranslation), + ), + ), + 4.height, + FadeTransition( + opacity: attachmentAnimation, + child: SlideTransition( + position: attachmentSlideAnimation, + child: FilesList( + showAsListView: true, + types: attachments + .whereType() + .where((e) => e.documentType != null && e.documentType!.name!.isNotEmpty) + .map((toElement) => toElement.documentType!.name!) + .toList(), + images: attachments.map((toElement) => URLs.getFileUrl(toElement.name!) ?? '').toList()), + ), + ), + ] + ], + ), + ], + ).toShadowContainer(context), + ).expanded, + if (context.userProvider.isEngineer && !(widget.assetModel.hasTrainingImageData ?? true)) + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: "Upload Images", + onPressed: widget.onUpload, + ), + ), + ], + ); + } +} diff --git a/lib/views/widgets/equipment/asset_document_history_view.dart b/lib/views/widgets/equipment/asset_document_history_view.dart new file mode 100644 index 00000000..12acaa90 --- /dev/null +++ b/lib/views/widgets/equipment/asset_document_history_view.dart @@ -0,0 +1,156 @@ +import 'dart:developer'; +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/devices_provider.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/views/widgets/images/files_list.dart'; +import 'package:test_sa/views/widgets/item_views/info_text_widget.dart'; +import 'package:test_sa/views/widgets/loaders/app_loading.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; + +class AssetDocumentHistoryView extends StatefulWidget { + final int assetId; + + const AssetDocumentHistoryView({ + Key? key, + required this.assetId, + }) : super(key: key); + + @override + State createState() => _AssetDocumentHistoryViewState(); +} + +class _AssetDocumentHistoryViewState extends State { + late AssetProvider _assetProvider; + final ScrollController _scrollController = ScrollController(); + List _documents = []; + bool _isLoading = false; + int _currentPage = 1; + int _totalRows = 0; + + @override + void initState() { + super.initState(); + _assetProvider = context.read(); + _scrollController.addListener(_onScroll); + _loadDocuments(); + } + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + + void _onScroll() { + final pixels = _scrollController.position.pixels; + final maxScroll = _scrollController.position.maxScrollExtent; + if (pixels >= maxScroll * 0.8) { + if (!_isLoading && _hasMore) { + _loadMore(); + } + } + } + + bool get _hasMore => _documents.length < _totalRows; + + Future _loadDocuments({bool refresh = false, bool loadMore = false}) async { + if (_isLoading) return; + setState(() { + _isLoading = true; + if (refresh) { + _documents.clear(); + _currentPage = 1; + } + if (loadMore) { + _currentPage++; + } + }); + try { + final result = await _assetProvider.getAssetDocumentHistory( + assetId: widget.assetId, + pageNumber: _currentPage, + ); + if (mounted) { + setState(() { + if (refresh) { + _documents = result.documents; + } else { + _documents.addAll(result.documents); + } + _totalRows = result.totalRows; + _isLoading = false; + }); + } + } catch (e) { + log('Error loading documents: $e'); + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + Future _loadMore() async { + await _loadDocuments(loadMore: true); + } + + Future _onRefresh() async { + await _loadDocuments(refresh: true); + } + + @override + Widget build(BuildContext context) { + if (_isLoading && _documents.isEmpty) { + return const Center(child: ALoading()); + } + if (_documents.isEmpty && !_isLoading) { + return const Center(child: NoDataFound()); + } + return RefreshIndicator( + onRefresh: _onRefresh, + child: ListView( + controller: _scrollController, + padding: const EdgeInsets.only(right: 16, left: 16, bottom: 16), + children: [ + FilesList( + showAsListView: true, + showDownloadButton: true, + itemGap: 12.toScreenHeight, + separator: const Divider().defaultStyle(context), + images: _documents + .map((doc) { + return URLs.getFileUrl(doc.name) ?? ''; + }) + .where((url) => url.isNotEmpty) + .toList(), + types: _documents.map((doc) { + final attachmentType = doc.documentType?.name ?? ''; + return attachmentType.isNotEmpty ? attachmentType : 'Asset Guide'; + }).toList(), + ).toShadowContainer(context), + if (_isLoading && _documents.isNotEmpty && _hasMore) ...[ + 16.height, + Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const ALoading(), + 8.height, + const InfoTextLabelWidget(label: 'Loading more...'), + ], + ), + ), + ), + ], + ], + ), + ); + } +} diff --git a/lib/views/widgets/equipment/asset_image_upload_page.dart b/lib/views/widgets/equipment/asset_image_upload_page.dart index 33d48a62..43094baa 100644 --- a/lib/views/widgets/equipment/asset_image_upload_page.dart +++ b/lib/views/widgets/equipment/asset_image_upload_page.dart @@ -10,6 +10,7 @@ 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_by_id_model.dart'; +import 'package:test_sa/models/enums/request_attachment_type_enum.dart'; import 'package:test_sa/models/generic_attachment_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'; @@ -109,11 +110,12 @@ class _AssetImageUploadPageState extends State { AttachmentPicker( label: "Additional Images", pickerTitle: "Attach Images", + moduleId: RequestAttachmentTypeEnum.transferAsset.id, attachment: trainingImageData.additionalImages!, buttonColor: AppColor.black10, onlyImages: true, + showAsListView: true, pickMultiple: true, - // showAsGrid: true, buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), onChange: (_attachments) { trainingImageData.additionalImages = _attachments; @@ -164,6 +166,8 @@ class _AssetImageUploadPageState extends State { child: AttachmentPicker( label: "", pickerTitle: title, + moduleId: RequestAttachmentTypeEnum.transferAsset.id, + showAsListView:true, onlyImages: true, checkQuality: true, enabled: attachment == null, diff --git a/lib/views/widgets/equipment/asset_picker.dart b/lib/views/widgets/equipment/asset_picker.dart index 9088ad37..762adac9 100644 --- a/lib/views/widgets/equipment/asset_picker.dart +++ b/lib/views/widgets/equipment/asset_picker.dart @@ -10,6 +10,7 @@ import 'package:test_sa/views/widgets/qr/asset_scan_qr.dart'; import '../../../models/device/asset.dart'; import '../../../new_views/app_style/app_color.dart'; +import 'asset_detail_page.dart'; class AssetPicker extends StatelessWidget { final Function(Asset)? onPick; @@ -185,21 +186,13 @@ class AssetPicker extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ InfoHeaderWidget( device.modelDefinition?.assetName?.cleanupWhitespace.capitalizeFirstOfEach ?? "", ).toShimmer(isShow: showLoading, context: context).expanded, - Icon(Icons.info, color: AppColor.icon2Color(context), size: 20).onPress(() { - showModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: AppColor.bottomSheetColor(context), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical(top: Radius.circular(20)), - ), - clipBehavior: Clip.antiAliasWithSaveLayer, - builder: (BuildContext context) => AssetDetailBottomSheet(device), - ); + const Icon(Icons.open_in_new_rounded, color: AppColor.primary10, size: 20).onPress(() { + Navigator.of(context).pushNamed(AssetDetailPage.id, arguments: device.id); }), if (multiSelection) ...[ 4.width, diff --git a/lib/views/widgets/images/files_list.dart b/lib/views/widgets/images/files_list.dart index 9ca23d8a..223fedff 100644 --- a/lib/views/widgets/images/files_list.dart +++ b/lib/views/widgets/images/files_list.dart @@ -1,5 +1,5 @@ +import 'dart:developer'; import 'dart:io'; - import 'package:ellipsized_text/ellipsized_text.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -11,7 +11,6 @@ import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; -import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; import 'package:test_sa/views/widgets/loaders/image_loader.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -20,15 +19,19 @@ class FilesList extends StatelessWidget { final List types; final EdgeInsets? padding; final bool showAsListView; + final bool showDownloadButton; + final double? itemGap; + final Widget? separator; - const FilesList({Key? key, this.images = const [], this.types = const [], this.padding, this.showAsListView = false}) : super(key: key); + const FilesList({Key? key, this.separator, this.images = const [], this.types = const [], this.padding, required this.showAsListView, this.showDownloadButton = false, this.itemGap}) + : super(key: key); @override Widget build(BuildContext context) { return showAsListView ? ListView.separated( shrinkWrap: true, - padding: const EdgeInsets.only(top: 8), + padding: padding ?? EdgeInsets.zero, physics: const NeverScrollableScrollPhysics(), itemBuilder: (cxt, itemIndex) { if (!images[itemIndex].contains(".")) { @@ -39,7 +42,16 @@ class FilesList extends StatelessWidget { var isPdf = images[itemIndex].split(".").last.toLowerCase() == "pdf"; var isExcel = images[itemIndex].split(".").last.toLowerCase() == "xlsx"; + String checkNull(int index) { + try { + return types[itemIndex]; + } catch (ex) { + return "Asset Guide"; + } + } + return Row( + spacing: 8, children: [ Container( width: 48.toScreenWidth, @@ -65,20 +77,20 @@ class FilesList extends StatelessWidget { : Image.asset("assets/images/${isPdf ? "pdf" : isExcel ? "excel" : "doc"}.png")), ), ), - 8.width, Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ EllipsizedText( images[itemIndex].split("/").last, - style: AppTextStyles.heading6.copyWith(color: AppColor.black10), - type: EllipsisType.start, // or EllipsisType.middle + style: AppTextStyles.bodyText2.copyWith(color: AppColor.labelTextStyleColor(context)), + // style: AppTextStyles.bodyText.copyWith(color: AppColor.textStyleColor(context)), + type: EllipsisType.start, ), - 4.height, + 2.height, RichText( text: TextSpan( - text: '${types.isEmpty ? "Asset Guide" : types[itemIndex]} | ', - style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral120), + text: '${types.isEmpty ? "Asset Guide" : checkNull(itemIndex)} | ', + style: AppTextStyles.tinyFont.copyWith(color: AppColor.lightTextColor(context)), children: [ TextSpan( text: 'View', @@ -105,14 +117,36 @@ class FilesList extends StatelessWidget { ), ), ], - ).expanded + ).expanded, + if (showDownloadButton) + IconButton( + icon: "download".toSvgAsset(height: 24, width: 24, color: AppColor.icon2Color(context)), + padding: EdgeInsets.zero, + visualDensity: VisualDensity.compact, + // tooltip: "Download", + onPressed: () async { + try { + if (!await launchUrl(Uri.parse(images[itemIndex]), mode: LaunchMode.externalApplication)) { + Fluttertoast.showToast(msg: "UnExpected Error with file."); + throw Exception('Could not launch '); + } + } catch (ex) { + Fluttertoast.showToast(msg: "No Viewer found."); + } + // if (Utils.isLocalFile(images[itemIndex])) { + // await OpenFile.open(images[itemIndex]); + // } else { + // await Utils.downloadFile(images[itemIndex], autoOpen: true, showToast: true); + // } + }, + ), ], ); }, - separatorBuilder: (cxt, index) => 8.height, + separatorBuilder: (cxt, index) => separator ?? SizedBox(height: itemGap ?? 8.toScreenHeight), itemCount: images.length) : GridView.builder( - padding: const EdgeInsets.only(top: 8, bottom: 8), + padding: padding ?? const EdgeInsets.only(top: 8, bottom: 8), physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 6, mainAxisSpacing: 8, crossAxisSpacing: 8), diff --git a/lib/views/widgets/images/multi_image_picker.dart b/lib/views/widgets/images/multi_image_picker.dart index 18c14732..6d1bcb3e 100644 --- a/lib/views/widgets/images/multi_image_picker.dart +++ b/lib/views/widgets/images/multi_image_picker.dart @@ -1,9 +1,10 @@ +import 'dart:developer'; import 'dart:io'; - import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:image_blur_detection/image_blur_detection.dart'; import 'package:image_picker/image_picker.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'; @@ -11,7 +12,11 @@ import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/helper/image_quality_helper.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/provider/attachment_type_provider.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/views/widgets/item_views/info_header_widget.dart'; +import 'package:test_sa/views/widgets/item_views/info_text_widget.dart'; import '../../../new_views/common_widgets/app_dashed_button.dart'; import '../../../new_views/common_widgets/app_lazy_loading.dart'; @@ -42,8 +47,9 @@ class AttachmentPicker extends StatefulWidget { final String pickerTitle; final String label; final bool error; + final bool showTypeDropdown; + final int moduleId; final List attachment; - final bool enabled, onlyImages; double? buttonHeight; Widget? buttonIcon; @@ -62,14 +68,17 @@ class AttachmentPicker extends StatefulWidget { this.pickerTitle = "Attach File", this.error = false, this.buttonHeight, + required this.moduleId, + required this.showAsListView, this.buttonIcon, this.enabled = true, this.onlyImages = false, this.onChange, this.documentType, - this.showAsListView = false, + // this.showAsListView = false, this.pickMultiple = false, this.checkQuality = false, + this.showTypeDropdown = true, this.child, this.buttonColor}) : super(key: key); @@ -80,6 +89,8 @@ class AttachmentPicker extends StatefulWidget { class _AttachmentPickerState extends State with SingleTickerProviderStateMixin { late AnimationController _animationController; + Lookup? documentLookup; + late AttachmentTypeLookupProviderLatest attachmentTypeLookupProvider; @override void initState() { @@ -89,6 +100,12 @@ class _AttachmentPickerState extends State with SingleTickerPr vsync: this, ); _animationController.forward(); + // if (widget.documentType != null) { + // documentLookup = widget.documentType; + // } + WidgetsBinding.instance.addPostFrameCallback((_) { + Provider.of(context, listen: false).reset(); + }); } @override @@ -123,7 +140,8 @@ class _AttachmentPickerState extends State with SingleTickerPr file: image, showAsListView: widget.showAsListView, enabled: widget.enabled, - documentType: widget.attachment[index].documentTypeId?.name, + // documentType: widget.documentType != null ? widget.documentType?.name : widget.attachment[index].documentType?.name, + documentType: widget.attachment[index].documentType?.name, onRemoveTap: (image) { if (!widget.enabled) { return; @@ -136,7 +154,7 @@ class _AttachmentPickerState extends State with SingleTickerPr }, ); }, - separatorBuilder: (cxt, index) => 8.height, + separatorBuilder: (cxt, index) => const Divider().defaultStyle(context), itemCount: widget.attachment.length) : Wrap( spacing: 8.toScreenWidth, @@ -173,7 +191,7 @@ class _AttachmentPickerState extends State with SingleTickerPr ); if (result != null) { for (var path in result.paths) { - widget.attachment.add(GenericAttachmentModel(id: 0, name: File(path!).path, documentTypeId: widget.documentType)); + widget.attachment.add(GenericAttachmentModel(id: 0, name: File(path!).path, documentType: widget.documentType ?? documentLookup)); } if (widget.onChange != null) { widget.onChange!(widget.attachment); @@ -207,113 +225,157 @@ class _AttachmentPickerState extends State with SingleTickerPr } onFilePicker(bool checkQuality) async { - // Reset and restart animation for bottom sheet _animationController.reset(); _animationController.forward(); + documentLookup = null; ImageSource? source = await showModalBottomSheet( context: context, + backgroundColor: Colors.transparent, builder: (BuildContext context) { - Widget listCard({required String icon, required String label, required VoidCallback onTap}) { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: AppColor.background(context), - borderRadius: BorderRadius.circular(16), - border: Border.all(color: AppColor.borderColor(context), width: 2), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - icon.toSvgAsset(width: 24, height: 24, color: AppColor.icon2Color(context)), - label.bodyText2(context).custom(color: AppColor.labelTextStyleColor(context), fontSize: context.isTablet() ? 10.toScreenWidth : null), - ], - ), - ).onPress(onTap); - } + return StatefulBuilder( + builder: (BuildContext context, StateSetter setModalState) { + Widget listCard({required String icon, required String label, required VoidCallback onTap}) { + bool isEnabled = !widget.showTypeDropdown ? true : documentLookup != null; + return Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: isEnabled ? AppColor.background(context) : AppColor.tabBarBackground(context), + borderRadius: BorderRadius.circular(16), + border: Border.all(color: AppColor.borderColor(context), width: 2), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + icon.toSvgAsset(width: 24, height: 24, color: isEnabled ? AppColor.icon2Color(context) : AppColor.icon2Color(context).withOpacity(0.4)), + label.bodyText2(context).custom( + color: isEnabled ? AppColor.labelTextStyleColor(context) : AppColor.labelTextStyleColor(context).withOpacity(0.4), fontSize: context.isTablet() ? 10.toScreenWidth : null), + ], + ), + ).onPress(() { + if (!isEnabled) return; + onTap(); + }); + } - List listItems = [ - listCard( - icon: 'camera_icon', - label: '${context.translation.open}\n${context.translation.camera}', - onTap: () { - Navigator.of(context).pop(ImageSource.camera); - }, - ), - listCard( - icon: 'gallery_icon', - label: '${context.translation.open}\n${context.translation.gallery}', - onTap: () { - Navigator.of(context).pop(ImageSource.gallery); - }, - ), - listCard( - icon: 'file_icon', - label: '${context.translation.open}\n${context.translation.files}', - onTap: () async { - // Capture before the await so the sheet is dismissed safely even - // if this element's context is gone by the time we resume. - final NavigatorState sheetNavigator = Navigator.of(context); - await fromFilePicker(); - if (sheetNavigator.canPop()) sheetNavigator.pop(); - }, - ), - ]; + List listItems = [ + listCard( + icon: 'camera_icon', + label: '${context.translation.open}\n${context.translation.camera}', + onTap: () { + Navigator.of(context).pop(ImageSource.camera); + }, + ), + listCard( + icon: 'gallery_icon', + label: '${context.translation.open}\n${context.translation.gallery}', + onTap: () { + Navigator.of(context).pop(ImageSource.gallery); + }, + ), + listCard( + icon: 'file_icon', + label: '${context.translation.open}\n${context.translation.files}', + onTap: () async { + final NavigatorState sheetNavigator = Navigator.of(context); + await fromFilePicker(); + if (sheetNavigator.canPop()) sheetNavigator.pop(); + }, + ), + ]; - return SafeArea( - top: false, - child: Container( - width: double.infinity, - color: AppColor.bottomSheetColor(context), - padding: const EdgeInsets.all(16.0), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - widget.pickerTitle.heading4(context), - GridView.builder( - padding: const EdgeInsets.only(top: 16, bottom: 0), - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 16, mainAxisSpacing: 16), - itemCount: listItems.length, - itemBuilder: (context, index) { - // Calculate staggered animation delay - final delay = index * 0.08; - final animation = Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation( - parent: _animationController, - curve: Interval( - delay.clamp(0.0, 0.8), - (delay + 0.3).clamp(0.0, 1.0), - curve: Curves.easeOut, - ), + return SafeArea( + top: false, + child: Container( + width: double.infinity, + decoration: BoxDecoration( + color: AppColor.bottomSheetColor(context), + borderRadius: const BorderRadius.only( + topRight: Radius.circular(30), + topLeft: Radius.circular(30), + ), + ), + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Align( + alignment: AlignmentDirectional.center, + child: Container( + width: 40.toScreenWidth, + height: 5.toScreenHeight, + decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), ), - ); - final slideAnimation = Tween( - begin: const Offset(0.0, 0.3), - end: Offset.zero, - ).animate( - CurvedAnimation( - parent: _animationController, - curve: Interval( - delay.clamp(0.0, 0.8), - (delay + 0.3).clamp(0.0, 1.0), - curve: Curves.easeOutCubic, - ), + ), + 8.height, + InfoHeader16Widget(widget.pickerTitle), + 8.height, + if (widget.showTypeDropdown) ...[ + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + requestById: widget.moduleId, + title: "Document Type", + initialValue: documentLookup, + showShadow: false, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + onSelect: (value) { + documentLookup = value; + setModalState(() {}); + }, ), - ); + if (documentLookup == null) ...[ + 4.height, + const InfoTextLabelWidget(label: 'Please Select Document Type before picking file', color: AppColor.red30), + ], + ], + GridView.builder( + padding: const EdgeInsets.only(top: 16, bottom: 0), + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 16, mainAxisSpacing: 16), + itemCount: listItems.length, + itemBuilder: (context, index) { + final delay = index * 0.08; + final animation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: Interval( + delay.clamp(0.0, 0.8), + (delay + 0.3).clamp(0.0, 1.0), + curve: Curves.easeOut, + ), + ), + ); + + final slideAnimation = Tween( + begin: const Offset(0.0, 0.3), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: Interval( + delay.clamp(0.0, 0.8), + (delay + 0.3).clamp(0.0, 1.0), + curve: Curves.easeOutCubic, + ), + ), + ); - return FadeTransition( - opacity: animation, - child: SlideTransition(position: slideAnimation, child: listItems[index]), - ); - }, + return FadeTransition( + opacity: animation, + child: SlideTransition(position: slideAnimation, child: listItems[index]), + ); + }, + ), + ], ), - ], - ), - ), + ), + ); + }, ); }, ); @@ -325,8 +387,8 @@ class _AttachmentPickerState extends State with SingleTickerPr if (pickedFiles.isNotEmpty) { for (final pickedFile in pickedFiles) { File fileImage = File(pickedFile.path); - widget.attachment.add(GenericAttachmentModel(id: 0, name: fileImage.path, documentTypeId: widget.documentType)); - } + widget.attachment.add(GenericAttachmentModel(id: 0, name: fileImage.path, documentType: widget.documentType ?? documentLookup)); + }); if (widget.onChange != null) { widget.onChange!(widget.attachment); } @@ -374,15 +436,12 @@ class _AttachmentPickerState extends State with SingleTickerPr } } - if (!mounted) return; - - widget.attachment.add(GenericAttachmentModel(id: 0, name: fileImage.path, documentTypeId: widget.documentType)); + if (!mounted) return; + widget.attachment.add(GenericAttachmentModel(id: 0, name: fileImage.path, documentType: widget.documentType ?? documentLookup)); if (widget.onChange != null) { widget.onChange!(widget.attachment); } setState(() {}); } - - // setState(() {}); } } diff --git a/lib/views/widgets/loaders/image_loader.dart b/lib/views/widgets/loaders/image_loader.dart index eed5d473..6197e620 100644 --- a/lib/views/widgets/loaders/image_loader.dart +++ b/lib/views/widgets/loaders/image_loader.dart @@ -1,5 +1,6 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; class ImageLoader extends StatelessWidget { final String? url; @@ -20,7 +21,7 @@ class ImageLoader extends StatelessWidget { alignment: Alignment.center, width: width, height: height, - placeholder: (context, url) => const Center(child: CircularProgressIndicator()), + placeholder: (context, url) => Center(child: CircularProgressIndicator(color: AppColor.loadingColor(context))), errorWidget: (context, url, error) => Icon(showDefaultIcon ? Icons.image_outlined : Icons.broken_image_rounded), ); } diff --git a/lib/views/widgets/timer/app_timer.dart b/lib/views/widgets/timer/app_timer.dart index d33b0274..759a9c17 100644 --- a/lib/views/widgets/timer/app_timer.dart +++ b/lib/views/widgets/timer/app_timer.dart @@ -158,6 +158,7 @@ class _AppTimerState extends State { @override Widget build(BuildContext context) { return Column( + spacing: 12, children: [ if (canPickTime) ...[ Row( @@ -228,7 +229,6 @@ class _AppTimerState extends State { ], ), if (_tempPickerTimer != null) ...[ - 8.height, Row( children: [ Column( @@ -248,7 +248,7 @@ class _AppTimerState extends State { ], ).toShadowContainer(context) ], - 8.height, + // 8.height, ], if (widget.showTimer) Container( diff --git a/pubspec.yaml b/pubspec.yaml index 70940db2..4f0032df 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.9.3+53 +version: 1.9.6+56 environment: sdk: ">=3.5.0 <4.0.0"