diff --git a/lib/common_widgets/autocomplete_generic_field.dart b/lib/common_widgets/autocomplete_generic_field.dart deleted file mode 100644 index b812efe8..00000000 --- a/lib/common_widgets/autocomplete_generic_field.dart +++ /dev/null @@ -1,144 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:test_sa/extensions/int_extensions.dart'; -import 'package:test_sa/extensions/text_extensions.dart'; -import 'package:test_sa/new_views/app_style/app_color.dart'; -import 'package:test_sa/views/app_style/sizing.dart'; - -class AutoCompleteGenericField extends StatefulWidget { - final String? label; - final String initialValue; - final bool clearAfterPick; - final Future> Function(String query) onSearch; - final String Function(T item) displayString; - final Function(T item) onPick; - - const AutoCompleteGenericField({ - Key? key, - this.label, - required this.initialValue, - required this.onSearch, - required this.displayString, - required this.onPick, - this.clearAfterPick = true, - }) : super(key: key); - - @override - State> createState() => _AutoCompleteGenericFieldState(); -} - -class _AutoCompleteGenericFieldState extends State> { - late TextEditingController _controller; - List _options = []; - bool _isLoading = false; - - @override - void initState() { - _controller = TextEditingController(text: widget.initialValue); - super.initState(); - } - - @override - void didUpdateWidget(covariant AutoCompleteGenericField oldWidget) { - if (widget.initialValue != oldWidget.initialValue) { - _controller.text = widget.initialValue; - } - super.didUpdateWidget(oldWidget); - } - - Future _search(String query) async { - if (query.isEmpty) { - setState(() => _options = []); - return; - } - setState(() => _isLoading = true); - try { - final results = await widget.onSearch(query); - setState(() => _options = results); - } finally { - setState(() => _isLoading = false); - } - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext 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)), - ), - child: RawAutocomplete( - // textEditingController: _controller, - optionsBuilder: (TextEditingValue textEditingValue) => _options, - displayStringForOption: widget.displayString, - fieldViewBuilder: (context, fieldTextEditingController, fieldFocusNode, 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), - // suffixIcon: _isLoading - // ? const Padding( - // padding: EdgeInsets.all(8.0), - // child: SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2)), - // ) - // : const Icon(Icons.search, size: 18), - filled: true, - fillColor: AppColor.fieldBgColor(context), - labelText: widget.label, - labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)), - ), - textInputAction: TextInputAction.search, - onChanged: (text) => _search(text), - onSubmitted: (_) => onFieldSubmitted(), - ); - }, - onSelected: (T selection) { - if (widget.clearAfterPick) { - _controller.clear(); - } else { - _controller.text = widget.displayString(selection); - } - widget.onPick(selection); - }, - optionsViewBuilder: (context, onSelected, options) { - return Align( - alignment: Alignment.topLeft, - child: Material( - elevation: 4, - borderRadius: BorderRadius.circular(10), - child: ConstrainedBox( - constraints: const BoxConstraints(maxHeight: 200, minWidth: 200), - child: ListView.builder( - padding: EdgeInsets.zero, - itemCount: options.length, - itemBuilder: (context, index) { - final option = options.elementAt(index); - return ListTile( - title: Text(widget.displayString(option)), - onTap: () => onSelected(option), - ); - }, - ), - ), - ), - ); - }, - ), - ); - } -} diff --git a/lib/common_widgets/lookup_autocomplete_field.dart b/lib/common_widgets/lookup_autocomplete_field.dart new file mode 100644 index 00000000..8b296a7d --- /dev/null +++ b/lib/common_widgets/lookup_autocomplete_field.dart @@ -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 { + 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(context); + final border = UnderlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(10)); + return Container( + decoration: BoxDecoration( + color: AppColor.background(context), + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], + ), + child: Autocomplete( + optionsBuilder: (TextEditingValue textEditingValue) async { + if (textEditingValue.text.isEmpty) { + return const Iterable.empty(); + } + return (await 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); + }, + ), + ); + } +} diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 5b82e823..d74444a1 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -298,7 +298,24 @@ class URLs { // asset inventory Urls. static get getAssetInventoryById => '$_baseUrl/AssetInventory/GetAssetInventoryById'; + static get getAssetsInSession => '$_baseUrl/AssetInventory/GetAssetsInSeassion'; + static get getInventoryDetailsByFilter => '$_baseUrl/AssetInventory/GetInventoryDetailsByFilter'; + static get searchAsset => '$_baseUrl/AssetInventory/SearchAsset'; + + static get saveAssetInSession => '$_baseUrl/AssetInventory/SaveAssetInSession'; + + static get deleteAssetInSession => '$_baseUrl/AssetInventory/DeleteAssetInSession'; + + static get getManufacturerOrModelAutoComplete => '$_baseUrl/AssetInventory/GetManufacturerOrModelAutoComplete'; + + static get searchAssetName => '$_baseUrl/AssetInventory/SearchAssetName'; + + static get getSuppliersAutoCompleteInventory => '$_baseUrl/Supplier/GetSuppliersMobile'; + + static get getAssetsTemp => '$_baseUrl/AssetInventory/GetAssetsTemp'; + + static get convertDetailToComplete => '$_baseUrl/AssetInventory/ConvertDetailToComplete'; } diff --git a/lib/controllers/providers/api/gas_refill_comments.dart b/lib/controllers/providers/api/gas_refill_comments.dart index 71e85f01..b40d44e4 100644 --- a/lib/controllers/providers/api/gas_refill_comments.dart +++ b/lib/controllers/providers/api/gas_refill_comments.dart @@ -48,7 +48,6 @@ class GasRefillCommentsProvider extends ChangeNotifier { late Response response; try { response = await ApiManager.instance.get(URLs.getGazRefillComments + "?gasRefillId=$callId"); - stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { List requestsListJson = json.decode(response.body)["data"]; diff --git a/lib/models/all_requests_and_count_model.dart b/lib/models/all_requests_and_count_model.dart index 511ece33..e980e164 100644 --- a/lib/models/all_requests_and_count_model.dart +++ b/lib/models/all_requests_and_count_model.dart @@ -123,11 +123,14 @@ class RequestsDetails { String? statusReceiver; String? assetTransferFrom; String? assetTransferTo; + String? sessionType; String? code; String? date; String? siteTransferFrom; String? siteTransferTo; int? transactionType; + int? numberOfAssets; + int? numberOfSites; RequestsDetails( {this.id, @@ -142,6 +145,9 @@ class RequestsDetails { this.manufacturer, this.requestType, this.requestNo, + this.numberOfAssets, + this.numberOfSites, + this.sessionType, this.gasType, this.site, this.statusReceiver, @@ -165,6 +171,9 @@ class RequestsDetails { supplier = json['supplier']; manufacturer = json['manufacturer']; requestType = json['requestType']; + sessionType = json['sessionType']; + numberOfAssets = json['numberOfAssets']; + numberOfSites = json['numberOfSites']; requestNo = json['requestNo']; gasType = json['gasType']; site = json['site']; @@ -197,6 +206,9 @@ class RequestsDetails { data['statusReceiver'] = statusReceiver; data['assetTransferFrom'] = assetTransferFrom; data['assetTransferTo'] = assetTransferTo; + data['sessionType'] = sessionType; + data['numberOfSites'] = numberOfSites; + data['numberOfAssets'] = numberOfAssets; data['code'] = code; data['date'] = date; data['siteTransferFrom'] = siteTransferFrom; diff --git a/lib/models/device/asset.dart b/lib/models/device/asset.dart index 9473cfcc..1e41dc31 100644 --- a/lib/models/device/asset.dart +++ b/lib/models/device/asset.dart @@ -142,11 +142,11 @@ class Asset { Building? building; // Now nullable Floor? floor; // Now nullable Department? department; // Now nullable + Rooms? room; MappedSite? mappedSite; // Now nullable MappedBuilding? mappedBuilding; // Now nullable MappedFloor? mappedFloor; // Now nullable - MappedDepartment? mappedDepartment; // No - Rooms? room; // Now nullable + MappedDepartment? mappedDepartment; // num? testsDay; // Now nullable num? purchasingPrice; // Now nullable String? nbv; // Now nullable diff --git a/lib/models/new_models/dashboard_detail.dart b/lib/models/new_models/dashboard_detail.dart index 3773dc64..093019b2 100644 --- a/lib/models/new_models/dashboard_detail.dart +++ b/lib/models/new_models/dashboard_detail.dart @@ -50,17 +50,34 @@ class Data { String? priorityName; bool? isHighPriority; String? assetName; + String? sessionType; String? rejectReason; String? assetNumber; String? requestTypeName; String? requestNo; int? transactionNo; + int? numberOfSites; + int? numberOfAssets; String? nameOfType; - Data({this.id, this.typeTransaction, this.nameOfType,this.transactionDate, this.statusName, this.priorityName, this.isHighPriority, this.assetName, this.assetNumber, this.requestTypeName, this.requestNo,this.transactionNo}); + Data( + {this.id, + this.typeTransaction, + this.nameOfType, + this.transactionDate, + this.statusName, + this.numberOfAssets, + this.numberOfSites, + this.sessionType, + this.priorityName, + this.isHighPriority, + this.assetName, + this.assetNumber, + this.requestTypeName, + this.requestNo, + this.transactionNo}); Data.fromJson(Map json) { - id = json['id']; typeTransaction = json['typeTransaction']; transactionDate = json['transactionDate']; @@ -68,6 +85,9 @@ class Data { priorityName = json['priorityName']; isHighPriority = json['isHighPriority']; assetName = json['assetName']; + sessionType = json['sessionType']; + numberOfSites = json['numberOfSites']; + numberOfAssets = json['numberOfAssets']; assetNumber = json['assetNumber']; requestTypeName = json['requestTypeName']; requestNo = json['requestNo']; @@ -90,6 +110,9 @@ class Data { data['requestNo'] = requestNo; data['rejectReason'] = rejectReason; data['transactionNo'] = transactionNo; + data['sessionType'] = sessionType; + data['numberOfAssets'] = numberOfAssets; + data['numberOfSites'] = numberOfSites; data['nameOfType'] = nameOfType; return data; } diff --git a/lib/modules/asset_inventory_module/models/asset_inventory_model.dart b/lib/modules/asset_inventory_module/models/asset_inventory_model.dart index 5ed9a0d7..0498b95a 100644 --- a/lib/modules/asset_inventory_module/models/asset_inventory_model.dart +++ b/lib/modules/asset_inventory_module/models/asset_inventory_model.dart @@ -1,3 +1,12 @@ +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; @@ -28,9 +37,7 @@ class AssetInventoryResponse { responseCode = json['responseCode']; isSuccess = json['isSuccess']; if (json['data'] != null) { - assetList = (json['data'] as List) - .map((item) => AssetInventoryModel.fromJson(item)) - .toList(); + assetList = (json['data'] as List).map((item) => AssetInventoryModel.fromJson(item)).toList(); } } @@ -43,7 +50,6 @@ class AssetInventoryResponse { 'innerMessage': innerMessage, 'responseCode': responseCode, 'isSuccess': isSuccess, - // assetList not needed in toJson because you’ll likely only send AssetInventoryModel for updates }; } } @@ -54,68 +60,69 @@ class AssetInventoryModel { String? assetNumber; String? serialNo; String? assetName; + num? assetNameId; String? model; String? manufacturer; String? supplierName; - String? site; - String? building; - String? floor; - String? department; - String? room; + 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? oldAssetNumber; String? newAssetNumber; - String? oldSerialNo; String? newSerialNo; - num? oldAssetNameId; num? newAssetNameId; String? newAssetNameText; - num? oldModelId; num? newModelId; String? newModelName; - num? oldManufacturerId; + num? manufacturerId; + num? modelId; num? newManufacturerId; String? newManufacturerName; - num? oldSupplierId; num? newSupplierId; String? newSupplierName; String? photo; String? photoOriginName; String? remarks; - num? oldSiteId; - num? oldBuildingId; - num? oldFloorId; - num? oldDepartmentId; - num? oldRoomId; + + 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.site, - this.building, - this.floor, - this.department, - this.room, + this.siteName, + this.buildingName, + this.floorName, + this.departmentName, + this.roomName, this.statusId, this.status, this.statusValue, @@ -123,92 +130,79 @@ class AssetInventoryModel { this.statusByAdmin, this.statusByAdminValue, this.isNotRegistered, - this.sessionId, this.assetImportId, this.siteId, this.buildingId, this.floorId, this.departmentId, + this.supplierId, this.roomId, - this.oldAssetNumber, this.newAssetNumber, - this.oldSerialNo, + this.manufacturerId, this.newSerialNo, - this.oldAssetNameId, this.newAssetNameId, this.newAssetNameText, - this.oldModelId, this.newModelId, + this.modelId, this.newModelName, - this.oldManufacturerId, this.newManufacturerId, this.newManufacturerName, - this.oldSupplierId, this.newSupplierId, this.newSupplierName, this.photo, this.photoOriginName, this.remarks, - this.oldSiteId, - this.oldBuildingId, - this.oldFloorId, - this.oldDepartmentId, - this.oldRoomId, + this.site, + this.department, + this.building, + this.floor, + this.room, + this.supplier, }); AssetInventoryModel.fromJson(Map json) { id = json['id']; assetId = json['assetId']; assetNumber = json['assetNumber']; + assetNameId = json['assetNameId']; serialNo = json['serialNo']; assetName = json['assetName']; - model = json['model']; - manufacturer = json['manufacturer']; + model = json['model'] ?? json['modelName']; + manufacturer = json['manufacturer'] ?? json['manufacturerName']; supplierName = json['supplierName']; - site = json['site']; - building = json['building']; - floor = json['floor']; - department = json['department']; - room = json['room']; + 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']; + status = json['status'] ?? json['classification']; statusValue = json['statusValue']; - statusByAdminId = json['statusByAdminId']; - statusByAdmin = json['statusByAdmin']; - statusByAdminValue = json['statusByAdminValue']; - isNotRegistered = json['isNotRegistered']; sessionId = json['sessionId']; - assetImportId = json['assetImportId']; + assetImportId = json['assetImportId']??json['id']; siteId = json['siteId']; buildingId = json['buildingId']; floorId = json['floorId']; + supplierId = json['supplierId']; departmentId = json['departmentId']; roomId = json['roomId']; - oldAssetNumber = json['oldAssetNumber']; - newAssetNumber = json['newAssetNumber']; - oldSerialNo = json['oldSerialNo']; - newSerialNo = json['newSerialNo']; - oldAssetNameId = json['oldAssetNameId']; - newAssetNameId = json['newAssetNameId']; - newAssetNameText = json['newAssetNameText']; - oldModelId = json['oldModelId']; - newModelId = json['newModelId']; - newModelName = json['newModelName']; - oldManufacturerId = json['oldManufacturerId']; - newManufacturerId = json['newManufacturerId']; - newManufacturerName = json['newManufacturerName']; - oldSupplierId = json['oldSupplierId']; - newSupplierId = json['newSupplierId']; - newSupplierName = json['newSupplierName']; + modelId = json['modelId']; photo = json['photo']; photoOriginName = json['photoOriginName']; remarks = json['remarks']; - oldSiteId = json['oldSiteId']; - oldBuildingId = json['oldBuildingId']; - oldFloorId = json['oldFloorId']; - oldDepartmentId = json['oldDepartmentId']; - oldRoomId = json['oldRoomId']; + //new data.. + // newAssetNumber = json['newAssetNumber'] ?? json['assetNumber']; + // manufacturerId = json['manufacturerId'] ?? json['manufacturerId']; + // newSerialNo = json['newSerialNo'] ?? json['serialNo']; + // newAssetNameId = json['newAssetNameId'] ?? json['assetNameId']; + // newAssetNameText = json['newAssetNameText'] ?? json['assetNameText']; + // newModelId = json['newModelId'] ?? json['modelId']; + // newModelName = json['newModelName'] ?? json['modelName']; + // newManufacturerId = json['newManufacturerId'] ?? json['manufacturerId']; + // newManufacturerName = json['newManufacturerName'] ?? json['manufacturerName']; + // newSupplierId = json['newSupplierId'] ?? json['supplierId']; + // newSupplierName = json['newSupplierName'] ?? json['supplierName']; } Map toJson() { @@ -222,30 +216,76 @@ class AssetInventoryModel { 'floorId': floorId, 'departmentId': departmentId, 'roomId': roomId, - 'oldAssetNumber': oldAssetNumber, - 'newAssetNumber': newAssetNumber, - 'oldSerialNo': oldSerialNo, 'newSerialNo': newSerialNo, - 'oldAssetNameId': oldAssetNameId, 'newAssetNameId': newAssetNameId, 'newAssetNameText': newAssetNameText, - 'oldModelId': oldModelId, 'newModelId': newModelId, 'newModelName': newModelName, - 'oldManufacturerId': oldManufacturerId, 'newManufacturerId': newManufacturerId, 'newManufacturerName': newManufacturerName, - 'oldSupplierId': oldSupplierId, 'newSupplierId': newSupplierId, 'newSupplierName': newSupplierName, 'photo': photo, - 'photoOriginName': photoOriginName, 'remarks': remarks, - 'oldSiteId': oldSiteId, - 'oldBuildingId': oldBuildingId, - 'oldFloorId': oldFloorId, - 'oldDepartmentId': oldDepartmentId, - 'oldRoomId': oldRoomId, }; } + + 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, + ); + } + + } diff --git a/lib/modules/asset_inventory_module/models/session_model.dart b/lib/modules/asset_inventory_module/models/session_model.dart index c758628c..e65e192c 100644 --- a/lib/modules/asset_inventory_module/models/session_model.dart +++ b/lib/modules/asset_inventory_module/models/session_model.dart @@ -5,6 +5,7 @@ class SessionModel { int? id; String? sessionName; int? sessionTypeId; + int? sessionTypeValue; String? sessionTypeName; int? statusId; String? statusName; @@ -17,6 +18,7 @@ class SessionModel { this.id, this.sessionName, this.sessionTypeId, + this.sessionTypeValue, this.sessionTypeName, this.statusId, this.statusName, @@ -33,6 +35,7 @@ class SessionModel { id = json['id']; sessionName = json['sessionName']; sessionTypeId = json['sessionTypeId']; + sessionTypeValue = json['sessionTypeValue']; sessionTypeName = json['sessionTypeName']; statusId = json['statusId']; statusName = json['statusName']; @@ -53,6 +56,7 @@ class SessionModel { map['id'] = id; map['sessionName'] = sessionName; map['sessionTypeId'] = sessionTypeId; + map['sessionTypeValue'] = sessionTypeValue; map['sessionTypeName'] = sessionTypeName; map['statusId'] = statusId; map['statusName'] = statusName; diff --git a/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart b/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart index 87a54e82..29769f79 100644 --- a/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart +++ b/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart @@ -1,3 +1,5 @@ +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'; @@ -11,10 +13,12 @@ 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 @@ -30,6 +34,10 @@ class AssetDetailCardView extends StatelessWidget { style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ), // 8.height, + 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), @@ -43,11 +51,19 @@ class AssetDetailCardView extends StatelessWidget { style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - '${context.translation.site}: ${assetInventoryModel.site ?? ''}', + '${context.translation.site}: ${assetInventoryModel.siteName ?? ''}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - '${context.translation.department}: ${assetInventoryModel.department ?? ''}', + '${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( @@ -64,19 +80,9 @@ class AssetDetailCardView extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.start, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 'edit_icon'.toSvgAsset().onPress(() { - //Handle edit... - }), - 20.width, - 'delete_icon'.toSvgAsset().onPress(() { - //handle delete.. - }) - ], - ), + 'delete_icon'.toSvgAsset().onPress(() { + onDeletePress(); + }), 20.height, Container( decoration: BoxDecoration(color: AppColor.neutral100, borderRadius: BorderRadius.circular(15)), diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart index 23ed3789..2440bbf6 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart @@ -1,81 +1,82 @@ +import 'dart:convert'; +import 'dart:developer'; import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; -import 'package:test_sa/common_widgets/autocomplete_generic_field.dart'; +import 'package:flutter_advanced_switch/flutter_advanced_switch.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/common_widgets/lookup_autocomplete_field.dart'; +import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/device/asset.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; -import 'package:test_sa/models/service_request/spare_parts.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/providers/work_order/vendor_provider.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 '../../../new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'asset_inventory_site_information_view.dart'; class AssetInventoryFormView extends StatefulWidget { static const String id = "/asset-inventory-form"; - // TODO need to use only one model AssetInventoryModel everywhere after completing flow . - Asset ? assetLocation; + AssetInventoryModel? assetInventoryModel; + int? sessionTypeValue; - AssetInventoryFormView({Key? key,this.assetLocation}) : super(key: key); + AssetInventoryFormView({Key? key, this.assetInventoryModel, this.sessionTypeValue}) : super(key: key); @override State createState() => _AssetInventoryFormViewState(); } class _AssetInventoryFormViewState extends State { - final AssetInventoryModel _assetInventoryModel = AssetInventoryModel(); + AssetInventoryModel? _scannedAssetModel = AssetInventoryModel(); + AssetInventoryModel? _pickedAssetModel = AssetInventoryModel(); final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); - Asset? _pickedAsset; + final TextEditingController _assetNoController = TextEditingController(); + final TextEditingController _serialNoController = TextEditingController(); + final TextEditingController _remarksController = TextEditingController(); + ValueNotifier? registeredController; + bool isRegistered = false; - final List attachments = []; + // TextEditingController _assetModelController = TextEditingController(); + // TextEditingController _assetManufacturerController = TextEditingController(); + // TextEditingController _assetSupplierController = TextEditingController(); - void _onSubmit() async { - _assetInventoryModel.assetId = _pickedAsset?.id; - _assetInventoryModel.oldSiteId = widget.assetLocation?.site?.id; - _assetInventoryModel.oldBuildingId = widget.assetLocation?.building?.id; - _assetInventoryModel.oldFloorId = widget.assetLocation?.floor?.id; - _assetInventoryModel.oldDepartmentId = widget.assetLocation?.department?.id; - _assetInventoryModel.oldRoomId = widget.assetLocation?.room?.id; + final List attachments = []; - if (!_formKey.currentState!.validate() || !(await validateRequest())) { - return; - } - _formKey.currentState!.save(); - //TODO need to confirm attachment structure and final api calling . - // List attachement = []; - // for (var item in attachments) { - // String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - // attachement.add(AssetTransferAttachment(id: item.id, attachmentName: fileName)); - // } - // _assetInventoryModel.attachments = attachement; - // await _deviceTransferProvider.createRequest( - // context: context, - // model: _transferModel, - // ); - // if (_deviceTransferProvider.stateCode == 200) { - // DashBoardProvider dashBoardProvider = Provider.of(context, listen: false); - // dashBoardProvider.refreshDashboard(context: context, userType: UsersTypes.nurse); - // } + @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 @@ -94,147 +95,206 @@ class _AssetInventoryFormViewState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - AssetPicker( - device: _pickedAsset, - showLoading: false, - labelColor: AppColor.white936, - iconColor: AppColor.neutral120, - label: 'Scan Asset'.addTranslation, - borderColor: AppColor.white936, - buttonColor: Colors.white, - showBorder: true, - onPick: (asset) async { - _pickedAsset = asset; - //TODO set value to model . - // if (_pickedAsset?.site != null && _transferModel.transferType?.value == 1) { - // await _deviceTransferProvider.getSiteData(siteId: int.tryParse(_pickedAsset!.site!.id.toString())); - // _assetDestination.site = _deviceTransferProvider.internalAssetDestination?.site; - // _assetDestination.building = null; - // _assetDestination.floor = null; - // _assetDestination.department = null; - // } else if (_pickedAsset?.site != null && _transferModel.transferType?.value == 2) { - // _assetDestination.site = null; - // _assetDestination.building = null; - // _assetDestination.floor = null; - // _assetDestination.department = null; - // } + 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, + ), + ], + ), + 16.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(() {}); - }), - 12.height, - AppTextFormField( - labelText: context.translation.assetNo, - backgroundColor: AppColor.fieldBgColor(context), - textAlign: TextAlign.center, - showShadow: false, - labelStyle: AppTextStyles.textFieldLabelStyle, - style: Theme.of(context).textTheme.titleMedium, - ), - 12.height, + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SearchAssetView( + sessionId: widget.assetInventoryModel?.sessionId ?? 0, + ))).then((value) { + if (value != null) { + _pickedAssetModel = value; + // _pickedAssetModel?.assetNumber = _scannedAssetModel?.assetNumber; + // _pickedAssetModel?.assetId = _scannedAssetModel?.assetId; + // _pickedAssetModel?.status = _scannedAssetModel?.status; + + _scannedAssetModel = _scannedAssetModel?.mergeWith(_pickedAssetModel) ?? _pickedAssetModel; + + populateFormValues(); + setState(() {}); + } + + ///Need to assign the values + }); + }, + ).paddingOnly(bottom: 12), + 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, - AutoCompleteGenericField( + LookUpAutoCompleteField( clearAfterPick: false, - label: 'Asset Name'.addTranslation, - displayString: (item) => "", - onSearch: (query) async { - // final provider = Provider.of(context, listen: false); - // final list = await provider.getPartsList(partName: query); - // return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList(); - return []; + forAssetName: true, + onChanged: (value) { + _scannedAssetModel?.newAssetNameId = null; + _scannedAssetModel?.newAssetNameText = value; }, - initialValue: '', - // initialValue: model.partCatalogItem?.partNumber ?? "", - onPick: (part) { + 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.. - AutoCompleteGenericField( + LookUpAutoCompleteField( clearAfterPick: false, + isManufacturer: true, + initialValue: _scannedAssetModel?.manufacturer ?? "", label: 'Manufacturer'.addTranslation, - displayString: (item) => "", - onSearch: (query) async { - // final provider = Provider.of(context, listen: false); - // final list = await provider.getPartsList(partName: query); - // return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList(); - return []; + onChanged: (value) { + _scannedAssetModel?.newManufacturerId = null; + _scannedAssetModel?.newManufacturerName = value; }, - initialValue: '', - // initialValue: model.partCatalogItem?.partNumber ?? "", - onPick: (part) { + onPick: (value) { + _scannedAssetModel?.newManufacturerName = null; + _scannedAssetModel?.manufacturer = value.name; + _scannedAssetModel?.newManufacturerId = value.id; + setState(() {}); }, ), 12.height, - //manufacture.. - AutoCompleteGenericField( + LookUpAutoCompleteField( clearAfterPick: false, + isManufacturer: false, + initialValue: _scannedAssetModel?.model ?? "", label: 'Model'.addTranslation, - displayString: (item) => "", - onSearch: (query) async { - // final provider = Provider.of(context, listen: false); - // final list = await provider.getPartsList(partName: query); - // return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList(); - return []; + onChanged: (value) { + _scannedAssetModel?.newModelId = null; + _scannedAssetModel?.newModelName = value; }, - initialValue: '', - // initialValue: model.partCatalogItem?.partNumber ?? "", - onPick: (part) { + onPick: (value) { + _scannedAssetModel?.newModelName = null; + _scannedAssetModel?.model = value.name; + _scannedAssetModel?.newModelId = value.id; setState(() {}); }, ), + 12.height, - //model.. - AutoCompleteGenericField( + + LookUpAutoCompleteField( clearAfterPick: false, - label: 'Asset Name'.addTranslation, - displayString: (item) => "", - onSearch: (query) async { - // final provider = Provider.of(context, listen: false); - // final list = await provider.getPartsList(partName: query); - // return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList(); - return []; + forSupplier: true, + initialValue: _scannedAssetModel?.supplierName ?? "", + label: context.translation.supplier, + onChanged: (value) { + _scannedAssetModel?.newSupplierId = null; + _scannedAssetModel?.newSupplierName = value; }, - initialValue: '', - // initialValue: model.partCatalogItem?.partNumber ?? "", - onPick: (part) { + onPick: (value) { + _scannedAssetModel?.newSupplierName = null; + _scannedAssetModel?.supplierName = value.name; + _scannedAssetModel?.newSupplierId = value.id; setState(() {}); }, ), + // SingleItemDropDownMenu( + // context: context, + // title: context.translation.supplier, + // backgroundColor: AppColor.fieldBgColor(context), + // initialValue: _scannedAssetModel?.supplier, + // showAsBottomSheet: true, + // showShadow: false, + // showCancel: true, + // onSelect: (supplier) { + // _scannedAssetModel?.supplier = supplier; + // _scannedAssetModel?.newSupplierId = supplier?.id; + // _scannedAssetModel?.newSupplierName = supplier?.name; + // setState(() {}); + // }, + // ), 12.height, - SingleItemDropDownMenu( - context: context, - title: context.translation.supplier, - backgroundColor: AppColor.fieldBgColor(context), - initialValue: null, - showAsBottomSheet: true, - showShadow: false, - showCancel: true, - onSelect: (supplier) { - setState(() {}); - }, - ), - 12.height, - siteInfoContainer(label: context.translation.site, value:widget.assetLocation?.site?.name??'-' ), + siteInfoContainer(label: context.translation.site, value: _scannedAssetModel?.siteName ?? '-'), 12.height, - siteInfoContainer(label: context.translation.building, value:widget.assetLocation?.building?.name??'-' ), + siteInfoContainer(label: context.translation.building, value: _scannedAssetModel?.buildingName ?? '-'), 12.height, - siteInfoContainer(label: context.translation.floor, value:widget.assetLocation?.floor?.name??'-' ), + siteInfoContainer(label: context.translation.floor, value: _scannedAssetModel?.floorName ?? '-'), 12.height, - siteInfoContainer(label: context.translation.department, value:widget.assetLocation?.department?.name??'-' ), + siteInfoContainer(label: context.translation.department, value: _scannedAssetModel?.departmentName ?? '-'), 12.height, - siteInfoContainer(label: context.translation.room, value:widget.assetLocation?.room?.name??'-' ), + siteInfoContainer(label: context.translation.room, value: _scannedAssetModel?.roomName ?? '-'), 12.height, - classificationWidget(label: 'Found'), + if (_scannedAssetModel?.status != null && _scannedAssetModel!.status!.isNotEmpty) classificationWidget(label: _scannedAssetModel?.status), 12.height, Text( 'Asset Photo'.addTranslation, @@ -269,8 +329,10 @@ class _AssetInventoryFormViewState extends State { alignLabelWithHint: true, textInputType: TextInputType.multiline, showShadow: false, + controller: _remarksController, onSaved: (text) { - _assetInventoryModel.remarks = text; + _scannedAssetModel?.remarks = text; + setState(() {}); }, ), // 100.height, @@ -288,21 +350,41 @@ class _AssetInventoryFormViewState extends State { ); } + Future searchAsset({required String assetNo}) async { + AssetInventoryProvider provider = Provider.of(context, listen: false); + + Map 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}){ + Widget siteInfoContainer({required String label, required String value}) { //TODO may be need to hide value for if empty or null . - return Container( + return Container( width: double.infinity, - padding: EdgeInsets.symmetric(horizontal: 12.toScreenWidth,vertical: 12.toScreenHeight), - decoration: BoxDecoration( - color: AppColor.neutral80, - borderRadius: BorderRadius.circular(8) - ), + 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,), + 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, + ), ], ), ); @@ -327,27 +409,53 @@ class _AssetInventoryFormViewState extends State { ); } - Future validateRequest() async { - if (_pickedAsset == null) { - await Fluttertoast.showToast(msg: "Please Select Asset"); - return false; + void _onSubmit() async { + AssetInventoryProvider assetInventoryProvider = Provider.of(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) { + ///Need to use push and remove until... + Navigator.pop(context); + if (success) { + // Navigator.pop(context); + // Navigator.pop(context); + /// need to confirm need to call this ... + AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); + allRequestsProvider.reset(); + allRequestsProvider.getAllRequests(context, typeTransaction: 8); + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (contxt) => SiteInformationView( + sessionModel: SessionModel(id: int.tryParse(widget.assetInventoryModel?.sessionId?.toString() ?? '') ?? 0), + ))); + } else { + log('api error...'); + } + }); + } + + void resetData({bool isScanned = true}) { + if (isScanned) { + _scannedAssetModel = AssetInventoryModel(); } - // if (_assetDestination.site == null) { - // await Fluttertoast.showToast(msg: "Please Select Site"); - // return false; - // } - // if (_assetDestination.building == null) { - // await Fluttertoast.showToast(msg: "Please Select Building"); - // return false; - // } - // if (_assetDestination.floor == null) { - // await Fluttertoast.showToast(msg: "Please Select Floor"); - // return false; - // } - // if (_assetDestination.department == null) { - // await Fluttertoast.showToast(msg: "Please Select Department"); - // return false; - // } - return true; + _assetNoController.clear(); + _serialNoController.clear(); + _pickedAssetModel = AssetInventoryModel(); + attachments.clear(); + _remarksController.clear(); + registeredController?.dispose(); } } diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart index f080f49c..284a9d0f 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart @@ -10,7 +10,7 @@ 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/pick_site_information_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_site_information_view.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'; @@ -121,6 +121,7 @@ class _AssetInventoryPageState extends State { } Future _scanAsset({required AssetInventoryProvider provider}) async { - Navigator.push(context, MaterialPageRoute(builder: (contxt) => PickSiteInformationView(sessionModel: provider.sessionModel ?? SessionModel()))); + provider.siteFilterAssetList.clear(); + Navigator.push(context, MaterialPageRoute(builder: (contxt) => SiteInformationView(sessionModel: provider.sessionModel ?? SessionModel()))); } } diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart index 180942dc..c7f5050b 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart @@ -1,77 +1,131 @@ +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/widget_extensions.dart'; -import 'package:test_sa/models/new_models/work_order_detail_model.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/new_views/app_style/app_color.dart'; -import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/views/widgets/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); + int sessionId; + + AssetInventoryScanAssetView({Key? key, required this.sessionId}) : super(key: key); @override State createState() => _AssetInventoryScanAssetViewState(); } - class _AssetInventoryScanAssetViewState extends State { - late AssetInventoryProvider assetInventoryProvider; + late AssetInventoryProvider assetInventoryProvider; + @override void initState() { - assetInventoryProvider = Provider.of(context,listen:false); + assetInventoryProvider = Provider.of(context, listen: false); super.initState(); } - Future getAssetList({bool reset = false}) async { - if (reset) { - assetInventoryProvider.pageNo = 1; - assetInventoryProvider.assetInventoryResponse = null; - } + + Future getAssetList({bool loadMore = false}) async { await assetInventoryProvider.getAssetsInSession( sessionId: widget.sessionId, + loadMore: loadMore, ); } + @override @override Widget build(BuildContext context) { return Consumer( 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 { - await getAssetList(); + return NotificationListener( + 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) { - return AssetDetailCardView(assetInventoryModel: assets[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, - itemCount: assets.length, ), ); }, ); } - void _addAsset(BuildContext context) { - //TODO need to confirm navigation... - Navigator.push(context, MaterialPageRoute(builder: (contxt) => AssetInventoryFormView())); - } +// Widget build(BuildContext context) { + // return Consumer( + // 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), + // ), + // ); + // }, + // ); + // } } diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_site_information_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_site_information_view.dart new file mode 100644 index 00000000..6374fb56 --- /dev/null +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_site_information_view.dart @@ -0,0 +1,311 @@ +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 SiteInformationView extends StatefulWidget { + SessionModel sessionModel; + + SiteInformationView({Key? key, required this.sessionModel}) : super(key: key); + + @override + State createState() => _SiteInformationViewState(); +} + +class _SiteInformationViewState extends State { + AssetInventoryModel assetInventoryModel = AssetInventoryModel(); + bool showMarkAsComplete = false; + + @override + void initState() { + super.initState(); + } + + final GlobalKey _scaffoldKey = GlobalKey(); + + @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: SafeArea( + child: Column( + children: [ + ListView( + 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: AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Add Asset'.addTranslation, + onPressed: () => _addAsset(), + // buttonColor: AppColor.primary10, + ), + ), + if (showMarkAsComplete) + AppFilledButton( + buttonColor: AppColor.green70, + label: 'Mark as completed'.addTranslation, + onPressed: () => _markAsCompleted(), + // buttonColor: AppColor.primary10, + ).paddingOnly(start: 16, end: 16), + // FooterActionButton.footerContainer( + // context: context, + // child: 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(context, listen: false); + Map 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); + log('success $success'); + if (success) { + ///TODO need to confirm need to call this or not .. + // AllRequestsProvider allRequestsProvider = Provider.of(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( + builder: (context, provider, _) { + if (provider.isLoading) { + return SizedBox(height: 300.toScreenHeight, child: const CircularProgressIndicator(color: AppColor.primary10).center); + } + final assets = provider.siteFilterAssetList; + return NotificationListener( + onNotification: (scrollInfo) { + if (!provider.isNextPageLoading && provider.nextPage && scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) { + getAssetFilteredList(loadMore: true); + } + return false; + }, + child: ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + return AssetDetailCardView( + assetInventoryModel: assets[index], + onDeletePress: () async { + log('Delete icon press'); + 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, + itemCount: assets.length, + ), + ); + }, + ); + } + + Widget siteInfoCard(BuildContext context, SessionModel sessionModel) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 12.height, + SingleItemDropDownMenu( + 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(() {}); + }, + ), + 8.height, + SingleItemDropDownMenu( + 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(() {}); + }, + ), + 8.height, + SingleItemDropDownMenu( + 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(() {}); + }, + ), + 8.height, + SingleItemDropDownMenu( + 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(() {}); + getAssetFilteredList(); + }, + ), + 8.height, + SingleItemDropDownMenu( + 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(); + } + }, + ), + 8.height, + ], + ).toShadowContainer(context); + } + + Future 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 getAssetFilteredList({bool loadMore = false}) async { + AssetInventoryProvider provider = Provider.of(context, listen: false); + Map 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); + } +} diff --git a/lib/modules/asset_inventory_module/pages/inventory_seession_card.dart b/lib/modules/asset_inventory_module/pages/inventory_seession_card.dart index 9a0d6912..3002a3c6 100644 --- a/lib/modules/asset_inventory_module/pages/inventory_seession_card.dart +++ b/lib/modules/asset_inventory_module/pages/inventory_seession_card.dart @@ -47,10 +47,9 @@ class InventorySessionCard extends StatelessWidget { ), 8.height, (requestData?.typeTransaction ?? context.translation.taskRequest).heading5(context), - //TODO replace with Api Data.. - infoWidget(label: 'Type'.addTranslation, value: requestData?.requestNo, context: context), - infoWidget(label: 'Assets'.addTranslation, value: requestData?.assetName, context: context), - infoWidget(label: 'Sites'.addTranslation, value: requestData?.assetNumber, context: context), + infoWidget(label: 'Type'.addTranslation, value: requestData?.sessionType, context: context), + infoWidget(label: 'Assets'.addTranslation, value: requestData?.numberOfAssets!=null? requestData?.numberOfAssets.toString():'-', context: context), + infoWidget(label: 'Sites'.addTranslation, value: requestData?.numberOfSites!=null? requestData?.numberOfSites.toString():'-', context: context), 8.height, Row( mainAxisSize: MainAxisSize.min, @@ -98,11 +97,9 @@ class InventorySessionCard extends StatelessWidget { ), 8.height, (requestDetails?.nameOfType ?? context.translation.taskRequest).heading5(context), - 8.height, - //TODO replace with Api Data.. - infoWidget(label: 'Type'.addTranslation, value: requestDetails?.requestNo, context: context), - infoWidget(label: 'Assets'.addTranslation, value: requestDetails?.assetName, context: context), - infoWidget(label: 'Sites'.addTranslation, value: requestDetails?.site, context: context), + infoWidget(label: 'Type'.addTranslation, value: requestDetails?.sessionType, context: context), + infoWidget(label: 'Assets'.addTranslation, value: requestDetails?.numberOfAssets!=null? requestDetails?.numberOfAssets.toString():'-', context: context), + infoWidget(label: 'Sites'.addTranslation, value: requestDetails?.numberOfSites!=null? requestDetails?.numberOfSites.toString():'-', context: context), 8.height, Row( mainAxisSize: MainAxisSize.min, diff --git a/lib/modules/asset_inventory_module/pages/pick_site_information_view.dart b/lib/modules/asset_inventory_module/pages/pick_site_information_view.dart deleted file mode 100644 index db8a1240..00000000 --- a/lib/modules/asset_inventory_module/pages/pick_site_information_view.dart +++ /dev/null @@ -1,257 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; -import 'package:provider/provider.dart'; -import 'package:test_sa/extensions/context_extension.dart'; -import 'package:test_sa/extensions/int_extensions.dart'; -import 'package:test_sa/extensions/string_extensions.dart'; -import 'package:test_sa/extensions/text_extensions.dart'; -import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/device/asset.dart'; -import 'package:test_sa/models/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/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/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'; -import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; - -import '../../../models/new_models/site.dart'; - -class PickSiteInformationView extends StatefulWidget { - SessionModel sessionModel; - - PickSiteInformationView({Key? key, required this.sessionModel}) : super(key: key); - - @override - State createState() => _PickSiteInformationViewState(); -} - -class _PickSiteInformationViewState extends State { - // TODO need to use only one model AssetInventoryModel everywhere after completing flow . - Asset assetLocation = Asset(); - - void _onSave() async {} - - @override - void initState() { - super.initState(); - } - - final GlobalKey _scaffoldKey = GlobalKey(); - - @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( - padding: const EdgeInsets.only(left: 16, right: 16, top: 16), - children: [ - siteInfoCard(context, widget.sessionModel), - 12.height, - //TODO need to implement when api is working ... - // assetDetailList(), - // 12.height, - AppFilledButton( - label: "Add Asset".addTranslation, - maxWidth: true, - - - height: 70, - textColor: AppColor.textColor(context), - buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, - icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), - showIcon: true, - onPressed: _addAsset, - ), - 12.height, - ], - ).expanded, - FooterActionButton.footerContainer( - context: context, - child: AppFilledButton(buttonColor: AppColor.primary10, label: context.translation.save, maxWidth: true, onPressed: _onSave), - ), - ], - )); - } - - void _addAsset() { - Navigator.push( - context, - MaterialPageRoute( - builder: (contxt) => AssetInventoryFormView( - assetLocation: assetLocation, - ))); - } - - Future getAssetList({bool reset = false}) async { - AssetInventoryProvider assetInventoryProvider = Provider.of(context,listen: false); - if (reset) { - assetInventoryProvider.pageNo = 1; - assetInventoryProvider.assetInventoryResponse = null; - } - await assetInventoryProvider.getAssetsInSession( - sessionId: widget.sessionModel.id??0, - ); - } - - Widget assetDetailList() { - return Consumer( - builder: (context, provider,child) { - return Consumer( - 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 { - await getAssetList(); - }, - child: ListView.separated( - padding: const EdgeInsets.all(16), - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) { - return AssetDetailCardView(assetInventoryModel: assets[index]); - }, - separatorBuilder: (context, index) => 12.height, - itemCount: assets.length, - ), - ); - }, - ); - } - ); - } - - - Widget siteInfoCard(BuildContext context, SessionModel sessionModel) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 12.height, - SingleItemDropDownMenu( - context: context, - title: context.translation.site, - initialValue: assetLocation.site, - showShadow: false, - staticData: sessionModel.assetInventorySites, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - onSelect: (value) { - assetLocation.site = value; - assetLocation.building = null; - assetLocation.floor = null; - assetLocation.department = null; - setState(() {}); - }, - ), - 8.height, - SingleItemDropDownMenu( - context: context, - title: context.translation.building, - initialValue: assetLocation.building, - showShadow: false, - showAsBottomSheet: true, - backgroundColor: AppColor.fieldBgColor(context), - enabled: assetLocation.site?.buildings?.isNotEmpty ?? false, - staticData: assetLocation.site?.buildings ?? [], - onSelect: (value) { - assetLocation.building = value; - assetLocation.floor = null; - assetLocation.department = null; - setState(() {}); - }, - ), - 8.height, - SingleItemDropDownMenu( - context: context, - title: context.translation.floor, - showShadow: false, - showAsBottomSheet: true, - initialValue: assetLocation.floor, - backgroundColor: AppColor.fieldBgColor(context), - enabled: assetLocation.building?.floors?.isNotEmpty ?? false, - staticData: assetLocation.building?.floors ?? [], - onSelect: (value) { - assetLocation.floor = value; - assetLocation.department = null; - setState(() {}); - }, - ), - 8.height, - SingleItemDropDownMenu( - context: context, - title: context.translation.department, - showShadow: false, - showAsBottomSheet: true, - initialValue: assetLocation.department, - backgroundColor: AppColor.fieldBgColor(context), - enabled: assetLocation.floor?.departments?.isNotEmpty ?? false, - staticData: assetLocation.floor?.departments ?? [], - onSelect: (value) { - assetLocation.department = value; - assetLocation.room = null; - setState(() {}); - }, - ), - 8.height, - SingleItemDropDownMenu( - context: context, - title: context.translation.room, - showShadow: false, - showAsBottomSheet: true, - initialValue: assetLocation.room, - backgroundColor: AppColor.fieldBgColor(context), - enabled: assetLocation.department?.rooms?.isNotEmpty ?? false, - staticData: assetLocation.department?.rooms ?? [], - onSelect: (value) { - assetLocation.room = value; - setState(() {}); - }, - ), - 8.height, - ], - ).toShadowContainer(context); - } - - Future validateRequest() async { - if (assetLocation.site == null) { - await Fluttertoast.showToast(msg: "Please Select Site"); - return false; - } - if (assetLocation.building == null) { - await Fluttertoast.showToast(msg: "Please Select Building"); - return false; - } - if (assetLocation.floor == null) { - await Fluttertoast.showToast(msg: "Please Select Floor"); - return false; - } - if (assetLocation.department == null) { - await Fluttertoast.showToast(msg: "Please Select Department"); - return false; - } - return true; - } -} diff --git a/lib/modules/asset_inventory_module/pages/search_asset_view.dart b/lib/modules/asset_inventory_module/pages/search_asset_view.dart new file mode 100644 index 00000000..6557d3ed --- /dev/null +++ b/lib/modules/asset_inventory_module/pages/search_asset_view.dart @@ -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 createState() => _SearchAssetViewState(); +} + +class _SearchAssetViewState extends State { + int _selectedIndex = 0; + DeviceSearch? search; + late TextEditingController _searchController; + late AssetInventoryProvider _assetInventoryProvider; + final List _searchableList = []; + final GlobalKey _formKey = GlobalKey(); + 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 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(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)); + } +} diff --git a/lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart b/lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart index 7fe233da..ed694c44 100644 --- a/lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart +++ b/lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart @@ -8,6 +8,9 @@ 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'; @@ -26,11 +29,22 @@ import '../../../new_views/common_widgets/app_lazy_loading.dart'; class AssetInventoryProvider extends ChangeNotifier { final pageItemNumber = 10; + final searchPageItemNumber = 10; int pageNo = 1; + List _devices = []; + List _searchDevices = []; + List get devices => _devices; + + List get searchDevices => _searchDevices; SessionModel? sessionModel; + + //TODO need to check i think don't need to create this obj AssetInventoryResponse? assetInventoryResponse; + AssetInventoryResponse? siteFilterAssetResponse; + List sessionAssetList = []; + List siteFilterAssetList = []; void reset() { pageNo = 1; @@ -42,23 +56,29 @@ class AssetInventoryProvider extends ChangeNotifier { int? stateCode; bool isDetailLoading = false; - bool nextPage = true; + bool nextPage = false; + bool isNextPageLoading = false; bool isLoading = false; bool isAllAssetLoading = false; - Future getSessionById({required int id}) async { + void searchReset() { + stateCode = null; + _searchDevices = []; + } + + Future getSessionById({required int id}) async { try { sessionModel = SessionModel(); isLoading = true; notifyListeners(); final response = await ApiManager.instance.get(URLs.getAssetInventoryById + "?assetInventoryId=$id"); - stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { sessionModel = SessionModel.fromJson(json.decode(response.body)["data"]); } else { sessionModel = null; } + isLoading = false; notifyListeners(); } catch (e) { @@ -72,49 +92,350 @@ class AssetInventoryProvider extends ChangeNotifier { Future getAssetsInSession({ required int sessionId, + bool loadMore = false, }) async { - if (isLoading == true) return -2; - isLoading = true; - + if (isLoading || isNextPageLoading) return -2; + if (loadMore) { + isNextPageLoading = true; + pageNo += 1; + } else { + isLoading = true; + pageNo = 1; // reset pagination + } + notifyListeners(); try { final payload = { "pageSize": pageItemNumber, "pageNumber": pageNo, "sessionId": sessionId, }; - final response = await ApiManager.instance.post(URLs.getAssetsInSession, body: payload); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { final Map jsonData = json.decode(response.body); final newResponse = AssetInventoryResponse.fromJson(jsonData); - if (pageNo == 1) { - assetInventoryResponse = newResponse; - sessionAssetList = newResponse.assetList ?? []; + + if (loadMore) { + assetInventoryResponse?.assetList?.addAll(newResponse.assetList ?? []); + assetInventoryResponse?.totalRows = newResponse.totalRows; } else { - sessionAssetList.addAll(newResponse.assetList ?? []); - assetInventoryResponse?.totalRows = newResponse.totalRows; // update total rows + assetInventoryResponse = newResponse; } - if ((sessionAssetList.length) < (assetInventoryResponse?.totalRows ?? 0)) { - nextPage = true; + nextPage = (assetInventoryResponse?.assetList?.length ?? 0) < (assetInventoryResponse?.totalRows ?? 0); + } else { + nextPage = false; + } + isLoading = false; + isNextPageLoading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + isLoading = false; + isNextPageLoading = false; + stateCode = -1; + nextPage = false; + notifyListeners(); + return -1; + } + } + + ///older code + // Future getAssetsInSession({ + // required int sessionId, + // bool loadMore = false, + // }) async { + // // if (isLoading || nextPage) return -2; + // + // if (loadMore) { + // nextPage = true; + // pageNo += 1; + // } else { + // isLoading = true; + // pageNo = 1; // reset pagination + // } + // + // notifyListeners(); + // log('Fetching page: $pageNo'); + // + // try { + // final payload = { + // "pageSize": pageItemNumber, + // "pageNumber": pageNo, + // "sessionId": sessionId, + // }; + // + // final response = await ApiManager.instance.post(URLs.getAssetsInSession, body: payload); + // stateCode = response.statusCode; + // + // if (response.statusCode >= 200 && response.statusCode < 300) { + // final Map jsonData = json.decode(response.body); + // final newResponse = AssetInventoryResponse.fromJson(jsonData); + // + // if (loadMore) { + // assetInventoryResponse?.assetList?.addAll(newResponse.assetList ?? []); + // assetInventoryResponse?.totalRows = newResponse.totalRows; + // } else { + // assetInventoryResponse = newResponse; + // } + // + // nextPage = (assetInventoryResponse?.assetList?.length ?? 0) < (assetInventoryResponse?.totalRows ?? 0); + // } + // + // isLoading = false; + // nextPage = false; + // notifyListeners(); + // return response.statusCode; + // } catch (error) { + // isLoading = false; + // nextPage = false; + // stateCode = -1; + // notifyListeners(); + // return -1; + // } + // } + + Future getInventoryDetailsByFilter({ + required Map payload, + bool loadMore = false, + }) async { + if (isLoading || isNextPageLoading) return -2; + + if (loadMore) { + isNextPageLoading = true; + pageNo += 1; + } else { + isLoading = true; + pageNo = 1; + } + + notifyListeners(); + log('Fetching inventory page: $pageNo'); + + try { + final paginatedPayload = { + ...payload, + "pageSize": pageItemNumber, + "pageNumber": pageNo, + }; + + final response = await ApiManager.instance.post(URLs.getInventoryDetailsByFilter, body: paginatedPayload); + stateCode = response.statusCode; + + if (response.statusCode >= 200 && response.statusCode < 300) { + final Map jsonData = json.decode(response.body); + final newResponse = AssetInventoryResponse.fromJson(jsonData); + + if (loadMore) { + siteFilterAssetList.addAll(newResponse.assetList ?? []); + siteFilterAssetResponse?.totalRows = newResponse.totalRows; } else { - nextPage = false; + siteFilterAssetResponse = newResponse; + siteFilterAssetList = newResponse.assetList ?? []; } + nextPage = (siteFilterAssetList.length) < (siteFilterAssetResponse?.totalRows ?? 0); + } else { + siteFilterAssetList = []; + nextPage = false; + } + + isLoading = false; + isNextPageLoading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + isLoading = false; + isNextPageLoading = false; + nextPage = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } + + Future searchAsset({ + required Map payload, + }) async { + isLoading = true; + try { + final response = await ApiManager.instance.post(URLs.searchAsset, body: payload); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + final Map jsonData = json.decode(response.body)["data"]; + AssetInventoryModel model = AssetInventoryModel.fromJson(jsonData); + log('model json ${model.toJson()}'); + isLoading = false; + notifyListeners(); + return model; + } else { + isLoading = false; + notifyListeners(); + return null; + } + } catch (error) { + isLoading = false; + stateCode = -1; + notifyListeners(); + return null; + } + } + + Future saveAssetInSession({ + AssetInventoryModel? model, + }) async { + isLoading = true; + try { + 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 response.statusCode; + return true; } else { - sessionAssetList = []; isLoading = false; notifyListeners(); - return response.statusCode; + return false; + } + } catch (error) { + isLoading = false; + notifyListeners(); + return false; + } + } + + Future deleteAssetISession({required num id}) async { + try { + isLoading = true; + notifyListeners(); + final response = await ApiManager.instance.get(URLs.deleteAssetInSession + "?id=$id"); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + isLoading = false; + notifyListeners(); + return true; + } + isLoading = false; + notifyListeners(); + return false; + } catch (e) { + log("Delete Asset [error] : $e"); + isLoading = false; + notifyListeners(); + return false; + } + } + + Future> getAutoCompleteDetails({ + bool? isManufacturer, + String? query, + int type = 0, + }) async { + try { + String url = ''; + switch (type) { + //for model and manufacturer.. + case 0: + url = URLs.getManufacturerOrModelAutoComplete; + break; + //for asset name.. + case 1: + url = URLs.searchAssetName; + break; + //for supplier... + case 2: + url = URLs.getSuppliersAutoCompleteInventory; + break; + default: + url = URLs.getManufacturerOrModelAutoComplete; + } + final queryParams = {}; + if (isManufacturer != null && type == 0) { + queryParams['isManufacturer'] = isManufacturer.toString(); + } + if (query != null && query.isNotEmpty) { + queryParams['searchText'] = query; + } + if (queryParams.isNotEmpty) { + url += '?${Uri(queryParameters: queryParams).query}'; + } + final response = await ApiManager.instance.get(url); + + List list = []; + if (response.statusCode >= 200 && response.statusCode < 300) { + final data = json.decode(response.body)["data"]; + list = (data as List).map((e) => Lookup.fromJson(e)).toList(); } + return list; + } catch (error) { + log('error $error'); + return []; + } + } + + Future getAssets({DeviceSearch? search, bool isQr = false, bool isSearchBy = false, num? sessionId}) async { + if (isLoading == true) return -2; + isLoading = true; + notifyListeners(); + late Response response; + try { + final Map body = { + "pageSize": isSearchBy ? searchPageItemNumber : pageItemNumber, + "pageNumber": isSearchBy ? (searchDevices.length / searchPageItemNumber).ceil() + 1 : devices.length ~/ pageItemNumber + 1, + "sessionId": sessionId ?? 0, + "assetSerialNo": search?.assetSerialNumber ?? '', + "assetName": search?.assetName ?? '', + "model": search?.model ?? '', + "manufacturer": search?.manufacturer ?? '', + "supplier": search?.supplier ?? '', + "siteName": search?.site ?? '', + // "buildingName":search?.??'', + // "floorName": search?.f??'', + "departmentName": search?.department ?? '', + // "roomName": search?.room + }; + // if (search != null) body.addAll(search.toJson()); + response = await ApiManager.instance.post(URLs.getAssetsTemp, body: body); } catch (error) { isLoading = false; stateCode = -1; notifyListeners(); return -1; } + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + // client's request was successfully received + List equipmentListJson = json.decode(response.body)["data"]; + var dList = equipmentListJson.map((asset) => AssetInventoryModel.fromJson(asset)).toList() ?? []; + isSearchBy ? _searchDevices.addAll(dList) : _devices.addAll(dList); + nextPage = true; + } else { + nextPage = false; + } + isLoading = false; + notifyListeners(); + return response.statusCode; } + Future markAsComplete({ + required Map payload, + }) async { + isLoading = true; + try { + final response = await ApiManager.instance.post(URLs.convertDetailToComplete, body: payload); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + isLoading = false; + notifyListeners(); + return true; + } else { + isLoading = false; + notifyListeners(); + return false; + } + } catch (error) { + isLoading = false; + notifyListeners(); + return false; + } + } } diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart index 6a2c20f2..03c7ea37 100644 --- a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart +++ b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart @@ -30,8 +30,7 @@ class RequestItemViewList extends StatelessWidget { if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading); switch (list[index].transactionType) { case 1: - // return ServiceRequestItemView(requestDetails: list[index]); - return InventorySessionCard(requestDetails: list[index]); + return ServiceRequestItemView(requestDetails: list[index]); case 2: return GasRefillItemView(requestDetails: list[index]); case 3: diff --git a/lib/views/widgets/equipment/asset_picker.dart b/lib/views/widgets/equipment/asset_picker.dart index 78a687ab..b5f029d5 100644 --- a/lib/views/widgets/equipment/asset_picker.dart +++ b/lib/views/widgets/equipment/asset_picker.dart @@ -26,6 +26,7 @@ class AssetPicker extends StatelessWidget { Color? backgroundColor; final bool forPPM; final bool showLoading; + final bool enablePickManually; final bool multiSelection; AssetPicker( @@ -45,7 +46,7 @@ class AssetPicker extends StatelessWidget { this.showAssetInfo = true, this.showBorder = false, this.multiSelection = false, - this.forPPM = false, + this.forPPM = false, this.enablePickManually = true, this.showLoading = false}) : assert( multiSelection == false || onMultiAssetPick != null, @@ -83,6 +84,7 @@ class AssetPicker extends StatelessWidget { builder: (context) => AssetScanQr( title: context.translation.assetScan, multiSelection: multiSelection, + enablePickManually: enablePickManually, ))) as List?; if (device?.isNotEmpty ?? false) { onMultiAssetPick!(device!); @@ -92,6 +94,7 @@ class AssetPicker extends StatelessWidget { builder: (context) => AssetScanQr( title: context.translation.assetScan, multiSelection: multiSelection, + enablePickManually: enablePickManually, ))) as Asset?; if (device != null) { onPick!(device); @@ -121,6 +124,7 @@ class AssetPicker extends StatelessWidget { builder: (context) => AssetScanQr( title: context.translation.assetScan, multiSelection: multiSelection, + enablePickManually: enablePickManually, ))) as List?; if (device?.isNotEmpty ?? false) { onMultiAssetPick!(device!); @@ -130,6 +134,7 @@ class AssetPicker extends StatelessWidget { builder: (context) => AssetScanQr( title: context.translation.assetScan, multiSelection: multiSelection, + enablePickManually: enablePickManually, ))) as Asset?; if (device != null) { onPick!(device); @@ -140,7 +145,7 @@ class AssetPicker extends StatelessWidget { if (deviceList.isNotEmpty && showAssetInfo) ListView.separated( shrinkWrap: true, - padding: EdgeInsets.only(top: 16), + padding: const EdgeInsets.only(top: 16), physics: const NeverScrollableScrollPhysics(), itemBuilder: (cxt, index) => _assetInfoView(deviceList[index], context), separatorBuilder: (cxt, index) => 12.height, @@ -204,10 +209,10 @@ class AssetPicker extends StatelessWidget { ], ), 8.height, - "${context.translation.assetNo}: ${device!.assetNumber}".bodyText2(context).toShimmer(isShow: showLoading,context: context), + "${context.translation.assetNo}: ${device.assetNumber}".bodyText2(context).toShimmer(isShow: showLoading,context: context), 2.height, // "${context.translation.manufacture}: ${device.modelDefinition?.manufacturerName}".bodyText(context), - "${context.translation.model}: ${device!.modelDefinition?.modelName}".bodyText2(context).toShimmer(isShow: showLoading,context: context), + "${context.translation.model}: ${device.modelDefinition?.modelName}".bodyText2(context).toShimmer(isShow: showLoading,context: context), // "${context.translation.serialNumber}: ${device.assetNumber}".bodyText(context), // const Divider().defaultStyle(context), // "${context.translation.department}: ${device.department?.departmentName}".bodyText(context), diff --git a/lib/views/widgets/qr/asset_scan_qr.dart b/lib/views/widgets/qr/asset_scan_qr.dart index 16b76dbd..c39483a6 100644 --- a/lib/views/widgets/qr/asset_scan_qr.dart +++ b/lib/views/widgets/qr/asset_scan_qr.dart @@ -20,9 +20,10 @@ import '../../pages/device_transfer/search_device_page.dart'; class AssetScanQr extends StatefulWidget { static const String id = "/asset-scan-qr"; - const AssetScanQr({Key? key, required this.title, this.multiSelection = false}) : super(key: key); + const AssetScanQr({Key? key, required this.title, this.multiSelection = false,this.enablePickManually = true}) : super(key: key); final String title; final bool multiSelection; + final bool enablePickManually; @override _AssetScanQrState createState() => _AssetScanQrState(); @@ -86,15 +87,23 @@ class _AssetScanQrState extends State { controller.scannedDataStream.listen((scanData) async { if (!_scanDone) { _scanDone = true; - final result = await _getDevice(scanData.code!, isQr: true); - if (result.isNotEmpty) { - if (widget.multiSelection) { - Navigator.of(context).pop([result[0]]); + if(!widget.enablePickManually){ + if(scanData.code!=null){ + Navigator.of(context).pop(Asset(assetNumber: scanData.code!)); + }else{ + _scanDone = false; + } + }else{ + final result = await _getDevice(scanData.code!, isQr: true); + if (result.isNotEmpty) { + if (widget.multiSelection) { + Navigator.of(context).pop([result[0]]); + } else { + Navigator.of(context).pop(result[0]); + } } else { - Navigator.of(context).pop(result[0]); + _scanDone = false; } - } else { - _scanDone = false; } } }); @@ -109,7 +118,8 @@ class _AssetScanQrState extends State { ), ], ).expanded, - FooterActionButton.footerContainer( + if(widget.enablePickManually) + FooterActionButton.footerContainer( context: context, child: AppFilledButton( label: context.translation.pickManually,