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