Merge branch 'refs/heads/design_3.0_asset_inventory_module' into design_3.0_GlobalHealth
# Conflicts: # lib/controllers/api_routes/urls.dart # lib/controllers/providers/api/all_requests_provider.dartdesign_3.0_GlobalHealth
						commit
						a39d8297a6
					
				| @ -0,0 +1,124 @@ | ||||
| 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/models/lookup.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; | ||||
| import 'package:test_sa/new_views/app_style/app_color.dart'; | ||||
| import 'package:test_sa/views/app_style/sizing.dart'; | ||||
| import '../../../extensions/text_extensions.dart'; | ||||
| import '../../../new_views/app_style/app_text_style.dart'; | ||||
| 
 | ||||
| class LookUpAutoCompleteField extends StatefulWidget { | ||||
|   final String initialValue; | ||||
|   final String label; | ||||
|   final num? assetId; | ||||
|   final bool forAssetName; | ||||
|   final bool  forSupplier; | ||||
|   final bool clearAfterPick, isManufacturer; | ||||
|   final Function(Lookup) onPick; | ||||
|   final Function(String) onChanged; | ||||
|    //need to pass directly url | ||||
|   const LookUpAutoCompleteField( | ||||
|       {Key? key, | ||||
|       this.isManufacturer = false, | ||||
|       required this.initialValue, | ||||
|       required this.label, | ||||
|       this.forAssetName = false, | ||||
|       this.forSupplier = false, | ||||
|       this.assetId, | ||||
|       required this.onPick, | ||||
|       this.clearAfterPick = true, | ||||
|       required this.onChanged}) | ||||
|       : super(key: key); | ||||
| 
 | ||||
|   @override | ||||
|   _AutoCompletePartsFieldState createState() => _AutoCompletePartsFieldState(); | ||||
| } | ||||
| 
 | ||||
| class _AutoCompletePartsFieldState extends State<LookUpAutoCompleteField> { | ||||
|   AssetInventoryProvider? assetInventoryProvider; | ||||
|   late TextEditingController _controller; | ||||
| 
 | ||||
|   @override | ||||
|   void initState() { | ||||
|     _controller = TextEditingController(text: widget.initialValue); | ||||
|     super.initState(); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   void didUpdateWidget(covariant LookUpAutoCompleteField oldWidget) { | ||||
|     if (widget.initialValue != oldWidget.initialValue) { | ||||
|       _controller = TextEditingController(text: widget.initialValue); | ||||
|     } | ||||
|     super.didUpdateWidget(oldWidget); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   void dispose() { | ||||
|     _controller.dispose(); | ||||
|     super.dispose(); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     assetInventoryProvider ??= Provider.of<AssetInventoryProvider>(context); | ||||
|     final border = UnderlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(10)); | ||||
|     return Container( | ||||
|       decoration: BoxDecoration( | ||||
|         color: AppColor.background(context), | ||||
|         borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), | ||||
|         //  boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], | ||||
|       ), | ||||
|       child: Autocomplete<Lookup>( | ||||
|         optionsBuilder: (TextEditingValue textEditingValue) async { | ||||
|           if (textEditingValue.text.isEmpty) { | ||||
|             return const Iterable<Lookup>.empty(); | ||||
|           } | ||||
|           return (await assetInventoryProvider!.getAutoCompleteDetails(query: textEditingValue.text, isManufacturer: widget.isManufacturer, type: widget.forAssetName?1:widget.forSupplier?2:0)); | ||||
|         }, | ||||
|         displayStringForOption: (Lookup option) => option.name ?? "", | ||||
|         fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) { | ||||
|           return TextField( | ||||
|             controller: _controller, | ||||
|             focusNode: fieldFocusNode, | ||||
|             style: AppTextStyles.bodyText.copyWith(color: AppColor.black10), | ||||
|             textAlign: TextAlign.start, | ||||
|             decoration: InputDecoration( | ||||
|               border: border, | ||||
|               disabledBorder: border, | ||||
|               focusedBorder: border, | ||||
|               enabledBorder: border, | ||||
|               errorBorder: border, | ||||
|               contentPadding: EdgeInsets.symmetric(vertical: 8.toScreenHeight, horizontal: 16.toScreenWidth), | ||||
|               constraints: const BoxConstraints(), | ||||
|               suffixIconConstraints: const BoxConstraints(minWidth: 0), | ||||
|               filled: true, | ||||
|               fillColor: AppColor.fieldBgColor(context), | ||||
|               errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60), | ||||
|               floatingLabelStyle: AppTextStyle.body1.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? null : AppColor.neutral20), | ||||
|               labelText: widget.label, | ||||
|               labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)), | ||||
|             ), | ||||
|             textInputAction: TextInputAction.search, | ||||
|             onChanged: (text) { | ||||
|               widget.onChanged(text); | ||||
|               fieldTextEditingController.text = text; | ||||
|             }, | ||||
|             onSubmitted: (String value) { | ||||
|               onFieldSubmitted(); | ||||
|             }, | ||||
|           ); | ||||
|         }, | ||||
|         onSelected: (Lookup selection) { | ||||
|           if (widget.clearAfterPick) { | ||||
|             _controller.clear(); | ||||
|           } else { | ||||
|             _controller.text = selection.name ?? ''; | ||||
|           } | ||||
|           widget.onPick(selection); | ||||
|         }, | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,292 @@ | ||||
| import 'dart:developer'; | ||||
| 
 | ||||
| import 'package:test_sa/models/new_models/building.dart'; | ||||
| import 'package:test_sa/models/new_models/floor.dart'; | ||||
| import 'package:test_sa/models/new_models/room_model.dart'; | ||||
| import 'package:test_sa/models/new_models/site.dart'; | ||||
| import 'package:test_sa/models/service_request/supplier_details.dart'; | ||||
| import '../../../models/new_models/department.dart'; | ||||
| 
 | ||||
| class AssetInventoryResponse { | ||||
|   num? totalRows; | ||||
|   num? count; | ||||
|   String? message; | ||||
|   String? title; | ||||
|   String? innerMessage; | ||||
|   num? responseCode; | ||||
|   bool? isSuccess; | ||||
|   List<AssetInventoryModel>? assetList; | ||||
| 
 | ||||
|   AssetInventoryResponse({ | ||||
|     this.totalRows, | ||||
|     this.count, | ||||
|     this.message, | ||||
|     this.title, | ||||
|     this.innerMessage, | ||||
|     this.responseCode, | ||||
|     this.isSuccess, | ||||
|     this.assetList, | ||||
|   }); | ||||
| 
 | ||||
|   AssetInventoryResponse.fromJson(Map<String, dynamic> json) { | ||||
|     totalRows = json['totalRows']; | ||||
|     count = json['count']; | ||||
|     message = json['message']; | ||||
|     title = json['title']; | ||||
|     innerMessage = json['innerMessage']; | ||||
|     responseCode = json['responseCode']; | ||||
|     isSuccess = json['isSuccess']; | ||||
|     if (json['data'] != null) { | ||||
|       assetList = (json['data'] as List).map((item) => AssetInventoryModel.fromJson(item)).toList(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   Map<String, dynamic> toJson() { | ||||
|     return { | ||||
|       'totalRows': totalRows, | ||||
|       'count': count, | ||||
|       'message': message, | ||||
|       'title': title, | ||||
|       'innerMessage': innerMessage, | ||||
|       'responseCode': responseCode, | ||||
|       'isSuccess': isSuccess, | ||||
|     }; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class AssetInventoryModel { | ||||
|   num? id; | ||||
|   num? assetId; | ||||
|   String? assetNumber; | ||||
|   String? serialNo; | ||||
|   String? assetName; | ||||
|   num? assetNameId; | ||||
|   String? model; | ||||
|   String? manufacturer; | ||||
|   String? supplierName; | ||||
|   String? siteName; | ||||
|   String? buildingName; | ||||
|   String? floorName; | ||||
|   String? departmentName; | ||||
|   String? roomName; | ||||
|   num? statusId; | ||||
|   String? status; | ||||
|   num? statusValue; | ||||
|   num? statusByAdminId; | ||||
|   String? statusByAdmin; | ||||
|   num? statusByAdminValue; | ||||
|   bool? isNotRegistered; | ||||
|   num? sessionId; | ||||
|   num? assetImportId; | ||||
|   num? siteId; | ||||
|   num? supplierId; | ||||
|   num? buildingId; | ||||
|   num? floorId; | ||||
|   num? departmentId; | ||||
|   num? roomId; | ||||
|   String? newAssetNumber; | ||||
|   String? newSerialNo; | ||||
|   num? newAssetNameId; | ||||
|   String? newAssetNameText; | ||||
|   num? newModelId; | ||||
|   String? newModelName; | ||||
|   num? manufacturerId; | ||||
|   num? modelId; | ||||
|   num? newManufacturerId; | ||||
|   String? newManufacturerName; | ||||
|   num? newSupplierId; | ||||
|   String? newSupplierName; | ||||
|   String? photo; | ||||
|   String? photoOriginName; | ||||
|   String? remarks; | ||||
| 
 | ||||
|   Site? site; | ||||
|   Building? building; | ||||
|   Floor? floor; | ||||
|   Department? department; | ||||
|   Rooms? room; | ||||
|   SupplierDetails? supplier; | ||||
| 
 | ||||
|   AssetInventoryModel({ | ||||
|     this.id, | ||||
|     this.sessionId, | ||||
|     this.assetId, | ||||
|     this.assetNumber, | ||||
|     this.assetNameId, | ||||
|     this.serialNo, | ||||
|     this.assetName, | ||||
|     this.model, | ||||
|     this.manufacturer, | ||||
|     this.supplierName, | ||||
|     this.siteName, | ||||
|     this.buildingName, | ||||
|     this.floorName, | ||||
|     this.departmentName, | ||||
|     this.roomName, | ||||
|     this.statusId, | ||||
|     this.status, | ||||
|     this.statusValue, | ||||
|     this.statusByAdminId, | ||||
|     this.statusByAdmin, | ||||
|     this.statusByAdminValue, | ||||
|     this.isNotRegistered, | ||||
|     this.assetImportId, | ||||
|     this.siteId, | ||||
|     this.buildingId, | ||||
|     this.floorId, | ||||
|     this.departmentId, | ||||
|     this.supplierId, | ||||
|     this.roomId, | ||||
|     this.newAssetNumber, | ||||
|     this.manufacturerId, | ||||
|     this.newSerialNo, | ||||
|     this.newAssetNameId, | ||||
|     this.newAssetNameText, | ||||
|     this.newModelId, | ||||
|     this.modelId, | ||||
|     this.newModelName, | ||||
|     this.newManufacturerId, | ||||
|     this.newManufacturerName, | ||||
|     this.newSupplierId, | ||||
|     this.newSupplierName, | ||||
|     this.photo, | ||||
|     this.photoOriginName, | ||||
|     this.remarks, | ||||
|     this.site, | ||||
|     this.department, | ||||
|     this.building, | ||||
|     this.floor, | ||||
|     this.room, | ||||
|     this.supplier, | ||||
|   }); | ||||
| 
 | ||||
|   AssetInventoryModel.fromJson(Map<String, dynamic> json) { | ||||
|     id = json['id']; | ||||
|     assetId = json['assetId']; | ||||
|     assetNumber = json['assetNumber']; | ||||
|     assetNameId = json['assetNameId']; | ||||
|     serialNo = json['serialNo']; | ||||
|     assetName = json['assetName']; | ||||
|     model = json['model'] ?? json['modelName']; | ||||
|     manufacturer = json['manufacturer'] ?? json['manufacturerName']; | ||||
|     supplierName = json['supplierName']; | ||||
|     siteName = json['site'] ?? json['siteName']; | ||||
|     buildingName = json['building'] ?? json['buildingName']; | ||||
|     floorName = json['floor'] ?? json['floorName']; | ||||
|     departmentName = json['department'] ?? json['departmentName']; | ||||
|     roomName = json['room'] ?? json['roomName']; | ||||
|     statusId = json['statusId']; | ||||
|     status = json['status'] ?? json['classification']; | ||||
|     statusValue = json['statusValue']; | ||||
|     isNotRegistered = json['isNotRegistered']; | ||||
|     sessionId = json['sessionId']; | ||||
|     assetImportId = json['assetImportId']??json['id']; | ||||
|     siteId = json['siteId']; | ||||
|     buildingId = json['buildingId']; | ||||
|     floorId = json['floorId']; | ||||
|     supplierId = json['supplierId']; | ||||
|     departmentId = json['departmentId']; | ||||
|     roomId = json['roomId']; | ||||
|     modelId = json['modelId']; | ||||
|     photo = json['photo']; | ||||
|     photoOriginName = json['photoOriginName']; | ||||
|     remarks = json['remarks']; | ||||
|     //new data.. | ||||
|     // newAssetNumber = json['newAssetNumber'] ?? json['assetNumber']; | ||||
|     // manufacturerId = json['manufacturerId'] ?? json['manufacturerId']; | ||||
|     // newSerialNo = json['newSerialNo'] ?? json['serialNo']; | ||||
|     // newAssetNameId = json['newAssetNameId'] ?? json['assetNameId']; | ||||
|     // newAssetNameText = json['newAssetNameText'] ?? json['assetNameText']; | ||||
|     // newModelId = json['newModelId'] ?? json['modelId']; | ||||
|     // newModelName = json['newModelName'] ?? json['modelName']; | ||||
|     // newManufacturerId = json['newManufacturerId'] ?? json['manufacturerId']; | ||||
|     // newManufacturerName = json['newManufacturerName'] ?? json['manufacturerName']; | ||||
|     // newSupplierId = json['newSupplierId'] ?? json['supplierId']; | ||||
|     // newSupplierName = json['newSupplierName'] ?? json['supplierName']; | ||||
|   } | ||||
| 
 | ||||
|   Map<String, dynamic> toJson() { | ||||
|     return { | ||||
|       'isNotRegistered': isNotRegistered, | ||||
|       'sessionId': sessionId, | ||||
|       'assetImportId': assetImportId, | ||||
|       'assetId': assetId, | ||||
|       'siteId': siteId, | ||||
|       'buildingId': buildingId, | ||||
|       'floorId': floorId, | ||||
|       'departmentId': departmentId, | ||||
|       'roomId': roomId, | ||||
|       'newSerialNo': newSerialNo, | ||||
|       'newAssetNameId': newAssetNameId, | ||||
|       'newAssetNameText': newAssetNameText, | ||||
|       'newAssetNumber': newAssetNumber, | ||||
|       'newModelId': newModelId, | ||||
|       'newModelName': newModelName, | ||||
|       'newManufacturerId': newManufacturerId, | ||||
|       'newManufacturerName': newManufacturerName, | ||||
|       'newSupplierId': newSupplierId, | ||||
|       'newSupplierName': newSupplierName, | ||||
|       'photo': photo, | ||||
|       'remarks': remarks, | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   AssetInventoryModel mergeWith(AssetInventoryModel? other) { | ||||
|     if (other == null) return this; | ||||
| 
 | ||||
|     return AssetInventoryModel( | ||||
|       id: id ?? other.id, | ||||
|       assetId: assetId ?? other.assetId, | ||||
|       assetNumber: assetNumber ?? other.assetNumber, | ||||
|       serialNo: serialNo ?? other.serialNo, | ||||
|       assetName: assetName ?? other.assetName, | ||||
|       assetNameId: assetNameId ?? other.assetNameId, | ||||
|       model: model ?? other.model, | ||||
|       manufacturer: manufacturer ?? other.manufacturer, | ||||
|       supplierName: supplierName ?? other.supplierName, | ||||
|       siteName: siteName ?? other.siteName, | ||||
|       buildingName: buildingName ?? other.buildingName, | ||||
|       floorName: floorName ?? other.floorName, | ||||
|       departmentName: departmentName ?? other.departmentName, | ||||
|       roomName: roomName ?? other.roomName, | ||||
|       statusId: statusId ?? other.statusId, | ||||
|       status: status ?? other.status, | ||||
|       statusValue: statusValue ?? other.statusValue, | ||||
|       statusByAdminId: statusByAdminId ?? other.statusByAdminId, | ||||
|       statusByAdmin: statusByAdmin ?? other.statusByAdmin, | ||||
|       statusByAdminValue: statusByAdminValue ?? other.statusByAdminValue, | ||||
|       isNotRegistered: isNotRegistered ?? other.isNotRegistered, | ||||
|       sessionId: sessionId ?? other.sessionId, | ||||
|       assetImportId: assetImportId ?? other.assetImportId, | ||||
|       siteId: siteId ?? other.siteId, | ||||
|       supplierId: supplierId ?? other.supplierId, | ||||
|       buildingId: buildingId ?? other.buildingId, | ||||
|       floorId: floorId ?? other.floorId, | ||||
|       departmentId: departmentId ?? other.departmentId, | ||||
|       roomId: roomId ?? other.roomId, | ||||
|       newAssetNumber: newAssetNumber ?? other.newAssetNumber, | ||||
|       newSerialNo: newSerialNo ?? other.newSerialNo, | ||||
|       newAssetNameId: newAssetNameId ?? other.newAssetNameId, | ||||
|       newAssetNameText: newAssetNameText ?? other.newAssetNameText, | ||||
|       newModelId: newModelId ?? other.newModelId, | ||||
|       newModelName: newModelName ?? other.newModelName, | ||||
|       manufacturerId: manufacturerId ?? other.manufacturerId, | ||||
|       modelId: modelId ?? other.modelId, | ||||
|       newManufacturerId: newManufacturerId ?? other.newManufacturerId, | ||||
|       newManufacturerName: newManufacturerName ?? other.newManufacturerName, | ||||
|       newSupplierId: newSupplierId ?? other.newSupplierId, | ||||
|       newSupplierName: newSupplierName ?? other.newSupplierName, | ||||
|       photo: photo ?? other.photo, | ||||
|       photoOriginName: photoOriginName ?? other.photoOriginName, | ||||
|       remarks: remarks ?? other.remarks, | ||||
|       site: site ?? other.site, | ||||
|       building: building ?? other.building, | ||||
|       floor: floor ?? other.floor, | ||||
|       department: department ?? other.department, | ||||
|       room: room ?? other.room, | ||||
|       supplier: supplier ?? other.supplier, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,231 @@ | ||||
| 
 | ||||
| import 'package:test_sa/models/new_models/site.dart'; | ||||
| 
 | ||||
| class SessionModel { | ||||
|   int? id; | ||||
|   String? sessionName; | ||||
|   int? sessionTypeId; | ||||
|   int? sessionTypeValue; | ||||
|   String? sessionTypeName; | ||||
|   int? statusId; | ||||
|   String? statusName; | ||||
|   String? startDate; | ||||
|   String? endDate; | ||||
|   List<Site> assetInventorySites = []; | ||||
|   List<AssetInventoryAssignedEmployee> assetInventoryAssignedEmployee = []; | ||||
| 
 | ||||
|   SessionModel({ | ||||
|     this.id, | ||||
|     this.sessionName, | ||||
|     this.sessionTypeId, | ||||
|     this.sessionTypeValue, | ||||
|     this.sessionTypeName, | ||||
|     this.statusId, | ||||
|     this.statusName, | ||||
|     this.startDate, | ||||
|     this.endDate, | ||||
|     List<Site>? assetInventorySites, | ||||
|     List<AssetInventoryAssignedEmployee>? assetInventoryAssignedEmployee, | ||||
|   }) { | ||||
|     this.assetInventorySites = assetInventorySites ?? []; | ||||
|     this.assetInventoryAssignedEmployee = assetInventoryAssignedEmployee ?? []; | ||||
|   } | ||||
| 
 | ||||
|   SessionModel.fromJson(Map<String, dynamic> json) { | ||||
|     id = json['id']; | ||||
|     sessionName = json['sessionName']; | ||||
|     sessionTypeId = json['sessionTypeId']; | ||||
|     sessionTypeValue = json['sessionTypeValue']; | ||||
|     sessionTypeName = json['sessionTypeName']; | ||||
|     statusId = json['statusId']; | ||||
|     statusName = json['statusName']; | ||||
|     startDate = json['startDate']; | ||||
|     endDate = json['endDate']; | ||||
| 
 | ||||
|     if (json['assetInventorySites'] != null) { | ||||
|       assetInventorySites = (json['assetInventorySites'] as List).map((e) => Site.fromJson(e)).toList(); | ||||
|     } | ||||
| 
 | ||||
|     if (json['assetInventoryAssignedEmployee'] != null) { | ||||
|       assetInventoryAssignedEmployee = (json['assetInventoryAssignedEmployee'] as List).map((e) => AssetInventoryAssignedEmployee.fromJson(e)).toList(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   Map<String, dynamic> toJson() { | ||||
|     final map = <String, dynamic>{}; | ||||
|     map['id'] = id; | ||||
|     map['sessionName'] = sessionName; | ||||
|     map['sessionTypeId'] = sessionTypeId; | ||||
|     map['sessionTypeValue'] = sessionTypeValue; | ||||
|     map['sessionTypeName'] = sessionTypeName; | ||||
|     map['statusId'] = statusId; | ||||
|     map['statusName'] = statusName; | ||||
|     map['startDate'] = startDate; | ||||
|     map['endDate'] = endDate; | ||||
|     map['assetInventorySites'] = assetInventorySites.map((e) => e.toJson()).toList(); | ||||
|     map['assetInventoryAssignedEmployee'] = assetInventoryAssignedEmployee.map((e) => e.toJson()).toList(); | ||||
|     return map; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // class AssetInventorySite { | ||||
| //   int? siteId; | ||||
| //   String? siteName; | ||||
| //   List<AssetInventoryBuilding> assetInventoryBuildings = []; | ||||
| // | ||||
| //   AssetInventorySite({ | ||||
| //     this.siteId, | ||||
| //     this.siteName, | ||||
| //     List<AssetInventoryBuilding>? assetInventoryBuildings, | ||||
| //   }) { | ||||
| //     this.assetInventoryBuildings = assetInventoryBuildings ?? []; | ||||
| //   } | ||||
| // | ||||
| //   AssetInventorySite.fromJson(Map<String, dynamic> json) { | ||||
| //     siteId = json['siteId']; | ||||
| //     siteName = json['siteName']; | ||||
| // | ||||
| //     if (json['assetInventoryBuildings'] != null) { | ||||
| //       assetInventoryBuildings = (json['assetInventoryBuildings'] as List).map((e) => AssetInventoryBuilding.fromJson(e)).toList(); | ||||
| //     } | ||||
| //   } | ||||
| // | ||||
| //   Map<String, dynamic> toJson() { | ||||
| //     final map = <String, dynamic>{}; | ||||
| //     map['siteId'] = siteId; | ||||
| //     map['siteName'] = siteName; | ||||
| //     map['assetInventoryBuildings'] = assetInventoryBuildings.map((e) => e.toJson()).toList(); | ||||
| //     return map; | ||||
| //   } | ||||
| // } | ||||
| // | ||||
| // class AssetInventoryBuilding { | ||||
| //   int? buildingId; | ||||
| //   String? buildingName; | ||||
| //   List<AssetInventoryFloor> assetInventoryFloors = []; | ||||
| // | ||||
| //   AssetInventoryBuilding({ | ||||
| //     this.buildingId, | ||||
| //     this.buildingName, | ||||
| //     List<AssetInventoryFloor>? assetInventoryFloors, | ||||
| //   }) { | ||||
| //     this.assetInventoryFloors = assetInventoryFloors ?? []; | ||||
| //   } | ||||
| // | ||||
| //   AssetInventoryBuilding.fromJson(Map<String, dynamic> json) { | ||||
| //     buildingId = json['buildingId']; | ||||
| //     buildingName = json['buildingName']; | ||||
| // | ||||
| //     if (json['assetInventoryFloors'] != null) { | ||||
| //       assetInventoryFloors = (json['assetInventoryFloors'] as List).map((e) => AssetInventoryFloor.fromJson(e)).toList(); | ||||
| //     } | ||||
| //   } | ||||
| // | ||||
| //   Map<String, dynamic> toJson() { | ||||
| //     final map = <String, dynamic>{}; | ||||
| //     map['buildingId'] = buildingId; | ||||
| //     map['buildingName'] = buildingName; | ||||
| //     map['assetInventoryFloors'] = assetInventoryFloors.map((e) => e.toJson()).toList(); | ||||
| //     return map; | ||||
| //   } | ||||
| // } | ||||
| // | ||||
| // class AssetInventoryFloor { | ||||
| //   int? floorId; | ||||
| //   String? floorName; | ||||
| //   List<AssetInventoryDepartment> assetInventoryDepartments = []; | ||||
| // | ||||
| //   AssetInventoryFloor({ | ||||
| //     this.floorId, | ||||
| //     this.floorName, | ||||
| //     List<AssetInventoryDepartment>? assetInventoryDepartments, | ||||
| //   }) { | ||||
| //     this.assetInventoryDepartments = assetInventoryDepartments ?? []; | ||||
| //   } | ||||
| // | ||||
| //   AssetInventoryFloor.fromJson(Map<String, dynamic> json) { | ||||
| //     floorId = json['floorId']; | ||||
| //     floorName = json['floorName']; | ||||
| // | ||||
| //     if (json['assetInventoryDepartments'] != null) { | ||||
| //       assetInventoryDepartments = (json['assetInventoryDepartments'] as List).map((e) => AssetInventoryDepartment.fromJson(e)).toList(); | ||||
| //     } | ||||
| //   } | ||||
| // | ||||
| //   Map<String, dynamic> toJson() { | ||||
| //     final map = <String, dynamic>{}; | ||||
| //     map['floorId'] = floorId; | ||||
| //     map['floorName'] = floorName; | ||||
| //     map['assetInventoryDepartments'] = assetInventoryDepartments.map((e) => e.toJson()).toList(); | ||||
| //     return map; | ||||
| //   } | ||||
| // } | ||||
| // | ||||
| // class AssetInventoryDepartment { | ||||
| //   int? departmentId; | ||||
| //   String? departmentName; | ||||
| //   List<AssetInventoryRoom> assetInventoryRooms = []; | ||||
| // | ||||
| //   AssetInventoryDepartment({ | ||||
| //     this.departmentId, | ||||
| //     this.departmentName, | ||||
| //     List<AssetInventoryRoom>? assetInventoryRooms, | ||||
| //   }) { | ||||
| //     this.assetInventoryRooms = assetInventoryRooms ?? []; | ||||
| //   } | ||||
| // | ||||
| //   AssetInventoryDepartment.fromJson(Map<String, dynamic> json) { | ||||
| //     departmentId = json['departmentId']; | ||||
| //     departmentName = json['departmentName']; | ||||
| // | ||||
| //     if (json['assetInventoryRooms'] != null) { | ||||
| //       assetInventoryRooms = (json['assetInventoryRooms'] as List).map((e) => AssetInventoryRoom.fromJson(e)).toList(); | ||||
| //     } | ||||
| //   } | ||||
| // | ||||
| //   Map<String, dynamic> toJson() { | ||||
| //     final map = <String, dynamic>{}; | ||||
| //     map['departmentId'] = departmentId; | ||||
| //     map['departmentName'] = departmentName; | ||||
| //     map['assetInventoryRooms'] = assetInventoryRooms.map((e) => e.toJson()).toList(); | ||||
| //     return map; | ||||
| //   } | ||||
| // } | ||||
| // | ||||
| // class AssetInventoryRoom { | ||||
| //   int? roomId; | ||||
| //   String? roomName; | ||||
| // | ||||
| //   AssetInventoryRoom({this.roomId, this.roomName}); | ||||
| // | ||||
| //   AssetInventoryRoom.fromJson(Map<String, dynamic> json) { | ||||
| //     roomId = json['roomId']; | ||||
| //     roomName = json['roomName']; | ||||
| //   } | ||||
| // | ||||
| //   Map<String, dynamic> toJson() { | ||||
| //     final map = <String, dynamic>{}; | ||||
| //     map['roomId'] = roomId; | ||||
| //     map['roomName'] = roomName; | ||||
| //     return map; | ||||
| //   } | ||||
| // } | ||||
| 
 | ||||
| class AssetInventoryAssignedEmployee { | ||||
|   String? assignedEngineerId; | ||||
|   String? assignedEngineerName; | ||||
| 
 | ||||
|   AssetInventoryAssignedEmployee({this.assignedEngineerId, this.assignedEngineerName}); | ||||
| 
 | ||||
|   AssetInventoryAssignedEmployee.fromJson(Map<String, dynamic> json) { | ||||
|     assignedEngineerId = json['assignedEngineerId']; | ||||
|     assignedEngineerName = json['assignedEngineerName']; | ||||
|   } | ||||
| 
 | ||||
|   Map<String, dynamic> toJson() { | ||||
|     final map = <String, dynamic>{}; | ||||
|     map['assignedEngineerId'] = assignedEngineerId; | ||||
|     map['assignedEngineerName'] = assignedEngineerName; | ||||
|     return map; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,109 @@ | ||||
| import 'dart:developer'; | ||||
| 
 | ||||
| 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/modules/asset_inventory_module/models/asset_inventory_model.dart'; | ||||
| import 'package:test_sa/new_views/app_style/app_color.dart'; | ||||
| import 'package:test_sa/views/widgets/loaders/image_loader.dart'; | ||||
| 
 | ||||
| class AssetDetailCardView extends StatelessWidget { | ||||
|   AssetInventoryModel assetInventoryModel; | ||||
|   VoidCallback onDeletePress; | ||||
| 
 | ||||
|   AssetDetailCardView({ | ||||
|     super.key, | ||||
|     required this.assetInventoryModel, | ||||
|     required this.onDeletePress, | ||||
|   }); | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Column( | ||||
|       children: [ | ||||
|         Row( | ||||
|           children: [ | ||||
|             Text( | ||||
|               context.translation.assetInformation, | ||||
|               style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), | ||||
|             ).expanded, | ||||
|             'delete_icon'.toSvgAsset().onPress(() { | ||||
|               onDeletePress(); | ||||
|             }), | ||||
|           ], | ||||
|         ), | ||||
|         8.height, | ||||
|         Row( | ||||
|           crossAxisAlignment: CrossAxisAlignment.start, | ||||
|           children: [ | ||||
|             Column( | ||||
|               crossAxisAlignment: CrossAxisAlignment.start, | ||||
|               children: [ | ||||
|                 Text( | ||||
|                   '${context.translation.assetNumber}:  ${assetInventoryModel.assetNumber ?? '-'}', | ||||
|                   style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), | ||||
|                 ), | ||||
|                 Text( | ||||
|                   '${context.translation.serialNo}:  ${assetInventoryModel.serialNo ?? '-'}', | ||||
|                   style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), | ||||
|                 ), | ||||
|                 Text( | ||||
|                   '${context.translation.manufacture}:  ${assetInventoryModel.manufacturer ?? ''}', | ||||
|                   style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), | ||||
|                 ), | ||||
|                 Text( | ||||
|                   '${context.translation.model}:  ${assetInventoryModel.model ?? ''}', | ||||
|                   style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), | ||||
|                 ), | ||||
|                 Text( | ||||
|                   '${context.translation.site}:  ${assetInventoryModel.siteName ?? ''}', | ||||
|                   style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), | ||||
|                 ), | ||||
|                 Text( | ||||
|                   '${context.translation.building}:  ${assetInventoryModel.buildingName ?? ''}', | ||||
|                   style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), | ||||
|                 ), | ||||
|                 Text( | ||||
|                   '${context.translation.floor}:  ${assetInventoryModel.floorName ?? ''}', | ||||
|                   style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), | ||||
|                 ), | ||||
|                 Text( | ||||
|                   '${context.translation.department}:  ${assetInventoryModel.departmentName ?? ''}', | ||||
|                   style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), | ||||
|                 ), | ||||
|                 Text( | ||||
|                   '${context.translation.supplier}:  ${assetInventoryModel.supplierName ?? ''}', | ||||
|                   style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), | ||||
|                 ), | ||||
|                 Text( | ||||
|                   '${'Remarks'.addTranslation}:  ${assetInventoryModel.remarks ?? ''}', | ||||
|                   style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), | ||||
|                 ), | ||||
|               ], | ||||
|             ).expanded, | ||||
|             Container( | ||||
|               decoration: BoxDecoration(color: AppColor.neutral100, borderRadius: BorderRadius.circular(15)), | ||||
|               height: 115.toScreenHeight, | ||||
|               width: 115.toScreenWidth, | ||||
|               margin: const EdgeInsets.only(top: 8), | ||||
|               child: assetInventoryModel.photo != null && assetInventoryModel.photo!.isNotEmpty | ||||
|                   ? ClipRRect( | ||||
|                       borderRadius: BorderRadius.circular(8), | ||||
|                       child: ImageLoader( | ||||
|                         url: URLs.getFileUrl(assetInventoryModel.photo), | ||||
|                         boxFit: BoxFit.cover, | ||||
|                         height: 48, | ||||
|                         width: 48, | ||||
|                       )) | ||||
|                   : 'image_placeholder'.toSvgAsset().center, | ||||
|             ) | ||||
|           ], | ||||
|         ), | ||||
|       ], | ||||
|     ).toShadowContainer(context, borderRadius: 20, padding: 12); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,163 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:test_sa/extensions/context_extension.dart'; | ||||
| import 'package:test_sa/extensions/int_extensions.dart'; | ||||
| import 'package:test_sa/extensions/string_extensions.dart'; | ||||
| import 'package:test_sa/extensions/text_extensions.dart'; | ||||
| import 'package:test_sa/extensions/widget_extensions.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; | ||||
| import 'package:test_sa/new_views/app_style/app_color.dart'; | ||||
| import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; | ||||
| import 'package:test_sa/views/widgets/requests/request_status.dart'; | ||||
| 
 | ||||
| class AssetInventoryDetailView extends StatefulWidget { | ||||
|   SessionModel sessionModel; | ||||
| 
 | ||||
|   AssetInventoryDetailView({Key? key, required this.sessionModel}) : super(key: key); | ||||
| 
 | ||||
|   @override | ||||
|   State<AssetInventoryDetailView> createState() => _AssetInventoryDetailViewState(); | ||||
| } | ||||
| 
 | ||||
| class _AssetInventoryDetailViewState extends State<AssetInventoryDetailView> { | ||||
|   @override | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return widget.sessionModel.id == null | ||||
|         ? const NoDataFound() | ||||
|         : ListView( | ||||
|             padding: const EdgeInsets.all(16), | ||||
|             children: [ | ||||
|               requestDetailCard(context, widget.sessionModel), | ||||
|               12.height, | ||||
|               siteListCard(context, widget.sessionModel), | ||||
|             ], | ||||
|           ); | ||||
|   } | ||||
| 
 | ||||
|   TextStyle infoTextStyle(context) => AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120); | ||||
| 
 | ||||
|   Widget requestDetailCard(BuildContext context, SessionModel sessionModel) { | ||||
|     return Column( | ||||
|       crossAxisAlignment: CrossAxisAlignment.start, | ||||
|       children: [ | ||||
|         Row( | ||||
|           crossAxisAlignment: CrossAxisAlignment.start, | ||||
|           mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|           children: [ | ||||
|             StatusLabel( | ||||
|               label: sessionModel.statusName, | ||||
|               id: sessionModel.statusId, | ||||
|               radius: 4, | ||||
|               textColor: AppColor.green15, | ||||
|               backgroundColor: AppColor.greenStatus(context), | ||||
|             ), | ||||
|             Text( | ||||
|               sessionModel.startDate!.toString().toServiceRequestCardFormat, | ||||
|               textAlign: TextAlign.end, | ||||
|               style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), | ||||
|             ) | ||||
|           ], | ||||
|         ), | ||||
|         8.height, | ||||
|         Text( | ||||
|           context.translation.requestDetails, | ||||
|           style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), | ||||
|         ), | ||||
|         8.height, | ||||
|         Text( | ||||
|           '${'Session Name'.addTranslation}: ${sessionModel.sessionName?.cleanupWhitespace.capitalizeFirstOfEach}', | ||||
|           style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), | ||||
|         ), | ||||
|         Text( | ||||
|           '${'Session Typ'.addTranslation}: ${sessionModel.sessionTypeName}', | ||||
|           style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), | ||||
|         ), | ||||
|         Text( | ||||
|           '${'Start Date'.addTranslation}: ${sessionModel.startDate?.toServiceRequestDetailsFormat ?? ""}', | ||||
|           style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), | ||||
|         ), | ||||
|         Text( | ||||
|           '${'End Date'.addTranslation}: ${sessionModel.endDate?.toServiceRequestDetailsFormat ?? ""}', | ||||
|           style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), | ||||
|         ), | ||||
|       ], | ||||
|     ).toShadowContainer(context, padding: 12, borderRadius: 20); | ||||
|   } | ||||
| 
 | ||||
|   Widget siteListCard(BuildContext context, SessionModel sessionModel) { | ||||
|     final sites = sessionModel.assetInventorySites ?? []; | ||||
| 
 | ||||
|     return Column( | ||||
|       mainAxisSize: MainAxisSize.min, | ||||
|       crossAxisAlignment: CrossAxisAlignment.start, | ||||
|       children: [ | ||||
|         Text( | ||||
|           "Sites Information", | ||||
|           style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), | ||||
|         ), | ||||
|         8.height, | ||||
|         ListView.separated( | ||||
|           physics: const NeverScrollableScrollPhysics(), | ||||
|           shrinkWrap: true, | ||||
|           padding: EdgeInsets.zero, | ||||
|           itemCount: sites.length, | ||||
|           itemBuilder: (cxt, siteIndex) { | ||||
|             final site = sites[siteIndex]; | ||||
|             final buildingNames = (site.buildings ?? []).map((b) => b.name).where((name) => name != null && name!.trim().isNotEmpty).join(', '); | ||||
|             final floorNames = (site.buildings ?? []).expand((b) => b.floors ?? []).map((f) => f.name).where((name) => name != null && name!.trim().isNotEmpty).join(', '); | ||||
|             final departmentNames = | ||||
|                 (site.buildings ?? []).expand((b) => b.floors ?? []).expand((f) => f.departments ?? []).map((d) => d.name).where((name) => name != null && name!.trim().isNotEmpty).join(', '); | ||||
|             final roomNames = (site.buildings ?? []) | ||||
|                 .expand((b) => b.floors ?? []) | ||||
|                 .expand((f) => f.departments ?? []) | ||||
|                 .expand((d) => d.rooms ?? []) | ||||
|                 .map((r) => r.name) | ||||
|                 .where((name) => name != null && name!.trim().isNotEmpty) | ||||
|                 .join(', '); | ||||
| 
 | ||||
|             return Column( | ||||
|               crossAxisAlignment: CrossAxisAlignment.start, | ||||
|               children: [ | ||||
|                 Text( | ||||
|                   site.name ?? '-', | ||||
|                   style: AppTextStyles.heading6.copyWith( | ||||
|                     color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, | ||||
|                   ), | ||||
|                 ), | ||||
|                 Text( | ||||
|                   '${context.translation.building}: ${buildingNames.isNotEmpty ? buildingNames : '-'}', | ||||
|                   style: AppTextStyles.bodyText.copyWith( | ||||
|                     color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, | ||||
|                   ), | ||||
|                 ), | ||||
|                 Text( | ||||
|                   '${context.translation.floor}: ${floorNames.isNotEmpty ? floorNames : '-'}', | ||||
|                   style: AppTextStyles.bodyText.copyWith( | ||||
|                     color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, | ||||
|                   ), | ||||
|                 ), | ||||
|                 Text( | ||||
|                   '${context.translation.department}: ${departmentNames.isNotEmpty ? departmentNames : '-'}', | ||||
|                   style: AppTextStyles.bodyText.copyWith( | ||||
|                     color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, | ||||
|                   ), | ||||
|                 ), | ||||
|                 Text( | ||||
|                   '${context.translation.room}: ${roomNames.isNotEmpty ? roomNames : '-'}', | ||||
|                   style: AppTextStyles.bodyText.copyWith( | ||||
|                     color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, | ||||
|                   ), | ||||
|                 ), | ||||
|               ], | ||||
|             ); | ||||
|           }, | ||||
|           separatorBuilder: (cxt, index) => const Divider().defaultStyle(context), | ||||
|         ), | ||||
|       ], | ||||
|     ).toShadowContainer(context, padding: 12, borderRadius: 20); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,466 @@ | ||||
| import 'dart:convert'; | ||||
| import 'dart:developer'; | ||||
| import 'dart:io'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_advanced_switch/flutter_advanced_switch.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:test_sa/common_widgets/lookup_autocomplete_field.dart'; | ||||
| import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; | ||||
| import 'package:test_sa/extensions/context_extension.dart'; | ||||
| import 'package:test_sa/extensions/int_extensions.dart'; | ||||
| import 'package:test_sa/extensions/string_extensions.dart'; | ||||
| import 'package:test_sa/extensions/text_extensions.dart'; | ||||
| import 'package:test_sa/extensions/widget_extensions.dart'; | ||||
| import 'package:test_sa/models/generic_attachment_model.dart'; | ||||
| import 'package:test_sa/models/service_request/supplier_details.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_page.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/pages/search_asset_view.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; | ||||
| import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; | ||||
| import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; | ||||
| import 'package:test_sa/new_views/app_style/app_color.dart'; | ||||
| import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; | ||||
| import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; | ||||
| import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; | ||||
| import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; | ||||
| import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; | ||||
| import 'package:test_sa/views/widgets/requests/request_status.dart'; | ||||
| import '../../../new_views/common_widgets/app_filled_button.dart'; | ||||
| import '../../../new_views/common_widgets/default_app_bar.dart'; | ||||
| import 'asset_inventory_site_information_page.dart'; | ||||
| 
 | ||||
| class AssetInventoryFormView extends StatefulWidget { | ||||
|   static const String id = "/asset-inventory-form"; | ||||
|   AssetInventoryModel? assetInventoryModel; | ||||
|   int? sessionTypeValue; | ||||
| 
 | ||||
|   AssetInventoryFormView({Key? key, this.assetInventoryModel, this.sessionTypeValue}) : super(key: key); | ||||
| 
 | ||||
|   @override | ||||
|   State<AssetInventoryFormView> createState() => _AssetInventoryFormViewState(); | ||||
| } | ||||
| 
 | ||||
| class _AssetInventoryFormViewState extends State<AssetInventoryFormView> { | ||||
|   AssetInventoryModel? _scannedAssetModel = AssetInventoryModel(); | ||||
|   AssetInventoryModel? _pickedAssetModel = AssetInventoryModel(); | ||||
|   final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); | ||||
|   final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); | ||||
|   final TextEditingController _assetNoController = TextEditingController(); | ||||
|   final TextEditingController _serialNoController = TextEditingController(); | ||||
|   final TextEditingController _remarksController = TextEditingController(); | ||||
|   ValueNotifier<bool>? registeredController; | ||||
|   bool isRegistered = false; | ||||
| 
 | ||||
|   final List<GenericAttachmentModel> attachments = []; | ||||
| 
 | ||||
|   @override | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   void dispose() { | ||||
|     super.dispose(); | ||||
|     resetData(); | ||||
|   } | ||||
| 
 | ||||
|   void populateFormValues() { | ||||
|     _serialNoController.text = _scannedAssetModel!.serialNo ?? ''; | ||||
|     _assetNoController.text = _scannedAssetModel!.assetNumber ?? ''; | ||||
|     // _scannedAssetModel?.supplier = SupplierDetails( | ||||
|     //   suppliername: _scannedAssetModel?.supplierName, | ||||
|     //   id: _scannedAssetModel?.supplierId, | ||||
|     // ); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Scaffold( | ||||
|       key: _scaffoldKey, | ||||
|       appBar: DefaultAppBar( | ||||
|         title: context.translation.addAsset, | ||||
|         titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), | ||||
|       ), | ||||
|       body: Form( | ||||
|         key: _formKey, | ||||
|         child: Column( | ||||
|           children: [ | ||||
|             SingleChildScrollView( | ||||
|                     padding: const EdgeInsets.all(16), | ||||
|                     child: Column( | ||||
|                       crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                       children: [ | ||||
|                         if (widget.sessionTypeValue == 1 || widget.sessionTypeValue == 2) ...[ | ||||
|                           Row( | ||||
|                             mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|                             children: [ | ||||
|                               'Not Registered'.addTranslation.heading5(context), | ||||
|                               AdvancedSwitch( | ||||
|                                 controller: registeredController, | ||||
|                                 activeColor: AppColor.green50.withOpacity(0.5), | ||||
|                                 inactiveColor: AppColor.neutral10, | ||||
|                                 thumb: CircleAvatar(backgroundColor: isRegistered == true ? AppColor.green50 : AppColor.neutral20), | ||||
|                                 borderRadius: const BorderRadius.all(Radius.circular(30)), | ||||
|                                 width: 42.toScreenWidth, | ||||
|                                 height: 24.toScreenHeight, | ||||
|                                 onChanged: (value) { | ||||
|                                   isRegistered = value; | ||||
|                                   resetData(); | ||||
|                                   setState(() {}); | ||||
|                                 }, | ||||
|                                 disabledOpacity: 1, | ||||
|                               ), | ||||
|                             ], | ||||
|                           ), | ||||
|                           12.height, | ||||
|                         ], | ||||
| 
 | ||||
|                         if ((!isRegistered && widget.sessionTypeValue == 1) || (widget.sessionTypeValue == 3) || (!isRegistered && widget.sessionTypeValue == 2)) ...[ | ||||
|                           AssetPicker( | ||||
|                               showLoading: false, | ||||
|                               labelColor: AppColor.white936, | ||||
|                               iconColor: AppColor.neutral120, | ||||
|                               label: 'Scan Asset'.addTranslation, | ||||
|                               borderColor: AppColor.white936, | ||||
|                               buttonColor: Colors.white, | ||||
|                               enablePickManually: false, | ||||
|                               showAssetInfo: false, | ||||
|                               showBorder: true, | ||||
|                               onPick: (asset) async { | ||||
|                                 resetData(); | ||||
|                                 setState(() {}); | ||||
|                                 if (asset.assetNumber != null) { | ||||
|                                   searchAsset(assetNo: asset.assetNumber!); | ||||
|                                 } | ||||
|                               }), | ||||
|                           12.height, | ||||
|                           AppTextFormField( | ||||
|                             labelText: context.translation.assetNo, | ||||
|                             backgroundColor: AppColor.fieldBgColor(context), | ||||
|                             textAlign: TextAlign.center, | ||||
|                             controller: _assetNoController, | ||||
|                             showShadow: false, | ||||
|                             enable: false, | ||||
|                             labelStyle: AppTextStyles.textFieldLabelStyle, | ||||
|                             style: Theme.of(context).textTheme.titleMedium, | ||||
|                           ), | ||||
|                           12.height, | ||||
|                         ], | ||||
| 
 | ||||
|                         if (((!isRegistered && widget.sessionTypeValue == 2))) ...[ | ||||
|                           AppFilledButton( | ||||
|                             label: 'Search Asset'.addTranslation, | ||||
|                             onPressed: () async { | ||||
|                               resetData(isScanned: false); | ||||
|                               setState(() {}); | ||||
|                               await Navigator.push( | ||||
|                                   context, | ||||
|                                   MaterialPageRoute( | ||||
|                                       builder: (context) => SearchAssetView( | ||||
|                                             sessionId: widget.assetInventoryModel?.sessionId ?? 0, | ||||
|                                           ))).then((value) { | ||||
|                                 if (value != null) { | ||||
|                                   _pickedAssetModel = value; | ||||
|                                   _scannedAssetModel = _scannedAssetModel?.mergeWith(_pickedAssetModel) ?? _pickedAssetModel; | ||||
| 
 | ||||
|                                   populateFormValues(); | ||||
|                                   setState(() {}); | ||||
|                                 } | ||||
| 
 | ||||
|                                 ///Need to assign the values | ||||
|                               }); | ||||
|                             }, | ||||
|                           ), | ||||
|                           12.height, | ||||
|                         ], | ||||
|                         if (((isRegistered && widget.sessionTypeValue != 3))) ...[ | ||||
|                           AppTextFormField( | ||||
|                             labelText: context.translation.assetNo, | ||||
|                             backgroundColor: AppColor.fieldBgColor(context), | ||||
|                             textAlign: TextAlign.center, | ||||
|                             showShadow: false, | ||||
|                             enable: true, | ||||
|                             labelStyle: AppTextStyles.textFieldLabelStyle, | ||||
|                             style: Theme.of(context).textTheme.titleMedium, | ||||
|                             onChange: (value) { | ||||
|                               _scannedAssetModel?.newAssetNumber = value; | ||||
|                             }, | ||||
|                           ), | ||||
|                           12.height, | ||||
|                         ], | ||||
|                         AppTextFormField( | ||||
|                           labelText: context.translation.serialNo, | ||||
|                           backgroundColor: AppColor.fieldBgColor(context), | ||||
|                           controller: _serialNoController, | ||||
|                           textAlign: TextAlign.center, | ||||
|                           showShadow: false, | ||||
|                           labelStyle: AppTextStyles.textFieldLabelStyle, | ||||
|                           onChange: (value) { | ||||
|                             if (value != _scannedAssetModel?.serialNo) { | ||||
|                               _scannedAssetModel?.newSerialNo = value; | ||||
|                               // setState(() {}); | ||||
|                             } | ||||
|                           }, | ||||
|                           style: Theme.of(context).textTheme.titleMedium, | ||||
|                         ), | ||||
|                         12.height, | ||||
|                         LookUpAutoCompleteField( | ||||
|                           clearAfterPick: false, | ||||
|                           forAssetName: true, | ||||
|                           onChanged: (value) { | ||||
|                             _scannedAssetModel?.newAssetNameId = null; | ||||
|                             _scannedAssetModel?.newAssetNameText = value; | ||||
|                           }, | ||||
|                           initialValue: _scannedAssetModel?.assetName ?? "", | ||||
|                           label: 'Asset Name'.addTranslation, | ||||
|                           onPick: (value) { | ||||
|                             _scannedAssetModel?.newAssetNameText = null; | ||||
|                             _scannedAssetModel?.assetName = value.name; | ||||
|                             _scannedAssetModel?.newAssetNameId = value.id; | ||||
|                             setState(() {}); | ||||
|                           }, | ||||
|                         ), | ||||
|                         12.height, | ||||
|                         //Asset Name.. | ||||
|                         LookUpAutoCompleteField( | ||||
|                           clearAfterPick: false, | ||||
|                           isManufacturer: true, | ||||
|                           initialValue: _scannedAssetModel?.manufacturer ?? "", | ||||
|                           label: 'Manufacturer'.addTranslation, | ||||
|                           onChanged: (value) { | ||||
|                             _scannedAssetModel?.newManufacturerId = null; | ||||
|                             _scannedAssetModel?.newManufacturerName = value; | ||||
|                           }, | ||||
|                           onPick: (value) { | ||||
|                             _scannedAssetModel?.newManufacturerName = null; | ||||
|                             _scannedAssetModel?.manufacturer = value.name; | ||||
|                             _scannedAssetModel?.newManufacturerId = value.id; | ||||
| 
 | ||||
|                             setState(() {}); | ||||
|                           }, | ||||
|                         ), | ||||
|                         12.height, | ||||
|                         LookUpAutoCompleteField( | ||||
|                           clearAfterPick: false, | ||||
|                           isManufacturer: false, | ||||
|                           initialValue: _scannedAssetModel?.model ?? "", | ||||
|                           label: 'Model'.addTranslation, | ||||
|                           onChanged: (value) { | ||||
|                             _scannedAssetModel?.newModelId = null; | ||||
|                             _scannedAssetModel?.newModelName = value; | ||||
|                           }, | ||||
|                           onPick: (value) { | ||||
|                             _scannedAssetModel?.newModelName = null; | ||||
|                             _scannedAssetModel?.model = value.name; | ||||
|                             _scannedAssetModel?.newModelId = value.id; | ||||
|                             setState(() {}); | ||||
|                           }, | ||||
|                         ), | ||||
| 
 | ||||
|                         12.height, | ||||
| 
 | ||||
|                         LookUpAutoCompleteField( | ||||
|                           clearAfterPick: false, | ||||
|                           forSupplier: true, | ||||
|                           initialValue: _scannedAssetModel?.supplierName ?? "", | ||||
|                           label: context.translation.supplier, | ||||
|                           onChanged: (value) { | ||||
|                             _scannedAssetModel?.newSupplierId = null; | ||||
|                             _scannedAssetModel?.newSupplierName = value; | ||||
|                           }, | ||||
|                           onPick: (value) { | ||||
|                             _scannedAssetModel?.newSupplierName = null; | ||||
|                             _scannedAssetModel?.supplierName = value.name; | ||||
|                             _scannedAssetModel?.newSupplierId = value.id; | ||||
|                             setState(() {}); | ||||
|                           }, | ||||
|                         ), | ||||
|                         if (!isRegistered) ...[ | ||||
|                           12.height, | ||||
|                           siteInfoContainer(label: context.translation.site, value: _scannedAssetModel?.siteName ?? '-'), | ||||
|                           12.height, | ||||
|                           siteInfoContainer(label: context.translation.building, value: _scannedAssetModel?.buildingName ?? '-'), | ||||
|                           12.height, | ||||
|                           siteInfoContainer(label: context.translation.floor, value: _scannedAssetModel?.floorName ?? '-'), | ||||
|                           12.height, | ||||
|                           siteInfoContainer(label: context.translation.department, value: _scannedAssetModel?.departmentName ?? '-'), | ||||
|                           12.height, | ||||
|                           siteInfoContainer(label: context.translation.room, value: _scannedAssetModel?.roomName ?? '-'), | ||||
|                           12.height, | ||||
|                         ], | ||||
|                         if (_scannedAssetModel?.status != null && _scannedAssetModel!.status!.isNotEmpty) classificationWidget(label: _scannedAssetModel?.status), | ||||
|                         12.height, | ||||
|                         Text( | ||||
|                           'Asset Photo'.addTranslation, | ||||
|                           style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.white936), | ||||
|                         ), | ||||
|                         12.height, | ||||
|                         attachments.isEmpty | ||||
|                             ? AttachmentPicker( | ||||
|                                 label: context.translation.attachImage, | ||||
|                                 attachment: attachments, | ||||
|                                 buttonColor: AppColor.black10, | ||||
|                                 onlyImages: true, | ||||
|                                 onChange: (value) { | ||||
|                                   setState(() {}); | ||||
|                                 }, | ||||
|                                 buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120), | ||||
|                               ) | ||||
|                             : MultiFilesPickerItem( | ||||
|                                 file: File(attachments.first.name ?? ''), | ||||
|                                 enabled: true, | ||||
|                                 onRemoveTap: (file) { | ||||
|                                   setState(() { | ||||
|                                     attachments.clear(); | ||||
|                                   }); | ||||
|                                 }, | ||||
|                               ), | ||||
|                         12.height, | ||||
|                         AppTextFormField( | ||||
|                           backgroundColor: AppColor.fieldBgColor(context), | ||||
|                           labelText: 'Remarks'.addTranslation, | ||||
|                           labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), | ||||
|                           alignLabelWithHint: true, | ||||
|                           textInputType: TextInputType.multiline, | ||||
|                           showShadow: false, | ||||
|                           controller: _remarksController, | ||||
|                           onSaved: (text) { | ||||
|                             _scannedAssetModel?.remarks = text; | ||||
|                             setState(() {}); | ||||
|                           }, | ||||
|                         ), | ||||
|                         // 100.height, | ||||
|                       ], | ||||
|                     ).toShadowContainer(context, borderRadius: 20, padding: 12)) | ||||
|                 .expanded, | ||||
|             FooterActionButton.footerContainer( | ||||
|               context: context, | ||||
|               child: AppFilledButton(buttonColor: AppColor.primary10, label: context.translation.submitRequest, maxWidth: true, onPressed: _onSubmit), | ||||
|             ), | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   Future<void> searchAsset({required String assetNo}) async { | ||||
|     AssetInventoryProvider provider = Provider.of<AssetInventoryProvider>(context, listen: false); | ||||
| 
 | ||||
|     Map<String, dynamic> payload = { | ||||
|       "assetNumber": assetNo, | ||||
|       "sessionId": widget.assetInventoryModel?.sessionId, | ||||
|       "siteId": widget.assetInventoryModel?.site?.id, | ||||
|       "buildingId": widget.assetInventoryModel?.building?.id, | ||||
|       "floorId": widget.assetInventoryModel?.floor?.id, | ||||
|       "departmentId": widget.assetInventoryModel?.department?.id, | ||||
|       "roomId": widget.assetInventoryModel?.room?.id, | ||||
|     }; | ||||
|     showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); | ||||
|     _scannedAssetModel = await provider.searchAsset(payload: payload); | ||||
|     Navigator.pop(context); | ||||
|     if (_scannedAssetModel != null) { | ||||
|       populateFormValues(); | ||||
|     } | ||||
|     setState(() {}); | ||||
|   } | ||||
| 
 | ||||
|   Widget siteInfoContainer({required String label, required String value}) { | ||||
|     //TODO may be need to hide value for if empty or null . | ||||
|     return Container( | ||||
|       width: double.infinity, | ||||
|       padding: EdgeInsets.symmetric(horizontal: 12.toScreenWidth, vertical: 12.toScreenHeight), | ||||
|       decoration: BoxDecoration(color: AppColor.neutral80, borderRadius: BorderRadius.circular(8)), | ||||
|       child: Column( | ||||
|         crossAxisAlignment: CrossAxisAlignment.start, | ||||
|         children: [ | ||||
|           Text(label, style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500)), | ||||
|           Text( | ||||
|             value, | ||||
|             style: Theme.of(context).textTheme.bodyLarge, | ||||
|           ), | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   Widget classificationWidget({String? label}) { | ||||
|     return Row( | ||||
|       mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|       children: [ | ||||
|         Text( | ||||
|           'Classification'.addTranslation, | ||||
|           style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.white936), | ||||
|         ), | ||||
|         //TODO Need to set background and text color according to data.. | ||||
|         StatusLabel( | ||||
|           label: label, | ||||
|           radius: 4, | ||||
|           textColor: AppColor.getPriorityStatusTextColor(context, 81), | ||||
|           backgroundColor: AppColor.getPriorityStatusColor(context, 370), | ||||
|         ), | ||||
|       ], | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   void _onSubmit() async { | ||||
|     AssetInventoryProvider assetInventoryProvider = Provider.of<AssetInventoryProvider>(context, listen: false); | ||||
|     _formKey.currentState!.save(); | ||||
|     _scannedAssetModel?.sessionId = widget.assetInventoryModel?.sessionId; | ||||
|     _scannedAssetModel?.siteId = widget.assetInventoryModel?.site?.id; | ||||
|     _scannedAssetModel?.buildingId = widget.assetInventoryModel?.building?.id; | ||||
|     _scannedAssetModel?.floorId = widget.assetInventoryModel?.floor?.id; | ||||
|     _scannedAssetModel?.departmentId = widget.assetInventoryModel?.department?.id; | ||||
|     _scannedAssetModel?.roomId = widget.assetInventoryModel?.room?.id; | ||||
|     _scannedAssetModel?.isNotRegistered = isRegistered; | ||||
|     if (attachments.isNotEmpty) { | ||||
|       String? photoName = attachments.first.name; | ||||
|       String fileName = ServiceRequestUtils.isLocalUrl(photoName ?? '') ? ("${photoName ?? ''.split("/").last}|${base64Encode(File(photoName ?? '').readAsBytesSync())}") : photoName ?? ''; | ||||
|       _scannedAssetModel?.photo = fileName; | ||||
|     } | ||||
|     showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); | ||||
|     assetInventoryProvider.saveAssetInSession(model: _scannedAssetModel).then((success) async { | ||||
|       ///Need to use push and remove until... | ||||
|       Navigator.pop(context); | ||||
|       if (success) { | ||||
|         /// need to confirm need to call this ... | ||||
|         AllRequestsProvider allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false); | ||||
|         allRequestsProvider.reset(); | ||||
|         allRequestsProvider.getAllRequests(context, typeTransaction: 8); | ||||
|         getAssetFilteredList(); | ||||
|         Navigator.pop(context); | ||||
|       } else { | ||||
|         log('api error...'); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   void resetData({bool isScanned = true}) { | ||||
|     if (isScanned) { | ||||
|       _scannedAssetModel = AssetInventoryModel(); | ||||
|     } | ||||
|     _assetNoController.clear(); | ||||
|     _serialNoController.clear(); | ||||
|     _pickedAssetModel = AssetInventoryModel(); | ||||
|     attachments.clear(); | ||||
|     _remarksController.clear(); | ||||
|     registeredController?.dispose(); | ||||
|   } | ||||
| 
 | ||||
|   Future<void> getAssetFilteredList({bool loadMore = false}) async { | ||||
|     AssetInventoryProvider provider = Provider.of<AssetInventoryProvider>(context, listen: false); | ||||
|     Map<String, dynamic> payload = { | ||||
|       "sessionId": widget.assetInventoryModel?.sessionId, | ||||
|       "siteId": widget.assetInventoryModel?.site?.id, | ||||
|       "buildingId": widget.assetInventoryModel?.building?.id, | ||||
|       "floorId": widget.assetInventoryModel?.floor?.id, | ||||
|       "departmentId": widget.assetInventoryModel?.department?.id, | ||||
|       "roomId": widget.assetInventoryModel?.room?.id, | ||||
|     }; | ||||
|     await provider.getInventoryDetailsByFilter(payload: payload, loadMore: loadMore); | ||||
|     provider.getAssetsInSession( | ||||
|       sessionId: (widget.assetInventoryModel?.sessionId ?? 0).toInt(), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,122 @@ | ||||
| import 'dart:developer'; | ||||
| 
 | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:test_sa/extensions/context_extension.dart'; | ||||
| import 'package:test_sa/extensions/int_extensions.dart'; | ||||
| import 'package:test_sa/extensions/string_extensions.dart'; | ||||
| import 'package:test_sa/extensions/text_extensions.dart'; | ||||
| import 'package:test_sa/extensions/widget_extensions.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_site_information_page.dart'; | ||||
| import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; | ||||
| import 'package:test_sa/new_views/app_style/app_color.dart'; | ||||
| import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; | ||||
| import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; | ||||
| import '../provider/asset_inventory_provider.dart'; | ||||
| 
 | ||||
| class AssetInventoryPage extends StatefulWidget { | ||||
|   final int sessionId; | ||||
| 
 | ||||
|   const AssetInventoryPage({Key? key, required this.sessionId}) : super(key: key); | ||||
| 
 | ||||
|   @override | ||||
|   _AssetInventoryPageState createState() { | ||||
|     return _AssetInventoryPageState(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class _AssetInventoryPageState extends State<AssetInventoryPage> { | ||||
|   late AssetInventoryProvider _assetInventoryProvider; | ||||
| 
 | ||||
|   @override | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
|     _assetInventoryProvider = Provider.of<AssetInventoryProvider>(context, listen: false); | ||||
|     WidgetsBinding.instance.addPostFrameCallback((_) { | ||||
|       getInitialData(); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   Future<void> getInitialData() async { | ||||
|     _assetInventoryProvider.reset(); | ||||
|     await _assetInventoryProvider.getSessionById(id: widget.sessionId); | ||||
|     await _assetInventoryProvider.getAssetsInSession( | ||||
|       sessionId: widget.sessionId, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   void dispose() { | ||||
|     super.dispose(); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Scaffold( | ||||
|         backgroundColor: Theme.of(context).scaffoldBackgroundColor, | ||||
|         appBar: DefaultAppBar( | ||||
|           title: 'Inventory Session Request'.addTranslation, | ||||
|           onBackPress: () { | ||||
|             Navigator.pop(context); | ||||
|           }, | ||||
|         ), | ||||
|         body: Consumer<AssetInventoryProvider>(builder: (context, provider, child) { | ||||
|           return DefaultTabController( | ||||
|             length: 2, | ||||
|             child: provider.isLoading | ||||
|                 ? const CircularProgressIndicator(color: AppColor.primary10).center | ||||
|                 : Column( | ||||
|                     mainAxisSize: MainAxisSize.min, | ||||
|                     children: <Widget>[ | ||||
|                       Container( | ||||
|                         margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight), | ||||
|                         decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.white10, borderRadius: BorderRadius.circular(10)), | ||||
|                         child: TabBar( | ||||
|                           padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth), | ||||
|                           labelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, | ||||
|                           unselectedLabelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, | ||||
|                           unselectedLabelStyle: AppTextStyles.bodyText, | ||||
|                           labelStyle: AppTextStyles.bodyText, | ||||
|                           indicatorPadding: EdgeInsets.zero, | ||||
|                           indicatorSize: TabBarIndicatorSize.tab, | ||||
|                           dividerColor: Colors.transparent, | ||||
|                           indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)), | ||||
|                           onTap: (index) {}, | ||||
|                           tabs: [ | ||||
|                             Tab(text: 'Request Details'.addTranslation, height: 57.toScreenHeight), | ||||
|                             Tab( | ||||
|                                 text: | ||||
|                                     '${'Scan Assets'.addTranslation} ${provider.assetInventoryResponse?.totalRows != null && provider.assetInventoryResponse!.totalRows! > 0 ? '(${provider.assetInventoryResponse?.totalRows})' : ''}', | ||||
|                                 height: 57.toScreenHeight), | ||||
|                           ], | ||||
|                         ), | ||||
|                       ), | ||||
|                       TabBarView( | ||||
|                         children: [ | ||||
|                           AssetInventoryDetailView(sessionModel: provider.sessionModel ?? SessionModel()), | ||||
|                           AssetInventoryScanAssetView(sessionId: provider.sessionModel?.id ?? 0), | ||||
|                         ], | ||||
|                       ).expanded, | ||||
|                       FooterActionButton.footerContainer( | ||||
|                         context: context, | ||||
|                         child: AppFilledButton( | ||||
|                           buttonColor: AppColor.primary10, | ||||
|                           label: 'Scan Assets'.addTranslation, | ||||
|                           onPressed: () => _scanAsset(provider: provider), | ||||
|                           // buttonColor: AppColor.primary10, | ||||
|                         ), | ||||
|                       ) | ||||
|                     ], | ||||
|                   ), | ||||
|           ); | ||||
|         })); | ||||
|   } | ||||
| 
 | ||||
|   Future<void> _scanAsset({required AssetInventoryProvider provider}) async { | ||||
|     provider.siteFilterAssetList.clear(); | ||||
|     Navigator.push(context, MaterialPageRoute(builder: (contxt) => SiteInformationPage(sessionModel: provider.sessionModel ?? SessionModel()))); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,129 @@ | ||||
| import 'dart:developer'; | ||||
| 
 | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:test_sa/extensions/int_extensions.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; | ||||
| import 'package:test_sa/views/widgets/loaders/lazy_loading.dart'; | ||||
| import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; | ||||
| 
 | ||||
| import 'asset_detail_card_view.dart'; | ||||
| 
 | ||||
| class AssetInventoryScanAssetView extends StatefulWidget { | ||||
|   int sessionId; | ||||
| 
 | ||||
|   AssetInventoryScanAssetView({Key? key, required this.sessionId}) : super(key: key); | ||||
| 
 | ||||
|   @override | ||||
|   State<AssetInventoryScanAssetView> createState() => _AssetInventoryScanAssetViewState(); | ||||
| } | ||||
| 
 | ||||
| class _AssetInventoryScanAssetViewState extends State<AssetInventoryScanAssetView> { | ||||
|   late AssetInventoryProvider assetInventoryProvider; | ||||
| 
 | ||||
|   @override | ||||
|   void initState() { | ||||
|     assetInventoryProvider = Provider.of<AssetInventoryProvider>(context, listen: false); | ||||
|     super.initState(); | ||||
|   } | ||||
| 
 | ||||
|   Future<void> getAssetList({bool loadMore = false}) async { | ||||
|     await assetInventoryProvider.getAssetsInSession( | ||||
|       sessionId: widget.sessionId, | ||||
|       loadMore: loadMore, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Consumer<AssetInventoryProvider>( | ||||
|       builder: (context, provider, _) { | ||||
|         if (provider.isLoading && provider.assetInventoryResponse == null) { | ||||
|           return const Center(child: CircularProgressIndicator()); | ||||
|         } | ||||
|         final assets = provider.assetInventoryResponse?.assetList ?? []; | ||||
|         if (assets.isEmpty) { | ||||
|           return const Center(child: NoDataFound()); | ||||
|         } | ||||
|         return NotificationListener<ScrollNotification>( | ||||
|           onNotification: (scrollInfo) { | ||||
|             if (!provider.isNextPageLoading && provider.nextPage && scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) { | ||||
|               getAssetList(loadMore: true); | ||||
|             } | ||||
|             return false; | ||||
|           }, | ||||
|           child: ListView.separated( | ||||
|             padding: const EdgeInsets.all(16), | ||||
|             itemCount: assets.length + (provider.isNextPageLoading ? 1 : 0), | ||||
|             itemBuilder: (context, index) { | ||||
|               if (index == assets.length) { | ||||
|                 return const Padding( | ||||
|                   padding: EdgeInsets.symmetric(vertical: 16), | ||||
|                   child: Center(child: CircularProgressIndicator()), | ||||
|                 ); | ||||
|               } | ||||
|               return AssetDetailCardView( | ||||
|                 assetInventoryModel: assets[index], | ||||
|                 onDeletePress: () async { | ||||
|                   await provider.deleteAssetISession(id: assets[index].id ?? 0).then((success) async { | ||||
|                     if (success) { | ||||
|                       await provider.getAssetsInSession(sessionId: widget.sessionId); | ||||
|                     } | ||||
|                   }); | ||||
|                 }, | ||||
|               ); | ||||
|             }, | ||||
|             separatorBuilder: (context, index) => 12.height, | ||||
|           ), | ||||
|         ); | ||||
|       }, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
| // Widget build(BuildContext context) { | ||||
| //   return Consumer<AssetInventoryProvider>( | ||||
| //     builder: (context, provider, _) { | ||||
| //       if (provider.isLoading && provider.assetInventoryResponse == null) { | ||||
| //         //TODO need use existing loader if found.. | ||||
| //         return const Center(child: CircularProgressIndicator()); | ||||
| //       } | ||||
| //       final assets = provider.assetInventoryResponse?.assetList ?? []; | ||||
| //       if (assets.isEmpty) { | ||||
| //         return const Center(child: NoDataFound()); | ||||
| //       } | ||||
| //       return LazyLoading( | ||||
| //         nextPage: provider.nextPage, | ||||
| //         onLazyLoad: () async { | ||||
| //           log('Loading next page...'); | ||||
| //           await getAssetList(loadMore: true); | ||||
| //         }, | ||||
| //         child: ListView.separated( | ||||
| //           padding: const EdgeInsets.all(16), | ||||
| //           itemBuilder: (context, index) { | ||||
| //             if (index == assets.length) { | ||||
| //               // bottom loader | ||||
| //               return const Padding( | ||||
| //                 padding: EdgeInsets.symmetric(vertical: 16), | ||||
| //                 child: Center(child: CircularProgressIndicator()), | ||||
| //               ); | ||||
| //             } | ||||
| //             return AssetDetailCardView( | ||||
| //               assetInventoryModel: assets[index], | ||||
| //               onDeletePress: () async { | ||||
| //                 await provider.deleteAssetISession(id: assets[index].id ?? 0).then((success) async { | ||||
| //                   if (success) { | ||||
| //                     await provider.getAssetsInSession(sessionId: widget.sessionId); | ||||
| //                   } | ||||
| //                 }); | ||||
| //               }, | ||||
| //             ); | ||||
| //           }, | ||||
| //           separatorBuilder: (context, index) => 12.height, | ||||
| //           itemCount: assets.length + (provider.nextPage ? 1 : 0), | ||||
| //         ), | ||||
| //       ); | ||||
| //     }, | ||||
| //   ); | ||||
| // } | ||||
| } | ||||
| @ -0,0 +1,308 @@ | ||||
| import 'dart:developer'; | ||||
| 
 | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:fluttertoast/fluttertoast.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; | ||||
| import 'package:test_sa/extensions/context_extension.dart'; | ||||
| import 'package:test_sa/extensions/int_extensions.dart'; | ||||
| import 'package:test_sa/extensions/string_extensions.dart'; | ||||
| import 'package:test_sa/extensions/text_extensions.dart'; | ||||
| import 'package:test_sa/extensions/widget_extensions.dart'; | ||||
| import 'package:test_sa/models/new_models/building.dart'; | ||||
| import 'package:test_sa/models/new_models/department.dart'; | ||||
| import 'package:test_sa/models/new_models/floor.dart'; | ||||
| import 'package:test_sa/models/new_models/room_model.dart'; | ||||
| import 'package:test_sa/models/new_models/site.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/pages/asset_detail_card_view.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_form_view.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; | ||||
| import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; | ||||
| import 'package:test_sa/new_views/app_style/app_color.dart'; | ||||
| import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; | ||||
| import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; | ||||
| import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; | ||||
| import 'package:test_sa/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/loaders/lazy_loading.dart'; | ||||
| 
 | ||||
| class SiteInformationPage extends StatefulWidget { | ||||
|   SessionModel sessionModel; | ||||
| 
 | ||||
|   SiteInformationPage({Key? key, required this.sessionModel}) : super(key: key); | ||||
| 
 | ||||
|   @override | ||||
|   State<SiteInformationPage> createState() => _SiteInformationPageState(); | ||||
| } | ||||
| 
 | ||||
| class _SiteInformationPageState extends State<SiteInformationPage> { | ||||
|   AssetInventoryModel assetInventoryModel = AssetInventoryModel(); | ||||
|   bool showMarkAsComplete = false; | ||||
|   final ScrollController _scrollController = ScrollController(); | ||||
| 
 | ||||
|   @override | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
|     _scrollController.addListener(() { | ||||
|       final provider = Provider.of<AssetInventoryProvider>(context, listen: false); | ||||
|       if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent && !provider.isNextPageLoading && provider.nextPage) { | ||||
|         getAssetFilteredList(loadMore: true); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Scaffold( | ||||
|       key: _scaffoldKey, | ||||
|       appBar: DefaultAppBar( | ||||
|         title: 'Inventory Session Request'.addTranslation, | ||||
|         titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), | ||||
|       ), | ||||
|       body: Column( | ||||
|         children: [ | ||||
|           ListView( | ||||
|             controller: _scrollController, | ||||
|             padding: const EdgeInsets.only(left: 16, right: 16, top: 16), | ||||
|             children: [ | ||||
|               siteInfoCard(context, widget.sessionModel), | ||||
|               12.height, | ||||
|               assetDetailList(), | ||||
|               8.height, | ||||
|             ], | ||||
|           ).expanded, | ||||
|           FooterActionButton.footerContainer( | ||||
|             context: context, | ||||
|             child: Column( | ||||
|               children: [ | ||||
|                 AppFilledButton( | ||||
|                   buttonColor: AppColor.primary10, | ||||
|                   label: 'Add Asset'.addTranslation, | ||||
|                   onPressed: () => _addAsset(), | ||||
|                   // buttonColor: AppColor.primary10, | ||||
|                 ), | ||||
|                 if (showMarkAsComplete) ...[ | ||||
|                   12.height, | ||||
|                   AppFilledButton( | ||||
|                     buttonColor: AppColor.green70, | ||||
|                     label: 'Mark as completed'.addTranslation, | ||||
|                     onPressed: () => _markAsCompleted(), | ||||
|                     // buttonColor: AppColor.primary10, | ||||
|                   ) | ||||
|                 ] | ||||
|               ], | ||||
|             ), | ||||
|           ), | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   void _addAsset() async { | ||||
|     if (await validateRequest()) { | ||||
|       assetInventoryModel.sessionId = widget.sessionModel.id; | ||||
|       Navigator.push( | ||||
|           context, | ||||
|           MaterialPageRoute( | ||||
|               builder: (contxt) => AssetInventoryFormView( | ||||
|                     assetInventoryModel: assetInventoryModel, | ||||
|                     sessionTypeValue: widget.sessionModel.sessionTypeValue, | ||||
|                   ))); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void _markAsCompleted() async { | ||||
|     if (await validateRequest()) { | ||||
|       assetInventoryModel.sessionId = widget.sessionModel.id; | ||||
|       AssetInventoryProvider provider = Provider.of<AssetInventoryProvider>(context, listen: false); | ||||
|       Map<String, dynamic> payload = { | ||||
|         "sessionId": widget.sessionModel.id, | ||||
|         "siteId": assetInventoryModel.site?.id, | ||||
|         "buildingId": assetInventoryModel.building?.id, | ||||
|         "floorId": assetInventoryModel.floor?.id, | ||||
|         "departmentId": assetInventoryModel.department?.id, | ||||
|         "roomId": assetInventoryModel.room?.id, | ||||
|       }; | ||||
|       showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); | ||||
|       await provider.markAsComplete(payload: payload).then((success) { | ||||
|         Navigator.pop(context); | ||||
|         if (success) { | ||||
|           ///TODO need to confirm need to call this or not .. | ||||
|           // AllRequestsProvider allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false); | ||||
|           // allRequestsProvider.reset(); | ||||
|           // allRequestsProvider.getAllRequests(context, typeTransaction: 8); | ||||
|           ///Need to call push and remove until... | ||||
|           Navigator.pop(context); | ||||
|           Navigator.pop(context); | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   Widget assetDetailList() { | ||||
|     return Consumer<AssetInventoryProvider>( | ||||
|       builder: (context, provider, _) { | ||||
|         if (provider.isLoading) { | ||||
|           return SizedBox( | ||||
|             height: 300.toScreenHeight, | ||||
|             child: const CircularProgressIndicator(color: AppColor.primary10).center, | ||||
|           ); | ||||
|         } | ||||
| 
 | ||||
|         final assets = provider.siteFilterAssetList; | ||||
|         return ListView.separated( | ||||
|           shrinkWrap: true, | ||||
|           physics: const NeverScrollableScrollPhysics(), | ||||
|           // Keep non-scrollable, parent handles scroll | ||||
|           itemCount: assets.length, | ||||
|           itemBuilder: (context, index) { | ||||
|             return AssetDetailCardView( | ||||
|               assetInventoryModel: assets[index], | ||||
|               onDeletePress: () async { | ||||
|                 await provider.deleteAssetISession(id: assets[index].id ?? 0).then((success) async { | ||||
|                   if (success) { | ||||
|                     await getAssetFilteredList(); | ||||
|                     await provider.getAssetsInSession(sessionId: widget.sessionModel.id ?? 0); | ||||
|                   } | ||||
|                 }); | ||||
|               }, | ||||
|             ); | ||||
|           }, | ||||
|           separatorBuilder: (context, index) => 12.height, | ||||
|         ); | ||||
|       }, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   Widget siteInfoCard(BuildContext context, SessionModel sessionModel) { | ||||
|     return Column( | ||||
|       crossAxisAlignment: CrossAxisAlignment.start, | ||||
|       children: [ | ||||
|         SingleItemDropDownMenu<Site, NullableLoadingProvider>( | ||||
|           context: context, | ||||
|           title: context.translation.site, | ||||
|           initialValue: assetInventoryModel.site, | ||||
|           showShadow: false, | ||||
|           staticData: sessionModel.assetInventorySites, | ||||
|           backgroundColor: AppColor.fieldBgColor(context), | ||||
|           showAsBottomSheet: true, | ||||
|           onSelect: (value) { | ||||
|             assetInventoryModel.site = value; | ||||
|             assetInventoryModel.building = null; | ||||
|             assetInventoryModel.floor = null; | ||||
|             assetInventoryModel.department = null; | ||||
|             setState(() {}); | ||||
|           }, | ||||
|         ), | ||||
|         12.height, | ||||
|         SingleItemDropDownMenu<Building, NullableLoadingProvider>( | ||||
|           context: context, | ||||
|           title: context.translation.building, | ||||
|           initialValue: assetInventoryModel.building, | ||||
|           showShadow: false, | ||||
|           showAsBottomSheet: true, | ||||
|           backgroundColor: AppColor.fieldBgColor(context), | ||||
|           enabled: assetInventoryModel.site?.buildings?.isNotEmpty ?? false, | ||||
|           staticData: assetInventoryModel.site?.buildings ?? [], | ||||
|           onSelect: (value) { | ||||
|             assetInventoryModel.building = value; | ||||
|             assetInventoryModel.floor = null; | ||||
|             assetInventoryModel.department = null; | ||||
|             setState(() {}); | ||||
|           }, | ||||
|         ), | ||||
|         12.height, | ||||
|         SingleItemDropDownMenu<Floor, NullableLoadingProvider>( | ||||
|           context: context, | ||||
|           title: context.translation.floor, | ||||
|           showShadow: false, | ||||
|           showAsBottomSheet: true, | ||||
|           initialValue: assetInventoryModel.floor, | ||||
|           backgroundColor: AppColor.fieldBgColor(context), | ||||
|           enabled: assetInventoryModel.building?.floors?.isNotEmpty ?? false, | ||||
|           staticData: assetInventoryModel.building?.floors ?? [], | ||||
|           onSelect: (value) { | ||||
|             assetInventoryModel.floor = value; | ||||
|             assetInventoryModel.department = null; | ||||
|             setState(() {}); | ||||
|           }, | ||||
|         ), | ||||
|         12.height, | ||||
|         SingleItemDropDownMenu<Department, NullableLoadingProvider>( | ||||
|           context: context, | ||||
|           title: context.translation.department, | ||||
|           showShadow: false, | ||||
|           showAsBottomSheet: true, | ||||
|           initialValue: assetInventoryModel.department, | ||||
|           backgroundColor: AppColor.fieldBgColor(context), | ||||
|           enabled: assetInventoryModel.floor?.departments?.isNotEmpty ?? false, | ||||
|           staticData: assetInventoryModel.floor?.departments ?? [], | ||||
|           onSelect: (value) { | ||||
|             assetInventoryModel.department = value; | ||||
|             assetInventoryModel.room = null; | ||||
|             showMarkAsComplete = true; | ||||
|             setState(() {}); | ||||
|             if (assetInventoryModel.department != null && assetInventoryModel.department!.rooms!.isEmpty) { | ||||
|               getAssetFilteredList(); | ||||
|             } | ||||
|           }, | ||||
|         ), | ||||
|         12.height, | ||||
|         SingleItemDropDownMenu<Rooms, NullableLoadingProvider>( | ||||
|           context: context, | ||||
|           title: context.translation.room, | ||||
|           showShadow: false, | ||||
|           showAsBottomSheet: true, | ||||
|           initialValue: assetInventoryModel.room, | ||||
|           backgroundColor: AppColor.fieldBgColor(context), | ||||
|           enabled: assetInventoryModel.department?.rooms?.isNotEmpty ?? false, | ||||
|           staticData: assetInventoryModel.department?.rooms ?? [], | ||||
|           onSelect: (value) { | ||||
|             assetInventoryModel.room = value; | ||||
|             setState(() {}); | ||||
|             if (assetInventoryModel.room != null) { | ||||
|               getAssetFilteredList(); | ||||
|             } | ||||
|           }, | ||||
|         ), | ||||
|       ], | ||||
|     ).toShadowContainer(context, borderRadius: 20, padding: 12); | ||||
|   } | ||||
| 
 | ||||
|   Future<bool> validateRequest() async { | ||||
|     if (assetInventoryModel.site == null) { | ||||
|       await Fluttertoast.showToast(msg: "Please Select Site"); | ||||
|       return false; | ||||
|     } | ||||
|     if (assetInventoryModel.building == null) { | ||||
|       await Fluttertoast.showToast(msg: "Please Select Building"); | ||||
|       return false; | ||||
|     } | ||||
|     if (assetInventoryModel.floor == null) { | ||||
|       await Fluttertoast.showToast(msg: "Please Select Floor"); | ||||
|       return false; | ||||
|     } | ||||
|     if (assetInventoryModel.department == null) { | ||||
|       await Fluttertoast.showToast(msg: "Please Select Department"); | ||||
|       return false; | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|   Future<void> getAssetFilteredList({bool loadMore = false}) async { | ||||
|     AssetInventoryProvider provider = Provider.of<AssetInventoryProvider>(context, listen: false); | ||||
|     Map<String, dynamic> payload = { | ||||
|       "sessionId": widget.sessionModel.id, | ||||
|       "siteId": assetInventoryModel.site?.id, | ||||
|       "buildingId": assetInventoryModel.building?.id, | ||||
|       "floorId": assetInventoryModel.floor?.id, | ||||
|       "departmentId": assetInventoryModel.department?.id, | ||||
|       "roomId": assetInventoryModel.room?.id, | ||||
|     }; | ||||
|     await provider.getInventoryDetailsByFilter(payload: payload, loadMore: loadMore); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,124 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:test_sa/extensions/context_extension.dart'; | ||||
| import 'package:test_sa/extensions/int_extensions.dart'; | ||||
| import 'package:test_sa/extensions/string_extensions.dart'; | ||||
| import 'package:test_sa/extensions/text_extensions.dart'; | ||||
| import 'package:test_sa/extensions/widget_extensions.dart'; | ||||
| import 'package:test_sa/models/all_requests_and_count_model.dart'; | ||||
| import 'package:test_sa/models/new_models/dashboard_detail.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_page.dart'; | ||||
| import 'package:test_sa/new_views/app_style/app_color.dart'; | ||||
| import 'package:test_sa/views/widgets/requests/request_status.dart'; | ||||
| 
 | ||||
| class InventorySessionItemView extends StatelessWidget { | ||||
|   final Data? requestData; | ||||
|   final RequestsDetails? requestDetails; | ||||
|   final bool showShadow; | ||||
| 
 | ||||
|   const InventorySessionItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     if (requestData != null) { | ||||
|       return Column( | ||||
|         crossAxisAlignment: CrossAxisAlignment.start, | ||||
|         children: [ | ||||
|           Row( | ||||
|             crossAxisAlignment: CrossAxisAlignment.start, | ||||
|             children: [ | ||||
|               StatusLabel( | ||||
|                 label: requestData!.priorityName!, | ||||
|                 textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.priorityName!), | ||||
|                 backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.priorityName!), | ||||
|               ), | ||||
|               8.width, | ||||
|               StatusLabel( | ||||
|                 label: requestData!.statusName!, | ||||
|                 textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.statusName!), | ||||
|                 backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.statusName!), | ||||
|               ), | ||||
|               1.width.expanded, | ||||
|               Text( | ||||
|                 requestData!.transactionDate?.toServiceRequestCardFormat ?? "", | ||||
|                 textAlign: TextAlign.end, | ||||
|                 style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), | ||||
|               ), | ||||
|             ], | ||||
|           ), | ||||
|           8.height, | ||||
|           (requestData?.typeTransaction ?? context.translation.taskRequest).heading5(context), | ||||
|           infoWidget(label: context.translation.requestType, value: requestData?.sessionType, context: context), | ||||
|           infoWidget(label: 'No of Assets'.addTranslation, value: requestData?.numberOfAssets != null ? requestData?.numberOfAssets.toString() : '-', context: context), | ||||
|           infoWidget(label: 'No of Sites'.addTranslation, value: requestData?.numberOfSites != null ? requestData?.numberOfSites.toString() : '-', context: context), | ||||
|           8.height, | ||||
|           Row( | ||||
|             mainAxisSize: MainAxisSize.min, | ||||
|             children: [ | ||||
|               Text( | ||||
|                 context.translation.viewDetails, | ||||
|                 style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), | ||||
|               ), | ||||
|               4.width, | ||||
|               Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) | ||||
|             ], | ||||
|           ), | ||||
|         ], | ||||
|       ).toShadowContainer(context, withShadow: showShadow).onPress(() async { | ||||
|         Navigator.of(context).push(MaterialPageRoute(builder: (_) => AssetInventoryPage(sessionId: requestData!.id!))); | ||||
|       }); | ||||
|     } | ||||
|     return Column( | ||||
|       crossAxisAlignment: CrossAxisAlignment.start, | ||||
|       children: [ | ||||
|         Row( | ||||
|           crossAxisAlignment: CrossAxisAlignment.start, | ||||
|           children: [ | ||||
|             StatusLabel( | ||||
|               label: requestDetails!.priority!, | ||||
|               textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.priority!), | ||||
|               backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.priority!), | ||||
|             ), | ||||
|             8.width, | ||||
|             StatusLabel( | ||||
|               label: requestDetails!.status!, | ||||
|               textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.status!), | ||||
|               backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.status!), | ||||
|             ), | ||||
|             1.width.expanded, | ||||
|             Text( | ||||
|               requestDetails!.date?.toServiceRequestCardFormat ?? "", | ||||
|               textAlign: TextAlign.end, | ||||
|               style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), | ||||
|             ), | ||||
|           ], | ||||
|         ), | ||||
|         8.height, | ||||
|         (requestDetails?.nameOfType ?? context.translation.taskRequest).heading5(context), | ||||
|         infoWidget(label: context.translation.requestType, value: requestDetails?.sessionType, context: context), | ||||
|         infoWidget(label: 'No of Assets'.addTranslation, value: requestDetails?.numberOfAssets != null ? requestDetails?.numberOfAssets.toString() : '-', context: context), | ||||
|         infoWidget(label: 'No of Sites'.addTranslation, value: requestDetails?.numberOfSites != null ? requestDetails?.numberOfSites.toString() : '-', context: context), | ||||
|         8.height, | ||||
|         Row( | ||||
|           mainAxisSize: MainAxisSize.min, | ||||
|           children: [ | ||||
|             Text( | ||||
|               context.translation.viewDetails, | ||||
|               style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), | ||||
|             ), | ||||
|             4.width, | ||||
|             Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) | ||||
|           ], | ||||
|         ), | ||||
|       ], | ||||
|     ).toShadowContainer(context, withShadow: showShadow).onPress(() async { | ||||
|       Navigator.of(context).push(MaterialPageRoute(builder: (_) => AssetInventoryPage(sessionId: requestDetails!.id!))); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   Widget infoWidget({required String label, String? value, required BuildContext context}) { | ||||
|     if (value != null && value.isNotEmpty) { | ||||
|       return '$label:  $value'.bodyText(context); | ||||
|     } | ||||
|     return const SizedBox(); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,276 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:test_sa/controllers/api_routes/urls.dart'; | ||||
| import 'package:test_sa/extensions/context_extension.dart'; | ||||
| import 'package:test_sa/extensions/int_extensions.dart'; | ||||
| import 'package:test_sa/extensions/string_extensions.dart'; | ||||
| import 'package:test_sa/extensions/text_extensions.dart'; | ||||
| import 'package:test_sa/extensions/widget_extensions.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; | ||||
| import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; | ||||
| import 'package:test_sa/views/widgets/equipment/asset_item_listview.dart'; | ||||
| import 'package:test_sa/views/widgets/horizontal_list_widget.dart'; | ||||
| import 'package:test_sa/views/widgets/loaders/lazy_loading.dart'; | ||||
| import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; | ||||
| import '../../../models/device/asset.dart'; | ||||
| import '../../../models/device/asset_search.dart'; | ||||
| import '../../../new_views/app_style/app_color.dart'; | ||||
| import '../../../new_views/common_widgets/app_lazy_loading.dart'; | ||||
| import '../../../new_views/common_widgets/custom_app_bar.dart'; | ||||
| 
 | ||||
| class SearchAssetView extends StatefulWidget { | ||||
|   static const String id = "asset_search_view"; | ||||
|   final num sessionId; | ||||
| 
 | ||||
|   const SearchAssetView({Key? key, required this.sessionId}) : super(key: key); | ||||
| 
 | ||||
|   @override | ||||
|   State<SearchAssetView> createState() => _SearchAssetViewState(); | ||||
| } | ||||
| 
 | ||||
| class _SearchAssetViewState extends State<SearchAssetView> { | ||||
|   int _selectedIndex = 0; | ||||
|   DeviceSearch? search; | ||||
|   late TextEditingController _searchController; | ||||
|   late AssetInventoryProvider _assetInventoryProvider; | ||||
|   final List<AssetInventoryModel> _searchableList = []; | ||||
|   final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); | ||||
|   bool _isFirst = true; | ||||
| 
 | ||||
|   @override | ||||
|   void initState() { | ||||
|     _searchController = TextEditingController(); | ||||
|     super.initState(); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   void dispose() { | ||||
|     _searchController.dispose(); | ||||
|     _assetInventoryProvider.searchReset(); | ||||
|     super.dispose(); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     List<String> searchBy = [ | ||||
|       context.translation.assetName, | ||||
|       context.translation.model, | ||||
|       context.translation.manufacture, | ||||
|       context.translation.snNumber, | ||||
|       context.translation.siteName, | ||||
|       // 'Building Name'.addTranslation, | ||||
|       // 'Floor Name'.addTranslation, | ||||
|       'Department Name'.addTranslation, | ||||
| 
 | ||||
|       ///need to check if want to add more filters | ||||
|     ]; | ||||
| 
 | ||||
|     _assetInventoryProvider = Provider.of<AssetInventoryProvider>(context, listen: false); | ||||
| 
 | ||||
|     return Scaffold( | ||||
|         resizeToAvoidBottomInset: false, | ||||
|         appBar: CustomAppBar( | ||||
|           title: context.translation.searchAsset, | ||||
|         ), | ||||
|         body: Column( | ||||
|           children: [ | ||||
|             HorizontalListWidget( | ||||
|               list: searchBy, | ||||
|               callBackFunction: (index) { | ||||
|                 setState(() { | ||||
|                   _selectedIndex = index; | ||||
|                 }); | ||||
|               }, | ||||
|             ).paddingOnly(top: 16, bottom: 0), | ||||
|             Form( | ||||
|               key: _formKey, | ||||
|               child: AppTextFormField( | ||||
|                 controller: _searchController, | ||||
|                 textInputAction: TextInputAction.search, | ||||
|                 labelText: "${context.translation.searchBy} ${searchBy[_selectedIndex]}", | ||||
|                 onAction: _search, | ||||
|                 onChange: (text) { | ||||
|                   _searchController.text = text; | ||||
|                   _searchController.selection = TextSelection.fromPosition(TextPosition(offset: _searchController.text.length)); | ||||
|                   setState(() {}); | ||||
|                 }, | ||||
|                 onSaved: (value) { | ||||
|                   setState(() { | ||||
|                     search = DeviceSearch(); | ||||
|                   }); | ||||
|                   _setValue(value); | ||||
|                 }, | ||||
|                 suffixIcon: IconButton( | ||||
|                   icon: const Icon(Icons.search), | ||||
|                   splashColor: Colors.transparent, | ||||
|                   onPressed: _searchController.text.isNotEmpty ? _search : null, | ||||
|                   color: AppColor.neutral20, | ||||
|                 ).paddingOnly(end: 0), | ||||
|               ).paddingOnly(top: 16, start: 16, end: 16, bottom: 8), | ||||
|             ), | ||||
|             Expanded( | ||||
|               child: _searchableList.isEmpty | ||||
|                   ? _isFirst | ||||
|                       ? const SizedBox() | ||||
|                       : NoDataFound(message: context.translation.noDeviceFound) | ||||
|                   : LazyLoading( | ||||
|                       nextPage: _assetInventoryProvider.nextPage, | ||||
|                       onLazyLoad: () async { | ||||
|                         if (_searchController.text.isNotEmpty) { | ||||
|                           await _assetInventoryProvider.getAssets(search: search, isSearchBy: true, sessionId: widget.sessionId); | ||||
|                           setState(() { | ||||
|                             _searchableList.clear(); | ||||
|                             _searchableList.addAll(_assetInventoryProvider.searchDevices); | ||||
|                           }); | ||||
|                         } | ||||
|                       }, | ||||
|                       child: Column( | ||||
|                         children: [ | ||||
|                           ListView.separated( | ||||
|                             itemCount: _searchableList.length, | ||||
|                             separatorBuilder: (listContext, itemIndex) => 8.height, | ||||
|                             padding: const EdgeInsets.all(16), | ||||
|                             itemBuilder: (listContext, itemIndex) { | ||||
|                               // bool isSelected = selectedAssets.contains(_searchableList[itemIndex].id!); | ||||
|                               // String title = isSelected ? "UnSelect" : "Select"; | ||||
|                               return InventoryAssetItemListView( | ||||
|                                 device: _searchableList[itemIndex], | ||||
|                                 // isSelected: isSelected, | ||||
|                                 onPressed: (device) { | ||||
|                                   // Navigator.of(context).pop(); | ||||
|                                   Navigator.of(context).pop(device); | ||||
|                                 }, | ||||
|                                 // selectButton: Text(title, style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context))), | ||||
|                               ); | ||||
|                             }, | ||||
|                           ).expanded, | ||||
|                         ], | ||||
|                       ), | ||||
|                     ), | ||||
|             ) | ||||
|           ], | ||||
|         )); | ||||
|   } | ||||
| 
 | ||||
|   void _search() async { | ||||
|     FocusScope.of(context).unfocus(); | ||||
|     _formKey.currentState!.save(); | ||||
|     _assetInventoryProvider.searchReset(); | ||||
|     showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); | ||||
|     await _assetInventoryProvider.getAssets(search: search, isSearchBy: true, sessionId: widget.sessionId); | ||||
|     setState(() { | ||||
|       _searchableList.clear(); | ||||
|       _searchableList.addAll(_assetInventoryProvider.searchDevices); | ||||
|       _isFirst = false; | ||||
|     }); | ||||
|     Navigator.pop(context); | ||||
|   } | ||||
| 
 | ||||
|   _setValue(value) { | ||||
|     /// todo : check oracle code (no matched parameter) | ||||
|     /// //ontext.translation.assetName, | ||||
|     //       context.translation.model, | ||||
|     //       context.translation.manufacture, | ||||
|     //       context.translation.snNumber, | ||||
|     //       context.translation.siteName, | ||||
|     //       // 'Building Name'.addTranslation, | ||||
|     //       // 'Floor Name'.addTranslation, | ||||
|     //       'Department Name'.addTranslation, | ||||
|     switch (_selectedIndex) { | ||||
|       case 0: | ||||
|         search!.assetName = value; | ||||
|         break; | ||||
|       case 1: | ||||
|         search!.model = value; | ||||
|         break; | ||||
|       case 2: | ||||
|         search!.manufacturer = value; | ||||
|         break; | ||||
|       case 3: | ||||
|         search!.assetSerialNumber = value; | ||||
|         break; | ||||
|       case 4: | ||||
|         search!.site = value; | ||||
|         break; | ||||
|       case 5: | ||||
|         search!.department = value; | ||||
|         break; | ||||
|       default: | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| // bool _showResetButton() { | ||||
| //   return (_searchController?.text?.isNotEmpty ?? false); | ||||
| // } | ||||
| } | ||||
| 
 | ||||
| class InventoryAssetItemListView extends StatelessWidget { | ||||
|   final AssetInventoryModel device; | ||||
|   final Function(AssetInventoryModel) onPressed; | ||||
|   final Widget? selectButton; | ||||
|   final bool isSelected; | ||||
| 
 | ||||
|   const InventoryAssetItemListView({Key? key, required this.device, required this.onPressed, this.selectButton, this.isSelected = false}) : super(key: key); | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Row( | ||||
|       crossAxisAlignment: CrossAxisAlignment.start, | ||||
|       children: [ | ||||
|         Container( | ||||
|           width: 95, | ||||
|           height: 95, | ||||
|           decoration: ShapeDecoration( | ||||
|               color: context.isDark ? AppColor.neutral50 : AppColor.neutral30, | ||||
|               shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), | ||||
|               image: DecorationImage( | ||||
|                 fit: BoxFit.cover, | ||||
|                 image: NetworkImage(device.photo != null ? URLs.getFileUrl(device.photo!)! : "https://www.lasteelcraft.com/images/no-image-available.png"), | ||||
|               )), | ||||
|         ), | ||||
|         15.width, | ||||
|         Column( | ||||
|           mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|           crossAxisAlignment: CrossAxisAlignment.start, | ||||
|           children: [ | ||||
|             Column( | ||||
|               crossAxisAlignment: CrossAxisAlignment.start, | ||||
|               mainAxisSize: MainAxisSize.min, | ||||
|               children: [ | ||||
|                 device.assetName!.cleanupWhitespace.capitalizeFirstOfEach.heading6(context), | ||||
|                 8.height, | ||||
|                 "${context.translation.assetNumber} : ${device.assetNumber}".bodyText(context), | ||||
|                 "${context.translation.modelName} : ${device.model}".cleanupWhitespace.capitalizeFirstOfEach.bodyText(context), | ||||
|               ], | ||||
|             ), | ||||
|             Row( | ||||
|               crossAxisAlignment: CrossAxisAlignment.end, | ||||
|               children: [ | ||||
|                 "${context.translation.serialNo} : ${device.serialNo}".bodyText(context).expanded, | ||||
|                 4.width, | ||||
|                 selectButton ?? | ||||
|                     Row( | ||||
|                       mainAxisSize: MainAxisSize.min, | ||||
|                       children: [ | ||||
|                         Text( | ||||
|                           context.translation.viewDetails, | ||||
|                           style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), | ||||
|                         ), | ||||
|                         4.width, | ||||
|                         Icon( | ||||
|                           Icons.arrow_forward, | ||||
|                           color: AppColor.blueStatus(context), | ||||
|                           size: 14, | ||||
|                         ) | ||||
|                       ], | ||||
|                     ), | ||||
|               ], | ||||
|             ) | ||||
|           ], | ||||
|         ).expanded | ||||
|       ], | ||||
|     ).toShadowContainer(context, padding: 12, borderColor: isSelected ? AppColor.blueStatus(context) : Colors.transparent).onPress(() => onPressed(device)); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,441 @@ | ||||
| import 'dart:convert'; | ||||
| import 'dart:developer'; | ||||
| 
 | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:fluttertoast/fluttertoast.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:test_sa/controllers/api_routes/api_manager.dart'; | ||||
| import 'package:test_sa/controllers/api_routes/urls.dart'; | ||||
| import 'package:test_sa/extensions/context_extension.dart'; | ||||
| import 'package:test_sa/extensions/string_extensions.dart'; | ||||
| import 'package:test_sa/models/device/asset.dart'; | ||||
| import 'package:test_sa/models/device/asset_search.dart'; | ||||
| import 'package:test_sa/models/lookup.dart'; | ||||
| import 'package:test_sa/models/service_request/pending_service_request_model.dart'; | ||||
| import 'package:test_sa/models/service_request/service_report.dart'; | ||||
| import 'package:test_sa/models/service_request/service_request.dart'; | ||||
| import 'package:test_sa/models/service_request/service_request_search.dart'; | ||||
| import 'package:test_sa/models/service_request/spare_parts.dart'; | ||||
| import 'package:test_sa/models/service_request/supp_engineer_work_orders.dart'; | ||||
| import 'package:test_sa/models/service_request/supplier_engineer_model.dart'; | ||||
| import 'package:test_sa/models/timer_model.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; | ||||
| import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; | ||||
| 
 | ||||
| import '../../../models/service_request/search_work_order.dart'; | ||||
| import '../../../models/service_request/wo_call_request.dart'; | ||||
| import '../../../models/user.dart'; | ||||
| import '../../../new_views/common_widgets/app_lazy_loading.dart'; | ||||
| 
 | ||||
| class AssetInventoryProvider extends ChangeNotifier { | ||||
|   final pageItemNumber = 10; | ||||
|   final searchPageItemNumber = 10; | ||||
|   int pageNo = 1; | ||||
|   List<AssetInventoryModel> _devices = []; | ||||
|   List<AssetInventoryModel> _searchDevices = []; | ||||
| 
 | ||||
|   List<AssetInventoryModel> get devices => _devices; | ||||
| 
 | ||||
|   List<AssetInventoryModel> get searchDevices => _searchDevices; | ||||
|   SessionModel? sessionModel; | ||||
| 
 | ||||
|   //TODO need to check i think don't need to create this obj | ||||
|   AssetInventoryResponse? assetInventoryResponse; | ||||
|   AssetInventoryResponse? siteFilterAssetResponse; | ||||
| 
 | ||||
|   List<AssetInventoryModel> sessionAssetList = []; | ||||
|   List<AssetInventoryModel> siteFilterAssetList = []; | ||||
| 
 | ||||
|   void reset() { | ||||
|     pageNo = 1; | ||||
|     assetInventoryResponse = null; | ||||
|     sessionModel = null; | ||||
|     sessionAssetList = []; | ||||
|     stateCode = null; | ||||
|   } | ||||
| 
 | ||||
|   int? stateCode; | ||||
|   bool isDetailLoading = false; | ||||
|   bool nextPage = false; | ||||
|   bool isNextPageLoading = false; | ||||
|   bool isLoading = false; | ||||
|   bool isAllAssetLoading = false; | ||||
| 
 | ||||
|   void searchReset() { | ||||
|     stateCode = null; | ||||
|     _searchDevices = []; | ||||
|   } | ||||
| 
 | ||||
|   Future<void> getSessionById({required int id}) async { | ||||
|     try { | ||||
|       sessionModel = SessionModel(); | ||||
|       isLoading = true; | ||||
|       notifyListeners(); | ||||
|       final response = await ApiManager.instance.get(URLs.getAssetInventoryById + "?assetInventoryId=$id"); | ||||
|       stateCode = response.statusCode; | ||||
|       if (response.statusCode >= 200 && response.statusCode < 300) { | ||||
|         sessionModel = SessionModel.fromJson(json.decode(response.body)["data"]); | ||||
|       } else { | ||||
|         sessionModel = null; | ||||
|       } | ||||
| 
 | ||||
|       isLoading = false; | ||||
|       notifyListeners(); | ||||
|     } catch (e) { | ||||
|       log("getSessionError [error] : $e"); | ||||
|       isLoading = false; | ||||
|       sessionModel = null; | ||||
|       notifyListeners(); | ||||
|       return null; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   Future<int> getAssetsInSession({ | ||||
|     required int sessionId, | ||||
|     bool loadMore = false, | ||||
|   }) async { | ||||
|     if (isLoading || isNextPageLoading) return -2; | ||||
|     if (loadMore) { | ||||
|       isNextPageLoading = true; | ||||
|       pageNo += 1; | ||||
|     } else { | ||||
|       isLoading = true; | ||||
|       pageNo = 1; // reset pagination | ||||
|     } | ||||
|     notifyListeners(); | ||||
|     try { | ||||
|       final payload = { | ||||
|         "pageSize": pageItemNumber, | ||||
|         "pageNumber": pageNo, | ||||
|         "sessionId": sessionId, | ||||
|       }; | ||||
|       final response = await ApiManager.instance.post(URLs.getAssetsInSession, body: payload); | ||||
|       stateCode = response.statusCode; | ||||
|       if (response.statusCode >= 200 && response.statusCode < 300) { | ||||
|         final Map<String, dynamic> jsonData = json.decode(response.body); | ||||
|         final newResponse = AssetInventoryResponse.fromJson(jsonData); | ||||
| 
 | ||||
|         if (loadMore) { | ||||
|           assetInventoryResponse?.assetList?.addAll(newResponse.assetList ?? []); | ||||
|           assetInventoryResponse?.totalRows = newResponse.totalRows; | ||||
|         } else { | ||||
|           assetInventoryResponse = newResponse; | ||||
|         } | ||||
|         nextPage = (assetInventoryResponse?.assetList?.length ?? 0) < (assetInventoryResponse?.totalRows ?? 0); | ||||
|       } else { | ||||
|         nextPage = false; | ||||
|       } | ||||
|       isLoading = false; | ||||
|       isNextPageLoading = false; | ||||
|       notifyListeners(); | ||||
|       return response.statusCode; | ||||
|     } catch (error) { | ||||
|       isLoading = false; | ||||
|       isNextPageLoading = false; | ||||
|       stateCode = -1; | ||||
|       nextPage = false; | ||||
|       notifyListeners(); | ||||
|       return -1; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   ///older code | ||||
|   // Future<int> getAssetsInSession({ | ||||
|   //   required int sessionId, | ||||
|   //   bool loadMore = false, | ||||
|   // }) async { | ||||
|   //   // if (isLoading || nextPage) return -2; | ||||
|   // | ||||
|   //   if (loadMore) { | ||||
|   //     nextPage = true; | ||||
|   //     pageNo += 1; | ||||
|   //   } else { | ||||
|   //     isLoading = true; | ||||
|   //     pageNo = 1; // reset pagination | ||||
|   //   } | ||||
|   // | ||||
|   //   notifyListeners(); | ||||
|   //   log('Fetching page: $pageNo'); | ||||
|   // | ||||
|   //   try { | ||||
|   //     final payload = { | ||||
|   //       "pageSize": pageItemNumber, | ||||
|   //       "pageNumber": pageNo, | ||||
|   //       "sessionId": sessionId, | ||||
|   //     }; | ||||
|   // | ||||
|   //     final response = await ApiManager.instance.post(URLs.getAssetsInSession, body: payload); | ||||
|   //     stateCode = response.statusCode; | ||||
|   // | ||||
|   //     if (response.statusCode >= 200 && response.statusCode < 300) { | ||||
|   //       final Map<String, dynamic> jsonData = json.decode(response.body); | ||||
|   //       final newResponse = AssetInventoryResponse.fromJson(jsonData); | ||||
|   // | ||||
|   //       if (loadMore) { | ||||
|   //         assetInventoryResponse?.assetList?.addAll(newResponse.assetList ?? []); | ||||
|   //         assetInventoryResponse?.totalRows = newResponse.totalRows; | ||||
|   //       } else { | ||||
|   //         assetInventoryResponse = newResponse; | ||||
|   //       } | ||||
|   // | ||||
|   //       nextPage = (assetInventoryResponse?.assetList?.length ?? 0) < (assetInventoryResponse?.totalRows ?? 0); | ||||
|   //     } | ||||
|   // | ||||
|   //     isLoading = false; | ||||
|   //     nextPage = false; | ||||
|   //     notifyListeners(); | ||||
|   //     return response.statusCode; | ||||
|   //   } catch (error) { | ||||
|   //     isLoading = false; | ||||
|   //     nextPage = false; | ||||
|   //     stateCode = -1; | ||||
|   //     notifyListeners(); | ||||
|   //     return -1; | ||||
|   //   } | ||||
|   // } | ||||
| 
 | ||||
|   Future<int> getInventoryDetailsByFilter({ | ||||
|     required Map<String, dynamic> payload, | ||||
|     bool loadMore = false, | ||||
|   }) async { | ||||
|     if (isLoading || isNextPageLoading) return -2; | ||||
| 
 | ||||
|     if (loadMore) { | ||||
|       isNextPageLoading = true; | ||||
|       pageNo += 1; | ||||
|     } else { | ||||
|       isLoading = true; | ||||
|       pageNo = 1; | ||||
|     } | ||||
| 
 | ||||
|     notifyListeners(); | ||||
|     log('Fetching inventory page: $pageNo'); | ||||
| 
 | ||||
|     try { | ||||
|       final paginatedPayload = { | ||||
|         ...payload, | ||||
|         "pageSize": pageItemNumber, | ||||
|         "pageNumber": pageNo, | ||||
|       }; | ||||
| 
 | ||||
|       final response = await ApiManager.instance.post(URLs.getInventoryDetailsByFilter, body: paginatedPayload); | ||||
|       stateCode = response.statusCode; | ||||
| 
 | ||||
|       if (response.statusCode >= 200 && response.statusCode < 300) { | ||||
|         final Map<String, dynamic> jsonData = json.decode(response.body); | ||||
|         final newResponse = AssetInventoryResponse.fromJson(jsonData); | ||||
| 
 | ||||
|         if (loadMore) { | ||||
|           siteFilterAssetList.addAll(newResponse.assetList ?? []); | ||||
|           siteFilterAssetResponse?.totalRows = newResponse.totalRows; | ||||
|         } else { | ||||
|           siteFilterAssetResponse = newResponse; | ||||
|           siteFilterAssetList = newResponse.assetList ?? []; | ||||
|         } | ||||
|         nextPage = (siteFilterAssetList.length) < (siteFilterAssetResponse?.totalRows ?? 0); | ||||
|       } else { | ||||
|         siteFilterAssetList = []; | ||||
|         nextPage = false; | ||||
|       } | ||||
| 
 | ||||
|       isLoading = false; | ||||
|       isNextPageLoading = false; | ||||
|       notifyListeners(); | ||||
|       return response.statusCode; | ||||
|     } catch (error) { | ||||
|       isLoading = false; | ||||
|       isNextPageLoading = false; | ||||
|       nextPage = false; | ||||
|       stateCode = -1; | ||||
|       notifyListeners(); | ||||
|       return -1; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   Future<AssetInventoryModel?> searchAsset({ | ||||
|     required Map<String, dynamic> payload, | ||||
|   }) async { | ||||
|     isLoading = true; | ||||
|     try { | ||||
|       final response = await ApiManager.instance.post(URLs.searchAsset, body: payload); | ||||
|       stateCode = response.statusCode; | ||||
|       if (response.statusCode >= 200 && response.statusCode < 300) { | ||||
|         final Map<String, dynamic> jsonData = json.decode(response.body)["data"]; | ||||
|         AssetInventoryModel model = AssetInventoryModel.fromJson(jsonData); | ||||
|         log('model json ${model.toJson()}'); | ||||
|         isLoading = false; | ||||
|         notifyListeners(); | ||||
|         return model; | ||||
|       } else { | ||||
|         isLoading = false; | ||||
|         notifyListeners(); | ||||
|         return null; | ||||
|       } | ||||
|     } catch (error) { | ||||
|       isLoading = false; | ||||
|       stateCode = -1; | ||||
|       notifyListeners(); | ||||
|       return null; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   Future<bool> saveAssetInSession({ | ||||
|     AssetInventoryModel? model, | ||||
|   }) async { | ||||
|     isLoading = true; | ||||
|     try { | ||||
|       log('payload i got is ${model?.toJson()}'); | ||||
|       final response = await ApiManager.instance.post(URLs.saveAssetInSession, body: model?.toJson() ?? {}); | ||||
|       stateCode = response.statusCode; | ||||
|       if (response.statusCode >= 200 && response.statusCode < 300) { | ||||
|         isLoading = false; | ||||
|         notifyListeners(); | ||||
|         return true; | ||||
|       } else { | ||||
|         isLoading = false; | ||||
|         notifyListeners(); | ||||
|         return false; | ||||
|       } | ||||
|     } catch (error) { | ||||
|       isLoading = false; | ||||
|       notifyListeners(); | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   Future<bool> deleteAssetISession({required num id}) async { | ||||
|     try { | ||||
|       isLoading = true; | ||||
|       notifyListeners(); | ||||
|       final response = await ApiManager.instance.get(URLs.deleteAssetInSession + "?id=$id"); | ||||
|       stateCode = response.statusCode; | ||||
|       if (response.statusCode >= 200 && response.statusCode < 300) { | ||||
|         isLoading = false; | ||||
|         notifyListeners(); | ||||
|         return true; | ||||
|       } | ||||
|       isLoading = false; | ||||
|       notifyListeners(); | ||||
|       return false; | ||||
|     } catch (e) { | ||||
|       log("Delete Asset [error] : $e"); | ||||
|       isLoading = false; | ||||
|       notifyListeners(); | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   Future<List<Lookup>> getAutoCompleteDetails({ | ||||
|     bool? isManufacturer, | ||||
|     String? query, | ||||
|     int type = 0, | ||||
|   }) async { | ||||
|     try { | ||||
|       String url = ''; | ||||
|       switch (type) { | ||||
|         //for model and manufacturer.. | ||||
|         case 0: | ||||
|           url = URLs.getManufacturerOrModelAutoComplete; | ||||
|           break; | ||||
|         //for asset name.. | ||||
|         case 1: | ||||
|           url = URLs.searchAssetName; | ||||
|           break; | ||||
|         //for supplier... | ||||
|         case 2: | ||||
|           url = URLs.getSuppliersAutoCompleteInventory; | ||||
|           break; | ||||
|         default: | ||||
|           url = URLs.getManufacturerOrModelAutoComplete; | ||||
|       } | ||||
|       final queryParams = <String, String>{}; | ||||
|       if (isManufacturer != null && type == 0) { | ||||
|         queryParams['isManufacturer'] = isManufacturer.toString(); | ||||
|       } | ||||
|       if (query != null && query.isNotEmpty) { | ||||
|         queryParams['searchText'] = query; | ||||
|       } | ||||
|       if (queryParams.isNotEmpty) { | ||||
|         url += '?${Uri(queryParameters: queryParams).query}'; | ||||
|       } | ||||
|       final response = await ApiManager.instance.get(url); | ||||
| 
 | ||||
|       List<Lookup> list = []; | ||||
|       if (response.statusCode >= 200 && response.statusCode < 300) { | ||||
|         final data = json.decode(response.body)["data"]; | ||||
|         list = (data as List).map((e) => Lookup.fromJson(e)).toList(); | ||||
|       } | ||||
|       return list; | ||||
|     } catch (error) { | ||||
|       log('error $error'); | ||||
|       return []; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   Future<int> getAssets({DeviceSearch? search, bool isQr = false, bool isSearchBy = false, num? sessionId}) async { | ||||
|     if (isLoading == true) return -2; | ||||
|     isLoading = true; | ||||
|     notifyListeners(); | ||||
|     late Response response; | ||||
|     try { | ||||
|       final Map<String, dynamic> body = { | ||||
|         "pageSize": isSearchBy ? searchPageItemNumber : pageItemNumber, | ||||
|         "pageNumber": isSearchBy ? (searchDevices.length / searchPageItemNumber).ceil() + 1 : devices.length ~/ pageItemNumber + 1, | ||||
|         "sessionId": sessionId ?? 0, | ||||
|         "assetSerialNo": search?.assetSerialNumber ?? '', | ||||
|         "assetName": search?.assetName ?? '', | ||||
|         "model": search?.model ?? '', | ||||
|         "manufacturer": search?.manufacturer ?? '', | ||||
|         "supplier": search?.supplier ?? '', | ||||
|         "siteName": search?.site ?? '', | ||||
|         // "buildingName":search?.??'', | ||||
|         // "floorName": search?.f??'', | ||||
|         "departmentName": search?.department ?? '', | ||||
|         // "roomName": search?.room | ||||
|       }; | ||||
|       // if (search != null) body.addAll(search.toJson()); | ||||
|       response = await ApiManager.instance.post(URLs.getAssetsTemp, body: body); | ||||
|     } catch (error) { | ||||
|       isLoading = false; | ||||
|       stateCode = -1; | ||||
|       notifyListeners(); | ||||
|       return -1; | ||||
|     } | ||||
|     stateCode = response.statusCode; | ||||
|     if (response.statusCode >= 200 && response.statusCode < 300) { | ||||
|       // client's request was successfully received | ||||
|       List equipmentListJson = json.decode(response.body)["data"]; | ||||
|       var dList = equipmentListJson.map<AssetInventoryModel>((asset) => AssetInventoryModel.fromJson(asset)).toList() ?? []; | ||||
|       isSearchBy ? _searchDevices.addAll(dList) : _devices.addAll(dList); | ||||
|       nextPage = true; | ||||
|     } else { | ||||
|       nextPage = false; | ||||
|     } | ||||
|     isLoading = false; | ||||
|     notifyListeners(); | ||||
|     return response.statusCode; | ||||
|   } | ||||
| 
 | ||||
|   Future<bool> markAsComplete({ | ||||
|     required Map<String, dynamic> payload, | ||||
|   }) async { | ||||
|     isLoading = true; | ||||
|     try { | ||||
|       final response = await ApiManager.instance.post(URLs.convertDetailToComplete, body: payload); | ||||
|       stateCode = response.statusCode; | ||||
|       if (response.statusCode >= 200 && response.statusCode < 300) { | ||||
|         isLoading = false; | ||||
|         notifyListeners(); | ||||
|         return true; | ||||
|       } else { | ||||
|         isLoading = false; | ||||
|         notifyListeners(); | ||||
|         return false; | ||||
|       } | ||||
|     } catch (error) { | ||||
|       isLoading = false; | ||||
|       notifyListeners(); | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
| } | ||||
					Loading…
					
					
				
		Reference in New Issue