From e5775019a4a6a8c99779132dc0c0ff89b90b0bf0 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Sun, 5 Oct 2025 15:32:09 +0300 Subject: [PATCH 01/11] asset inventory design --- lib/app_strings/app_asset.dart | 4 +- .../autocomplete_generic_field.dart | 144 ++++++ lib/controllers/api_routes/urls.dart | 12 +- .../providers/api/all_requests_provider.dart | 2 +- .../widgets/request_category_list.dart | 5 + lib/main.dart | 2 + .../models/session_model.dart | 225 +++++++++ .../pages/asset_detail_card_view.dart | 95 ++++ .../pages/asset_inventory_detail_view.dart | 163 +++++++ .../pages/asset_inventory_form_view.dart | 426 ++++++++++++++++++ .../pages/asset_inventory_page.dart | 116 +++++ .../asset_inventory_scan_assets_view.dart | 53 +++ .../pages/inventory_seession_card.dart | 133 ++++++ .../pages/pick_site_information_view.dart | 225 +++++++++ .../provider/asset_inventory_provider.dart | 62 +++ .../land_page/contact_us_bottom_sheet.dart | 4 +- .../my_request/my_requests_page.dart | 4 +- .../requests/request_paginated_listview.dart | 62 +-- .../widgets/request_item_view_list.dart | 6 +- lib/views/widgets/equipment/asset_picker.dart | 13 +- pubspec.lock | 8 + 21 files changed, 1712 insertions(+), 52 deletions(-) create mode 100644 lib/common_widgets/autocomplete_generic_field.dart create mode 100644 lib/modules/asset_inventory_module/models/session_model.dart create mode 100644 lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart create mode 100644 lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart create mode 100644 lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart create mode 100644 lib/modules/asset_inventory_module/pages/asset_inventory_page.dart create mode 100644 lib/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart create mode 100644 lib/modules/asset_inventory_module/pages/inventory_seession_card.dart create mode 100644 lib/modules/asset_inventory_module/pages/pick_site_information_view.dart create mode 100644 lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart diff --git a/lib/app_strings/app_asset.dart b/lib/app_strings/app_asset.dart index 242f0170..b5d64cea 100644 --- a/lib/app_strings/app_asset.dart +++ b/lib/app_strings/app_asset.dart @@ -10,7 +10,7 @@ class AppAsset { static String maintenanceIcon = 'maintenance_icon'; static String retiredAssetIcon = 'assets/images/retired_asset_icon.svg'; static String sparePartIcon = 'spare_part_icon'; - static String editIcon = 'assets/images/edit_icon.svg'; - static String deleteIcon = 'assets/images/delete_icon.svg'; + static String editIcon = 'assets/images/edit_icon'; + static String deleteIcon = 'assets/images/delete_icon'; static String overDueIcon = 'assets/images/overdue.svg'; } diff --git a/lib/common_widgets/autocomplete_generic_field.dart b/lib/common_widgets/autocomplete_generic_field.dart new file mode 100644 index 00000000..b812efe8 --- /dev/null +++ b/lib/common_widgets/autocomplete_generic_field.dart @@ -0,0 +1,144 @@ +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/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 2cac62b1..26bc7b04 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -4,12 +4,12 @@ class URLs { static const String appReleaseBuildNumber = "26"; // static const host1 = "https://atomsm.hmg.com"; // production url - // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + static const host1 = "https://atomsmdev.hmg.com"; // local DEV url + // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static String _baseUrl = "$_host/mobile"; - // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis - static final String _baseUrl = "$_host/mobile"; // host local UAT + static final String _baseUrl = "$_host/v3/mobile"; // new V3 apis + // static final String _baseUrl = "$_host/mobile"; // host local UAT // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM static String _host = host1; @@ -295,4 +295,8 @@ class URLs { static get addComment => "$_baseUrl/CallRequest/AddHistoryComment"; // add static get getSiteContactInfo => "$_baseUrl/AssetGroupSiteContactInfo"; // add + +// asset inventory Urls. + static get getAssetInventoryById => '$_baseUrl/AssetInventory/GetAssetInventoryById'; +// AssetInventory/GetAssetInventoryById } diff --git a/lib/controllers/providers/api/all_requests_provider.dart b/lib/controllers/providers/api/all_requests_provider.dart index 54fd7776..f95ef38d 100644 --- a/lib/controllers/providers/api/all_requests_provider.dart +++ b/lib/controllers/providers/api/all_requests_provider.dart @@ -143,7 +143,7 @@ class AllRequestsProvider extends ChangeNotifier { } final type = typeTransaction == null ? search?.typeTransaction == null || (search?.typeTransaction?.isEmpty ?? false) - ? [1, 2, 3, 4, 5, 6,7] + ? [1, 2, 3, 4, 5, 6,7,8] : search!.typeTransaction : [typeTransaction]; List status = (search?.statuses == null || (search?.statuses?.isEmpty ?? false)) ? (((search?.isArchived ?? false) ? [3] : [1, 2, 4])) : search!.statuses!; diff --git a/lib/dashboard_latest/widgets/request_category_list.dart b/lib/dashboard_latest/widgets/request_category_list.dart index 5c6fe481..9247fdbb 100644 --- a/lib/dashboard_latest/widgets/request_category_list.dart +++ b/lib/dashboard_latest/widgets/request_category_list.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/inventory_seession_card.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart'; @@ -48,6 +49,10 @@ class RequestCategoryList extends StatelessWidget { return RecurrentWoItemView(requestData: request); case 6: return TaskRequestItemView(requestData: request); + case 7: + return TaskRequestItemView(requestData: request); + case 8: + return InventorySessionCard(requestData: request); default: return Container( height: 100, diff --git a/lib/main.dart b/lib/main.dart index e60fb1e8..d9fabe55 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -25,6 +25,7 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/report/servic import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_repair_location_provider.dart'; import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart'; +import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart'; @@ -280,6 +281,7 @@ class MyApp extends StatelessWidget { //ChangeNotifierProvider(create: (_) => RequestStatusProvider()), ChangeNotifierProvider(create: (_) => VendorProvider()), ChangeNotifierProvider(create: (_) => PpmChecklistStatusProvider()), + ChangeNotifierProvider(create: (_) => AssetInventoryProvider()), ], child: GestureDetector( onTap: () { diff --git a/lib/modules/asset_inventory_module/models/session_model.dart b/lib/modules/asset_inventory_module/models/session_model.dart new file mode 100644 index 00000000..1860d02d --- /dev/null +++ b/lib/modules/asset_inventory_module/models/session_model.dart @@ -0,0 +1,225 @@ + +class SessionModel { + int? id; + String? sessionName; + int? sessionTypeId; + String? sessionTypeName; + int? statusId; + String? statusName; + String? startDate; + String? endDate; + List assetInventorySites = []; + List assetInventoryAssignedEmployee = []; + + SessionModel({ + this.id, + this.sessionName, + this.sessionTypeId, + this.sessionTypeName, + this.statusId, + this.statusName, + this.startDate, + this.endDate, + List? assetInventorySites, + List? assetInventoryAssignedEmployee, + }) { + this.assetInventorySites = assetInventorySites ?? []; + this.assetInventoryAssignedEmployee = assetInventoryAssignedEmployee ?? []; + } + + SessionModel.fromJson(Map json) { + id = json['id']; + sessionName = json['sessionName']; + sessionTypeId = json['sessionTypeId']; + sessionTypeName = json['sessionTypeName']; + statusId = json['statusId']; + statusName = json['statusName']; + startDate = json['startDate']; + endDate = json['endDate']; + + if (json['assetInventorySites'] != null) { + assetInventorySites = (json['assetInventorySites'] as List).map((e) => AssetInventorySite.fromJson(e)).toList(); + } + + if (json['assetInventoryAssignedEmployee'] != null) { + assetInventoryAssignedEmployee = (json['assetInventoryAssignedEmployee'] as List).map((e) => AssetInventoryAssignedEmployee.fromJson(e)).toList(); + } + } + + Map toJson() { + final map = {}; + map['id'] = id; + map['sessionName'] = sessionName; + map['sessionTypeId'] = sessionTypeId; + map['sessionTypeName'] = sessionTypeName; + map['statusId'] = statusId; + map['statusName'] = statusName; + map['startDate'] = startDate; + map['endDate'] = endDate; + map['assetInventorySites'] = assetInventorySites.map((e) => e.toJson()).toList(); + map['assetInventoryAssignedEmployee'] = assetInventoryAssignedEmployee.map((e) => e.toJson()).toList(); + return map; + } +} + +class AssetInventorySite { + int? siteId; + String? siteName; + List assetInventoryBuildings = []; + + AssetInventorySite({ + this.siteId, + this.siteName, + List? assetInventoryBuildings, + }) { + this.assetInventoryBuildings = assetInventoryBuildings ?? []; + } + + AssetInventorySite.fromJson(Map json) { + siteId = json['siteId']; + siteName = json['siteName']; + + if (json['assetInventoryBuildings'] != null) { + assetInventoryBuildings = (json['assetInventoryBuildings'] as List).map((e) => AssetInventoryBuilding.fromJson(e)).toList(); + } + } + + Map toJson() { + final map = {}; + map['siteId'] = siteId; + map['siteName'] = siteName; + map['assetInventoryBuildings'] = assetInventoryBuildings.map((e) => e.toJson()).toList(); + return map; + } +} + +class AssetInventoryBuilding { + int? buildingId; + String? buildingName; + List assetInventoryFloors = []; + + AssetInventoryBuilding({ + this.buildingId, + this.buildingName, + List? assetInventoryFloors, + }) { + this.assetInventoryFloors = assetInventoryFloors ?? []; + } + + AssetInventoryBuilding.fromJson(Map json) { + buildingId = json['buildingId']; + buildingName = json['buildingName']; + + if (json['assetInventoryFloors'] != null) { + assetInventoryFloors = (json['assetInventoryFloors'] as List).map((e) => AssetInventoryFloor.fromJson(e)).toList(); + } + } + + Map toJson() { + final map = {}; + map['buildingId'] = buildingId; + map['buildingName'] = buildingName; + map['assetInventoryFloors'] = assetInventoryFloors.map((e) => e.toJson()).toList(); + return map; + } +} + +class AssetInventoryFloor { + int? floorId; + String? floorName; + List assetInventoryDepartments = []; + + AssetInventoryFloor({ + this.floorId, + this.floorName, + List? assetInventoryDepartments, + }) { + this.assetInventoryDepartments = assetInventoryDepartments ?? []; + } + + AssetInventoryFloor.fromJson(Map json) { + floorId = json['floorId']; + floorName = json['floorName']; + + if (json['assetInventoryDepartments'] != null) { + assetInventoryDepartments = (json['assetInventoryDepartments'] as List).map((e) => AssetInventoryDepartment.fromJson(e)).toList(); + } + } + + Map toJson() { + final map = {}; + map['floorId'] = floorId; + map['floorName'] = floorName; + map['assetInventoryDepartments'] = assetInventoryDepartments.map((e) => e.toJson()).toList(); + return map; + } +} + +class AssetInventoryDepartment { + int? departmentId; + String? departmentName; + List assetInventoryRooms = []; + + AssetInventoryDepartment({ + this.departmentId, + this.departmentName, + List? assetInventoryRooms, + }) { + this.assetInventoryRooms = assetInventoryRooms ?? []; + } + + AssetInventoryDepartment.fromJson(Map json) { + departmentId = json['departmentId']; + departmentName = json['departmentName']; + + if (json['assetInventoryRooms'] != null) { + assetInventoryRooms = (json['assetInventoryRooms'] as List).map((e) => AssetInventoryRoom.fromJson(e)).toList(); + } + } + + Map toJson() { + final map = {}; + map['departmentId'] = departmentId; + map['departmentName'] = departmentName; + map['assetInventoryRooms'] = assetInventoryRooms.map((e) => e.toJson()).toList(); + return map; + } +} + +class AssetInventoryRoom { + int? roomId; + String? roomName; + + AssetInventoryRoom({this.roomId, this.roomName}); + + AssetInventoryRoom.fromJson(Map json) { + roomId = json['roomId']; + roomName = json['roomName']; + } + + Map toJson() { + final map = {}; + map['roomId'] = roomId; + map['roomName'] = roomName; + return map; + } +} + +class AssetInventoryAssignedEmployee { + String? assignedEngineerId; + String? assignedEngineerName; + + AssetInventoryAssignedEmployee({this.assignedEngineerId, this.assignedEngineerName}); + + AssetInventoryAssignedEmployee.fromJson(Map json) { + assignedEngineerId = json['assignedEngineerId']; + assignedEngineerName = json['assignedEngineerName']; + } + + Map toJson() { + final map = {}; + map['assignedEngineerId'] = assignedEngineerId; + map['assignedEngineerName'] = assignedEngineerName; + return map; + } +} diff --git a/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart b/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart new file mode 100644 index 00000000..a77a6f6a --- /dev/null +++ b/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/new_models/work_order_detail_model.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class AssetDetailCardView extends StatelessWidget { + WorkOrderData workOrder; + + AssetDetailCardView({super.key,required this.workOrder}); + + @override + Widget build(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: workOrder.priority?.name, + id: workOrder.priority!.id!, + radius: 4, + textColor: AppColor.getPriorityStatusTextColor(context, workOrder.priority!.id!), + backgroundColor: AppColor.getPriorityStatusColor(context, workOrder.priority!.id!), + ), + 8.height, + Text( + context.translation.assetInformation, + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + // 8.height, + Text( + '${context.translation.serialNo}: ${workOrder.workOrderContactPerson[0].name ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.manufacture}: ${workOrder.workOrderContactPerson[0].name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.model}: ${workOrder.workOrderContactPerson[0].name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.site}: ${workOrder.workOrderContactPerson[0].name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.department}: ${workOrder.workOrderContactPerson[0].name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ),Text( + '${context.translation.supplier}: ${workOrder.workOrderContactPerson[0].name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ),Text( + '${'Remarks'.addTranslation}: ${workOrder.workOrderContactPerson[0].name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + ], + ).expanded, + Column( + 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.. + }) + ], + ), + 20.height, + Container( + height: 100, + width:100, + color: Colors.red, + child: 'edit_icon'.toSvgAsset().center, + ) + + ],) + ], + ).toShadowContainer(context); + } +} diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart new file mode 100644 index 00000000..a805f1b1 --- /dev/null +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart @@ -0,0 +1,163 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/new_models/work_order_detail_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; +import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class AssetInventoryDetailView extends StatefulWidget { + SessionModel sessionModel; + + AssetInventoryDetailView({Key? key, required this.sessionModel}) : super(key: key); + + @override + State createState() => _AssetInventoryDetailViewState(); +} + +class _AssetInventoryDetailViewState extends State { + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + //TODO remove this provider and loading obj as well don't need here ... + return Consumer(builder: (pContext, requestProvider, _) { + return requestProvider.isLoading + ? const CircularProgressIndicator(color: AppColor.primary10).center + : requestProvider.currentWorkOrder == null + ? const NoDataFound() + : Column( + children: [ + SingleChildScrollView( + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + requestDetailCard(context, requestProvider.currentWorkOrder!.data!), + 12.height, + siteListCard(context, requestProvider.currentWorkOrder!.data!), + // 20.height, + ], + ), + ).expanded, + ], + ); + }); + } + + + + TextStyle infoTextStyle(context) => AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120); + + Widget requestDetailCard(BuildContext context, WorkOrderData workOrder) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Wrap( + runSpacing: 8, + children: [ + StatusLabel( + label: workOrder.priority?.name, + id: workOrder.priority!.id!, + radius: 4, + textColor: AppColor.getPriorityStatusTextColor(context, workOrder.priority!.id!), + backgroundColor: AppColor.getPriorityStatusColor(context, workOrder.priority!.id!), + ), + 8.width, + StatusLabel( + radius: 4, + label: workOrder.status!.name, + textColor: AppColor.getHistoryLogStatusTextColorByName(workOrder.status!.name!), + backgroundColor: AppColor.getHistoryLogStatusColorByName(workOrder.status!.name!), + ), + ], + ).expanded, + Text( + workOrder.requestedDate!.toString().toServiceRequestCardFormat, + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ) + ], + ), + 8.height, + Text( + context.translation.requestDetails, + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 8.height, + Text( + '${'Session Name'.addTranslation}: ${workOrder.assetNdModel!.name?.cleanupWhitespace.capitalizeFirstOfEach}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + + // 8.height, + Text( + '${'Session Typ'.addTranslation}: ${workOrder.asset!.assetNumber}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${'Start Date:'.addTranslation}: ${workOrder.asset!.assetSerialNo}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${'End Date:'.addTranslation}: ${workOrder.asset!.assetSerialNo}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + ], + ).paddingOnly(start: 16, end: 16, top: 16, bottom: 8).toShadowContainer(context, padding: 0); + } + + Widget siteListCard(BuildContext context, WorkOrderData workOrder) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListView.separated( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsets.zero, + itemBuilder: (cxt, index) => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '${workOrder.workOrderContactPerson[0].name ?? '-'}', + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + Text( + '${context.translation.building}: ${workOrder.workOrderContactPerson[0].employeeId ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.floor}: ${workOrder.workOrderContactPerson[0].mobilePhone ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.department} ${workOrder.workOrderContactPerson[0].position ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.room}: ${workOrder.workOrderContactPerson[0].email ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + ], + ), + separatorBuilder: (cxt, index) => const Divider().defaultStyle(context), + itemCount: 4), + ], + ).toShadowContainer(context, padding: 12); + } +} 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 new file mode 100644 index 00000000..dc2c6736 --- /dev/null +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart @@ -0,0 +1,426 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/common_widgets/autocomplete_generic_field.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/controllers/providers/api/device_transfer_provider.dart'; +import 'package:test_sa/dashboard_latest/dashboard_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/device/asset_transfer_attachment.dart'; +import 'package:test_sa/models/device/device_transfer.dart'; +import 'package:test_sa/models/enums/user_types.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/new_models/department.dart'; +import 'package:test_sa/models/new_models/floor.dart'; +import 'package:test_sa/models/service_request/pending_service_request_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/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_text_form_field.dart'; +import 'package:test_sa/providers/ppm_service_provider.dart'; +import 'package:test_sa/providers/work_order/vendor_provider.dart'; +import 'package:test_sa/views/pages/user/requests/pending_requests_screen.dart'; +import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; +import 'package:test_sa/views/widgets/images/files_list.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; +import 'package:test_sa/views/widgets/parts/auto_complete_parts_field.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +import '../../../models/new_models/building.dart'; +import '../../../models/new_models/site.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 '../../../providers/gas_request_providers/site_provider.dart'; +import '../../../providers/loading_list_notifier.dart'; + +class AssetInventoryFormView extends StatefulWidget { + static const String id = "/request-device-transfer"; + + const AssetInventoryFormView({Key? key}) : super(key: key); + + @override + State createState() => _AssetInventoryFormViewState(); +} + +class _AssetInventoryFormViewState extends State { + //TODO Need to replace with provider and models we have ... + late DeviceTransferProvider _deviceTransferProvider; + final DeviceTransfer _transferModel = DeviceTransfer(id: 0); + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + Asset _assetDestination = Asset(); + Asset? _pickedAsset; + final List attachments = []; + + void _onSubmit() async { + _transferModel.assetId = _pickedAsset?.id; + _transferModel.destSiteId = _assetDestination.site?.id; + _transferModel.destBuildingId = _assetDestination.building?.id; + _transferModel.destFloorId = _assetDestination.floor?.id; + _transferModel.destDepartmentId = _assetDestination.department?.id; + _transferModel.destRoomId = _assetDestination.room?.id; + + if (!_formKey.currentState!.validate() || !(await validateRequest())) { + return; + } + _formKey.currentState!.save(); + 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)); + } + _transferModel.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() { + WidgetsBinding.instance.addPostFrameCallback((_) async { + //need to get internal and external request type data.. + await Provider.of(context, listen: false).getData(); + }); + super.initState(); + } + + @override + void dispose() { + _deviceTransferProvider.reset(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + _deviceTransferProvider = Provider.of(context, listen: false); + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar( + title: context.translation.addAsset, + titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + 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; + 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; + } + + 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, + AppTextFormField( + labelText: context.translation.serialNo, + backgroundColor: AppColor.fieldBgColor(context), + textAlign: TextAlign.center, + showShadow: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + style: Theme.of(context).textTheme.titleMedium, + ), + 12.height, + //TODO need to indentify where to + 12.height, + //model.. + AutoCompleteGenericField( + 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 []; + }, + initialValue: '', + // initialValue: model.partCatalogItem?.partNumber ?? "", + onPick: (part) { + setState(() {}); + }, + ), + 12.height, + //Asset Name.. + AutoCompleteGenericField( + clearAfterPick: false, + 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 []; + }, + initialValue: '', + // initialValue: model.partCatalogItem?.partNumber ?? "", + onPick: (part) { + setState(() {}); + }, + ), + 12.height, + //manufacture.. + AutoCompleteGenericField( + clearAfterPick: false, + 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 []; + }, + initialValue: '', + // initialValue: model.partCatalogItem?.partNumber ?? "", + onPick: (part) { + setState(() {}); + }, + ), + 12.height, + //model.. + AutoCompleteGenericField( + 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 []; + }, + initialValue: '', + // initialValue: model.partCatalogItem?.partNumber ?? "", + onPick: (part) { + 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, + + 12.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.site, + initialValue: _assetDestination.site, + disableValue: _pickedAsset?.site, + showShadow: false, + loading: _deviceTransferProvider.isSiteLoading, + enabled: false, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + onSelect: (value) { + _assetDestination.site = value; + _assetDestination.building = null; + _assetDestination.floor = null; + _assetDestination.department = null; + setState(() {}); + }, + ), + 12.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.building, + initialValue: _assetDestination.building, + showShadow: false, + showAsBottomSheet: true, + backgroundColor: AppColor.fieldBgColor(context), + enabled: _assetDestination.site?.buildings?.isNotEmpty ?? false, + staticData: _assetDestination.site?.buildings ?? [], + onSelect: (value) { + _assetDestination.building = value; + _assetDestination.floor = null; + _assetDestination.department = null; + setState(() {}); + }, + ), + 12.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.floor, + showShadow: false, + showAsBottomSheet: true, + initialValue: _assetDestination.floor, + backgroundColor: AppColor.fieldBgColor(context), + enabled: _assetDestination.building?.floors?.isNotEmpty ?? false, + staticData: _assetDestination.building?.floors ?? [], + onSelect: (value) { + _assetDestination.floor = value; + _assetDestination.department = null; + setState(() {}); + }, + ), + 12.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.department, + showShadow: false, + showAsBottomSheet: true, + initialValue: _assetDestination.department, + backgroundColor: AppColor.fieldBgColor(context), + enabled: _assetDestination.floor?.departments?.isNotEmpty ?? false, + staticData: _assetDestination.floor?.departments ?? [], + onSelect: (value) { + _assetDestination.department = value; + _assetDestination.room = null; + setState(() {}); + }, + ), + 12.height, + classificationWidget(label: 'Found'), + 12.height, + Text( + 'Asset Photo'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.white936), + ), + 12.height, + attachments.isEmpty + ? AttachmentPicker( + label: context.translation.attachImage, + attachment: attachments, + buttonColor: AppColor.black10, + onlyImages: true, + onChange: (value) { + setState(() {}); + }, + buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120), + ) + : MultiFilesPickerItem( + file: File(attachments.first.name ?? ''), + enabled: true, + onRemoveTap: (file) { + setState(() { + attachments.clear(); + }); + }, + ), + 12.height, + AppTextFormField( + backgroundColor: AppColor.fieldBgColor(context), + labelText: 'Remarks'.addTranslation, + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + showShadow: false, + onSaved: (text) { + _transferModel.comment = text; + }, + ), + // 100.height, + ], + ).toShadowContainer(context).paddingOnly(top: 20, start: 16, end: 16), + ).expanded, + 10.height, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton(buttonColor: AppColor.primary10, label: context.translation.submitRequest, maxWidth: true, onPressed: _onSubmit), + ), + ], + ), + ), + ); + } + + Widget classificationWidget({String? label}) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Classification'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.white936), + ), + //TODO Need to set background and text color according to data.. + StatusLabel( + label: label, + radius: 4, + textColor: AppColor.getPriorityStatusTextColor(context, 81), + backgroundColor: AppColor.getPriorityStatusColor(context, 370), + ), + ], + ); + } + + Future validateRequest() async { + if (_pickedAsset == null) { + await Fluttertoast.showToast(msg: "Please Select Asset"); + return false; + } + 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; + } +} diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart new file mode 100644 index 00000000..f68f7fa1 --- /dev/null +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart @@ -0,0 +1,116 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/pick_site_information_view.dart'; +import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import '../provider/asset_inventory_provider.dart'; + +class AssetInventoryPage extends StatefulWidget { + final int sessionId; + + const AssetInventoryPage({Key? key, required this.sessionId}) : super(key: key); + + @override + _AssetInventoryPageState createState() { + return _AssetInventoryPageState(); + } +} + +class _AssetInventoryPageState extends State { + late AssetInventoryProvider _assetInventoryProvider; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + getInitialData(); + }); + } + + Future getInitialData() async { + _assetInventoryProvider = Provider.of(context, listen: false); + ServiceRequestDetailProvider _provider = Provider.of(context, listen: false); + await _provider.getWorkOrderById(id: widget.sessionId); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + appBar: DefaultAppBar( + title: 'Inventory Session Request'.addTranslation, + onBackPress: () { + Navigator.pop(context); + }, + ), + body: DefaultTabController( + length: 2, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight), + decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.white10, borderRadius: BorderRadius.circular(10)), + child: TabBar( + padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth), + labelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, + unselectedLabelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, + unselectedLabelStyle: AppTextStyles.bodyText, + labelStyle: AppTextStyles.bodyText, + indicatorPadding: EdgeInsets.zero, + indicatorSize: TabBarIndicatorSize.tab, + dividerColor: Colors.transparent, + indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)), + onTap: (index) { + }, + tabs: [ + Tab(text: 'Request Details'.addTranslation, height: 57.toScreenHeight), + Tab(text: '${'Scan Assets'.addTranslation} (1)', height: 57.toScreenHeight), + ], + ), + ), + 12.height, + TabBarView( + children: [ + AssetInventoryDetailView(sessionModel: SessionModel(),), + AssetInventoryScanAssetView(workOrderData: Provider.of(context,listen: false).currentWorkOrder!.data!,), + ], + ).expanded, + SafeArea( + top: false, + right: false, + left: false, + child: FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Scan Assets'.addTranslation, + onPressed: _scanAsset, + // buttonColor: AppColor.primary10, + ), + ), + ).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0), + ], + ), + )); + } + Future _scanAsset() async { + Navigator.push(context, MaterialPageRoute(builder: (contxt) => PickSiteInformationView(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 new file mode 100644 index 00000000..419afd9c --- /dev/null +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart @@ -0,0 +1,53 @@ + +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/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/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; + +import 'asset_detail_card_view.dart'; + +class AssetInventoryScanAssetView extends StatelessWidget { + WorkOrderData workOrderData ; + AssetInventoryScanAssetView({Key? key,required this.workOrderData}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SafeArea( + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListView.separated( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsets.zero, + itemBuilder: (cxt, index) => AssetDetailCardView(workOrder:workOrderData), + separatorBuilder: (cxt, index) => 12.height, + itemCount: 4), + 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(context), + ), + ], + ).paddingOnly(start: 16, end: 16,), + ), + ); + } + void _addAsset(BuildContext context ){ + //TODO need to confirm navigation... + Navigator.push(context, MaterialPageRoute(builder: (contxt) => const AssetInventoryFormView())); + } +} diff --git a/lib/modules/asset_inventory_module/pages/inventory_seession_card.dart b/lib/modules/asset_inventory_module/pages/inventory_seession_card.dart new file mode 100644 index 00000000..9a0d6912 --- /dev/null +++ b/lib/modules/asset_inventory_module/pages/inventory_seession_card.dart @@ -0,0 +1,133 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/all_requests_and_count_model.dart'; +import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_page.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class InventorySessionCard extends StatelessWidget { + final Data? requestData; + final RequestsDetails? requestDetails; + final bool showShadow; + + const InventorySessionCard({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); + + @override + Widget build(BuildContext context) { + if (requestData != null) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: requestData!.priorityName!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.priorityName!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.priorityName!), + ), + 8.width, + StatusLabel( + label: requestData!.statusName!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.statusName!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.statusName!), + ), + 1.width.expanded, + Text( + requestData!.transactionDate?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + ], + ), + 8.height, + (requestData?.typeTransaction ?? context.translation.taskRequest).heading5(context), + //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), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.of(context).push(MaterialPageRoute( + builder: (_) => AssetInventoryPage( + sessionId: requestData!.id!, + ))); + }); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: requestDetails!.priority!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.priority!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.priority!), + ), + 8.width, + StatusLabel( + label: requestDetails!.status!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.status!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.status!), + ), + 1.width.expanded, + Text( + requestDetails!.date?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + ], + ), + 8.height, + (requestDetails?.nameOfType ?? context.translation.taskRequest).heading5(context), + 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), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.of(context).push(MaterialPageRoute( + builder: (_) => AssetInventoryPage( + sessionId: requestDetails!.id!, + ))); + }); + } + + Widget infoWidget({required String label, String? value, required BuildContext context}) { + if (value != null && value.isNotEmpty) { + return '$label: $value'.bodyText(context); + } + return const SizedBox(); + } +} 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 new file mode 100644 index 00000000..b784f08e --- /dev/null +++ b/lib/modules/asset_inventory_module/pages/pick_site_information_view.dart @@ -0,0 +1,225 @@ +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/models/new_models/work_order_detail_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/cm_module/service_request_detail_provider.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/gas_request_providers/site_provider.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +import '../../../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 { + late SessionModel _sessionModel; + + //TODO need to remove this ... + Asset _assetDestination = Asset(); + late ServiceRequestDetailProvider _requestDetailProvider; + + void _onSave() async {} + + @override + void initState() { + _sessionModel = widget.sessionModel; + super.initState(); + } + + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + _requestDetailProvider = Provider.of(context, listen: false); + 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: [ + SingleChildScrollView( + child: Column( + children: [ + siteInfoCard(context), + 12.height, + assetDetailCard(context, _requestDetailProvider.currentWorkOrder!.data!), + 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, + ], + ).paddingOnly(start: 16, end: 16, top: 16), + ).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) => const AssetInventoryFormView())); + } + Widget assetDetailCard(BuildContext context, WorkOrderData workOrder) { + + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListView.separated( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsets.zero, + itemBuilder: (cxt, index) => AssetDetailCardView(workOrder:workOrder), + separatorBuilder: (cxt, index) => 12.height, + itemCount: 4), + ], + ); + } + + + Widget siteInfoCard(BuildContext context,){ + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 12.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.site, + initialValue: _assetDestination.site, + showShadow: false, + // loading: _deviceTransferProvider.isSiteLoading, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + onSelect: (value) { + _assetDestination.site = value; + _assetDestination.building = null; + _assetDestination.floor = null; + _assetDestination.department = null; + setState(() {}); + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.building, + initialValue: _assetDestination.building, + showShadow: false, + showAsBottomSheet: true, + backgroundColor: AppColor.fieldBgColor(context), + enabled: _assetDestination.site?.buildings?.isNotEmpty ?? false, + staticData: _assetDestination.site?.buildings ?? [], + onSelect: (value) { + _assetDestination.building = value; + _assetDestination.floor = null; + _assetDestination.department = null; + setState(() {}); + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.floor, + showShadow: false, + showAsBottomSheet: true, + initialValue: _assetDestination.floor, + backgroundColor: AppColor.fieldBgColor(context), + enabled: _assetDestination.building?.floors?.isNotEmpty ?? false, + staticData: _assetDestination.building?.floors ?? [], + onSelect: (value) { + _assetDestination.floor = value; + _assetDestination.department = null; + setState(() {}); + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.department, + showShadow: false, + showAsBottomSheet: true, + initialValue: _assetDestination.department, + backgroundColor: AppColor.fieldBgColor(context), + enabled: _assetDestination.floor?.departments?.isNotEmpty ?? false, + staticData: _assetDestination.floor?.departments ?? [], + onSelect: (value) { + _assetDestination.department = value; + _assetDestination.room = null; + setState(() {}); + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.room, + showShadow: false, + showAsBottomSheet: true, + initialValue: _assetDestination.room, + backgroundColor: AppColor.fieldBgColor(context), + enabled: _assetDestination.department?.rooms?.isNotEmpty ?? false, + staticData: _assetDestination.department?.rooms ?? [], + onSelect: (value) { + _assetDestination.room = value; + setState(() {}); + }, + ), + 8.height, + ], + ).toShadowContainer(context); + } + + Future validateRequest() async { + 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; + } +} diff --git a/lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart b/lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart new file mode 100644 index 00000000..2d5de6c4 --- /dev/null +++ b/lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart @@ -0,0 +1,62 @@ +import 'dart:convert'; +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:http/http.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/models/service_request/pending_service_request_model.dart'; +import 'package:test_sa/models/service_request/service_report.dart'; +import 'package:test_sa/models/service_request/service_request.dart'; +import 'package:test_sa/models/service_request/service_request_search.dart'; +import 'package:test_sa/models/service_request/spare_parts.dart'; +import 'package:test_sa/models/service_request/supp_engineer_work_orders.dart'; +import 'package:test_sa/models/service_request/supplier_engineer_model.dart'; +import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; + +import '../../../models/service_request/search_work_order.dart'; +import '../../../models/service_request/wo_call_request.dart'; +import '../../../models/user.dart'; +import '../../../new_views/common_widgets/app_lazy_loading.dart'; + +class AssetInventoryProvider extends ChangeNotifier { + final pageItemNumber = 10; + + SessionModel? sessionModel; + + void reset() { + nextPage = true; + stateCode = null; + } + + int? stateCode; + bool isDetailLoading = false; + bool nextPage = true; + bool isLoading = false; + + Future getSessionById({required int id}) async { + try { + isLoading = true; + notifyListeners(); + final response = await ApiManager.instance.get(URLs.getAssetInventoryById + "?assetInventoryId=$id"); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + sessionModel = await SessionModel.fromJson(json.decode(response.body)); + } else { + sessionModel = null; + } + isLoading = false; + notifyListeners(); + } catch (e) { + log("getSessionError [error] : $e"); + isLoading = false; + sessionModel = null; + notifyListeners(); + return null; + } + } +} diff --git a/lib/new_views/pages/land_page/contact_us_bottom_sheet.dart b/lib/new_views/pages/land_page/contact_us_bottom_sheet.dart index 3d35de8e..784a125e 100644 --- a/lib/new_views/pages/land_page/contact_us_bottom_sheet.dart +++ b/lib/new_views/pages/land_page/contact_us_bottom_sheet.dart @@ -1,11 +1,9 @@ -import 'package:clipboard/clipboard.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; -import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/site_contact_info_model.dart'; @@ -77,7 +75,7 @@ class ContactUsBottomSheet extends StatelessWidget { padding: EdgeInsets.zero, iconSize: 20, onPressed: () { - FlutterClipboard.copy('Hello Flutter friends'); + // FlutterClipboard.copy('Hello Flutter friends'); }, ) ], diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index 23f1c89a..d7fb13c4 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -3,10 +3,12 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/device_transfer_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/enums/user_types.dart'; @@ -50,7 +52,7 @@ class _MyRequestsPageState extends State { if (context.settingProvider.isUserFlowMedical) { requestsList.add(Request(7, 'Recall and Alert')); } - + requestsList.add(Request(8, 'Inventory Session'.addTranslation)); _provider = Provider.of(context, listen: false); _provider!.reset(); WidgetsBinding.instance.addPostFrameCallback((_) { diff --git a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart index ace4047f..d27e9a4d 100644 --- a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart +++ b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/inventory_seession_card.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart'; @@ -45,44 +46,29 @@ class RequestPaginatedListview extends StatelessWidget { } Widget _buildRequestItem(Data request) { - bool isServiceRequest = request.transactionNo == 1; - bool isGasRefill = request.transactionNo == 2; - bool isAssetTransfer = request.transactionNo == 3; - bool isPPMs = request.transactionNo == 4; - bool isRecurrentTask = request.transactionNo == 5; - bool isTask = request.transactionNo == 6; - - if (isServiceRequest) { - return ServiceRequestItemView(requestData: request, refreshData: false); - } else if (isGasRefill) { - return GasRefillItemView(requestData: request); - } else if (isPPMs) { - return PpmItemView(requestData: request); - } else if (isAssetTransfer) { - return DeviceItemView(requestData: request); - } else if (isRecurrentTask) { - return RecurrentWoItemView(requestData: request); - } else if (isTask) { - return TaskRequestItemView(requestData: request); - } else { - return Container( - height: 100, - width: double.infinity, - color: Colors.grey, - ); + switch (request.transactionNo) { + case 1: + return ServiceRequestItemView(requestData: request); + case 2: + return GasRefillItemView(requestData: request); + case 3: + return DeviceItemView(requestData: request); + case 4: + return PpmItemView(requestData: request); + case 5: + return RecurrentWoItemView(requestData: request); + case 6: + return TaskRequestItemView(requestData: request); + case 7: + return TaskRequestItemView(requestData: request); + case 8: + return InventorySessionCard(requestData: request); + default: + return Container( + height: 100, + width: double.infinity, + color: Colors.grey, + ); } } } - -// return Column( -// mainAxisSize: MainAxisSize.min, -// children: List.generate(isLoading ? 6 : list.length, (index) { -// // if (isLoading) { -// // return const SizedBox().toRequestShimmer(context, isLoading); -// // } -// // else { -// return Padding( -// padding: EdgeInsets.symmetric(vertical: 10.toScreenHeight), -// child: _buildRequestItem(list[index])); -// // } -// })); 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 a3548947..6a2c20f2 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 @@ -4,6 +4,7 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/all_requests_and_count_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/inventory_seession_card.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/gas_refill_item_view.dart'; @@ -29,7 +30,8 @@ class RequestItemViewList extends StatelessWidget { if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading); switch (list[index].transactionType) { case 1: - return ServiceRequestItemView(requestDetails: list[index]); + // return ServiceRequestItemView(requestDetails: list[index]); + return InventorySessionCard(requestDetails: list[index]); case 2: return GasRefillItemView(requestDetails: list[index]); case 3: @@ -42,6 +44,8 @@ class RequestItemViewList extends StatelessWidget { return TaskRequestItemView(requestDetails: list[index]); case 7: return TaskRequestItemView(requestDetails: list[index]); + case 8: + return InventorySessionCard(requestDetails: list[index]); default: Container( height: 100, diff --git a/lib/views/widgets/equipment/asset_picker.dart b/lib/views/widgets/equipment/asset_picker.dart index a9d8e5f0..78a687ab 100644 --- a/lib/views/widgets/equipment/asset_picker.dart +++ b/lib/views/widgets/equipment/asset_picker.dart @@ -17,8 +17,12 @@ class AssetPicker extends StatelessWidget { final List deviceList; final bool editable; final bool showAssetInfo; + final bool showBorder; final Color? borderColor; final Color? buttonColor; + final Color? iconColor; + final Color? labelColor; + final String? label; Color? backgroundColor; final bool forPPM; final bool showLoading; @@ -34,8 +38,12 @@ class AssetPicker extends StatelessWidget { this.onAssetRemove, this.borderColor, this.buttonColor, + this.label, + this.iconColor, + this.labelColor, this.backgroundColor, this.showAssetInfo = true, + this.showBorder = false, this.multiSelection = false, this.forPPM = false, this.showLoading = false}) @@ -57,15 +65,16 @@ class AssetPicker extends StatelessWidget { decoration: BoxDecoration( color: buttonColor ?? backgroundColor ?? AppColor.blueStatus(context), borderRadius: BorderRadius.circular(10), + border: showBorder?Border.all(color: borderColor ?? AppColor.blueStatus(context), width: 2):null, // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 14)], ), padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), child: Row( mainAxisSize: MainAxisSize.min, children: [ - "scan_asset".toSvgAsset(height: 22, fit: BoxFit.fitHeight, color: context.isDark ? AppColor.neutral20 : Colors.white), + "scan_asset".toSvgAsset(height: 22, fit: BoxFit.fitHeight, color: context.isDark ? AppColor.neutral20 :iconColor?? Colors.white), 8.width, - "Scan or Pick Asset".bodyText(context).custom(color: context.isDark ? AppColor.neutral20 : Colors.white), + ' ${label??"Scan or Pick Asset"}'.bodyText(context).custom(color: context.isDark ? AppColor.neutral20 : labelColor?? Colors.white), ], ), ).onPress(() async { diff --git a/pubspec.lock b/pubspec.lock index 484acd6c..1b05ec91 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -177,6 +177,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.1" + clipboard: + dependency: "direct main" + description: + name: clipboard + sha256: "1920c0337f8808be4166c5f1b236301ff381ef69633b0757c502d97f1f740102" + url: "https://pub.dev" + source: hosted + version: "2.0.2" clock: dependency: transitive description: From f9b101c2335564c8f9ba396a258eb751361bdcb3 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Sun, 5 Oct 2025 17:19:03 +0300 Subject: [PATCH 02/11] improvement. --- .../pages/asset_detail_card_view.dart | 75 ++++++++++--------- .../pages/asset_inventory_detail_view.dart | 27 ++----- .../pages/asset_inventory_form_view.dart | 1 - .../pages/asset_inventory_page.dart | 25 +++---- .../asset_inventory_scan_assets_view.dart | 60 +++++++-------- .../pages/pick_site_information_view.dart | 64 +++++++--------- 6 files changed, 114 insertions(+), 138 deletions(-) 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 a77a6f6a..82c0954f 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 @@ -9,56 +9,59 @@ import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart'; class AssetDetailCardView extends StatelessWidget { - WorkOrderData workOrder; + // WorkOrderData workOrder; - AssetDetailCardView({super.key,required this.workOrder}); + AssetDetailCardView({ + super.key, + }); @override Widget build(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - StatusLabel( - label: workOrder.priority?.name, - id: workOrder.priority!.id!, - radius: 4, - textColor: AppColor.getPriorityStatusTextColor(context, workOrder.priority!.id!), - backgroundColor: AppColor.getPriorityStatusColor(context, workOrder.priority!.id!), - ), - 8.height, + // StatusLabel( + // label: workOrder.priority?.name, + // id: workOrder.priority!.id!, + // radius: 4, + // textColor: AppColor.getPriorityStatusTextColor(context, workOrder.priority!.id!), + // backgroundColor: AppColor.getPriorityStatusColor(context, workOrder.priority!.id!), + // ), + // 8.height, Text( context.translation.assetInformation, style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ), // 8.height, Text( - '${context.translation.serialNo}: ${workOrder.workOrderContactPerson[0].name ?? '-'}', + '${context.translation.serialNo}: ${"workOrder.workOrderContactPerson[0].name" ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - '${context.translation.manufacture}: ${workOrder.workOrderContactPerson[0].name}', + '${context.translation.manufacture}: ${"workOrder.workOrderContactPerson[0].name"}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - '${context.translation.model}: ${workOrder.workOrderContactPerson[0].name}', + '${context.translation.model}: ${"workOrder.workOrderContactPerson[0].name"}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - '${context.translation.site}: ${workOrder.workOrderContactPerson[0].name}', + '${context.translation.site}: ${"workOrder.workOrderContactPerson[0].name"}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - '${context.translation.department}: ${workOrder.workOrderContactPerson[0].name}', + '${context.translation.department}: ${"workOrder.workOrderContactPerson[0].name"}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ),Text( - '${context.translation.supplier}: ${workOrder.workOrderContactPerson[0].name}', + ), + Text( + '${context.translation.supplier}: ${"workOrder.workOrderContactPerson[0].name"}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ),Text( - '${'Remarks'.addTranslation}: ${workOrder.workOrderContactPerson[0].name}', + ), + Text( + '${'Remarks'.addTranslation}: ${"workOrder.workOrderContactPerson[0].name"}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), ], @@ -67,28 +70,28 @@ 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.. - }) - ], - ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 'edit_icon'.toSvgAsset().onPress(() { + //Handle edit... + }), + 20.width, + 'delete_icon'.toSvgAsset().onPress(() { + //handle delete.. + }) + ], + ), 20.height, Container( height: 100, - width:100, + width: 100, color: Colors.red, child: 'edit_icon'.toSvgAsset().center, ) - - ],) + ], + ) ], ).toShadowContainer(context); } diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart index a805f1b1..0421ab13 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart @@ -35,28 +35,17 @@ class _AssetInventoryDetailViewState extends State { ? const CircularProgressIndicator(color: AppColor.primary10).center : requestProvider.currentWorkOrder == null ? const NoDataFound() - : Column( - children: [ - SingleChildScrollView( - padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - requestDetailCard(context, requestProvider.currentWorkOrder!.data!), - 12.height, - siteListCard(context, requestProvider.currentWorkOrder!.data!), - // 20.height, - ], - ), - ).expanded, - ], - ); + : ListView( + padding: const EdgeInsets.all(16), + children: [ + requestDetailCard(context, requestProvider.currentWorkOrder!.data!), + 12.height, + siteListCard(context, requestProvider.currentWorkOrder!.data!), + ], + ); }); } - - TextStyle infoTextStyle(context) => AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120); Widget requestDetailCard(BuildContext context, WorkOrderData workOrder) { 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 dc2c6736..68cde22a 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 @@ -256,7 +256,6 @@ class _AssetInventoryFormViewState extends State { setState(() {}); }, ), - 12.height, 12.height, SingleItemDropDownMenu( 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 f68f7fa1..924891c2 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart @@ -40,8 +40,8 @@ class _AssetInventoryPageState extends State { Future getInitialData() async { _assetInventoryProvider = Provider.of(context, listen: false); - ServiceRequestDetailProvider _provider = Provider.of(context, listen: false); - await _provider.getWorkOrderById(id: widget.sessionId); + // ServiceRequestDetailProvider _provider = Provider.of(context, listen: false); + // await _provider.getWorkOrderById(id: widget.sessionId); } @override @@ -89,21 +89,16 @@ class _AssetInventoryPageState extends State { TabBarView( children: [ AssetInventoryDetailView(sessionModel: SessionModel(),), - AssetInventoryScanAssetView(workOrderData: Provider.of(context,listen: false).currentWorkOrder!.data!,), + AssetInventoryScanAssetView(), ], ).expanded, - SafeArea( - top: false, - right: false, - left: false, - child: FooterActionButton.footerContainer( - context: context, - child: AppFilledButton( - buttonColor: AppColor.primary10, - label: 'Scan Assets'.addTranslation, - onPressed: _scanAsset, - // buttonColor: AppColor.primary10, - ), + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Scan Assets'.addTranslation, + onPressed: _scanAsset, + // buttonColor: AppColor.primary10, ), ).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0), ], 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 419afd9c..a732705e 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,4 +1,3 @@ - import 'package:flutter/material.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; @@ -12,42 +11,41 @@ import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'asset_detail_card_view.dart'; class AssetInventoryScanAssetView extends StatelessWidget { - WorkOrderData workOrderData ; - AssetInventoryScanAssetView({Key? key,required this.workOrderData}) : super(key: key); + AssetInventoryScanAssetView({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - return SafeArea( - child: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ListView.separated( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - padding: EdgeInsets.zero, - itemBuilder: (cxt, index) => AssetDetailCardView(workOrder:workOrderData), - separatorBuilder: (cxt, index) => 12.height, - itemCount: 4), - 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(context), - ), - ], - ).paddingOnly(start: 16, end: 16,), + return SingleChildScrollView( + padding: EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListView.separated( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsets.zero, + itemBuilder: (cxt, index) => AssetDetailCardView(), + separatorBuilder: (cxt, index) => 12.height, + itemCount: 4), + 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(context), + ), + ], ), ); } - void _addAsset(BuildContext context ){ + + void _addAsset(BuildContext context) { //TODO need to confirm navigation... - Navigator.push(context, MaterialPageRoute(builder: (contxt) => const AssetInventoryFormView())); + Navigator.push(context, MaterialPageRoute(builder: (contxt) => const AssetInventoryFormView())); } } 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 index b784f08e..a9995ed0 100644 --- a/lib/modules/asset_inventory_module/pages/pick_site_information_view.dart +++ b/lib/modules/asset_inventory_module/pages/pick_site_information_view.dart @@ -56,15 +56,15 @@ class _PickSiteInformationViewState extends State { Widget build(BuildContext context) { _requestDetailProvider = Provider.of(context, listen: false); 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: [ - SingleChildScrollView( - child: Column( + 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), 12.height, @@ -82,38 +82,30 @@ class _PickSiteInformationViewState extends State { ), 12.height, ], - ).paddingOnly(start: 16, end: 16, top: 16), - ).expanded, - FooterActionButton.footerContainer( - context: context, - child: AppFilledButton(buttonColor: AppColor.primary10, label: context.translation.save, maxWidth: true, onPressed: _onSave), - ), - ], - ) - ); + ).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) => const AssetInventoryFormView())); - } - Widget assetDetailCard(BuildContext context, WorkOrderData workOrder) { - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ListView.separated( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - padding: EdgeInsets.zero, - itemBuilder: (cxt, index) => AssetDetailCardView(workOrder:workOrder), - separatorBuilder: (cxt, index) => 12.height, - itemCount: 4), - ], - ); + void _addAsset() { + Navigator.push(context, MaterialPageRoute(builder: (contxt) => const AssetInventoryFormView())); } + Widget assetDetailCard(BuildContext context, WorkOrderData workOrder) { + return ListView.separated( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsets.zero, + itemBuilder: (cxt, index) => AssetDetailCardView(), + separatorBuilder: (cxt, index) => 12.height, + itemCount: 4); + } - Widget siteInfoCard(BuildContext context,){ + Widget siteInfoCard(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ From c19fdb173ba96e7ff988cda3d39bed073a117b08 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Mon, 6 Oct 2025 18:03:55 +0300 Subject: [PATCH 03/11] api integrated for main views --- android/app/build.gradle | 6 +- lib/controllers/api_routes/urls.dart | 4 +- lib/models/new_models/building.dart | 13 +- lib/models/new_models/department.dart | 7 +- lib/models/new_models/floor.dart | 10 +- lib/models/new_models/room_model.dart | 4 +- lib/models/new_models/site.dart | 10 +- .../models/asset_inventory_model.dart | 251 +++++++++++++++ .../models/session_model.dart | 292 +++++++++--------- .../pages/asset_detail_card_view.dart | 47 +-- .../pages/asset_inventory_detail_view.dart | 156 +++++----- .../pages/asset_inventory_form_view.dart | 240 +++++--------- .../pages/asset_inventory_page.dart | 115 ++++--- .../asset_inventory_scan_assets_view.dart | 82 +++-- .../pages/pick_site_information_view.dart | 148 +++++---- .../provider/asset_inventory_provider.dart | 62 +++- .../common_widgets/app_filled_button.dart | 4 +- 17 files changed, 904 insertions(+), 547 deletions(-) create mode 100644 lib/modules/asset_inventory_module/models/asset_inventory_model.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index b92d6c6d..b315f561 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -38,12 +38,12 @@ android { compileOptions { coreLibraryDesugaringEnabled true - sourceCompatibility JavaVersion.VERSION_21 - targetCompatibility JavaVersion.VERSION_21 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = "21" // Must match the compileOptions target + jvmTarget = "17" // Must match the compileOptions target } defaultConfig { diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 26bc7b04..5b82e823 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -298,5 +298,7 @@ class URLs { // asset inventory Urls. static get getAssetInventoryById => '$_baseUrl/AssetInventory/GetAssetInventoryById'; -// AssetInventory/GetAssetInventoryById + static get getAssetsInSession => '$_baseUrl/AssetInventory/GetAssetsInSeassion'; + static get getInventoryDetailsByFilter => '$_baseUrl/AssetInventory/GetInventoryDetailsByFilter'; + } diff --git a/lib/models/new_models/building.dart b/lib/models/new_models/building.dart index 131d8d40..e112af11 100644 --- a/lib/models/new_models/building.dart +++ b/lib/models/new_models/building.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:test_sa/models/base.dart'; import 'package:test_sa/models/new_models/floor.dart'; @@ -10,15 +12,20 @@ class Building extends Base { }) : super(identifier: id?.toString() ?? '', name: name); // Handle potential null id Building.fromJson(dynamic json) { - id = json['id']; - identifier = id?.toString() ?? ''; // Handle potential null id - name = json['name']; + id = json['id'] ?? json['buildingId']; + identifier = id?.toString() ?? ''; + name = json['name'] ?? json['buildingName']; value = json['value']; if (json['floors'] != null) { floors = []; json['floors'].forEach((v) { floors!.add(Floor.fromJson(v)); }); + } else if (json['assetInventoryFloors'] != null) { + floors = []; + json['assetInventoryFloors'].forEach((v) { + floors!.add(Floor.fromJson(v)); + }); } } diff --git a/lib/models/new_models/department.dart b/lib/models/new_models/department.dart index fb93cc40..a2f23206 100644 --- a/lib/models/new_models/department.dart +++ b/lib/models/new_models/department.dart @@ -13,7 +13,7 @@ class Department extends Base { }) : super(identifier: id?.toString() ?? '', name: departmentName); // Handle potential null id Department.fromJson(dynamic json) { - id = json['id']; + id = json['id']??json['departmentId']; identifier = id?.toString() ?? ''; // Handle potential null id departmentName = json['departmentName'] ?? json['name']; name = departmentName; @@ -25,6 +25,11 @@ class Department extends Base { json['rooms'].forEach((v) { rooms!.add(Rooms.fromJson(v)); // Use '!' since rooms is non-nullable after initialization }); + } else if (json['assetInventoryRooms'] != null) { + rooms = []; + json['assetInventoryRooms'].forEach((v) { + rooms!.add(Rooms.fromJson(v)); // Use '!' since rooms is non-nullable after initialization + }); } } diff --git a/lib/models/new_models/floor.dart b/lib/models/new_models/floor.dart index 2f62da25..33e74d8b 100644 --- a/lib/models/new_models/floor.dart +++ b/lib/models/new_models/floor.dart @@ -10,9 +10,9 @@ class Floor extends Base { }) : super(identifier: id?.toString() ?? '', name: name); // Handle potentialnull id Floor.fromJson(dynamic json) { - id = json['id']; + id = json['id']??json['floorId']; identifier = id?.toString() ?? ''; // Handle potential null id - name = json['name']; + name = json['name']??json['floorName']; value = json['value']; if (json['departments'] != null) { departments = []; @@ -20,6 +20,12 @@ class Floor extends Base { departments!.add(Department.fromJson(v)); // Use '!' since departments is non-nullable after initialization }); } + else if (json['assetInventoryDepartments'] != null) { + departments = []; + json['assetInventoryDepartments'].forEach((v) { + departments!.add(Department.fromJson(v)); // Use '!' since departments is non-nullable after initialization + }); + } } num? id; // Now nullable diff --git a/lib/models/new_models/room_model.dart b/lib/models/new_models/room_model.dart index 1fa7ccbe..62012565 100644 --- a/lib/models/new_models/room_model.dart +++ b/lib/models/new_models/room_model.dart @@ -10,8 +10,8 @@ class Rooms extends Base { Rooms.fromJson(Map? json) { // Handle potential null json input - id = json?['id']; // Use null-aware operator - name = json?['name']; + id = json?['id']?? json?['roomId']; + name = json?['name']??json?['roomName']; value = json?['value']; } diff --git a/lib/models/new_models/site.dart b/lib/models/new_models/site.dart index e76839fd..83922549 100644 --- a/lib/models/new_models/site.dart +++ b/lib/models/new_models/site.dart @@ -9,9 +9,9 @@ class Site extends Base { }) : super(identifier: id?.toString() ?? '', name: custName); // Handle potential null id Site.fromJson(dynamic json) { - id = json['id']; + id = json['siteId'] ?? json['id']; identifier = id?.toString() ?? ''; // Handle potential null id - custName = json['custName']?? json['siteName']; + custName = json['custName']?? json['siteName']; name = custName; if (json['buildings'] != null) { buildings = []; @@ -19,6 +19,12 @@ class Site extends Base { buildings!.add(Building.fromJson(v)); // Use '!' since buildings is initialized here }); } + else if (json['assetInventoryBuildings'] != null) { + buildings = []; + json['assetInventoryBuildings'].forEach((v) { + buildings!.add(Building.fromJson(v)); + }); + } } num? id; // Now nullable diff --git a/lib/modules/asset_inventory_module/models/asset_inventory_model.dart b/lib/modules/asset_inventory_module/models/asset_inventory_model.dart new file mode 100644 index 00000000..5ed9a0d7 --- /dev/null +++ b/lib/modules/asset_inventory_module/models/asset_inventory_model.dart @@ -0,0 +1,251 @@ +class AssetInventoryResponse { + num? totalRows; + num? count; + String? message; + String? title; + String? innerMessage; + num? responseCode; + bool? isSuccess; + List? assetList; + + AssetInventoryResponse({ + this.totalRows, + this.count, + this.message, + this.title, + this.innerMessage, + this.responseCode, + this.isSuccess, + this.assetList, + }); + + AssetInventoryResponse.fromJson(Map json) { + totalRows = json['totalRows']; + count = json['count']; + message = json['message']; + title = json['title']; + innerMessage = json['innerMessage']; + responseCode = json['responseCode']; + isSuccess = json['isSuccess']; + if (json['data'] != null) { + assetList = (json['data'] as List) + .map((item) => AssetInventoryModel.fromJson(item)) + .toList(); + } + } + + Map toJson() { + return { + 'totalRows': totalRows, + 'count': count, + 'message': message, + 'title': title, + 'innerMessage': innerMessage, + 'responseCode': responseCode, + 'isSuccess': isSuccess, + // assetList not needed in toJson because you’ll likely only send AssetInventoryModel for updates + }; + } +} + +class AssetInventoryModel { + num? id; + num? assetId; + String? assetNumber; + String? serialNo; + String? assetName; + String? model; + String? manufacturer; + String? supplierName; + String? site; + String? building; + String? floor; + String? department; + String? room; + num? statusId; + String? status; + num? statusValue; + num? statusByAdminId; + String? statusByAdmin; + num? statusByAdminValue; + + bool? isNotRegistered; + num? sessionId; + num? assetImportId; + num? siteId; + 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? 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; + + AssetInventoryModel({ + this.id, + this.assetId, + this.assetNumber, + this.serialNo, + this.assetName, + this.model, + this.manufacturer, + this.supplierName, + this.site, + this.building, + this.floor, + this.department, + this.room, + this.statusId, + this.status, + this.statusValue, + this.statusByAdminId, + this.statusByAdmin, + this.statusByAdminValue, + this.isNotRegistered, + this.sessionId, + this.assetImportId, + this.siteId, + this.buildingId, + this.floorId, + this.departmentId, + this.roomId, + this.oldAssetNumber, + this.newAssetNumber, + this.oldSerialNo, + this.newSerialNo, + this.oldAssetNameId, + this.newAssetNameId, + this.newAssetNameText, + this.oldModelId, + this.newModelId, + 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, + }); + + AssetInventoryModel.fromJson(Map json) { + id = json['id']; + assetId = json['assetId']; + assetNumber = json['assetNumber']; + serialNo = json['serialNo']; + assetName = json['assetName']; + model = json['model']; + manufacturer = json['manufacturer']; + supplierName = json['supplierName']; + site = json['site']; + building = json['building']; + floor = json['floor']; + department = json['department']; + room = json['room']; + statusId = json['statusId']; + status = json['status']; + statusValue = json['statusValue']; + statusByAdminId = json['statusByAdminId']; + statusByAdmin = json['statusByAdmin']; + statusByAdminValue = json['statusByAdminValue']; + + isNotRegistered = json['isNotRegistered']; + sessionId = json['sessionId']; + assetImportId = json['assetImportId']; + siteId = json['siteId']; + buildingId = json['buildingId']; + floorId = json['floorId']; + 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']; + photo = json['photo']; + photoOriginName = json['photoOriginName']; + remarks = json['remarks']; + oldSiteId = json['oldSiteId']; + oldBuildingId = json['oldBuildingId']; + oldFloorId = json['oldFloorId']; + oldDepartmentId = json['oldDepartmentId']; + oldRoomId = json['oldRoomId']; + } + + Map toJson() { + return { + 'isNotRegistered': isNotRegistered, + 'sessionId': sessionId, + 'assetImportId': assetImportId, + 'assetId': assetId, + 'siteId': siteId, + 'buildingId': buildingId, + '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, + }; + } +} diff --git a/lib/modules/asset_inventory_module/models/session_model.dart b/lib/modules/asset_inventory_module/models/session_model.dart index 1860d02d..c758628c 100644 --- a/lib/modules/asset_inventory_module/models/session_model.dart +++ b/lib/modules/asset_inventory_module/models/session_model.dart @@ -1,4 +1,6 @@ +import 'package:test_sa/models/new_models/site.dart'; + class SessionModel { int? id; String? sessionName; @@ -8,7 +10,7 @@ class SessionModel { String? statusName; String? startDate; String? endDate; - List assetInventorySites = []; + List assetInventorySites = []; List assetInventoryAssignedEmployee = []; SessionModel({ @@ -20,7 +22,7 @@ class SessionModel { this.statusName, this.startDate, this.endDate, - List? assetInventorySites, + List? assetInventorySites, List? assetInventoryAssignedEmployee, }) { this.assetInventorySites = assetInventorySites ?? []; @@ -38,7 +40,7 @@ class SessionModel { endDate = json['endDate']; if (json['assetInventorySites'] != null) { - assetInventorySites = (json['assetInventorySites'] as List).map((e) => AssetInventorySite.fromJson(e)).toList(); + assetInventorySites = (json['assetInventorySites'] as List).map((e) => Site.fromJson(e)).toList(); } if (json['assetInventoryAssignedEmployee'] != null) { @@ -62,148 +64,148 @@ class SessionModel { } } -class AssetInventorySite { - int? siteId; - String? siteName; - List assetInventoryBuildings = []; - - AssetInventorySite({ - this.siteId, - this.siteName, - List? assetInventoryBuildings, - }) { - this.assetInventoryBuildings = assetInventoryBuildings ?? []; - } - - AssetInventorySite.fromJson(Map json) { - siteId = json['siteId']; - siteName = json['siteName']; - - if (json['assetInventoryBuildings'] != null) { - assetInventoryBuildings = (json['assetInventoryBuildings'] as List).map((e) => AssetInventoryBuilding.fromJson(e)).toList(); - } - } - - Map toJson() { - final map = {}; - map['siteId'] = siteId; - map['siteName'] = siteName; - map['assetInventoryBuildings'] = assetInventoryBuildings.map((e) => e.toJson()).toList(); - return map; - } -} - -class AssetInventoryBuilding { - int? buildingId; - String? buildingName; - List assetInventoryFloors = []; - - AssetInventoryBuilding({ - this.buildingId, - this.buildingName, - List? assetInventoryFloors, - }) { - this.assetInventoryFloors = assetInventoryFloors ?? []; - } - - AssetInventoryBuilding.fromJson(Map json) { - buildingId = json['buildingId']; - buildingName = json['buildingName']; - - if (json['assetInventoryFloors'] != null) { - assetInventoryFloors = (json['assetInventoryFloors'] as List).map((e) => AssetInventoryFloor.fromJson(e)).toList(); - } - } - - Map toJson() { - final map = {}; - map['buildingId'] = buildingId; - map['buildingName'] = buildingName; - map['assetInventoryFloors'] = assetInventoryFloors.map((e) => e.toJson()).toList(); - return map; - } -} - -class AssetInventoryFloor { - int? floorId; - String? floorName; - List assetInventoryDepartments = []; - - AssetInventoryFloor({ - this.floorId, - this.floorName, - List? assetInventoryDepartments, - }) { - this.assetInventoryDepartments = assetInventoryDepartments ?? []; - } - - AssetInventoryFloor.fromJson(Map json) { - floorId = json['floorId']; - floorName = json['floorName']; - - if (json['assetInventoryDepartments'] != null) { - assetInventoryDepartments = (json['assetInventoryDepartments'] as List).map((e) => AssetInventoryDepartment.fromJson(e)).toList(); - } - } - - Map toJson() { - final map = {}; - map['floorId'] = floorId; - map['floorName'] = floorName; - map['assetInventoryDepartments'] = assetInventoryDepartments.map((e) => e.toJson()).toList(); - return map; - } -} - -class AssetInventoryDepartment { - int? departmentId; - String? departmentName; - List assetInventoryRooms = []; - - AssetInventoryDepartment({ - this.departmentId, - this.departmentName, - List? assetInventoryRooms, - }) { - this.assetInventoryRooms = assetInventoryRooms ?? []; - } - - AssetInventoryDepartment.fromJson(Map json) { - departmentId = json['departmentId']; - departmentName = json['departmentName']; - - if (json['assetInventoryRooms'] != null) { - assetInventoryRooms = (json['assetInventoryRooms'] as List).map((e) => AssetInventoryRoom.fromJson(e)).toList(); - } - } - - Map toJson() { - final map = {}; - map['departmentId'] = departmentId; - map['departmentName'] = departmentName; - map['assetInventoryRooms'] = assetInventoryRooms.map((e) => e.toJson()).toList(); - return map; - } -} - -class AssetInventoryRoom { - int? roomId; - String? roomName; - - AssetInventoryRoom({this.roomId, this.roomName}); - - AssetInventoryRoom.fromJson(Map json) { - roomId = json['roomId']; - roomName = json['roomName']; - } - - Map toJson() { - final map = {}; - map['roomId'] = roomId; - map['roomName'] = roomName; - return map; - } -} +// class AssetInventorySite { +// int? siteId; +// String? siteName; +// List assetInventoryBuildings = []; +// +// AssetInventorySite({ +// this.siteId, +// this.siteName, +// List? assetInventoryBuildings, +// }) { +// this.assetInventoryBuildings = assetInventoryBuildings ?? []; +// } +// +// AssetInventorySite.fromJson(Map json) { +// siteId = json['siteId']; +// siteName = json['siteName']; +// +// if (json['assetInventoryBuildings'] != null) { +// assetInventoryBuildings = (json['assetInventoryBuildings'] as List).map((e) => AssetInventoryBuilding.fromJson(e)).toList(); +// } +// } +// +// Map toJson() { +// final map = {}; +// map['siteId'] = siteId; +// map['siteName'] = siteName; +// map['assetInventoryBuildings'] = assetInventoryBuildings.map((e) => e.toJson()).toList(); +// return map; +// } +// } +// +// class AssetInventoryBuilding { +// int? buildingId; +// String? buildingName; +// List assetInventoryFloors = []; +// +// AssetInventoryBuilding({ +// this.buildingId, +// this.buildingName, +// List? assetInventoryFloors, +// }) { +// this.assetInventoryFloors = assetInventoryFloors ?? []; +// } +// +// AssetInventoryBuilding.fromJson(Map json) { +// buildingId = json['buildingId']; +// buildingName = json['buildingName']; +// +// if (json['assetInventoryFloors'] != null) { +// assetInventoryFloors = (json['assetInventoryFloors'] as List).map((e) => AssetInventoryFloor.fromJson(e)).toList(); +// } +// } +// +// Map toJson() { +// final map = {}; +// map['buildingId'] = buildingId; +// map['buildingName'] = buildingName; +// map['assetInventoryFloors'] = assetInventoryFloors.map((e) => e.toJson()).toList(); +// return map; +// } +// } +// +// class AssetInventoryFloor { +// int? floorId; +// String? floorName; +// List assetInventoryDepartments = []; +// +// AssetInventoryFloor({ +// this.floorId, +// this.floorName, +// List? assetInventoryDepartments, +// }) { +// this.assetInventoryDepartments = assetInventoryDepartments ?? []; +// } +// +// AssetInventoryFloor.fromJson(Map json) { +// floorId = json['floorId']; +// floorName = json['floorName']; +// +// if (json['assetInventoryDepartments'] != null) { +// assetInventoryDepartments = (json['assetInventoryDepartments'] as List).map((e) => AssetInventoryDepartment.fromJson(e)).toList(); +// } +// } +// +// Map toJson() { +// final map = {}; +// map['floorId'] = floorId; +// map['floorName'] = floorName; +// map['assetInventoryDepartments'] = assetInventoryDepartments.map((e) => e.toJson()).toList(); +// return map; +// } +// } +// +// class AssetInventoryDepartment { +// int? departmentId; +// String? departmentName; +// List assetInventoryRooms = []; +// +// AssetInventoryDepartment({ +// this.departmentId, +// this.departmentName, +// List? assetInventoryRooms, +// }) { +// this.assetInventoryRooms = assetInventoryRooms ?? []; +// } +// +// AssetInventoryDepartment.fromJson(Map json) { +// departmentId = json['departmentId']; +// departmentName = json['departmentName']; +// +// if (json['assetInventoryRooms'] != null) { +// assetInventoryRooms = (json['assetInventoryRooms'] as List).map((e) => AssetInventoryRoom.fromJson(e)).toList(); +// } +// } +// +// Map toJson() { +// final map = {}; +// map['departmentId'] = departmentId; +// map['departmentName'] = departmentName; +// map['assetInventoryRooms'] = assetInventoryRooms.map((e) => e.toJson()).toList(); +// return map; +// } +// } +// +// class AssetInventoryRoom { +// int? roomId; +// String? roomName; +// +// AssetInventoryRoom({this.roomId, this.roomName}); +// +// AssetInventoryRoom.fromJson(Map json) { +// roomId = json['roomId']; +// roomName = json['roomName']; +// } +// +// Map toJson() { +// final map = {}; +// map['roomId'] = roomId; +// map['roomName'] = roomName; +// return map; +// } +// } class AssetInventoryAssignedEmployee { String? assignedEngineerId; 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 82c0954f..87a54e82 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,18 +1,20 @@ import 'package:flutter/material.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/new_models/work_order_detail_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; -import 'package:test_sa/views/widgets/requests/request_status.dart'; +import 'package:test_sa/views/widgets/loaders/image_loader.dart'; class AssetDetailCardView extends StatelessWidget { - // WorkOrderData workOrder; + AssetInventoryModel assetInventoryModel; AssetDetailCardView({ super.key, + required this.assetInventoryModel, }); @override @@ -23,45 +25,37 @@ class AssetDetailCardView extends StatelessWidget { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // StatusLabel( - // label: workOrder.priority?.name, - // id: workOrder.priority!.id!, - // radius: 4, - // textColor: AppColor.getPriorityStatusTextColor(context, workOrder.priority!.id!), - // backgroundColor: AppColor.getPriorityStatusColor(context, workOrder.priority!.id!), - // ), - // 8.height, Text( context.translation.assetInformation, style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ), // 8.height, Text( - '${context.translation.serialNo}: ${"workOrder.workOrderContactPerson[0].name" ?? '-'}', + '${context.translation.serialNo}: ${assetInventoryModel.serialNo ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - '${context.translation.manufacture}: ${"workOrder.workOrderContactPerson[0].name"}', + '${context.translation.manufacture}: ${assetInventoryModel.manufacturer ?? ''}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - '${context.translation.model}: ${"workOrder.workOrderContactPerson[0].name"}', + '${context.translation.model}: ${assetInventoryModel.model ?? ''}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - '${context.translation.site}: ${"workOrder.workOrderContactPerson[0].name"}', + '${context.translation.site}: ${assetInventoryModel.site ?? ''}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - '${context.translation.department}: ${"workOrder.workOrderContactPerson[0].name"}', + '${context.translation.department}: ${assetInventoryModel.department ?? ''}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - '${context.translation.supplier}: ${"workOrder.workOrderContactPerson[0].name"}', + '${context.translation.supplier}: ${assetInventoryModel.supplierName ?? ''}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - '${'Remarks'.addTranslation}: ${"workOrder.workOrderContactPerson[0].name"}', + '${'Remarks'.addTranslation}: ${assetInventoryModel.remarks ?? ''}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), ], @@ -85,10 +79,19 @@ class AssetDetailCardView extends StatelessWidget { ), 20.height, Container( - height: 100, - width: 100, - color: Colors.red, - child: 'edit_icon'.toSvgAsset().center, + decoration: BoxDecoration(color: AppColor.neutral100, borderRadius: BorderRadius.circular(15)), + height: 115.toScreenHeight, + width: 115.toScreenWidth, + child: assetInventoryModel.photo != null && assetInventoryModel.photo!.isNotEmpty + ? ClipRRect( + borderRadius: BorderRadius.circular(8), + child: ImageLoader( + url: URLs.getFileUrl(assetInventoryModel.photo), + boxFit: BoxFit.cover, + height: 48, + width: 48, + )) + : 'image_placeholder'.toSvgAsset().center, ) ], ) diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart index 0421ab13..f7cacee2 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart @@ -1,13 +1,10 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/new_models/work_order_detail_model.dart'; import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; -import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart'; @@ -29,54 +26,37 @@ class _AssetInventoryDetailViewState extends State { @override Widget build(BuildContext context) { - //TODO remove this provider and loading obj as well don't need here ... - return Consumer(builder: (pContext, requestProvider, _) { - return requestProvider.isLoading - ? const CircularProgressIndicator(color: AppColor.primary10).center - : requestProvider.currentWorkOrder == null - ? const NoDataFound() - : ListView( - padding: const EdgeInsets.all(16), - children: [ - requestDetailCard(context, requestProvider.currentWorkOrder!.data!), - 12.height, - siteListCard(context, requestProvider.currentWorkOrder!.data!), - ], - ); - }); + return widget.sessionModel.id == null + ? const NoDataFound() + : ListView( + padding: const EdgeInsets.all(16), + children: [ + requestDetailCard(context, widget.sessionModel), + 12.height, + siteListCard(context, widget.sessionModel), + ], + ); } TextStyle infoTextStyle(context) => AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120); - Widget requestDetailCard(BuildContext context, WorkOrderData workOrder) { + Widget requestDetailCard(BuildContext context, SessionModel sessionModel) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( - mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Wrap( - runSpacing: 8, - children: [ - StatusLabel( - label: workOrder.priority?.name, - id: workOrder.priority!.id!, - radius: 4, - textColor: AppColor.getPriorityStatusTextColor(context, workOrder.priority!.id!), - backgroundColor: AppColor.getPriorityStatusColor(context, workOrder.priority!.id!), - ), - 8.width, - StatusLabel( - radius: 4, - label: workOrder.status!.name, - textColor: AppColor.getHistoryLogStatusTextColorByName(workOrder.status!.name!), - backgroundColor: AppColor.getHistoryLogStatusColorByName(workOrder.status!.name!), - ), - ], - ).expanded, + StatusLabel( + label: sessionModel.statusName, + id: sessionModel.statusId, + radius: 4, + textColor: AppColor.green15, + backgroundColor: AppColor.greenStatus(context), + ), Text( - workOrder.requestedDate!.toString().toServiceRequestCardFormat, + sessionModel.startDate!.toString().toServiceRequestCardFormat, textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ) @@ -89,63 +69,91 @@ class _AssetInventoryDetailViewState extends State { ), 8.height, Text( - '${'Session Name'.addTranslation}: ${workOrder.assetNdModel!.name?.cleanupWhitespace.capitalizeFirstOfEach}', + '${'Session Name'.addTranslation}: ${sessionModel.sessionName?.cleanupWhitespace.capitalizeFirstOfEach}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), // 8.height, Text( - '${'Session Typ'.addTranslation}: ${workOrder.asset!.assetNumber}', + '${'Session Typ'.addTranslation}: ${sessionModel.sessionTypeName}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - '${'Start Date:'.addTranslation}: ${workOrder.asset!.assetSerialNo}', + '${'Start Date:'.addTranslation}: ${sessionModel.startDate}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - '${'End Date:'.addTranslation}: ${workOrder.asset!.assetSerialNo}', + '${'End Date:'.addTranslation}: ${sessionModel.endDate}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), ], ).paddingOnly(start: 16, end: 16, top: 16, bottom: 8).toShadowContainer(context, padding: 0); } - Widget siteListCard(BuildContext context, WorkOrderData workOrder) { + Widget siteListCard(BuildContext context, SessionModel sessionModel) { + final sites = sessionModel.assetInventorySites ?? []; + return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ ListView.separated( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - padding: EdgeInsets.zero, - itemBuilder: (cxt, index) => Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '${workOrder.workOrderContactPerson[0].name ?? '-'}', - style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), - ), - Text( - '${context.translation.building}: ${workOrder.workOrderContactPerson[0].employeeId ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.floor}: ${workOrder.workOrderContactPerson[0].mobilePhone ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.department} ${workOrder.workOrderContactPerson[0].position ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.room}: ${workOrder.workOrderContactPerson[0].email ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - ], + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsets.zero, + itemCount: sites.length, + itemBuilder: (cxt, siteIndex) { + final site = sites[siteIndex]; + final buildingNames = (site.buildings ?? []).map((b) => b.name).where((name) => name != null && name!.trim().isNotEmpty).join(', '); + final floorNames = (site.buildings ?? []).expand((b) => b.floors ?? []).map((f) => f.name).where((name) => name != null && name!.trim().isNotEmpty).join(', '); + final departmentNames = + (site.buildings ?? []).expand((b) => b.floors ?? []).expand((f) => f.departments ?? []).map((d) => d.name).where((name) => name != null && name!.trim().isNotEmpty).join(', '); + final roomNames = (site.buildings ?? []) + .expand((b) => b.floors ?? []) + .expand((f) => f.departments ?? []) + .expand((d) => d.rooms ?? []) + .map((r) => r.name) + .where((name) => name != null && name!.trim().isNotEmpty) + .join(', '); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + site.name ?? '-', + style: AppTextStyles.heading6.copyWith( + color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, + ), ), - separatorBuilder: (cxt, index) => const Divider().defaultStyle(context), - itemCount: 4), + Text( + '${context.translation.building}: ${buildingNames.isNotEmpty ? buildingNames : '-'}', + style: AppTextStyles.bodyText.copyWith( + color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, + ), + ), + Text( + '${context.translation.floor}: ${floorNames.isNotEmpty ? floorNames : '-'}', + style: AppTextStyles.bodyText.copyWith( + color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, + ), + ), + Text( + '${context.translation.department}: ${departmentNames.isNotEmpty ? departmentNames : '-'}', + style: AppTextStyles.bodyText.copyWith( + color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, + ), + ), + Text( + '${context.translation.room}: ${roomNames.isNotEmpty ? roomNames : '-'}', + style: AppTextStyles.bodyText.copyWith( + color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, + ), + ), + ], + ); + }, + separatorBuilder: (cxt, index) => const Divider().defaultStyle(context), + ), ], ).toShadowContainer(context, padding: 12); } 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 68cde22a..23ed3789 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,116 +1,85 @@ -import 'dart:convert'; import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; -import 'package:provider/provider.dart'; import 'package:test_sa/common_widgets/autocomplete_generic_field.dart'; -import 'package:test_sa/controllers/api_routes/urls.dart'; -import 'package:test_sa/controllers/providers/api/device_transfer_provider.dart'; -import 'package:test_sa/dashboard_latest/dashboard_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/device/asset.dart'; -import 'package:test_sa/models/device/asset_transfer_attachment.dart'; -import 'package:test_sa/models/device/device_transfer.dart'; -import 'package:test_sa/models/enums/user_types.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; -import 'package:test_sa/models/new_models/department.dart'; -import 'package:test_sa/models/new_models/floor.dart'; -import 'package:test_sa/models/service_request/pending_service_request_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/cm_module/utilities/service_request_utils.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; -import 'package:test_sa/providers/ppm_service_provider.dart'; import 'package:test_sa/providers/work_order/vendor_provider.dart'; -import 'package:test_sa/views/pages/user/requests/pending_requests_screen.dart'; import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; -import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; -import 'package:test_sa/views/widgets/parts/auto_complete_parts_field.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart'; - -import '../../../models/new_models/building.dart'; -import '../../../models/new_models/site.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 '../../../providers/gas_request_providers/site_provider.dart'; -import '../../../providers/loading_list_notifier.dart'; class AssetInventoryFormView extends StatefulWidget { - static const String id = "/request-device-transfer"; + static const String id = "/asset-inventory-form"; + // TODO need to use only one model AssetInventoryModel everywhere after completing flow . + Asset ? assetLocation; - const AssetInventoryFormView({Key? key}) : super(key: key); + AssetInventoryFormView({Key? key,this.assetLocation}) : super(key: key); @override State createState() => _AssetInventoryFormViewState(); } class _AssetInventoryFormViewState extends State { - //TODO Need to replace with provider and models we have ... - late DeviceTransferProvider _deviceTransferProvider; - final DeviceTransfer _transferModel = DeviceTransfer(id: 0); + final AssetInventoryModel _assetInventoryModel = AssetInventoryModel(); final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); - Asset _assetDestination = Asset(); Asset? _pickedAsset; + final List attachments = []; void _onSubmit() async { - _transferModel.assetId = _pickedAsset?.id; - _transferModel.destSiteId = _assetDestination.site?.id; - _transferModel.destBuildingId = _assetDestination.building?.id; - _transferModel.destFloorId = _assetDestination.floor?.id; - _transferModel.destDepartmentId = _assetDestination.department?.id; - _transferModel.destRoomId = _assetDestination.room?.id; + _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; if (!_formKey.currentState!.validate() || !(await validateRequest())) { return; } _formKey.currentState!.save(); - 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)); - } - _transferModel.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); - } + //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() { - WidgetsBinding.instance.addPostFrameCallback((_) async { - //need to get internal and external request type data.. - await Provider.of(context, listen: false).getData(); - }); - super.initState(); - } @override void dispose() { - _deviceTransferProvider.reset(); super.dispose(); } @override Widget build(BuildContext context) { - _deviceTransferProvider = Provider.of(context, listen: false); return Scaffold( key: _scaffoldKey, appBar: DefaultAppBar( @@ -136,18 +105,19 @@ class _AssetInventoryFormViewState extends State { showBorder: true, onPick: (asset) async { _pickedAsset = asset; - 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; - } + //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; + // } setState(() {}); }), @@ -170,9 +140,6 @@ class _AssetInventoryFormViewState extends State { style: Theme.of(context).textTheme.titleMedium, ), 12.height, - //TODO need to indentify where to - 12.height, - //model.. AutoCompleteGenericField( clearAfterPick: false, label: 'Asset Name'.addTranslation, @@ -256,75 +223,16 @@ class _AssetInventoryFormViewState extends State { setState(() {}); }, ), - 12.height, - SingleItemDropDownMenu( - context: context, - title: context.translation.site, - initialValue: _assetDestination.site, - disableValue: _pickedAsset?.site, - showShadow: false, - loading: _deviceTransferProvider.isSiteLoading, - enabled: false, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - onSelect: (value) { - _assetDestination.site = value; - _assetDestination.building = null; - _assetDestination.floor = null; - _assetDestination.department = null; - setState(() {}); - }, - ), + siteInfoContainer(label: context.translation.site, value:widget.assetLocation?.site?.name??'-' ), 12.height, - SingleItemDropDownMenu( - context: context, - title: context.translation.building, - initialValue: _assetDestination.building, - showShadow: false, - showAsBottomSheet: true, - backgroundColor: AppColor.fieldBgColor(context), - enabled: _assetDestination.site?.buildings?.isNotEmpty ?? false, - staticData: _assetDestination.site?.buildings ?? [], - onSelect: (value) { - _assetDestination.building = value; - _assetDestination.floor = null; - _assetDestination.department = null; - setState(() {}); - }, - ), + siteInfoContainer(label: context.translation.building, value:widget.assetLocation?.building?.name??'-' ), 12.height, - SingleItemDropDownMenu( - context: context, - title: context.translation.floor, - showShadow: false, - showAsBottomSheet: true, - initialValue: _assetDestination.floor, - backgroundColor: AppColor.fieldBgColor(context), - enabled: _assetDestination.building?.floors?.isNotEmpty ?? false, - staticData: _assetDestination.building?.floors ?? [], - onSelect: (value) { - _assetDestination.floor = value; - _assetDestination.department = null; - setState(() {}); - }, - ), + siteInfoContainer(label: context.translation.floor, value:widget.assetLocation?.floor?.name??'-' ), 12.height, - SingleItemDropDownMenu( - context: context, - title: context.translation.department, - showShadow: false, - showAsBottomSheet: true, - initialValue: _assetDestination.department, - backgroundColor: AppColor.fieldBgColor(context), - enabled: _assetDestination.floor?.departments?.isNotEmpty ?? false, - staticData: _assetDestination.floor?.departments ?? [], - onSelect: (value) { - _assetDestination.department = value; - _assetDestination.room = null; - setState(() {}); - }, - ), + siteInfoContainer(label: context.translation.department, value:widget.assetLocation?.department?.name??'-' ), + 12.height, + siteInfoContainer(label: context.translation.room, value:widget.assetLocation?.room?.name??'-' ), 12.height, classificationWidget(label: 'Found'), 12.height, @@ -362,7 +270,7 @@ class _AssetInventoryFormViewState extends State { textInputType: TextInputType.multiline, showShadow: false, onSaved: (text) { - _transferModel.comment = text; + _assetInventoryModel.remarks = text; }, ), // 100.height, @@ -380,6 +288,26 @@ class _AssetInventoryFormViewState extends State { ); } + + Widget siteInfoContainer({required String label , required String value}){ + //TODO may be need to hide value for if empty or null . + return Container( + width: double.infinity, + padding: EdgeInsets.symmetric(horizontal: 12.toScreenWidth,vertical: 12.toScreenHeight), + decoration: BoxDecoration( + color: AppColor.neutral80, + borderRadius: BorderRadius.circular(8) + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(label,style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500)), + Text(value,style:Theme.of(context).textTheme.bodyLarge,), + ], + ), + ); + } + Widget classificationWidget({String? label}) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -404,22 +332,22 @@ class _AssetInventoryFormViewState extends State { await Fluttertoast.showToast(msg: "Please Select Asset"); return false; } - 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; - } + // 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; } } 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 924891c2..f080f49c 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; @@ -9,7 +11,6 @@ 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/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; @@ -33,15 +34,18 @@ class _AssetInventoryPageState extends State { @override void initState() { super.initState(); + _assetInventoryProvider = Provider.of(context, listen: false); WidgetsBinding.instance.addPostFrameCallback((_) { getInitialData(); }); } Future getInitialData() async { - _assetInventoryProvider = Provider.of(context, listen: false); - // ServiceRequestDetailProvider _provider = Provider.of(context, listen: false); - // await _provider.getWorkOrderById(id: widget.sessionId); + _assetInventoryProvider.reset(); + await _assetInventoryProvider.getSessionById(id: widget.sessionId); + await _assetInventoryProvider.getAssetsInSession( + sessionId: widget.sessionId, + ); } @override @@ -59,53 +63,64 @@ class _AssetInventoryPageState extends State { Navigator.pop(context); }, ), - body: DefaultTabController( - length: 2, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight), - decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.white10, borderRadius: BorderRadius.circular(10)), - child: TabBar( - padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth), - labelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, - unselectedLabelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, - unselectedLabelStyle: AppTextStyles.bodyText, - labelStyle: AppTextStyles.bodyText, - indicatorPadding: EdgeInsets.zero, - indicatorSize: TabBarIndicatorSize.tab, - dividerColor: Colors.transparent, - indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)), - onTap: (index) { - }, - tabs: [ - Tab(text: 'Request Details'.addTranslation, height: 57.toScreenHeight), - Tab(text: '${'Scan Assets'.addTranslation} (1)', height: 57.toScreenHeight), - ], + body: Consumer(builder: (context, provider, child) { + return DefaultTabController( + length: 2, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight), + decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.white10, borderRadius: BorderRadius.circular(10)), + child: TabBar( + padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth), + labelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, + unselectedLabelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, + unselectedLabelStyle: AppTextStyles.bodyText, + labelStyle: AppTextStyles.bodyText, + indicatorPadding: EdgeInsets.zero, + indicatorSize: TabBarIndicatorSize.tab, + dividerColor: Colors.transparent, + indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)), + onTap: (index) {}, + tabs: [ + Tab(text: 'Request Details'.addTranslation, height: 57.toScreenHeight), + Tab( + text: + '${'Scan Assets'.addTranslation} ${provider.assetInventoryResponse?.totalRows != null && provider.assetInventoryResponse!.totalRows! > 0 ? '(${provider.assetInventoryResponse?.totalRows})' : ''}', + height: 57.toScreenHeight), + ], + ), ), - ), - 12.height, - TabBarView( - children: [ - AssetInventoryDetailView(sessionModel: SessionModel(),), - AssetInventoryScanAssetView(), - ], - ).expanded, - FooterActionButton.footerContainer( - context: context, - child: AppFilledButton( - buttonColor: AppColor.primary10, - label: 'Scan Assets'.addTranslation, - onPressed: _scanAsset, - // buttonColor: AppColor.primary10, - ), - ).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0), - ], - ), - )); + 12.height, + TabBarView( + children: [ + provider.isLoading + ? const CircularProgressIndicator(color: AppColor.primary10).center + : AssetInventoryDetailView( + sessionModel: provider.sessionModel ?? SessionModel(), + ), + AssetInventoryScanAssetView( + sessionId: provider.sessionModel?.id ?? 0, + ), + ], + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Scan Assets'.addTranslation, + onPressed: () => _scanAsset(provider: provider), + // buttonColor: AppColor.primary10, + ), + ).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0), + ], + ), + ); + })); } - Future _scanAsset() async { - Navigator.push(context, MaterialPageRoute(builder: (contxt) => PickSiteInformationView(sessionModel: SessionModel()))); + + Future _scanAsset({required AssetInventoryProvider provider}) async { + Navigator.push(context, MaterialPageRoute(builder: (contxt) => PickSiteInformationView(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 a732705e..180942dc 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,51 +1,77 @@ 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 StatelessWidget { - AssetInventoryScanAssetView({Key? key}) : super(key: key); +class AssetInventoryScanAssetView extends StatefulWidget { + int sessionId ; + AssetInventoryScanAssetView({Key? key,required this.sessionId}) : super(key: key); + + @override + State createState() => _AssetInventoryScanAssetViewState(); +} + + +class _AssetInventoryScanAssetViewState extends State { + late AssetInventoryProvider assetInventoryProvider; + @override + void initState() { + assetInventoryProvider = Provider.of(context,listen:false); + super.initState(); + } + Future getAssetList({bool reset = false}) async { + if (reset) { + assetInventoryProvider.pageNo = 1; + assetInventoryProvider.assetInventoryResponse = null; + } + await assetInventoryProvider.getAssetsInSession( + sessionId: widget.sessionId, + ); + } @override Widget build(BuildContext context) { - return SingleChildScrollView( - padding: EdgeInsets.all(16), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ListView.separated( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - padding: EdgeInsets.zero, - itemBuilder: (cxt, index) => AssetDetailCardView(), - separatorBuilder: (cxt, index) => 12.height, - itemCount: 4), - 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(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(); + }, + child: ListView.separated( + padding: const EdgeInsets.all(16), + itemBuilder: (context, index) { + return AssetDetailCardView(assetInventoryModel: assets[index]); + }, + separatorBuilder: (context, index) => 12.height, + itemCount: assets.length, ), - ], - ), + ); + }, ); } void _addAsset(BuildContext context) { //TODO need to confirm navigation... - Navigator.push(context, MaterialPageRoute(builder: (contxt) => const AssetInventoryFormView())); + Navigator.push(context, MaterialPageRoute(builder: (contxt) => AssetInventoryFormView())); } } 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 index a9995ed0..db8a1240 100644 --- a/lib/modules/asset_inventory_module/pages/pick_site_information_view.dart +++ b/lib/modules/asset_inventory_module/pages/pick_site_information_view.dart @@ -11,18 +11,19 @@ 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/work_order_detail_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/cm_module/service_request_detail_provider.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/gas_request_providers/site_provider.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'; @@ -36,17 +37,13 @@ class PickSiteInformationView extends StatefulWidget { } class _PickSiteInformationViewState extends State { - late SessionModel _sessionModel; - - //TODO need to remove this ... - Asset _assetDestination = Asset(); - late ServiceRequestDetailProvider _requestDetailProvider; + // TODO need to use only one model AssetInventoryModel everywhere after completing flow . + Asset assetLocation = Asset(); void _onSave() async {} @override void initState() { - _sessionModel = widget.sessionModel; super.initState(); } @@ -54,7 +51,6 @@ class _PickSiteInformationViewState extends State { @override Widget build(BuildContext context) { - _requestDetailProvider = Provider.of(context, listen: false); return Scaffold( key: _scaffoldKey, appBar: DefaultAppBar( @@ -66,13 +62,16 @@ class _PickSiteInformationViewState extends State { ListView( padding: const EdgeInsets.only(left: 16, right: 16, top: 16), children: [ - siteInfoCard(context), - 12.height, - assetDetailCard(context, _requestDetailProvider.currentWorkOrder!.data!), + 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, @@ -92,37 +91,78 @@ class _PickSiteInformationViewState extends State { } void _addAsset() { - Navigator.push(context, MaterialPageRoute(builder: (contxt) => const AssetInventoryFormView())); + Navigator.push( + context, + MaterialPageRoute( + builder: (contxt) => AssetInventoryFormView( + assetLocation: assetLocation, + ))); } - Widget assetDetailCard(BuildContext context, WorkOrderData workOrder) { - return ListView.separated( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - padding: EdgeInsets.zero, - itemBuilder: (cxt, index) => AssetDetailCardView(), - separatorBuilder: (cxt, index) => 12.height, - itemCount: 4); + 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 siteInfoCard(BuildContext context) { + 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( + SingleItemDropDownMenu( context: context, title: context.translation.site, - initialValue: _assetDestination.site, + initialValue: assetLocation.site, showShadow: false, - // loading: _deviceTransferProvider.isSiteLoading, + staticData: sessionModel.assetInventorySites, backgroundColor: AppColor.fieldBgColor(context), showAsBottomSheet: true, onSelect: (value) { - _assetDestination.site = value; - _assetDestination.building = null; - _assetDestination.floor = null; - _assetDestination.department = null; + assetLocation.site = value; + assetLocation.building = null; + assetLocation.floor = null; + assetLocation.department = null; setState(() {}); }, ), @@ -130,16 +170,16 @@ class _PickSiteInformationViewState extends State { SingleItemDropDownMenu( context: context, title: context.translation.building, - initialValue: _assetDestination.building, + initialValue: assetLocation.building, showShadow: false, showAsBottomSheet: true, backgroundColor: AppColor.fieldBgColor(context), - enabled: _assetDestination.site?.buildings?.isNotEmpty ?? false, - staticData: _assetDestination.site?.buildings ?? [], + enabled: assetLocation.site?.buildings?.isNotEmpty ?? false, + staticData: assetLocation.site?.buildings ?? [], onSelect: (value) { - _assetDestination.building = value; - _assetDestination.floor = null; - _assetDestination.department = null; + assetLocation.building = value; + assetLocation.floor = null; + assetLocation.department = null; setState(() {}); }, ), @@ -149,13 +189,13 @@ class _PickSiteInformationViewState extends State { title: context.translation.floor, showShadow: false, showAsBottomSheet: true, - initialValue: _assetDestination.floor, + initialValue: assetLocation.floor, backgroundColor: AppColor.fieldBgColor(context), - enabled: _assetDestination.building?.floors?.isNotEmpty ?? false, - staticData: _assetDestination.building?.floors ?? [], + enabled: assetLocation.building?.floors?.isNotEmpty ?? false, + staticData: assetLocation.building?.floors ?? [], onSelect: (value) { - _assetDestination.floor = value; - _assetDestination.department = null; + assetLocation.floor = value; + assetLocation.department = null; setState(() {}); }, ), @@ -165,13 +205,13 @@ class _PickSiteInformationViewState extends State { title: context.translation.department, showShadow: false, showAsBottomSheet: true, - initialValue: _assetDestination.department, + initialValue: assetLocation.department, backgroundColor: AppColor.fieldBgColor(context), - enabled: _assetDestination.floor?.departments?.isNotEmpty ?? false, - staticData: _assetDestination.floor?.departments ?? [], + enabled: assetLocation.floor?.departments?.isNotEmpty ?? false, + staticData: assetLocation.floor?.departments ?? [], onSelect: (value) { - _assetDestination.department = value; - _assetDestination.room = null; + assetLocation.department = value; + assetLocation.room = null; setState(() {}); }, ), @@ -181,12 +221,12 @@ class _PickSiteInformationViewState extends State { title: context.translation.room, showShadow: false, showAsBottomSheet: true, - initialValue: _assetDestination.room, + initialValue: assetLocation.room, backgroundColor: AppColor.fieldBgColor(context), - enabled: _assetDestination.department?.rooms?.isNotEmpty ?? false, - staticData: _assetDestination.department?.rooms ?? [], + enabled: assetLocation.department?.rooms?.isNotEmpty ?? false, + staticData: assetLocation.department?.rooms ?? [], onSelect: (value) { - _assetDestination.room = value; + assetLocation.room = value; setState(() {}); }, ), @@ -196,19 +236,19 @@ class _PickSiteInformationViewState extends State { } Future validateRequest() async { - if (_assetDestination.site == null) { + if (assetLocation.site == null) { await Fluttertoast.showToast(msg: "Please Select Site"); return false; } - if (_assetDestination.building == null) { + if (assetLocation.building == null) { await Fluttertoast.showToast(msg: "Please Select Building"); return false; } - if (_assetDestination.floor == null) { + if (assetLocation.floor == null) { await Fluttertoast.showToast(msg: "Please Select Floor"); return false; } - if (_assetDestination.department == null) { + if (assetLocation.department == null) { await Fluttertoast.showToast(msg: "Please Select Department"); return false; } 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 2d5de6c4..7fe233da 100644 --- a/lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart +++ b/lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart @@ -16,6 +16,7 @@ import 'package:test_sa/models/service_request/spare_parts.dart'; import 'package:test_sa/models/service_request/supp_engineer_work_orders.dart'; import 'package:test_sa/models/service_request/supplier_engineer_model.dart'; import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; import '../../../models/service_request/search_work_order.dart'; @@ -25,11 +26,17 @@ import '../../../new_views/common_widgets/app_lazy_loading.dart'; class AssetInventoryProvider extends ChangeNotifier { final pageItemNumber = 10; + int pageNo = 1; SessionModel? sessionModel; + AssetInventoryResponse? assetInventoryResponse; + List sessionAssetList = []; void reset() { - nextPage = true; + pageNo = 1; + assetInventoryResponse = null; + sessionModel = null; + sessionAssetList = []; stateCode = null; } @@ -37,15 +44,18 @@ class AssetInventoryProvider extends ChangeNotifier { bool isDetailLoading = false; bool nextPage = true; bool isLoading = false; + bool isAllAssetLoading = false; 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 = await SessionModel.fromJson(json.decode(response.body)); + sessionModel = SessionModel.fromJson(json.decode(response.body)["data"]); } else { sessionModel = null; } @@ -59,4 +69,52 @@ class AssetInventoryProvider extends ChangeNotifier { return null; } } + + Future getAssetsInSession({ + required int sessionId, + }) async { + if (isLoading == true) return -2; + isLoading = true; + + 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 ?? []; + } else { + sessionAssetList.addAll(newResponse.assetList ?? []); + assetInventoryResponse?.totalRows = newResponse.totalRows; // update total rows + } + if ((sessionAssetList.length) < (assetInventoryResponse?.totalRows ?? 0)) { + nextPage = true; + } else { + nextPage = false; + } + isLoading = false; + notifyListeners(); + return response.statusCode; + } else { + sessionAssetList = []; + isLoading = false; + notifyListeners(); + return response.statusCode; + } + } catch (error) { + isLoading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } + } diff --git a/lib/new_views/common_widgets/app_filled_button.dart b/lib/new_views/common_widgets/app_filled_button.dart index 8e1e67f2..f543615a 100644 --- a/lib/new_views/common_widgets/app_filled_button.dart +++ b/lib/new_views/common_widgets/app_filled_button.dart @@ -50,8 +50,8 @@ class AppFilledButton extends StatelessWidget { ), child: loading ? SizedBox( - width: 24, - height: 24, + width: 24.toScreenHeight, + height: 24.toScreenHeight, child: CircularProgressIndicator( color: textColor ?? AppColor.background(context), strokeWidth: 2, From 8578319cc392051d844e675066c78aea8a7ef8af Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Thu, 9 Oct 2025 17:46:48 +0300 Subject: [PATCH 04/11] asset inventory module ready for qa --- .../autocomplete_generic_field.dart | 144 ------ .../lookup_autocomplete_field.dart | 124 +++++ lib/controllers/api_routes/urls.dart | 17 + .../providers/api/gas_refill_comments.dart | 1 - lib/models/all_requests_and_count_model.dart | 12 + lib/models/device/asset.dart | 4 +- lib/models/new_models/dashboard_detail.dart | 27 +- .../models/asset_inventory_model.dart | 210 +++++---- .../models/session_model.dart | 4 + .../pages/asset_detail_card_view.dart | 36 +- .../pages/asset_inventory_form_view.dart | 444 +++++++++++------- .../pages/asset_inventory_page.dart | 5 +- .../asset_inventory_scan_assets_view.dart | 110 +++-- ...asset_inventory_site_information_view.dart | 311 ++++++++++++ .../pages/inventory_seession_card.dart | 15 +- .../pages/pick_site_information_view.dart | 257 ---------- .../pages/search_asset_view.dart | 276 +++++++++++ .../provider/asset_inventory_provider.dart | 357 +++++++++++++- .../widgets/request_item_view_list.dart | 3 +- lib/views/widgets/equipment/asset_picker.dart | 13 +- lib/views/widgets/qr/asset_scan_qr.dart | 28 +- 21 files changed, 1652 insertions(+), 746 deletions(-) delete mode 100644 lib/common_widgets/autocomplete_generic_field.dart create mode 100644 lib/common_widgets/lookup_autocomplete_field.dart create mode 100644 lib/modules/asset_inventory_module/pages/asset_inventory_site_information_view.dart delete mode 100644 lib/modules/asset_inventory_module/pages/pick_site_information_view.dart create mode 100644 lib/modules/asset_inventory_module/pages/search_asset_view.dart 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, From d3c000004e4bebffc158aad603dc840eb6d7a956 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 9 Oct 2025 18:23:41 +0300 Subject: [PATCH 05/11] code improvements --- .../providers/api/all_requests_provider.dart | 21 +- .../pages/asset_detail_card_view.dart | 112 +++-- .../pages/asset_inventory_detail_view.dart | 4 +- .../pages/asset_inventory_form_view.dart | 475 +++++++++--------- .../pages/asset_inventory_page.dart | 95 ++-- .../asset_inventory_scan_assets_view.dart | 92 ++-- ...sset_inventory_site_information_page.dart} | 96 ++-- .../my_request/my_requests_page.dart | 4 +- .../selection_fullscreen_dialog.dart | 4 +- 9 files changed, 460 insertions(+), 443 deletions(-) rename lib/modules/asset_inventory_module/pages/{asset_inventory_site_information_view.dart => asset_inventory_site_information_page.dart} (84%) diff --git a/lib/controllers/providers/api/all_requests_provider.dart b/lib/controllers/providers/api/all_requests_provider.dart index f95ef38d..b1af1d28 100644 --- a/lib/controllers/providers/api/all_requests_provider.dart +++ b/lib/controllers/providers/api/all_requests_provider.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:http/http.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/models/all_requests_and_count_model.dart'; import 'package:test_sa/models/enums/user_types.dart'; import 'package:test_sa/models/ppm/recurrent_wo.dart'; @@ -130,6 +131,24 @@ class AllRequestsProvider extends ChangeNotifier { SearchAllRequestsModel? searchedModel; + List getStatues(BuildContext context) { + List list = [1, 2, 3, 4]; + + if (context.userProvider.user!.type != UsersTypes.normal_user) { + list.add(5); + } + list.add(6); // task module + + if (context.settingProvider.isUserFlowMedical && context.userProvider.user!.type != UsersTypes.normal_user) { + list.add(7); // task mod + } + if (context.userProvider.user!.type != UsersTypes.normal_user) { + list.add(8); // + } + + return list; + } + Future getAllRequests(BuildContext context, {int? typeTransaction, SearchAllRequestsModel? search}) async { if (isAllLoading == true) return -2; isAllLoading = true; @@ -143,7 +162,7 @@ class AllRequestsProvider extends ChangeNotifier { } final type = typeTransaction == null ? search?.typeTransaction == null || (search?.typeTransaction?.isEmpty ?? false) - ? [1, 2, 3, 4, 5, 6,7,8] + ? getStatues(context) : search!.typeTransaction : [typeTransaction]; List status = (search?.statuses == null || (search?.statuses?.isEmpty ?? false)) ? (((search?.isArchived ?? false) ? [3] : [1, 2, 4])) : search!.statuses!; 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 29769f79..889451de 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 @@ -23,71 +23,73 @@ class AssetDetailCardView extends StatelessWidget { @override Widget build(BuildContext context) { - return Row( - crossAxisAlignment: CrossAxisAlignment.start, + return Column( children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, + Row( children: [ Text( context.translation.assetInformation, 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), - ), - Text( - '${context.translation.manufacture}: ${assetInventoryModel.manufacturer ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.model}: ${assetInventoryModel.model ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.site}: ${assetInventoryModel.siteName ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.building}: ${assetInventoryModel.buildingName ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.floor}: ${assetInventoryModel.floorName ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.department}: ${assetInventoryModel.departmentName ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.supplier}: ${assetInventoryModel.supplierName ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${'Remarks'.addTranslation}: ${assetInventoryModel.remarks ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - ], - ).expanded, - Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.start, - children: [ + ).expanded, 'delete_icon'.toSvgAsset().onPress(() { onDeletePress(); }), - 20.height, + ], + ), + 8.height, + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '${context.translation.assetNumber}: ${assetInventoryModel.assetNumber ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.serialNo}: ${assetInventoryModel.serialNo ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.manufacture}: ${assetInventoryModel.manufacturer ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.model}: ${assetInventoryModel.model ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.site}: ${assetInventoryModel.siteName ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.building}: ${assetInventoryModel.buildingName ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.floor}: ${assetInventoryModel.floorName ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.department}: ${assetInventoryModel.departmentName ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.supplier}: ${assetInventoryModel.supplierName ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${'Remarks'.addTranslation}: ${assetInventoryModel.remarks ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + ], + ).expanded, Container( decoration: BoxDecoration(color: AppColor.neutral100, borderRadius: BorderRadius.circular(15)), height: 115.toScreenHeight, width: 115.toScreenWidth, + margin: const EdgeInsets.only(top: 8), child: assetInventoryModel.photo != null && assetInventoryModel.photo!.isNotEmpty ? ClipRRect( borderRadius: BorderRadius.circular(8), @@ -100,8 +102,8 @@ class AssetDetailCardView extends StatelessWidget { : 'image_placeholder'.toSvgAsset().center, ) ], - ) + ), ], - ).toShadowContainer(context); + ).toShadowContainer(context, borderRadius: 20, padding: 12); } } diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart index f7cacee2..cb157b57 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart @@ -87,7 +87,7 @@ class _AssetInventoryDetailViewState extends State { style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), ], - ).paddingOnly(start: 16, end: 16, top: 16, bottom: 8).toShadowContainer(context, padding: 0); + ).toShadowContainer(context, padding: 12, borderRadius: 20); } Widget siteListCard(BuildContext context, SessionModel sessionModel) { @@ -155,6 +155,6 @@ class _AssetInventoryDetailViewState extends State { separatorBuilder: (cxt, index) => const Divider().defaultStyle(context), ), ], - ).toShadowContainer(context, padding: 12); + ).toShadowContainer(context, padding: 12, borderRadius: 20); } } 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 2440bbf6..4ee73a94 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 @@ -29,7 +29,7 @@ import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart'; import '../../../new_views/common_widgets/app_filled_button.dart'; import '../../../new_views/common_widgets/default_app_bar.dart'; -import 'asset_inventory_site_information_view.dart'; +import 'asset_inventory_site_information_page.dart'; class AssetInventoryFormView extends StatefulWidget { static const String id = "/asset-inventory-form"; @@ -92,254 +92,255 @@ class _AssetInventoryFormViewState extends State { child: Column( children: [ SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (widget.sessionTypeValue == 1 || widget.sessionTypeValue == 2) ...[ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, 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 (widget.sessionTypeValue == 1 || widget.sessionTypeValue == 2) ...[ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + 'Not Registered'.addTranslation.heading5(context), + AdvancedSwitch( + controller: registeredController, + activeColor: AppColor.green50.withOpacity(0.5), + inactiveColor: AppColor.neutral10, + thumb: CircleAvatar(backgroundColor: isRegistered == true ? AppColor.green50 : AppColor.neutral20), + borderRadius: const BorderRadius.all(Radius.circular(30)), + width: 42.toScreenWidth, + height: 24.toScreenHeight, + onChanged: (value) { + isRegistered = value; + resetData(); + setState(() {}); + }, + disabledOpacity: 1, + ), + ], + ), + 12.height, + ], - if (((!isRegistered && widget.sessionTypeValue == 2))) - AppFilledButton( - label: 'Search Asset'.addTranslation, - onPressed: () async { - resetData(isScanned: false); - setState(() {}); - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => SearchAssetView( - sessionId: widget.assetInventoryModel?.sessionId ?? 0, - ))).then((value) { - if (value != null) { - _pickedAssetModel = value; - // _pickedAssetModel?.assetNumber = _scannedAssetModel?.assetNumber; - // _pickedAssetModel?.assetId = _scannedAssetModel?.assetId; - // _pickedAssetModel?.status = _scannedAssetModel?.status; + 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, + ], - _scannedAssetModel = _scannedAssetModel?.mergeWith(_pickedAssetModel) ?? _pickedAssetModel; + if (((!isRegistered && widget.sessionTypeValue == 2))) ...[ + AppFilledButton( + label: 'Search Asset'.addTranslation, + onPressed: () async { + resetData(isScanned: false); + setState(() {}); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SearchAssetView( + sessionId: widget.assetInventoryModel?.sessionId ?? 0, + ))).then((value) { + if (value != null) { + _pickedAssetModel = value; + // _pickedAssetModel?.assetNumber = _scannedAssetModel?.assetNumber; + // _pickedAssetModel?.assetId = _scannedAssetModel?.assetId; + // _pickedAssetModel?.status = _scannedAssetModel?.status; - populateFormValues(); - setState(() {}); - } + _scannedAssetModel = _scannedAssetModel?.mergeWith(_pickedAssetModel) ?? _pickedAssetModel; - ///Need to assign the values - }); - }, - ).paddingOnly(bottom: 12), + populateFormValues(); + setState(() {}); + } - AppTextFormField( - labelText: context.translation.serialNo, - backgroundColor: AppColor.fieldBgColor(context), - controller: _serialNoController, - textAlign: TextAlign.center, - showShadow: false, - labelStyle: AppTextStyles.textFieldLabelStyle, - onChange: (value) { - if (value != _scannedAssetModel?.serialNo) { - _scannedAssetModel?.newSerialNo = value; - // setState(() {}); - } - }, - style: Theme.of(context).textTheme.titleMedium, - ), - 12.height, - LookUpAutoCompleteField( - clearAfterPick: false, - forAssetName: true, - onChanged: (value) { - _scannedAssetModel?.newAssetNameId = null; - _scannedAssetModel?.newAssetNameText = value; - }, - initialValue: _scannedAssetModel?.assetName ?? "", - label: 'Asset Name'.addTranslation, - onPick: (value) { - _scannedAssetModel?.newAssetNameText = null; - _scannedAssetModel?.assetName = value.name; - _scannedAssetModel?.newAssetNameId = value.id; - setState(() {}); - }, - ), - 12.height, - //Asset Name.. - LookUpAutoCompleteField( - clearAfterPick: false, - isManufacturer: true, - initialValue: _scannedAssetModel?.manufacturer ?? "", - label: 'Manufacturer'.addTranslation, - onChanged: (value) { - _scannedAssetModel?.newManufacturerId = null; - _scannedAssetModel?.newManufacturerName = value; - }, - onPick: (value) { - _scannedAssetModel?.newManufacturerName = null; - _scannedAssetModel?.manufacturer = value.name; - _scannedAssetModel?.newManufacturerId = value.id; + ///Need to assign the values + }); + }, + ), + 12.height, + ], + AppTextFormField( + labelText: context.translation.serialNo, + backgroundColor: AppColor.fieldBgColor(context), + controller: _serialNoController, + textAlign: TextAlign.center, + showShadow: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + onChange: (value) { + if (value != _scannedAssetModel?.serialNo) { + _scannedAssetModel?.newSerialNo = value; + // setState(() {}); + } + }, + style: Theme.of(context).textTheme.titleMedium, + ), + 12.height, + LookUpAutoCompleteField( + clearAfterPick: false, + forAssetName: true, + onChanged: (value) { + _scannedAssetModel?.newAssetNameId = null; + _scannedAssetModel?.newAssetNameText = value; + }, + initialValue: _scannedAssetModel?.assetName ?? "", + label: 'Asset Name'.addTranslation, + onPick: (value) { + _scannedAssetModel?.newAssetNameText = null; + _scannedAssetModel?.assetName = value.name; + _scannedAssetModel?.newAssetNameId = value.id; + setState(() {}); + }, + ), + 12.height, + //Asset Name.. + LookUpAutoCompleteField( + clearAfterPick: false, + isManufacturer: true, + initialValue: _scannedAssetModel?.manufacturer ?? "", + label: 'Manufacturer'.addTranslation, + onChanged: (value) { + _scannedAssetModel?.newManufacturerId = null; + _scannedAssetModel?.newManufacturerName = value; + }, + onPick: (value) { + _scannedAssetModel?.newManufacturerName = null; + _scannedAssetModel?.manufacturer = value.name; + _scannedAssetModel?.newManufacturerId = value.id; - setState(() {}); - }, - ), - 12.height, - LookUpAutoCompleteField( - clearAfterPick: false, - isManufacturer: false, - initialValue: _scannedAssetModel?.model ?? "", - label: 'Model'.addTranslation, - onChanged: (value) { - _scannedAssetModel?.newModelId = null; - _scannedAssetModel?.newModelName = value; - }, - onPick: (value) { - _scannedAssetModel?.newModelName = null; - _scannedAssetModel?.model = value.name; - _scannedAssetModel?.newModelId = value.id; - setState(() {}); - }, - ), + setState(() {}); + }, + ), + 12.height, + LookUpAutoCompleteField( + clearAfterPick: false, + isManufacturer: false, + initialValue: _scannedAssetModel?.model ?? "", + label: 'Model'.addTranslation, + onChanged: (value) { + _scannedAssetModel?.newModelId = null; + _scannedAssetModel?.newModelName = value; + }, + onPick: (value) { + _scannedAssetModel?.newModelName = null; + _scannedAssetModel?.model = value.name; + _scannedAssetModel?.newModelId = value.id; + setState(() {}); + }, + ), - 12.height, + 12.height, - LookUpAutoCompleteField( - clearAfterPick: false, - forSupplier: true, - initialValue: _scannedAssetModel?.supplierName ?? "", - label: context.translation.supplier, - onChanged: (value) { - _scannedAssetModel?.newSupplierId = null; - _scannedAssetModel?.newSupplierName = value; - }, - onPick: (value) { - _scannedAssetModel?.newSupplierName = null; - _scannedAssetModel?.supplierName = value.name; - _scannedAssetModel?.newSupplierId = value.id; - setState(() {}); - }, - ), - // 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, - siteInfoContainer(label: context.translation.site, value: _scannedAssetModel?.siteName ?? '-'), - 12.height, - siteInfoContainer(label: context.translation.building, value: _scannedAssetModel?.buildingName ?? '-'), - 12.height, - siteInfoContainer(label: context.translation.floor, value: _scannedAssetModel?.floorName ?? '-'), - 12.height, - siteInfoContainer(label: context.translation.department, value: _scannedAssetModel?.departmentName ?? '-'), - 12.height, - siteInfoContainer(label: context.translation.room, value: _scannedAssetModel?.roomName ?? '-'), - 12.height, - if (_scannedAssetModel?.status != null && _scannedAssetModel!.status!.isNotEmpty) classificationWidget(label: _scannedAssetModel?.status), - 12.height, - Text( - 'Asset Photo'.addTranslation, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.white936), - ), - 12.height, - attachments.isEmpty - ? AttachmentPicker( - label: context.translation.attachImage, - attachment: attachments, - buttonColor: AppColor.black10, - onlyImages: true, - onChange: (value) { + LookUpAutoCompleteField( + clearAfterPick: false, + forSupplier: true, + initialValue: _scannedAssetModel?.supplierName ?? "", + label: context.translation.supplier, + onChanged: (value) { + _scannedAssetModel?.newSupplierId = null; + _scannedAssetModel?.newSupplierName = value; + }, + onPick: (value) { + _scannedAssetModel?.newSupplierName = null; + _scannedAssetModel?.supplierName = value.name; + _scannedAssetModel?.newSupplierId = value.id; setState(() {}); }, - buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120), - ) - : MultiFilesPickerItem( - file: File(attachments.first.name ?? ''), - enabled: true, - onRemoveTap: (file) { - setState(() { - attachments.clear(); - }); + ), + // 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, + siteInfoContainer(label: context.translation.site, value: _scannedAssetModel?.siteName ?? '-'), + 12.height, + siteInfoContainer(label: context.translation.building, value: _scannedAssetModel?.buildingName ?? '-'), + 12.height, + siteInfoContainer(label: context.translation.floor, value: _scannedAssetModel?.floorName ?? '-'), + 12.height, + siteInfoContainer(label: context.translation.department, value: _scannedAssetModel?.departmentName ?? '-'), + 12.height, + siteInfoContainer(label: context.translation.room, value: _scannedAssetModel?.roomName ?? '-'), + 12.height, + if (_scannedAssetModel?.status != null && _scannedAssetModel!.status!.isNotEmpty) classificationWidget(label: _scannedAssetModel?.status), + 12.height, + Text( + 'Asset Photo'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.white936), + ), + 12.height, + attachments.isEmpty + ? AttachmentPicker( + label: context.translation.attachImage, + attachment: attachments, + buttonColor: AppColor.black10, + onlyImages: true, + onChange: (value) { + setState(() {}); + }, + buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120), + ) + : MultiFilesPickerItem( + file: File(attachments.first.name ?? ''), + enabled: true, + onRemoveTap: (file) { + setState(() { + attachments.clear(); + }); + }, + ), + 12.height, + AppTextFormField( + backgroundColor: AppColor.fieldBgColor(context), + labelText: 'Remarks'.addTranslation, + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + showShadow: false, + controller: _remarksController, + onSaved: (text) { + _scannedAssetModel?.remarks = text; + setState(() {}); }, ), - 12.height, - AppTextFormField( - backgroundColor: AppColor.fieldBgColor(context), - labelText: 'Remarks'.addTranslation, - labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), - alignLabelWithHint: true, - textInputType: TextInputType.multiline, - showShadow: false, - controller: _remarksController, - onSaved: (text) { - _scannedAssetModel?.remarks = text; - setState(() {}); - }, - ), - // 100.height, - ], - ).toShadowContainer(context).paddingOnly(top: 20, start: 16, end: 16), - ).expanded, - 10.height, + // 100.height, + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12)) + .expanded, FooterActionButton.footerContainer( context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: context.translation.submitRequest, maxWidth: true, onPressed: _onSubmit), @@ -438,7 +439,7 @@ class _AssetInventoryFormViewState extends State { Navigator.pushReplacement( context, MaterialPageRoute( - builder: (contxt) => SiteInformationView( + builder: (contxt) => SiteInformationPage( sessionModel: SessionModel(id: int.tryParse(widget.assetInventoryModel?.sessionId?.toString() ?? '') ?? 0), ))); } else { 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 284a9d0f..88e21b07 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/asset_inventory_site_information_view.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_site_information_page.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; @@ -66,62 +66,57 @@ class _AssetInventoryPageState extends State { body: Consumer(builder: (context, provider, child) { return DefaultTabController( length: 2, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight), - decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.white10, borderRadius: BorderRadius.circular(10)), - child: TabBar( - padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth), - labelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, - unselectedLabelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, - unselectedLabelStyle: AppTextStyles.bodyText, - labelStyle: AppTextStyles.bodyText, - indicatorPadding: EdgeInsets.zero, - indicatorSize: TabBarIndicatorSize.tab, - dividerColor: Colors.transparent, - indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)), - onTap: (index) {}, - tabs: [ - Tab(text: 'Request Details'.addTranslation, height: 57.toScreenHeight), - Tab( - text: - '${'Scan Assets'.addTranslation} ${provider.assetInventoryResponse?.totalRows != null && provider.assetInventoryResponse!.totalRows! > 0 ? '(${provider.assetInventoryResponse?.totalRows})' : ''}', - height: 57.toScreenHeight), + child: provider.isLoading + ? const CircularProgressIndicator(color: AppColor.primary10).center + : Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight), + decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.white10, borderRadius: BorderRadius.circular(10)), + child: TabBar( + padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth), + labelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, + unselectedLabelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, + unselectedLabelStyle: AppTextStyles.bodyText, + labelStyle: AppTextStyles.bodyText, + indicatorPadding: EdgeInsets.zero, + indicatorSize: TabBarIndicatorSize.tab, + dividerColor: Colors.transparent, + indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)), + onTap: (index) {}, + tabs: [ + Tab(text: 'Request Details'.addTranslation, height: 57.toScreenHeight), + Tab( + text: + '${'Scan Assets'.addTranslation} ${provider.assetInventoryResponse?.totalRows != null && provider.assetInventoryResponse!.totalRows! > 0 ? '(${provider.assetInventoryResponse?.totalRows})' : ''}', + height: 57.toScreenHeight), + ], + ), + ), + TabBarView( + children: [ + AssetInventoryDetailView(sessionModel: provider.sessionModel ?? SessionModel()), + AssetInventoryScanAssetView(sessionId: provider.sessionModel?.id ?? 0), + ], + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Scan Assets'.addTranslation, + onPressed: () => _scanAsset(provider: provider), + // buttonColor: AppColor.primary10, + ), + ) ], ), - ), - 12.height, - TabBarView( - children: [ - provider.isLoading - ? const CircularProgressIndicator(color: AppColor.primary10).center - : AssetInventoryDetailView( - sessionModel: provider.sessionModel ?? SessionModel(), - ), - AssetInventoryScanAssetView( - sessionId: provider.sessionModel?.id ?? 0, - ), - ], - ).expanded, - FooterActionButton.footerContainer( - context: context, - child: AppFilledButton( - buttonColor: AppColor.primary10, - label: 'Scan Assets'.addTranslation, - onPressed: () => _scanAsset(provider: provider), - // buttonColor: AppColor.primary10, - ), - ).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0), - ], - ), ); })); } Future _scanAsset({required AssetInventoryProvider provider}) async { provider.siteFilterAssetList.clear(); - Navigator.push(context, MaterialPageRoute(builder: (contxt) => SiteInformationView(sessionModel: provider.sessionModel ?? SessionModel()))); + Navigator.push(context, MaterialPageRoute(builder: (contxt) => SiteInformationPage(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 c7f5050b..4bf38915 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 @@ -48,9 +48,7 @@ class _AssetInventoryScanAssetViewState extends State( onNotification: (scrollInfo) { - if (!provider.isNextPageLoading && - provider.nextPage && - scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) { + if (!provider.isNextPageLoading && provider.nextPage && scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) { getAssetList(loadMore: true); } return false; @@ -84,48 +82,48 @@ class _AssetInventoryScanAssetViewState extends State( - // 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), - // ), - // ); - // }, - // ); - // } +// 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_page.dart similarity index 84% rename from lib/modules/asset_inventory_module/pages/asset_inventory_site_information_view.dart rename to lib/modules/asset_inventory_module/pages/asset_inventory_site_information_page.dart index 6374fb56..50266f40 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_site_information_view.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_site_information_page.dart @@ -28,16 +28,16 @@ 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 { +class SiteInformationPage extends StatefulWidget { SessionModel sessionModel; - SiteInformationView({Key? key, required this.sessionModel}) : super(key: key); + SiteInformationPage({Key? key, required this.sessionModel}) : super(key: key); @override - State createState() => _SiteInformationViewState(); + State createState() => _SiteInformationPageState(); } -class _SiteInformationViewState extends State { +class _SiteInformationPageState extends State { AssetInventoryModel assetInventoryModel = AssetInventoryModel(); bool showMarkAsComplete = false; @@ -56,45 +56,49 @@ class _SiteInformationViewState extends State { 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), + body: 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: Column( children: [ - siteInfoCard(context, widget.sessionModel), - 12.height, - assetDetailList(), - 8.height, + AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Add Asset'.addTranslation, + onPressed: () => _addAsset(), + // buttonColor: AppColor.primary10, + ), + if (showMarkAsComplete) ...[ + 12.height, + AppFilledButton( + buttonColor: AppColor.green70, + label: 'Mark as completed'.addTranslation, + onPressed: () => _markAsCompleted(), + // buttonColor: AppColor.primary10, + ) + ] ], - ).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, - // ), - // ), - ], - ), + ), + // FooterActionButton.footerContainer( + // context: context, + // child: AppFilledButton( + // buttonColor: AppColor.green70, + // label: 'Mark as completed'.addTranslation, + // onPressed: () => _markAsCompleted(), + // // buttonColor: AppColor.primary10, + // ), + // ), + ], )); } @@ -185,7 +189,6 @@ class _SiteInformationViewState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - 12.height, SingleItemDropDownMenu( context: context, title: context.translation.site, @@ -202,7 +205,7 @@ class _SiteInformationViewState extends State { setState(() {}); }, ), - 8.height, + 12.height, SingleItemDropDownMenu( context: context, title: context.translation.building, @@ -219,7 +222,7 @@ class _SiteInformationViewState extends State { setState(() {}); }, ), - 8.height, + 12.height, SingleItemDropDownMenu( context: context, title: context.translation.floor, @@ -235,7 +238,7 @@ class _SiteInformationViewState extends State { setState(() {}); }, ), - 8.height, + 12.height, SingleItemDropDownMenu( context: context, title: context.translation.department, @@ -253,7 +256,7 @@ class _SiteInformationViewState extends State { getAssetFilteredList(); }, ), - 8.height, + 12.height, SingleItemDropDownMenu( context: context, title: context.translation.room, @@ -271,9 +274,8 @@ class _SiteInformationViewState extends State { } }, ), - 8.height, ], - ).toShadowContainer(context); + ).toShadowContainer(context, borderRadius: 20, padding: 12); } Future validateRequest() async { diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index d7fb13c4..821567ac 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -52,7 +52,9 @@ class _MyRequestsPageState extends State { if (context.settingProvider.isUserFlowMedical) { requestsList.add(Request(7, 'Recall and Alert')); } - requestsList.add(Request(8, 'Inventory Session'.addTranslation)); + if (Provider.of(context, listen: false).user!.type != UsersTypes.normal_user) { + requestsList.add(Request(8, 'Inventory Session'.addTranslation)); + } _provider = Provider.of(context, listen: false); _provider!.reset(); WidgetsBinding.instance.addPostFrameCallback((_) { diff --git a/lib/views/widgets/fullscreen_dialogs/selection_fullscreen_dialog.dart b/lib/views/widgets/fullscreen_dialogs/selection_fullscreen_dialog.dart index ce08754f..b7227dda 100644 --- a/lib/views/widgets/fullscreen_dialogs/selection_fullscreen_dialog.dart +++ b/lib/views/widgets/fullscreen_dialogs/selection_fullscreen_dialog.dart @@ -87,9 +87,7 @@ class _SelectionBottomSheetState extends State(0), - backgroundColor: WidgetStateProperty.all( - AppColor.fieldBgColor(context), // Your custom background color - ), + backgroundColor: WidgetStateProperty.all(context.isDark ? AppColor.neutral120 : null), leading: Icon(Icons.search, color: AppColor.iconColor(context)), textStyle: WidgetStateProperty.all( TextStyle(color: AppColor.textColor(context), fontSize: 16.0), From aae42ddb27a33d7d5ea5a4d93e19f2803d01250c Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Sun, 12 Oct 2025 10:17:46 +0300 Subject: [PATCH 06/11] Apk Provided to QA, UAT v4 --- lib/controllers/api_routes/urls.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index d74444a1..f8cc806a 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -4,11 +4,12 @@ class URLs { static const String appReleaseBuildNumber = "26"; // static const host1 = "https://atomsm.hmg.com"; // production url - static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url + static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static String _baseUrl = "$_host/mobile"; - static final String _baseUrl = "$_host/v3/mobile"; // new V3 apis + // static final String _baseUrl = "$_host/v3/mobile"; // new V3 apis + static final String _baseUrl = "$_host/v4/mobile"; // for asset inventory on UAT // static final String _baseUrl = "$_host/mobile"; // host local UAT // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM From f83109d5ca31306dcac18a5e949edac91c8c4334 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Sun, 12 Oct 2025 10:27:54 +0300 Subject: [PATCH 07/11] pagination fixes and --- lib/models/new_models/department.dart | 2 +- .../pages/asset_inventory_form_view.dart | 33 +++- ...asset_inventory_site_information_page.dart | 147 +++++++++--------- 3 files changed, 98 insertions(+), 84 deletions(-) diff --git a/lib/models/new_models/department.dart b/lib/models/new_models/department.dart index a2f23206..e48585da 100644 --- a/lib/models/new_models/department.dart +++ b/lib/models/new_models/department.dart @@ -38,7 +38,7 @@ class Department extends Base { String? departmentCode; // Now nullable dynamic departmentId; // Now nullable String? ntCode; // Now nullable - List? rooms; // Now nullable + List? rooms=[]; // Now nullable Department copyWith({ num? id, // Parameters are now nullable 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 4ee73a94..28a46706 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 @@ -426,7 +426,7 @@ class _AssetInventoryFormViewState extends State { _scannedAssetModel?.photo = fileName; } showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - assetInventoryProvider.saveAssetInSession(model: _scannedAssetModel).then((success) { + assetInventoryProvider.saveAssetInSession(model: _scannedAssetModel).then((success) async{ ///Need to use push and remove until... Navigator.pop(context); if (success) { @@ -436,12 +436,14 @@ class _AssetInventoryFormViewState extends State { AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); allRequestsProvider.reset(); allRequestsProvider.getAllRequests(context, typeTransaction: 8); - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (contxt) => SiteInformationPage( - sessionModel: SessionModel(id: int.tryParse(widget.assetInventoryModel?.sessionId?.toString() ?? '') ?? 0), - ))); + getAssetFilteredList(); + Navigator.pop(context); + // Navigator.pushReplacement( + // context, + // MaterialPageRoute( + // builder: (contxt) => SiteInformationPage( + // sessionModel: SessionModel(id: int.tryParse(widget.assetInventoryModel?.sessionId?.toString() ?? '') ?? 0), + // ))); } else { log('api error...'); } @@ -459,4 +461,21 @@ class _AssetInventoryFormViewState extends State { _remarksController.clear(); registeredController?.dispose(); } + + + Future getAssetFilteredList({bool loadMore = false}) async { + AssetInventoryProvider provider = Provider.of(context, listen: false); + Map payload = { + "sessionId": widget.assetInventoryModel?.sessionId, + "siteId": widget.assetInventoryModel?.site?.id, + "buildingId": widget.assetInventoryModel?.building?.id, + "floorId": widget.assetInventoryModel?.floor?.id, + "departmentId": widget.assetInventoryModel?.department?.id, + "roomId": widget.assetInventoryModel?.room?.id, + }; + await provider.getInventoryDetailsByFilter(payload: payload, loadMore: loadMore); + provider.getAssetsInSession( + sessionId: (widget.assetInventoryModel?.sessionId ?? 0).toInt(), + ); + } } diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_site_information_page.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_site_information_page.dart index 50266f40..11dcc31b 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_site_information_page.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_site_information_page.dart @@ -40,10 +40,17 @@ class SiteInformationPage extends StatefulWidget { class _SiteInformationPageState extends State { AssetInventoryModel assetInventoryModel = AssetInventoryModel(); bool showMarkAsComplete = false; + final ScrollController _scrollController = ScrollController(); @override void initState() { super.initState(); + _scrollController.addListener(() { + final provider = Provider.of(context, listen: false); + if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent && !provider.isNextPageLoading && provider.nextPage) { + getAssetFilteredList(loadMore: true); + } + }); } final GlobalKey _scaffoldKey = GlobalKey(); @@ -51,55 +58,48 @@ class _SiteInformationPageState extends State { @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), + key: _scaffoldKey, + appBar: DefaultAppBar( + title: 'Inventory Session Request'.addTranslation, + titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + body: Column( + children: [ + ListView( + controller: _scrollController, + padding: const EdgeInsets.only(left: 16, right: 16, top: 16), + children: [ + siteInfoCard(context, widget.sessionModel), + 12.height, + assetDetailList(), + 8.height, + ], + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: Column( children: [ - siteInfoCard(context, widget.sessionModel), - 12.height, - assetDetailList(), - 8.height, - ], - ).expanded, - FooterActionButton.footerContainer( - context: context, - child: Column( - children: [ + AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Add Asset'.addTranslation, + onPressed: () => _addAsset(), + // buttonColor: AppColor.primary10, + ), + if (showMarkAsComplete) ...[ + 12.height, AppFilledButton( - buttonColor: AppColor.primary10, - label: 'Add Asset'.addTranslation, - onPressed: () => _addAsset(), + buttonColor: AppColor.green70, + label: 'Mark as completed'.addTranslation, + onPressed: () => _markAsCompleted(), // buttonColor: AppColor.primary10, - ), - if (showMarkAsComplete) ...[ - 12.height, - AppFilledButton( - buttonColor: AppColor.green70, - label: 'Mark as completed'.addTranslation, - onPressed: () => _markAsCompleted(), - // buttonColor: AppColor.primary10, - ) - ] - ], - ), + ) + ] + ], ), - // FooterActionButton.footerContainer( - // context: context, - // child: AppFilledButton( - // buttonColor: AppColor.green70, - // label: 'Mark as completed'.addTranslation, - // onPressed: () => _markAsCompleted(), - // // buttonColor: AppColor.primary10, - // ), - // ), - ], - )); + ), + ], + ), + ); } void _addAsset() async { @@ -130,7 +130,6 @@ class _SiteInformationPageState extends State { 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); @@ -148,38 +147,32 @@ class _SiteInformationPageState extends State { return Consumer( builder: (context, provider, _) { if (provider.isLoading) { - return SizedBox(height: 300.toScreenHeight, child: const CircularProgressIndicator(color: AppColor.primary10).center); + 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; + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + // Keep non-scrollable, parent handles scroll + itemCount: assets.length, + itemBuilder: (context, index) { + return AssetDetailCardView( + assetInventoryModel: assets[index], + onDeletePress: () async { + await provider.deleteAssetISession(id: assets[index].id ?? 0).then((success) async { + if (success) { + await getAssetFilteredList(); + await provider.getAssetsInSession(sessionId: widget.sessionModel.id ?? 0); + } + }); + }, + ); }, - 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, - ), + separatorBuilder: (context, index) => 12.height, ); }, ); @@ -253,7 +246,9 @@ class _SiteInformationPageState extends State { assetInventoryModel.room = null; showMarkAsComplete = true; setState(() {}); - getAssetFilteredList(); + if (assetInventoryModel.department != null && assetInventoryModel.department!.rooms!.isEmpty) { + getAssetFilteredList(); + } }, ), 12.height, From d0565a321a806fb38f8e7eaa7713e3079941756c Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Sun, 12 Oct 2025 15:12:32 +0300 Subject: [PATCH 08/11] asset number free text field added for existing project and manual project not registered --- lib/controllers/api_routes/urls.dart | 8 ++++---- .../models/asset_inventory_model.dart | 1 + .../pages/asset_inventory_form_view.dart | 20 +++++++++++++++---- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index f8cc806a..f2767383 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -4,12 +4,12 @@ class URLs { static const String appReleaseBuildNumber = "26"; // static const host1 = "https://atomsm.hmg.com"; // production url - // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + static const host1 = "https://atomsmdev.hmg.com"; // local DEV url + // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static String _baseUrl = "$_host/mobile"; - // static final String _baseUrl = "$_host/v3/mobile"; // new V3 apis - static final String _baseUrl = "$_host/v4/mobile"; // for asset inventory on UAT + static final String _baseUrl = "$_host/v3/mobile"; // new V3 apis + // static final String _baseUrl = "$_host/v4/mobile"; // for asset inventory on UAT // static final String _baseUrl = "$_host/mobile"; // host local UAT // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM 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 0498b95a..a07d980a 100644 --- a/lib/modules/asset_inventory_module/models/asset_inventory_model.dart +++ b/lib/modules/asset_inventory_module/models/asset_inventory_model.dart @@ -219,6 +219,7 @@ class AssetInventoryModel { 'newSerialNo': newSerialNo, 'newAssetNameId': newAssetNameId, 'newAssetNameText': newAssetNameText, + 'newAssetNumber': newAssetNumber, 'newModelId': newModelId, 'newModelName': newModelName, 'newManufacturerId': newManufacturerId, 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 28a46706..de5cb11a 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 @@ -167,10 +167,6 @@ class _AssetInventoryFormViewState extends State { ))).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(); @@ -183,6 +179,22 @@ class _AssetInventoryFormViewState extends State { ), 12.height, ], + if (((isRegistered && widget.sessionTypeValue != 3)))...[ + AppTextFormField( + labelText: context.translation.assetNo, + backgroundColor: AppColor.fieldBgColor(context), + textAlign: TextAlign.center, + // controller: _assetNoController, + showShadow: false, + enable: true, + labelStyle: AppTextStyles.textFieldLabelStyle, + style: Theme.of(context).textTheme.titleMedium, + onChange: (value){ + _scannedAssetModel?.newAssetNumber = value; + }, + ), + 12.height, + ], AppTextFormField( labelText: context.translation.serialNo, backgroundColor: AppColor.fieldBgColor(context), From 866ec5754ed7f5ded1974f9ffd528c0195b5dfa6 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 23 Oct 2025 15:33:04 +0300 Subject: [PATCH 09/11] improvements --- lib/controllers/api_routes/urls.dart | 8 +++--- .../widgets/request_category_list.dart | 4 +-- .../pages/asset_inventory_detail_view.dart | 13 ++++++---- ....dart => inventory_session_item_view.dart} | 26 +++++++------------ .../requests/request_paginated_listview.dart | 4 +-- .../widgets/request_item_view_list.dart | 4 +-- 6 files changed, 28 insertions(+), 31 deletions(-) rename lib/modules/asset_inventory_module/pages/{inventory_seession_card.dart => inventory_session_item_view.dart} (77%) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index f2767383..f8cc806a 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -4,12 +4,12 @@ class URLs { static const String appReleaseBuildNumber = "26"; // static const host1 = "https://atomsm.hmg.com"; // production url - static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url + static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static String _baseUrl = "$_host/mobile"; - static final String _baseUrl = "$_host/v3/mobile"; // new V3 apis - // static final String _baseUrl = "$_host/v4/mobile"; // for asset inventory on UAT + // static final String _baseUrl = "$_host/v3/mobile"; // new V3 apis + static final String _baseUrl = "$_host/v4/mobile"; // for asset inventory on UAT // static final String _baseUrl = "$_host/mobile"; // host local UAT // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM diff --git a/lib/dashboard_latest/widgets/request_category_list.dart b/lib/dashboard_latest/widgets/request_category_list.dart index 9247fdbb..744958e5 100644 --- a/lib/dashboard_latest/widgets/request_category_list.dart +++ b/lib/dashboard_latest/widgets/request_category_list.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; -import 'package:test_sa/modules/asset_inventory_module/pages/inventory_seession_card.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart'; @@ -52,7 +52,7 @@ class RequestCategoryList extends StatelessWidget { case 7: return TaskRequestItemView(requestData: request); case 8: - return InventorySessionCard(requestData: request); + return InventorySessionItemView(requestData: request); default: return Container( height: 100, diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart index cb157b57..ae48817c 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart @@ -72,18 +72,16 @@ class _AssetInventoryDetailViewState extends State { '${'Session Name'.addTranslation}: ${sessionModel.sessionName?.cleanupWhitespace.capitalizeFirstOfEach}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), - - // 8.height, Text( - '${'Session Typ'.addTranslation}: ${sessionModel.sessionTypeName}', + '${'Session Typ'.addTranslation}: ${sessionModel.sessionTypeName}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - '${'Start Date:'.addTranslation}: ${sessionModel.startDate}', + '${'Start Date'.addTranslation}: ${sessionModel.startDate?.toServiceRequestDetailsFormat ?? ""}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( - '${'End Date:'.addTranslation}: ${sessionModel.endDate}', + '${'End Date'.addTranslation}: ${sessionModel.endDate?.toServiceRequestDetailsFormat ?? ""}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), ], @@ -97,6 +95,11 @@ class _AssetInventoryDetailViewState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text( + "Sites Information", + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 8.height, ListView.separated( physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, diff --git a/lib/modules/asset_inventory_module/pages/inventory_seession_card.dart b/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart similarity index 77% rename from lib/modules/asset_inventory_module/pages/inventory_seession_card.dart rename to lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart index 3002a3c6..8d9abfdd 100644 --- a/lib/modules/asset_inventory_module/pages/inventory_seession_card.dart +++ b/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart @@ -10,12 +10,12 @@ import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_pag import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart'; -class InventorySessionCard extends StatelessWidget { +class InventorySessionItemView extends StatelessWidget { final Data? requestData; final RequestsDetails? requestDetails; final bool showShadow; - const InventorySessionCard({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); + const InventorySessionItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); @override Widget build(BuildContext context) { @@ -47,9 +47,9 @@ class InventorySessionCard extends StatelessWidget { ), 8.height, (requestData?.typeTransaction ?? context.translation.taskRequest).heading5(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), + infoWidget(label: context.translation.requestType, value: requestData?.sessionType, context: context), + infoWidget(label: 'No of Assets'.addTranslation, value: requestData?.numberOfAssets != null ? requestData?.numberOfAssets.toString() : '-', context: context), + infoWidget(label: 'No of Sites'.addTranslation, value: requestData?.numberOfSites != null ? requestData?.numberOfSites.toString() : '-', context: context), 8.height, Row( mainAxisSize: MainAxisSize.min, @@ -64,10 +64,7 @@ class InventorySessionCard extends StatelessWidget { ), ], ).toShadowContainer(context, withShadow: showShadow).onPress(() async { - Navigator.of(context).push(MaterialPageRoute( - builder: (_) => AssetInventoryPage( - sessionId: requestData!.id!, - ))); + Navigator.of(context).push(MaterialPageRoute(builder: (_) => AssetInventoryPage(sessionId: requestData!.id!))); }); } return Column( @@ -97,9 +94,9 @@ class InventorySessionCard extends StatelessWidget { ), 8.height, (requestDetails?.nameOfType ?? context.translation.taskRequest).heading5(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), + infoWidget(label: context.translation.requestType, value: requestDetails?.sessionType, context: context), + infoWidget(label: 'No of Assets'.addTranslation, value: requestDetails?.numberOfAssets != null ? requestDetails?.numberOfAssets.toString() : '-', context: context), + infoWidget(label: 'No of Sites'.addTranslation, value: requestDetails?.numberOfSites != null ? requestDetails?.numberOfSites.toString() : '-', context: context), 8.height, Row( mainAxisSize: MainAxisSize.min, @@ -114,10 +111,7 @@ class InventorySessionCard extends StatelessWidget { ), ], ).toShadowContainer(context, withShadow: showShadow).onPress(() async { - Navigator.of(context).push(MaterialPageRoute( - builder: (_) => AssetInventoryPage( - sessionId: requestDetails!.id!, - ))); + Navigator.of(context).push(MaterialPageRoute(builder: (_) => AssetInventoryPage(sessionId: requestDetails!.id!))); }); } diff --git a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart index d27e9a4d..16ac1c20 100644 --- a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart +++ b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; -import 'package:test_sa/modules/asset_inventory_module/pages/inventory_seession_card.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart'; @@ -62,7 +62,7 @@ class RequestPaginatedListview extends StatelessWidget { case 7: return TaskRequestItemView(requestData: request); case 8: - return InventorySessionCard(requestData: request); + return InventorySessionItemView(requestData: request); default: return Container( height: 100, diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart index 03c7ea37..5031a033 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 @@ -4,7 +4,7 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/all_requests_and_count_model.dart'; -import 'package:test_sa/modules/asset_inventory_module/pages/inventory_seession_card.dart'; +import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/gas_refill_item_view.dart'; @@ -44,7 +44,7 @@ class RequestItemViewList extends StatelessWidget { case 7: return TaskRequestItemView(requestDetails: list[index]); case 8: - return InventorySessionCard(requestDetails: list[index]); + return InventorySessionItemView(requestDetails: list[index]); default: Container( height: 100, From 549e5f4fd978f8077a9506ebde02cb8cc12bccc1 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Thu, 23 Oct 2025 16:11:36 +0300 Subject: [PATCH 10/11] ATOMS-1305 bug fixes --- .../pages/asset_inventory_form_view.dart | 61 ++++++------------- 1 file changed, 17 insertions(+), 44 deletions(-) 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 de5cb11a..d7acf11c 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 @@ -53,10 +53,6 @@ class _AssetInventoryFormViewState extends State { ValueNotifier? registeredController; bool isRegistered = false; - // TextEditingController _assetModelController = TextEditingController(); - // TextEditingController _assetManufacturerController = TextEditingController(); - // TextEditingController _assetSupplierController = TextEditingController(); - final List attachments = []; @override @@ -179,17 +175,16 @@ class _AssetInventoryFormViewState extends State { ), 12.height, ], - if (((isRegistered && widget.sessionTypeValue != 3)))...[ + if (((isRegistered && widget.sessionTypeValue != 3))) ...[ AppTextFormField( labelText: context.translation.assetNo, backgroundColor: AppColor.fieldBgColor(context), textAlign: TextAlign.center, - // controller: _assetNoController, showShadow: false, enable: true, labelStyle: AppTextStyles.textFieldLabelStyle, style: Theme.of(context).textTheme.titleMedium, - onChange: (value){ + onChange: (value) { _scannedAssetModel?.newAssetNumber = value; }, ), @@ -282,32 +277,19 @@ class _AssetInventoryFormViewState extends State { 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, - siteInfoContainer(label: context.translation.site, value: _scannedAssetModel?.siteName ?? '-'), - 12.height, - siteInfoContainer(label: context.translation.building, value: _scannedAssetModel?.buildingName ?? '-'), - 12.height, - siteInfoContainer(label: context.translation.floor, value: _scannedAssetModel?.floorName ?? '-'), - 12.height, - siteInfoContainer(label: context.translation.department, value: _scannedAssetModel?.departmentName ?? '-'), - 12.height, - siteInfoContainer(label: context.translation.room, value: _scannedAssetModel?.roomName ?? '-'), - 12.height, + if (!isRegistered) ...[ + 12.height, + siteInfoContainer(label: context.translation.site, value: _scannedAssetModel?.siteName ?? '-'), + 12.height, + siteInfoContainer(label: context.translation.building, value: _scannedAssetModel?.buildingName ?? '-'), + 12.height, + siteInfoContainer(label: context.translation.floor, value: _scannedAssetModel?.floorName ?? '-'), + 12.height, + siteInfoContainer(label: context.translation.department, value: _scannedAssetModel?.departmentName ?? '-'), + 12.height, + siteInfoContainer(label: context.translation.room, value: _scannedAssetModel?.roomName ?? '-'), + 12.height, + ], if (_scannedAssetModel?.status != null && _scannedAssetModel!.status!.isNotEmpty) classificationWidget(label: _scannedAssetModel?.status), 12.height, Text( @@ -438,24 +420,16 @@ class _AssetInventoryFormViewState extends State { _scannedAssetModel?.photo = fileName; } showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - assetInventoryProvider.saveAssetInSession(model: _scannedAssetModel).then((success) async{ + assetInventoryProvider.saveAssetInSession(model: _scannedAssetModel).then((success) async { ///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); - getAssetFilteredList(); + getAssetFilteredList(); Navigator.pop(context); - // Navigator.pushReplacement( - // context, - // MaterialPageRoute( - // builder: (contxt) => SiteInformationPage( - // sessionModel: SessionModel(id: int.tryParse(widget.assetInventoryModel?.sessionId?.toString() ?? '') ?? 0), - // ))); } else { log('api error...'); } @@ -474,7 +448,6 @@ class _AssetInventoryFormViewState extends State { registeredController?.dispose(); } - Future getAssetFilteredList({bool loadMore = false}) async { AssetInventoryProvider provider = Provider.of(context, listen: false); Map payload = { From 4f2cb42a3f1baa9c31191d822812195a2996e49d Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Sun, 26 Oct 2025 09:34:07 +0300 Subject: [PATCH 11/11] temporary server added. --- lib/controllers/api_routes/urls.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index f8cc806a..8b94e771 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -6,7 +6,8 @@ class URLs { // static const host1 = "https://atomsm.hmg.com"; // production url // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url static const host1 = "https://atomsmuat.hmg.com"; // local UAT url - + // static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url + // http://10.201.111.125:9495/v4/swagger/index.html // static String _baseUrl = "$_host/mobile"; // static final String _baseUrl = "$_host/v3/mobile"; // new V3 apis static final String _baseUrl = "$_host/v4/mobile"; // for asset inventory on UAT